diff --git a/patch/0001-i2c-mlxcpld-Update-module-license.patch b/patch/0001-i2c-mlxcpld-Update-module-license.patch index a80d1564d..e956bd44b 100644 --- a/patch/0001-i2c-mlxcpld-Update-module-license.patch +++ b/patch/0001-i2c-mlxcpld-Update-module-license.patch @@ -1,6 +1,7 @@ +From ff35f857e936ddd68635b390c789b203c7cbbbc2 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 10 Dec 2020 18:51:11 +0200 -Subject: 0001 i2c: mlxcpld: Update module license +Subject: [PATCH backport 5.10 001/182] i2c: mlxcpld: Update module license Update license to SPDX-License. @@ -53,5 +54,5 @@ index 71d7bae2cbca..dbd185368c38 100644 #include -- -2.17.1 +2.20.1 diff --git a/patch/0002-i2c-mlxcpld-Decrease-polling-time-for-performan.patch b/patch/0002-i2c-mlxcpld-Decrease-polling-time-for-performance-im.patch similarity index 86% rename from patch/0002-i2c-mlxcpld-Decrease-polling-time-for-performan.patch rename to patch/0002-i2c-mlxcpld-Decrease-polling-time-for-performance-im.patch index 8c5755b90..833508647 100644 --- a/patch/0002-i2c-mlxcpld-Decrease-polling-time-for-performan.patch +++ b/patch/0002-i2c-mlxcpld-Decrease-polling-time-for-performance-im.patch @@ -1,6 +1,7 @@ +From 12fe50acf879f7552616a539e7b4a580da809a7b Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 10 Dec 2020 18:51:12 +0200 -Subject: 0002 i2c: mlxcpld: Decrease polling time for +Subject: [PATCH backport 5.10 002/182] i2c: mlxcpld: Decrease polling time for performance improvement Decrease polling time 'MLXCPLD_I2C_POLL_TIME' from 2000 usec to 400 @@ -29,5 +30,5 @@ index dbd185368c38..9e45214d1eb6 100644 /* LPC I2C registers */ #define MLXCPLD_LPCI2C_CPBLTY_REG 0x0 -- -2.17.1 +2.20.1 diff --git a/patch/0003-i2c-mlxcpld-Add-support-for-I2C-bus-frequency-s.patch b/patch/0003-i2c-mlxcpld-Add-support-for-I2C-bus-frequency-settin.patch similarity index 95% rename from patch/0003-i2c-mlxcpld-Add-support-for-I2C-bus-frequency-s.patch rename to patch/0003-i2c-mlxcpld-Add-support-for-I2C-bus-frequency-settin.patch index 4aa3589d9..e33c56243 100644 --- a/patch/0003-i2c-mlxcpld-Add-support-for-I2C-bus-frequency-s.patch +++ b/patch/0003-i2c-mlxcpld-Add-support-for-I2C-bus-frequency-settin.patch @@ -1,7 +1,8 @@ +From 70a2f64a3d7b680a509c519015e4a46b6bc15ca4 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 6 Jan 2021 01:33:47 +0200 -Subject: 0003 i2c: mlxcpld: Add support for I2C bus frequency - setting +Subject: [PATCH backport 5.10 003/182] i2c: mlxcpld: Add support for I2C bus + frequency setting Add support for I2C bus frequency setting according to the specific system capability. This capability is obtained from CPLD frequency @@ -123,5 +124,5 @@ index 9e45214d1eb6..4e0b7c2882ce 100644 } -- -2.17.1 +2.20.1 diff --git a/patch/0004-i2c-mux-mlxcpld-Update-module-license.patch b/patch/0004-i2c-mux-mlxcpld-Update-module-license.patch index ed6c12647..726f12379 100644 --- a/patch/0004-i2c-mux-mlxcpld-Update-module-license.patch +++ b/patch/0004-i2c-mux-mlxcpld-Update-module-license.patch @@ -1,6 +1,8 @@ +From 9f63205197ecd85ef2f7e0c54c4aac5f7aecc9b8 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Fri, 22 Jan 2021 21:24:56 +0200 -Subject: 0004 i2c: mux: mlxcpld: Update module license +Subject: [PATCH backport 5.10 004/182] i2c: mux: mlxcpld: Update module + license Update license to SPDX-License. @@ -55,5 +57,5 @@ index 5ed55ca4fe93..53bce81cf5c9 100644 #include -- -2.17.1 +2.20.1 diff --git a/patch/0005-i2c-mux-mlxcpld-Move-header-file-out-of-x86-rea.patch b/patch/0005-i2c-mux-mlxcpld-Move-header-file-out-of-x86-realm.patch similarity index 88% rename from patch/0005-i2c-mux-mlxcpld-Move-header-file-out-of-x86-rea.patch rename to patch/0005-i2c-mux-mlxcpld-Move-header-file-out-of-x86-realm.patch index 33c53aaea..15ce3b531 100644 --- a/patch/0005-i2c-mux-mlxcpld-Move-header-file-out-of-x86-rea.patch +++ b/patch/0005-i2c-mux-mlxcpld-Move-header-file-out-of-x86-realm.patch @@ -1,7 +1,8 @@ +From 0f351fad0a71a2b6ec4709af908e621a90649634 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Fri, 22 Jan 2021 21:24:58 +0200 -Subject: 0005 i2c: mux: mlxcpld: Move header file out of x86 - realm +Subject: [PATCH backport 5.10 005/182] i2c: mux: mlxcpld: Move header file out + of x86 realm Move out header file from include/linux/platform_data/x86/ to include/linux/platform_data/, since it does not depend on x86 @@ -35,5 +36,5 @@ similarity index 100% rename from include/linux/platform_data/x86/mlxcpld.h rename to include/linux/platform_data/mlxcpld.h -- -2.17.1 +2.20.1 diff --git a/patch/0006-i2c-mux-mlxcpld-Convert-driver-to-platform-driv.patch b/patch/0006-i2c-mux-mlxcpld-Convert-driver-to-platform-driver.patch similarity index 97% rename from patch/0006-i2c-mux-mlxcpld-Convert-driver-to-platform-driv.patch rename to patch/0006-i2c-mux-mlxcpld-Convert-driver-to-platform-driver.patch index dc8aeba93..0eecfd1f6 100644 --- a/patch/0006-i2c-mux-mlxcpld-Convert-driver-to-platform-driv.patch +++ b/patch/0006-i2c-mux-mlxcpld-Convert-driver-to-platform-driver.patch @@ -1,8 +1,8 @@ +From de8fd8e73df9249c260d174c5e55b7af6b3d11f5 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 8 Feb 2021 22:16:01 +0200 -Subject: 0006 i2c: mux: mlxcpld: Convert driver to platform - driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 - Content-Transfer-Encoding: 8bit +Subject: [PATCH backport 5.10 006/182] i2c: mux: mlxcpld: Convert driver to + platform driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -181,5 +181,5 @@ index 3d894cfb19df..b53f1479272d 100644 MODULE_AUTHOR("Michael Shych (michaels@mellanox.com)"); MODULE_DESCRIPTION("Mellanox I2C-CPLD-MUX driver"); -- -2.17.1 +2.20.1 diff --git a/patch/0007-i2c-mux-mlxcpld-Prepare-mux-selection-infrastru.patch b/patch/0007-i2c-mux-mlxcpld-Prepare-mux-selection-infrastructure.patch similarity index 93% rename from patch/0007-i2c-mux-mlxcpld-Prepare-mux-selection-infrastru.patch rename to patch/0007-i2c-mux-mlxcpld-Prepare-mux-selection-infrastructure.patch index f21617d28..dc2b25934 100644 --- a/patch/0007-i2c-mux-mlxcpld-Prepare-mux-selection-infrastru.patch +++ b/patch/0007-i2c-mux-mlxcpld-Prepare-mux-selection-infrastructure.patch @@ -1,7 +1,8 @@ +From 36e27ec3550453192cdf3788a20f82d074122c58 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 8 Feb 2021 22:16:02 +0200 -Subject: 0007 i2c: mux: mlxcpld: Prepare mux selection - infrastructure for two-byte support +Subject: [PATCH backport 5.10 007/182] i2c: mux: mlxcpld: Prepare mux + selection infrastructure for two-byte support Allow to program register value zero to the mux register, which is required for word address mux register space support. @@ -84,5 +85,5 @@ index b53f1479272d..113ad84cdd94 100644 /* Create an adapter for each channel. */ for (num = 0; num < CPLD_MUX_MAX_NCHANS; num++) { -- -2.17.1 +2.20.1 diff --git a/patch/0008-i2c-mux-mlxcpld-Get-rid-of-adapter-numbers-enfo.patch b/patch/0008-i2c-mux-mlxcpld-Get-rid-of-adapter-numbers-enforceme.patch similarity index 92% rename from patch/0008-i2c-mux-mlxcpld-Get-rid-of-adapter-numbers-enfo.patch rename to patch/0008-i2c-mux-mlxcpld-Get-rid-of-adapter-numbers-enforceme.patch index a153d2427..d8557be1a 100644 --- a/patch/0008-i2c-mux-mlxcpld-Get-rid-of-adapter-numbers-enfo.patch +++ b/patch/0008-i2c-mux-mlxcpld-Get-rid-of-adapter-numbers-enforceme.patch @@ -1,7 +1,8 @@ +From a57efb1d682024397507e3d1f21455289ae2af67 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 8 Feb 2021 22:16:03 +0200 -Subject: 0008 i2c: mux: mlxcpld: Get rid of adapter numbers - enforcement +Subject: [PATCH backport 5.10 008/182] i2c: mux: mlxcpld: Get rid of adapter + numbers enforcement Do not set the argument 'force_nr' of i2c_mux_add_adapter() routine, instead provide argument 'chan_id'. @@ -67,5 +68,5 @@ index b08dcb183fca..f3cb628bb779 100644 int sel_reg_addr; }; -- -2.17.1 +2.20.1 diff --git a/patch/0009-i2c-mux-mlxcpld-Extend-driver-to-support-word-a.patch b/patch/0009-i2c-mux-mlxcpld-Extend-driver-to-support-word-addres.patch similarity index 94% rename from patch/0009-i2c-mux-mlxcpld-Extend-driver-to-support-word-a.patch rename to patch/0009-i2c-mux-mlxcpld-Extend-driver-to-support-word-addres.patch index d616ecc9c..7bd99a3b5 100644 --- a/patch/0009-i2c-mux-mlxcpld-Extend-driver-to-support-word-a.patch +++ b/patch/0009-i2c-mux-mlxcpld-Extend-driver-to-support-word-addres.patch @@ -1,7 +1,8 @@ +From 1436eab9059e8f2a137ca657cc133dd6aabfe7f0 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 8 Feb 2021 22:16:04 +0200 -Subject: 0009 i2c: mux: mlxcpld: Extend driver to support word - address space devices +Subject: [PATCH backport 5.10 009/182] i2c: mux: mlxcpld: Extend driver to + support word address space devices Extend driver to allow I2C routing control through CPLD devices with word address space. Till now only CPLD devices with byte address space @@ -111,5 +112,5 @@ index f3cb628bb779..341c7796e36b 100644 #endif /* _LINUX_I2C_MLXCPLD_H */ -- -2.17.1 +2.20.1 diff --git a/patch/0010-i2c-mux-mlxcpld-Extend-supported-mux-number.patch b/patch/0010-i2c-mux-mlxcpld-Extend-supported-mux-number.patch index c1b335ea1..7693e62ac 100644 --- a/patch/0010-i2c-mux-mlxcpld-Extend-supported-mux-number.patch +++ b/patch/0010-i2c-mux-mlxcpld-Extend-supported-mux-number.patch @@ -1,6 +1,8 @@ +From 3b78386d062ab776009356916ff5d82bd423cd8e Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 8 Feb 2021 22:16:05 +0200 -Subject: 0010 i2c: mux: mlxcpld: Extend supported mux number +Subject: [PATCH backport 5.10 010/182] i2c: mux: mlxcpld: Extend supported mux + number Allow to extend mux number supported by driver. Currently it is limited by eight, which is not enough for new coming @@ -51,5 +53,5 @@ index 10767ad4adb4..5e0672f9979b 100644 if (err) goto virt_reg_failed; -- -2.17.1 +2.20.1 diff --git a/patch/0011-i2c-mux-mlxcpld-Add-callback-to-notify-mux-crea.patch b/patch/0011-i2c-mux-mlxcpld-Add-callback-to-notify-mux-creation-.patch similarity index 91% rename from patch/0011-i2c-mux-mlxcpld-Add-callback-to-notify-mux-crea.patch rename to patch/0011-i2c-mux-mlxcpld-Add-callback-to-notify-mux-creation-.patch index 85d8c2047..61d942c82 100644 --- a/patch/0011-i2c-mux-mlxcpld-Add-callback-to-notify-mux-crea.patch +++ b/patch/0011-i2c-mux-mlxcpld-Add-callback-to-notify-mux-creation-.patch @@ -1,7 +1,8 @@ +From d07723d636eed0ac64b2903d2e5bc92af9abfe40 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 8 Feb 2021 22:16:06 +0200 -Subject: 0011 i2c: mux: mlxcpld: Add callback to notify mux - creation completion +Subject: [PATCH backport 5.10 011/182] i2c: mux: mlxcpld: Add callback to + notify mux creation completion Add notification to inform caller that mux objects array has been created. It allows to user, invoked platform device registration for @@ -55,5 +56,5 @@ index 341c7796e36b..68f5c5a9b172 100644 #endif /* _LINUX_I2C_MLXCPLD_H */ -- -2.17.1 +2.20.1 diff --git a/patch/0012-hwmon-mlxreg-fan-Add-support-for-fan-drawers-ca.patch b/patch/0012-hwmon-mlxreg-fan-Add-support-for-fan-drawers-capabil.patch similarity index 95% rename from patch/0012-hwmon-mlxreg-fan-Add-support-for-fan-drawers-ca.patch rename to patch/0012-hwmon-mlxreg-fan-Add-support-for-fan-drawers-capabil.patch index f47cd11c0..3ead7b7b0 100644 --- a/patch/0012-hwmon-mlxreg-fan-Add-support-for-fan-drawers-ca.patch +++ b/patch/0012-hwmon-mlxreg-fan-Add-support-for-fan-drawers-capabil.patch @@ -1,7 +1,8 @@ +From 868be8beaf13aefd82d53a6aa9d5c9644652e5f4 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 22 Mar 2021 19:22:37 +0200 -Subject: 0012 hwmon: (mlxreg-fan) Add support for fan drawers - capability and present registers +Subject: [PATCH backport 5.10 012/182] hwmon: (mlxreg-fan) Add support for fan + drawers capability and present registers Add support for fan drawer's capability and present registers in order to set mapping between the fan drawers and tachometers. Some systems @@ -130,5 +131,5 @@ index bd8f5a3aaad9..89fe7b9fe26b 100644 for (i = 0; i < MLXREG_FAN_SPEED_MIN_LEVEL; i++) fan->cooling_levels[i] = MLXREG_FAN_SPEED_MIN_LEVEL; -- -2.17.1 +2.20.1 diff --git a/patch/0013-hwmon-pmbus-shrink-code-and-remove-pmbus_do_rem.patch b/patch/0013-hwmon-pmbus-shrink-code-and-remove-pmbus_do_remove.patch similarity index 98% rename from patch/0013-hwmon-pmbus-shrink-code-and-remove-pmbus_do_rem.patch rename to patch/0013-hwmon-pmbus-shrink-code-and-remove-pmbus_do_remove.patch index 110a5026d..a33825f17 100644 --- a/patch/0013-hwmon-pmbus-shrink-code-and-remove-pmbus_do_rem.patch +++ b/patch/0013-hwmon-pmbus-shrink-code-and-remove-pmbus_do_remove.patch @@ -1,7 +1,7 @@ +From ab269af4b9fc3631547a09d9050b266a7b2fd113 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 26 Oct 2020 11:53:52 +0100 -Subject: 0013 hwmon: (pmbus) shrink code and remove - pmbus_do_remove() +Subject: [PATCH 13/66] hwmon: (pmbus) shrink code and remove pmbus_do_remove() The only action currently performed in pmbus_do_remove() is removing the debugfs hierarchy. We can schedule a devm action at probe time and remove @@ -150,10 +150,10 @@ index decbd07c6d6e..c7400d4f1bfa 100644 }; diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c -index da261d32450d..830003fe7024 100644 +index 2fb7540ee952..d6bbbb223871 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c -@@ -623,7 +623,6 @@ static struct i2c_driver ibm_cffps_driver = { +@@ -617,7 +617,6 @@ static struct i2c_driver ibm_cffps_driver = { .of_match_table = ibm_cffps_of_match, }, .probe_new = ibm_cffps_probe, @@ -342,7 +342,7 @@ index 4b2239a6afd3..329dc851fc59 100644 }; diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c -index a41fe06e0ad4..74060bc477cf 100644 +index 1c3e2a9453b1..60fbdb371332 100644 --- a/drivers/hwmon/pmbus/mp2975.c +++ b/drivers/hwmon/pmbus/mp2975.c @@ -758,7 +758,6 @@ static struct i2c_driver mp2975_driver = { diff --git a/patch/0015-mlxsw-core-Remove-critical-trip-points-from-the.patch b/patch/0015-mlxsw-core-Remove-critical-trip-points-from-thermal-.patch similarity index 96% rename from patch/0015-mlxsw-core-Remove-critical-trip-points-from-the.patch rename to patch/0015-mlxsw-core-Remove-critical-trip-points-from-thermal-.patch index 7c0a35232..600339762 100644 --- a/patch/0015-mlxsw-core-Remove-critical-trip-points-from-the.patch +++ b/patch/0015-mlxsw-core-Remove-critical-trip-points-from-thermal-.patch @@ -1,7 +1,8 @@ +From 2bea2ba313dd45240a0295de02762b2a2af2a18d Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Tue, 6 Apr 2021 15:27:33 +0300 -Subject: 0015 mlxsw: core: Remove critical trip points from - thermal zones +Subject: [PATCH backport 5.10 015/182] mlxsw: core: Remove critical trip + points from thermal zones Disable software thermal protection by removing critical trip points from all thermal zones. @@ -119,5 +120,5 @@ index ecd1856bef5e..5b37449d4b66 100644 tz->trips[trip].temp = temp; -- -2.17.1 +2.20.1 diff --git a/patch/0016-net-don-t-include-ethtool.h-from-netdevice.h.patch b/patch/0016-net-don-t-include-ethtool.h-from-netdevice.h.patch index d7d47f849..e025e2025 100644 --- a/patch/0016-net-don-t-include-ethtool.h-from-netdevice.h.patch +++ b/patch/0016-net-don-t-include-ethtool.h-from-netdevice.h.patch @@ -1,6 +1,8 @@ +From e8c1cb7fb9d5ab0cfcf496efa208dae75d25a789 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 20 Nov 2020 14:50:52 -0800 -Subject: 0016 net: don't include ethtool.h from netdevice.h +Subject: [PATCH backport 5.10 016/182] net: don't include ethtool.h from + netdevice.h linux/netdevice.h is included in very many places, touching any of its dependecies causes large incremental builds. @@ -99,7 +101,7 @@ index fd5c9cbe45b1..56d34be5e797 100644 #include #include diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c -index 3f759fae81fe..76d6cee81981 100644 +index a879200eaab0..5503eb028902 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -9,6 +9,7 @@ @@ -123,7 +125,7 @@ index 3b2cd28f962d..6cdd9efe8df3 100644 #include "ena_netdev.h" diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h -index 926cca9a0c83..1a7148041e3d 100644 +index 6da3efa289a3..b7f7d6f66633 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -10,6 +10,8 @@ @@ -136,7 +138,7 @@ index 926cca9a0c83..1a7148041e3d 100644 #include "aq_rss.h" #include "aq_hw.h" diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h -index 92f9f7f5240b..91d45a83b67a 100644 +index 34affd1de91d..b74884e6b8c6 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -20,6 +20,7 @@ @@ -148,7 +150,7 @@ index 92f9f7f5240b..91d45a83b67a 100644 #include #include diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c -index 23b80aa171dd..a217316228f4 100644 +index 819f9df9425c..883905db21a3 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c @@ -8,6 +8,7 @@ @@ -208,7 +210,7 @@ index cd8f9a481d73..d546993bda09 100644 #include "t4vf_common.h" diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c -index 7b44769bd87c..2fb197fd3daf 100644 +index c53a04313944..458e79b8d625 100644 --- a/drivers/net/ethernet/google/gve/gve_ethtool.c +++ b/drivers/net/ethernet/google/gve/gve_ethtool.c @@ -4,6 +4,7 @@ @@ -318,7 +320,7 @@ index 28bfe1ea9d94..131b2a53d261 100644 #include #include diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c -index e95c09dc2c30..81b22520ba78 100644 +index cb12d0171517..209ebe3f2569 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -1,6 +1,7 @@ @@ -354,7 +356,7 @@ index 2adcf24848a4..ab1e0fcccabb 100644 #include #include "rmnet_config.h" diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c -index 5ddb2dbb8572..e2e58493e115 100644 +index 081939cb420b..c339cf5339da 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -7,6 +7,7 @@ @@ -366,7 +368,7 @@ index 5ddb2dbb8572..e2e58493e115 100644 #include #include diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c -index 261e6e55a907..d17bbc75f5e7 100644 +index f2020be43cfe..2548a40dc5d2 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -10,6 +10,7 @@ @@ -413,7 +415,7 @@ index afb119f38325..5e19a6839dea 100644 #include #include diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c -index 615f3776b4be..6d308183c25f 100644 +index 7117d559a32e..af1977e6c307 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -4,6 +4,7 @@ @@ -497,7 +499,7 @@ index ace4a6d28562..ad55cd738847 100644 static struct { diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h -index 861f2480c457..71fea53dacc9 100644 +index ef75567efd27..c70027ea28a2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -34,7 +34,6 @@ @@ -565,7 +567,7 @@ index ac6ffa561884..48c4503c16de 100644 #include #include diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c -index a31334b92be7..2a3ade22d34b 100644 +index eaa030e2ad55..d8816ae47015 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -46,6 +46,7 @@ @@ -589,7 +591,7 @@ index 2eaac2ff380f..459cc240eda9 100644 #include #include diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c -index 806babdd838d..9d4d9e8ecfdd 100644 +index 7f33b31c7b8b..360e24afd9b1 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -6,6 +6,7 @@ @@ -601,7 +603,7 @@ index 806babdd838d..9d4d9e8ecfdd 100644 #include #include diff --git a/net/socket.c b/net/socket.c -index d52c265ad449..6415983cf5b6 100644 +index 8657112a687a..eceffde4e0f1 100644 --- a/net/socket.c +++ b/net/socket.c @@ -52,6 +52,7 @@ @@ -613,5 +615,5 @@ index d52c265ad449..6415983cf5b6 100644 #include #include -- -2.17.1 +2.20.1 diff --git a/patch/0017-mlxsw-reg-Extend-MTMP-register-with-new-thresho.patch b/patch/0017-mlxsw-reg-Extend-MTMP-register-with-new-threshold-fi.patch similarity index 97% rename from patch/0017-mlxsw-reg-Extend-MTMP-register-with-new-thresho.patch rename to patch/0017-mlxsw-reg-Extend-MTMP-register-with-new-threshold-fi.patch index 33d976b71..7aefcf08f 100644 --- a/patch/0017-mlxsw-reg-Extend-MTMP-register-with-new-thresho.patch +++ b/patch/0017-mlxsw-reg-Extend-MTMP-register-with-new-threshold-fi.patch @@ -1,7 +1,8 @@ +From 91f0e76459d7a0e3156e7427d6ad347d345e2909 Mon Sep 17 00:00:00 2001 From: Mykola Kostenok Date: Tue, 8 Jun 2021 15:44:11 +0300 -Subject: 0017 mlxsw: reg: Extend MTMP register with new - threshold field +Subject: [PATCH backport 5.10 017/182] mlxsw: reg: Extend MTMP register with + new threshold field Extend Management Temperature (MTMP) register with new field specifying the maximum temperature threshold. @@ -143,5 +144,5 @@ index c670bf3464c2..dfcde953174c 100644 mlxsw_reg_mtmp_sensor_name_memcpy_from(payload, sensor_name); } -- -2.17.1 +2.20.1 diff --git a/patch/0018-mlxsw-thermal-Add-function-for-reading-module-t.patch b/patch/0018-mlxsw-thermal-Add-function-for-reading-module-temper.patch similarity index 94% rename from patch/0018-mlxsw-thermal-Add-function-for-reading-module-t.patch rename to patch/0018-mlxsw-thermal-Add-function-for-reading-module-temper.patch index ca19465aa..859469331 100644 --- a/patch/0018-mlxsw-thermal-Add-function-for-reading-module-t.patch +++ b/patch/0018-mlxsw-thermal-Add-function-for-reading-module-temper.patch @@ -1,7 +1,8 @@ +From 890ffa911705403d5f56ec57bf92f74b65758c87 Mon Sep 17 00:00:00 2001 From: Mykola Kostenok Date: Tue, 8 Jun 2021 15:44:13 +0300 -Subject: 0018 mlxsw: thermal: Add function for reading module - temperature and thresholds +Subject: [PATCH backport 5.10 018/182] mlxsw: thermal: Add function for + reading module temperature and thresholds Provide new function mlxsw_thermal_module_temp_and_thresholds_get() for reading temperature and temperature thresholds by a single operation. @@ -90,5 +91,5 @@ index a1025177c6ae..abbe02546164 100644 if (!temp) -- -2.17.1 +2.20.1 diff --git a/patch/0019-mlxsw-thermal-Read-module-temperature-threshold.patch b/patch/0019-mlxsw-thermal-Read-module-temperature-thresholds-usi.patch similarity index 96% rename from patch/0019-mlxsw-thermal-Read-module-temperature-threshold.patch rename to patch/0019-mlxsw-thermal-Read-module-temperature-thresholds-usi.patch index 72cf6d31c..1c9c57a16 100644 --- a/patch/0019-mlxsw-thermal-Read-module-temperature-threshold.patch +++ b/patch/0019-mlxsw-thermal-Read-module-temperature-thresholds-usi.patch @@ -1,7 +1,8 @@ +From 5e6f570de0f814bd843fdc5b36251538bdf7405f Mon Sep 17 00:00:00 2001 From: Mykola Kostenok Date: Tue, 8 Jun 2021 15:44:14 +0300 -Subject: 0019 mlxsw: thermal: Read module temperature thresholds - using MTMP register +Subject: [PATCH backport 5.10 019/182] mlxsw: thermal: Read module temperature + thresholds using MTMP register mlxsw_thermal_module_trips_update() is used to update the trip points of the module's thermal zone. Currently, this is done by querying the @@ -127,5 +128,5 @@ index abbe02546164..1f9ae663e133 100644 static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz) -- -2.17.1 +2.20.1 diff --git a/patch/0020-mlxsw-thermal-Fix-null-dereference-of-NULL-temp.patch b/patch/0020-mlxsw-thermal-Fix-null-dereference-of-NULL-temperatu.patch similarity index 91% rename from patch/0020-mlxsw-thermal-Fix-null-dereference-of-NULL-temp.patch rename to patch/0020-mlxsw-thermal-Fix-null-dereference-of-NULL-temperatu.patch index 383489edb..c60370265 100644 --- a/patch/0020-mlxsw-thermal-Fix-null-dereference-of-NULL-temp.patch +++ b/patch/0020-mlxsw-thermal-Fix-null-dereference-of-NULL-temperatu.patch @@ -1,7 +1,8 @@ +From d64eceef0d6b71a60ba6d5981463c639c89b2cce Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 9 Jun 2021 18:56:57 +0100 -Subject: 0020 mlxsw: thermal: Fix null dereference of NULL - temperature parameter +Subject: [PATCH backport 5.10 020/182] mlxsw: thermal: Fix null dereference of + NULL temperature parameter The call to mlxsw_thermal_module_temp_and_thresholds_get passes a NULL pointer for the temperature and this can be dereferenced in this function @@ -40,5 +41,5 @@ index 1f9ae663e133..b29824448aa8 100644 /* Update trip point according to the module data. */ return mlxsw_thermal_module_trips_update(dev, core, module_tz, -- -2.17.1 +2.20.1 diff --git a/patch/0021-mlxsw-reg-Add-bank-number-to-MCIA-register.patch b/patch/0021-mlxsw-reg-Add-bank-number-to-MCIA-register.patch index b7e4b7159..a77915383 100644 --- a/patch/0021-mlxsw-reg-Add-bank-number-to-MCIA-register.patch +++ b/patch/0021-mlxsw-reg-Add-bank-number-to-MCIA-register.patch @@ -1,6 +1,8 @@ +From 4fb08df650df57f76a7bbe71a6e9e6e9e0b447e9 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 21 Jun 2021 10:50:39 +0300 -Subject: 0021 mlxsw: reg: Add bank number to MCIA register +Subject: [PATCH backport 5.10 021/182] mlxsw: reg: Add bank number to MCIA + register Add bank number to MCIA (Management Cable Info Access) register in order to allow access to banked pages on EEPROMs using CMIS (Common Management @@ -31,5 +33,5 @@ index dfcde953174c..d9b5cfb939f0 100644 * Number of bytes to read/write (up to 48 bytes). * Access: RW -- -2.17.1 +2.20.1 diff --git a/patch/0022-mlxsw-reg-Document-possible-MCIA-status-values.patch b/patch/0022-mlxsw-reg-Document-possible-MCIA-status-values.patch index 4a7c91a3b..2aae853fa 100644 --- a/patch/0022-mlxsw-reg-Document-possible-MCIA-status-values.patch +++ b/patch/0022-mlxsw-reg-Document-possible-MCIA-status-values.patch @@ -1,6 +1,8 @@ +From 40d91f6687efb9d0f12e1b5a00e0260032255047 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 21 Jun 2021 10:50:40 +0300 -Subject: 0022 mlxsw: reg: Document possible MCIA status values +Subject: [PATCH backport 5.10 022/182] mlxsw: reg: Document possible MCIA + status values Will be used to emit meaningful messages to user space via extack in a subsequent patch. @@ -38,5 +40,5 @@ index d9b5cfb939f0..04f0c96c8068 100644 * Module status. * Access: RO -- -2.17.1 +2.20.1 diff --git a/patch/0023-ethtool-Allow-network-drivers-to-dump-arbitrary.patch b/patch/0023-ethtool-Allow-network-drivers-to-dump-arbitrary-EEPR.patch similarity index 99% rename from patch/0023-ethtool-Allow-network-drivers-to-dump-arbitrary.patch rename to patch/0023-ethtool-Allow-network-drivers-to-dump-arbitrary-EEPR.patch index 8d867ad68..c83c0a043 100644 --- a/patch/0023-ethtool-Allow-network-drivers-to-dump-arbitrary.patch +++ b/patch/0023-ethtool-Allow-network-drivers-to-dump-arbitrary-EEPR.patch @@ -1,7 +1,8 @@ +From fb781e6c43371a263caf5dd3ab4d43f5dc7eeb76 Mon Sep 17 00:00:00 2001 From: Vladyslav Tarasiuk Date: Fri, 9 Apr 2021 11:06:34 +0300 -Subject: 0023 ethtool: Allow network drivers to dump arbitrary - EEPROM data +Subject: [PATCH backport 5.10 023/182] ethtool: Allow network drivers to dump + arbitrary EEPROM data Define get_module_eeprom_by_page() ethtool callback and implement netlink infrastructure. @@ -510,5 +511,5 @@ index 979dee6bb88c..4a07fc93c5cc 100644 int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info); -- -2.17.1 +2.20.1 diff --git a/patch/0024-net-ethtool-Export-helpers-for-getting-EEPROM-i.patch b/patch/0024-net-ethtool-Export-helpers-for-getting-EEPROM-info.patch similarity index 94% rename from patch/0024-net-ethtool-Export-helpers-for-getting-EEPROM-i.patch rename to patch/0024-net-ethtool-Export-helpers-for-getting-EEPROM-info.patch index 4f7230f48..8bf61f94c 100644 --- a/patch/0024-net-ethtool-Export-helpers-for-getting-EEPROM-i.patch +++ b/patch/0024-net-ethtool-Export-helpers-for-getting-EEPROM-info.patch @@ -1,7 +1,8 @@ +From a7f17fca2ddb48f6f4505a17a68e8014ffe52af2 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 9 Apr 2021 11:06:38 +0300 -Subject: 0024 net: ethtool: Export helpers for getting EEPROM - info +Subject: [PATCH backport 5.10 024/182] net: ethtool: Export helpers for + getting EEPROM info There are two ways to retrieve information from SFP EEPROMs. Many devices make use of the common code, and assign the sfp_bus pointer in @@ -83,5 +84,5 @@ index 80d2a00d3097..3aee0a25e443 100644 } -- -2.17.1 +2.20.1 diff --git a/patch/0025-ethtool-Add-fallback-to-get_module_eeprom-from-.patch b/patch/0025-ethtool-Add-fallback-to-get_module_eeprom-from-netli.patch similarity index 93% rename from patch/0025-ethtool-Add-fallback-to-get_module_eeprom-from-.patch rename to patch/0025-ethtool-Add-fallback-to-get_module_eeprom-from-netli.patch index 6ddf835c2..4a360a70a 100644 --- a/patch/0025-ethtool-Add-fallback-to-get_module_eeprom-from-.patch +++ b/patch/0025-ethtool-Add-fallback-to-get_module_eeprom-from-netli.patch @@ -1,7 +1,8 @@ +From cc57dbcfd101433cdb7238aa6640d83faacaa9f0 Mon Sep 17 00:00:00 2001 From: Vladyslav Tarasiuk Date: Fri, 9 Apr 2021 11:06:39 +0300 -Subject: 0025 ethtool: Add fallback to get_module_eeprom from - netlink command +Subject: [PATCH backport 5.10 025/182] ethtool: Add fallback to + get_module_eeprom from netlink command In case netlink get_module_eeprom_by_page() callback is not implemented by the driver, try to call old get_module_info() and get_module_eeprom() @@ -96,5 +97,5 @@ index 8536dd905da5..1a49c133d401 100644 page_data.offset = request->offset; page_data.length = request->length; -- -2.17.1 +2.20.1 diff --git a/patch/0026-mlxsw-core-Add-support-for-module-EEPROM-read-b.patch b/patch/0026-mlxsw-core-Add-support-for-module-EEPROM-read-by-pag.patch similarity index 97% rename from patch/0026-mlxsw-core-Add-support-for-module-EEPROM-read-b.patch rename to patch/0026-mlxsw-core-Add-support-for-module-EEPROM-read-by-pag.patch index e61dbc27e..0c74eda54 100644 --- a/patch/0026-mlxsw-core-Add-support-for-module-EEPROM-read-b.patch +++ b/patch/0026-mlxsw-core-Add-support-for-module-EEPROM-read-by-pag.patch @@ -1,7 +1,8 @@ +From 37a0a27a7d38597e4b60b4ff483a20a2cdfeaac6 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 21 Jun 2021 10:50:41 +0300 -Subject: 0026 mlxsw: core: Add support for module EEPROM read by - page +Subject: [PATCH backport 5.10 026/182] mlxsw: core: Add support for module + EEPROM read by page Add support for ethtool_ops::get_module_eeprom_by_page() which allows user space to read transceiver module EEPROM based on passed parameters. @@ -228,5 +229,5 @@ index 68333ecf6151..369b9d0dc5d4 100644 struct mlxsw_sp1_port_link_mode { -- -2.17.1 +2.20.1 diff --git a/patch/0027-ethtool-Decrease-size-of-module-EEPROM-get-poli.patch b/patch/0027-ethtool-Decrease-size-of-module-EEPROM-get-policy-ar.patch similarity index 87% rename from patch/0027-ethtool-Decrease-size-of-module-EEPROM-get-poli.patch rename to patch/0027-ethtool-Decrease-size-of-module-EEPROM-get-policy-ar.patch index d42905f3c..51e2b23f5 100644 --- a/patch/0027-ethtool-Decrease-size-of-module-EEPROM-get-poli.patch +++ b/patch/0027-ethtool-Decrease-size-of-module-EEPROM-get-policy-ar.patch @@ -1,7 +1,8 @@ +From 9de352f9a4b7575e8934eb000b1cf388520020e5 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 22 Jun 2021 09:50:48 +0300 -Subject: 0027 ethtool: Decrease size of module EEPROM get policy - array +Subject: [PATCH backport 5.10 027/182] ethtool: Decrease size of module EEPROM + get policy array The 'ETHTOOL_A_MODULE_EEPROM_DATA' attribute is not part of the get request. @@ -26,5 +27,5 @@ index 4a07fc93c5cc..28dbd582c860 100644 int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info); -- -2.17.1 +2.20.1 diff --git a/patch/0028-ethtool-Use-kernel-data-types-for-internal-EEPR.patch b/patch/0028-ethtool-Use-kernel-data-types-for-internal-EEPROM-st.patch similarity index 83% rename from patch/0028-ethtool-Use-kernel-data-types-for-internal-EEPR.patch rename to patch/0028-ethtool-Use-kernel-data-types-for-internal-EEPROM-st.patch index fda463efe..39c905997 100644 --- a/patch/0028-ethtool-Use-kernel-data-types-for-internal-EEPR.patch +++ b/patch/0028-ethtool-Use-kernel-data-types-for-internal-EEPROM-st.patch @@ -1,7 +1,8 @@ +From e6b7a06472dd05d7eb4d8daec023534223e6772f Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 22 Jun 2021 09:50:50 +0300 -Subject: 0028 ethtool: Use kernel data types for internal EEPROM - struct +Subject: [PATCH backport 5.10 028/182] ethtool: Use kernel data types for + internal EEPROM struct The struct is not visible to user space and therefore should not use the user visible data types. @@ -38,5 +39,5 @@ index 4d199de36e02..dbabd804b2cb 100644 /** -- -2.17.1 +2.20.1 diff --git a/patch/0029-ethtool-Validate-module-EEPROM-length-as-part-o.patch b/patch/0029-ethtool-Validate-module-EEPROM-length-as-part-of-pol.patch similarity index 91% rename from patch/0029-ethtool-Validate-module-EEPROM-length-as-part-o.patch rename to patch/0029-ethtool-Validate-module-EEPROM-length-as-part-of-pol.patch index f34cd7953..a383cc9c4 100644 --- a/patch/0029-ethtool-Validate-module-EEPROM-length-as-part-o.patch +++ b/patch/0029-ethtool-Validate-module-EEPROM-length-as-part-of-pol.patch @@ -1,7 +1,8 @@ +From fcd35def3bc31428ecc63e8c5f2e8c3c7b61ba9f Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 22 Jun 2021 09:50:51 +0300 -Subject: 0029 ethtool: Validate module EEPROM length as part of - policy +Subject: [PATCH backport 5.10 029/182] ethtool: Validate module EEPROM length + as part of policy Validate the number of bytes to read from the module EEPROM as part of the netlink policy and remove the corresponding check from the code. @@ -44,5 +45,5 @@ index 1a49c133d401..a08fc04bcfd2 100644 [ETHTOOL_A_MODULE_EEPROM_BANK] = { .type = NLA_U8 }, [ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS] = -- -2.17.1 +2.20.1 diff --git a/patch/0030-ethtool-Validate-module-EEPROM-offset-as-part-o.patch b/patch/0030-ethtool-Validate-module-EEPROM-offset-as-part-of-pol.patch similarity index 91% rename from patch/0030-ethtool-Validate-module-EEPROM-offset-as-part-o.patch rename to patch/0030-ethtool-Validate-module-EEPROM-offset-as-part-of-pol.patch index 444f6b98b..20c0ded34 100644 --- a/patch/0030-ethtool-Validate-module-EEPROM-offset-as-part-o.patch +++ b/patch/0030-ethtool-Validate-module-EEPROM-offset-as-part-of-pol.patch @@ -1,7 +1,8 @@ +From 51dcef46e453de30ef187afd4e7086d3af2ea432 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 22 Jun 2021 09:50:52 +0300 -Subject: 0030 ethtool: Validate module EEPROM offset as part of - policy +Subject: [PATCH backport 5.10 030/182] ethtool: Validate module EEPROM offset + as part of policy Validate the offset to read from module EEPROM as part of the netlink policy and remove the corresponding check from the code. @@ -45,5 +46,5 @@ index a08fc04bcfd2..937c08902c71 100644 NLA_POLICY_RANGE(NLA_U32, 1, ETH_MODULE_EEPROM_PAGE_LEN), [ETHTOOL_A_MODULE_EEPROM_PAGE] = { .type = NLA_U8 }, -- -2.17.1 +2.20.1 diff --git a/patch/0031-mlxsw-core_env-Read-module-temperature-threshol.patch b/patch/0031-mlxsw-core_env-Read-module-temperature-thresholds-us.patch similarity index 93% rename from patch/0031-mlxsw-core_env-Read-module-temperature-threshol.patch rename to patch/0031-mlxsw-core_env-Read-module-temperature-thresholds-us.patch index 520efd6a9..693e3a0be 100644 --- a/patch/0031-mlxsw-core_env-Read-module-temperature-threshol.patch +++ b/patch/0031-mlxsw-core_env-Read-module-temperature-thresholds-us.patch @@ -1,7 +1,8 @@ +From b99eea2d9ce7ba73de38b82a7ed2057a777d4893 Mon Sep 17 00:00:00 2001 From: Mykola Kostenok Date: Tue, 8 Jun 2021 15:44:12 +0300 -Subject: 0031 mlxsw: core_env: Read module temperature - thresholds using MTMP register +Subject: [PATCH backport 5.10 031/182] mlxsw: core_env: Read module + temperature thresholds using MTMP register Currently, module temperature thresholds are obtained from Management Cable Info Access (MCIA) register by specifying the thresholds offsets @@ -69,5 +70,5 @@ index db85923547b0..4a0dbdb6730b 100644 * (MSB at lower byte address). * Bytes: -- -2.17.1 +2.20.1 diff --git a/patch/0032-mlxsw-core_env-Avoid-unnecessary-memcpy-s.patch b/patch/0032-mlxsw-core_env-Avoid-unnecessary-memcpy-s.patch index 44f21c884..8e4ab4ac2 100644 --- a/patch/0032-mlxsw-core_env-Avoid-unnecessary-memcpy-s.patch +++ b/patch/0032-mlxsw-core_env-Avoid-unnecessary-memcpy-s.patch @@ -1,6 +1,8 @@ +From 3aed771d128c6c2789da04ec0d09f11688d17855 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 24 Jun 2021 22:47:24 +0300 -Subject: 0032 mlxsw: core_env: Avoid unnecessary memcpy()s +Subject: [PATCH backport 5.10 032/182] mlxsw: core_env: Avoid unnecessary + memcpy()s Simply get a pointer to the data in the register payload instead of copying it to a temporary buffer. @@ -98,5 +100,5 @@ index 4a0dbdb6730b..3713c45cfa1e 100644 bytes_read += size; } -- -2.17.1 +2.20.1 diff --git a/patch/0035-hwmon-pmbus-Increase-maximum-number-of-phases-p.patch b/patch/0035-hwmon-pmbus-Increase-maximum-number-of-phases-per-pa.patch similarity index 76% rename from patch/0035-hwmon-pmbus-Increase-maximum-number-of-phases-p.patch rename to patch/0035-hwmon-pmbus-Increase-maximum-number-of-phases-per-pa.patch index a6852dbf4..8c567981f 100644 --- a/patch/0035-hwmon-pmbus-Increase-maximum-number-of-phases-p.patch +++ b/patch/0035-hwmon-pmbus-Increase-maximum-number-of-phases-per-pa.patch @@ -1,7 +1,8 @@ +From 9a37a1e841f05b5a2f35728c6531411335c8db00 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Tue, 11 May 2021 08:56:17 +0300 -Subject: 0035 hwmon: (pmbus) Increase maximum number of phases - per page +Subject: [PATCH backport 5.10 035/182] hwmon: (pmbus) Increase maximum number + of phases per page Increase maximum number of phases from 8 to 10 to support multi-phase devices allowing up to 10 phases. @@ -14,10 +15,10 @@ Signed-off-by: Guenter Roeck 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h -index 4c30ec89f5bf..fd43873011a4 100644 +index c88ac5fd91f0..cb6dbe29c0bf 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h -@@ -375,7 +375,7 @@ enum pmbus_sensor_classes { +@@ -376,7 +376,7 @@ enum pmbus_sensor_classes { }; #define PMBUS_PAGES 32 /* Per PMBus specification */ @@ -27,5 +28,5 @@ index 4c30ec89f5bf..fd43873011a4 100644 /* Functionality bit mask */ #define PMBUS_HAVE_VIN BIT(0) -- -2.17.1 +2.20.1 diff --git a/patch/0036-hwmon-pmbus-Add-support-for-MPS-Multi-phase-mp2.patch b/patch/0036-hwmon-pmbus-Add-support-for-MPS-Multi-phase-mp2888-c.patch similarity index 100% rename from patch/0036-hwmon-pmbus-Add-support-for-MPS-Multi-phase-mp2.patch rename to patch/0036-hwmon-pmbus-Add-support-for-MPS-Multi-phase-mp2888-c.patch diff --git a/patch/0037-dt-bindings-Add-MP2888-voltage-regulator-device.patch b/patch/0037-dt-bindings-Add-MP2888-voltage-regulator-device.patch index 071816a03..e29b37ab6 100644 --- a/patch/0037-dt-bindings-Add-MP2888-voltage-regulator-device.patch +++ b/patch/0037-dt-bindings-Add-MP2888-voltage-regulator-device.patch @@ -1,6 +1,8 @@ +From f5c7f2a6c2443f8991fef683ad7bd8b2cddf5415 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Tue, 11 May 2021 08:56:19 +0300 -Subject: 0037 dt-bindings: Add MP2888 voltage regulator device +Subject: [PATCH backport 5.10 037/182] dt-bindings: Add MP2888 voltage + regulator device Monolithic Power Systems, Inc. (MPS) dual-loop, digital, multi-phase controller. @@ -27,5 +29,5 @@ index ab623ba930d5..52bc54b2d723 100644 - mps,mp2975 # G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface -- -2.17.1 +2.20.1 diff --git a/patch/0038-ethtool-wire-in-generic-SFP-module-access.patch b/patch/0038-ethtool-wire-in-generic-SFP-module-access.patch index c4e982085..21d2a7acc 100644 --- a/patch/0038-ethtool-wire-in-generic-SFP-module-access.patch +++ b/patch/0038-ethtool-wire-in-generic-SFP-module-access.patch @@ -1,6 +1,8 @@ +From 0d7b7f6e65905dbfcda016e81987587cd19bc3a4 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 9 Apr 2021 11:06:41 +0300 -Subject: 0038 ethtool: wire in generic SFP module access +Subject: [PATCH backport 5.10 038/182] ethtool: wire in generic SFP module + access If the device has a sfp bus attached, call its sfp_get_module_eeprom_by_page() function, otherwise use the ethtool op @@ -77,5 +79,5 @@ index 937c08902c71..d0a5484ec423 100644 } -- -2.17.1 +2.20.1 diff --git a/patch/0039-ethtool-Fix-NULL-pointer-dereference-during-mod.patch b/patch/0039-ethtool-Fix-NULL-pointer-dereference-during-module-E.patch similarity index 89% rename from patch/0039-ethtool-Fix-NULL-pointer-dereference-during-mod.patch rename to patch/0039-ethtool-Fix-NULL-pointer-dereference-during-module-E.patch index fff08a23a..915fa7178 100644 --- a/patch/0039-ethtool-Fix-NULL-pointer-dereference-during-mod.patch +++ b/patch/0039-ethtool-Fix-NULL-pointer-dereference-during-module-E.patch @@ -1,7 +1,8 @@ +From 0802cc637330e62a5db45bb3cfaa4d92f1df9a14 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 6 Jun 2021 17:24:22 +0300 -Subject: 0039 ethtool: Fix NULL pointer dereference during - module EEPROM dump +Subject: [PATCH backport 5.10 039/182] ethtool: Fix NULL pointer dereference + during module EEPROM dump When get_module_eeprom_by_page() is not implemented by the driver, NULL pointer dereference can occur [1]. @@ -49,5 +50,5 @@ index d0a5484ec423..7e6b37a54add 100644 return -EOPNOTSUPP; -- -2.17.1 +2.20.1 diff --git a/patch/0040-phy-sfp-add-netlink-SFP-support-to-generic-SFP-.patch b/patch/0040-phy-sfp-add-netlink-SFP-support-to-generic-SFP-code.patch similarity index 91% rename from patch/0040-phy-sfp-add-netlink-SFP-support-to-generic-SFP-.patch rename to patch/0040-phy-sfp-add-netlink-SFP-support-to-generic-SFP-code.patch index 4eb809412..edb898e85 100644 --- a/patch/0040-phy-sfp-add-netlink-SFP-support-to-generic-SFP-.patch +++ b/patch/0040-phy-sfp-add-netlink-SFP-support-to-generic-SFP-code.patch @@ -1,7 +1,8 @@ +From 8d067ab81436b720438e85423718bdb590092a2a Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 9 Apr 2021 11:06:40 +0300 -Subject: 0040 phy: sfp: add netlink SFP support to generic SFP - code +Subject: [PATCH backport 5.10 040/182] phy: sfp: add netlink SFP support to + generic SFP code The new netlink API for reading SFP data requires a new op to be implemented. The idea of the new netlink SFP code is that userspace is @@ -25,10 +26,10 @@ Signed-off-by: David S. Miller 4 files changed, 58 insertions(+) diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c -index a05d8372669c..30119f175781 100644 +index 850915a37f4c..d973110c2868 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c -@@ -538,6 +538,26 @@ int sfp_get_module_eeprom(struct sfp_bus *bus, struct ethtool_eeprom *ee, +@@ -544,6 +544,26 @@ int sfp_get_module_eeprom(struct sfp_bus *bus, struct ethtool_eeprom *ee, } EXPORT_SYMBOL_GPL(sfp_get_module_eeprom); @@ -56,10 +57,10 @@ index a05d8372669c..30119f175781 100644 * sfp_upstream_start() - Inform the SFP that the network device is up * @bus: a pointer to the &struct sfp_bus structure for the sfp module diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c -index efffa65f8214..817c74d476e5 100644 +index dcbe278086dc..cc171c0087db 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c -@@ -2295,6 +2295,30 @@ static int sfp_module_eeprom(struct sfp *sfp, struct ethtool_eeprom *ee, +@@ -2302,6 +2302,30 @@ static int sfp_module_eeprom(struct sfp *sfp, struct ethtool_eeprom *ee, return 0; } @@ -90,7 +91,7 @@ index efffa65f8214..817c74d476e5 100644 static const struct sfp_socket_ops sfp_module_ops = { .attach = sfp_attach, .detach = sfp_detach, -@@ -2302,6 +2326,7 @@ static const struct sfp_socket_ops sfp_module_ops = { +@@ -2309,6 +2333,7 @@ static const struct sfp_socket_ops sfp_module_ops = { .stop = sfp_stop, .module_info = sfp_module_info, .module_eeprom = sfp_module_eeprom, @@ -141,5 +142,5 @@ index 38893e4dd0f0..302094b855fb 100644 { } -- -2.17.1 +2.20.1 diff --git a/patch/0042-ethtool-support-FEC-settings-over-netlink.patch b/patch/0042-ethtool-support-FEC-settings-over-netlink.patch index 9ca71c81e..9f068e85c 100644 --- a/patch/0042-ethtool-support-FEC-settings-over-netlink.patch +++ b/patch/0042-ethtool-support-FEC-settings-over-netlink.patch @@ -1,6 +1,8 @@ +From f2b51f5d52f45a147feb6a5a8d05695849d19d46 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 8 Jul 2021 06:46:53 +0000 -Subject: 0042 ethtool: support FEC settings over netlink +Subject: [PATCH backport 5.10 042/182] ethtool: support FEC settings over + netlink Backport from upstream commit 1e5d1f69d9fb8ea0679f9e85915e8e7fdacfbe7a Added in order to align UAPI interface for 'ethtool' (need for @@ -58,5 +60,5 @@ index 7dda2cee919b..8ac5c7e64314 100644 /* add new constants above here */ -- -2.17.1 +2.20.1 diff --git a/patch/0045-i2c-mlxcpld-Fix-criteria-for-frequency-setting.patch b/patch/0045-i2c-mlxcpld-Fix-criteria-for-frequency-setting.patch index abedc2e6e..07d2df567 100644 --- a/patch/0045-i2c-mlxcpld-Fix-criteria-for-frequency-setting.patch +++ b/patch/0045-i2c-mlxcpld-Fix-criteria-for-frequency-setting.patch @@ -1,6 +1,8 @@ +From a0ea663d696f2d67fc5ac8f33ab26b60b932f5cd Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 10 Jul 2021 07:24:22 +0000 -Subject: 0045 i2c: mlxcpld: Fix criteria for frequency setting +Subject: [PATCH backport 5.10 045/182] i2c: mlxcpld: Fix criteria for + frequency setting Value for getting frequency capability wrongly has been taken from register offset instead of register value. @@ -25,5 +27,5 @@ index 4e0b7c2882ce..6d41c3db8a2b 100644 freq = MLXCPLD_I2C_FREQ_1000KHZ_SET; break; -- -2.17.1 +2.20.1 diff --git a/patch/0046-i2c-mlxcpld-Reduce-polling-time-for-performance.patch b/patch/0046-i2c-mlxcpld-Reduce-polling-time-for-performance-impr.patch similarity index 84% rename from patch/0046-i2c-mlxcpld-Reduce-polling-time-for-performance.patch rename to patch/0046-i2c-mlxcpld-Reduce-polling-time-for-performance-impr.patch index 337c780e8..88bce22b4 100644 --- a/patch/0046-i2c-mlxcpld-Reduce-polling-time-for-performance.patch +++ b/patch/0046-i2c-mlxcpld-Reduce-polling-time-for-performance-impr.patch @@ -1,7 +1,8 @@ +From fdcccb92ef348e32a9e3693f8a2e3df9dfa48ccf Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Tue, 6 Jul 2021 09:37:04 +0000 -Subject: 0046 i2c: mlxcpld: Reduce polling time for performance - improvement +Subject: [PATCH backport 5.10 046/182] i2c: mlxcpld: Reduce polling time for + performance improvement Decrease polling time 'MLXCPLD_I2C_POLL_TIME' from 400 usec to 200 usec. It improves performance of I2C transactions. @@ -28,5 +29,5 @@ index 6d41c3db8a2b..8e110d792147 100644 /* LPC I2C registers */ #define MLXCPLD_LPCI2C_CPBLTY_REG 0x0 -- -2.17.1 +2.20.1 diff --git a/patch/0047-i2c-mlxcpld-Allow-flexible-polling-time-setting.patch b/patch/0047-i2c-mlxcpld-Allow-flexible-polling-time-setting-for-.patch similarity index 93% rename from patch/0047-i2c-mlxcpld-Allow-flexible-polling-time-setting.patch rename to patch/0047-i2c-mlxcpld-Allow-flexible-polling-time-setting-for-.patch index 255ed2813..57f526861 100644 --- a/patch/0047-i2c-mlxcpld-Allow-flexible-polling-time-setting.patch +++ b/patch/0047-i2c-mlxcpld-Allow-flexible-polling-time-setting-for-.patch @@ -1,7 +1,8 @@ +From a0fb4893521ea063db085162385c1eac83cafb07 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Tue, 6 Jul 2021 18:23:46 +0000 -Subject: 0047 i2c: mlxcpld: Allow flexible polling time setting - for I2C transactions +Subject: [PATCH backport 5.10 047/182] i2c: mlxcpld: Allow flexible polling + time setting for I2C transactions Allow polling time setting according to I2C frequency supported across the system. For base frequency 400 KHz and 1 MHz set polling time is set @@ -78,5 +79,5 @@ index 8e110d792147..56aa424fd71d 100644 /* Set I2C bus frequency if platform data provides this info. */ pdata = dev_get_platdata(&pdev->dev); -- -2.17.1 +2.20.1 diff --git a/patch/0052-hwmon-mlxreg-fan-Return-non-zero-value-when-fan.patch b/patch/0052-hwmon-mlxreg-fan-Return-non-zero-value-when-fan.patch deleted file mode 100644 index 8bbdd4a26..000000000 --- a/patch/0052-hwmon-mlxreg-fan-Return-non-zero-value-when-fan.patch +++ /dev/null @@ -1,88 +0,0 @@ -From: Vadim Pasternak -Date: Thu, 8 Jul 2021 09:44:28 +0000 -Subject: 0052 hwmon: (mlxreg-fan) Return non-zero value when fan - current state is enforced from sysfs - -Fan speed minimum can be enforced from sysfs. For example, setting -current fan speed to 20 is used to enforce fan speed to be at 100% -speed, 19 - to be not below 90% speed, etcetera. This feature provides -ability to limit fan speed according to some system wise -considerations, like absence of some replaceable units or high system -ambient temperature. - -Request for changing fan minimum speed is configuration request and can -be set only through 'sysfs' write procedure. In this situation value of -argument 'state' is above nominal fan speed maximum. - -Return non-zero code in this case to avoid -thermal_cooling_device_stats_update() call, because in this case -statistics update violates thermal statistics table range. -The issues is observed in case kernel is configured with option -CONFIG_THERMAL_STATISTICS. - -Here is the trace from KASAN: -[ 159.506659] BUG: KASAN: slab-out-of-bounds in thermal_cooling_device_stats_update+0x7d/0xb0 -[ 159.516016] Read of size 4 at addr ffff888116163840 by task hw-management.s/7444 -[ 159.545625] Call Trace: -[ 159.548366] dump_stack+0x92/0xc1 -[ 159.552084] ? thermal_cooling_device_stats_update+0x7d/0xb0 -[ 159.635869] thermal_zone_device_update+0x345/0x780 -[ 159.688711] thermal_zone_device_set_mode+0x7d/0xc0 -[ 159.694174] mlxsw_thermal_modules_init+0x48f/0x590 [mlxsw_core] -[ 159.700972] ? mlxsw_thermal_set_cur_state+0x5a0/0x5a0 [mlxsw_core] -[ 159.731827] mlxsw_thermal_init+0x763/0x880 [mlxsw_core] -[ 160.070233] RIP: 0033:0x7fd995909970 -[ 160.074239] Code: 73 01 c3 48 8b 0d 28 d5 2b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 0f 1f 44 00 00 83 3d 99 2d 2c 00 00 75 10 b8 01 00 00 00 0f 05 <48> 3d 01 f0 ff .. -[ 160.095242] RSP: 002b:00007fff54f5d938 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 -[ 160.103722] RAX: ffffffffffffffda RBX: 0000000000000013 RCX: 00007fd995909970 -[ 160.111710] RDX: 0000000000000013 RSI: 0000000001906008 RDI: 0000000000000001 -[ 160.119699] RBP: 0000000001906008 R08: 00007fd995bc9760 R09: 00007fd996210700 -[ 160.127687] R10: 0000000000000073 R11: 0000000000000246 R12: 0000000000000013 -[ 160.135673] R13: 0000000000000001 R14: 00007fd995bc8600 R15: 0000000000000013 -[ 160.143671] -[ 160.145338] Allocated by task 2924: -[ 160.149242] kasan_save_stack+0x19/0x40 -[ 160.153541] __kasan_kmalloc+0x7f/0xa0 -[ 160.157743] __kmalloc+0x1a2/0x2b0 -[ 160.161552] thermal_cooling_device_setup_sysfs+0xf9/0x1a0 -[ 160.167687] __thermal_cooling_device_register+0x1b5/0x500 -[ 160.173833] devm_thermal_of_cooling_device_register+0x60/0xa0 -[ 160.180356] mlxreg_fan_probe+0x474/0x5e0 [mlxreg_fan] -[ 160.248140] -[ 160.249807] The buggy address belongs to the object at ffff888116163400 -[ 160.249807] which belongs to the cache kmalloc-1k of size 1024 -[ 160.263814] The buggy address is located 64 bytes to the right of -[ 160.263814] 1024-byte region [ffff888116163400, ffff888116163800) -[ 160.277536] The buggy address belongs to the page: -[ 160.282898] page:0000000012275840 refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff888116167000 pfn:0x116160 -[ 160.294872] head:0000000012275840 order:3 compound_mapcount:0 compound_pincount:0 -[ 160.303251] flags: 0x200000000010200(slab|head|node=0|zone=2) -[ 160.309694] raw: 0200000000010200 ffffea00046f7208 ffffea0004928208 ffff88810004dbc0 -[ 160.318367] raw: ffff888116167000 00000000000a0006 00000001ffffffff 0000000000000000 -[ 160.327033] page dumped because: kasan: bad access detected -[ 160.333270] -[ 160.334937] Memory state around the buggy address: -[ 160.356469] >ffff888116163800: fc .. - -Fixes: 65afb4c8e7e4: (hwmon: (mlxreg-fan) Add support for Mellanox FAN driver) -Signed-off-by: Vadim Pasternak ---- - drivers/hwmon/mlxreg-fan.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c -index 89fe7b9fe26b..93fb991a5f4e 100644 ---- a/drivers/hwmon/mlxreg-fan.c -+++ b/drivers/hwmon/mlxreg-fan.c -@@ -334,7 +334,7 @@ static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev, - * For configuration non-zero value is to be returned to avoid thermal - * statistics update. - */ -- config = 1; -+ config = 0; /*1*/; - state -= MLXREG_FAN_MAX_STATE; - for (i = 0; i < state; i++) - fan->cooling_levels[i] = state; --- -2.17.1 - diff --git a/patch/0053-mlxsw-core-Avoid-creation-virtual-hwmon-objects.patch b/patch/0053-mlxsw-core-Avoid-creation-virtual-hwmon-objects-by-t.patch similarity index 93% rename from patch/0053-mlxsw-core-Avoid-creation-virtual-hwmon-objects.patch rename to patch/0053-mlxsw-core-Avoid-creation-virtual-hwmon-objects-by-t.patch index 057c4a140..f5d69776d 100644 --- a/patch/0053-mlxsw-core-Avoid-creation-virtual-hwmon-objects.patch +++ b/patch/0053-mlxsw-core-Avoid-creation-virtual-hwmon-objects-by-t.patch @@ -1,7 +1,8 @@ +From 25d36748f03a4c652abd29e909bbe5a30ea67ecf Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 4 Nov 2020 20:07:15 +0200 -Subject: 0053 mlxsw: core: Avoid creation virtual hwmon objects - by thermal module +Subject: [PATCH backport 5.10 053/182] mlxsw: core: Avoid creation virtual + hwmon objects by thermal module Extend initialization of each thermal zone with 'thermal_zone_params', set field 'no_hwmon' in this structure to 'true'. @@ -70,5 +71,5 @@ index b29824448aa8..e1a760519097 100644 if (IS_ERR(thermal->tzdev)) { err = PTR_ERR(thermal->tzdev); -- -2.17.1 +2.20.1 diff --git a/patch/0054-mlxsw-minimal-Simplify-method-of-modules-number.patch b/patch/0054-mlxsw-minimal-Simplify-method-of-modules-number-dete.patch similarity index 96% rename from patch/0054-mlxsw-minimal-Simplify-method-of-modules-number.patch rename to patch/0054-mlxsw-minimal-Simplify-method-of-modules-number-dete.patch index eed28ead0..bf1bf2ed3 100644 --- a/patch/0054-mlxsw-minimal-Simplify-method-of-modules-number.patch +++ b/patch/0054-mlxsw-minimal-Simplify-method-of-modules-number-dete.patch @@ -1,7 +1,8 @@ +From 675042fec21be3fbd12388b239676608759f0497 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 19 Jul 2021 17:07:02 +0000 -Subject: 0054 mlxsw: minimal: Simplify method of modules number - detection +Subject: [PATCH backport 5.10 054/182] mlxsw: minimal: Simplify method of + modules number detection Remove unnecessary access to PMLP register, used to find the number of module supported by the system. Obtain this information through MGPIR @@ -178,5 +179,5 @@ index af4c9b44d9cf..a8c67b763c8b 100644 kfree(mlxsw_m->module_to_port); kfree(mlxsw_m->ports); -- -2.17.1 +2.20.1 diff --git a/patch/0055-platform_data-mlxreg-Add-new-type-to-support-mo.patch b/patch/0055-platform_data-mlxreg-Add-new-type-to-support-modular.patch similarity index 97% rename from patch/0055-platform_data-mlxreg-Add-new-type-to-support-mo.patch rename to patch/0055-platform_data-mlxreg-Add-new-type-to-support-modular.patch index 0ad18d902..aa54be4ba 100644 --- a/patch/0055-platform_data-mlxreg-Add-new-type-to-support-mo.patch +++ b/patch/0055-platform_data-mlxreg-Add-new-type-to-support-modular.patch @@ -1,7 +1,8 @@ +From 8f9032570ba6f1b6ddb6cca99ae7712d9e41ea0d Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 12 Jul 2021 14:55:49 +0000 -Subject: 0055 platform_data/mlxreg: Add new type to support - modular systems +Subject: [PATCH backport 5.10 055/182] platform_data/mlxreg: Add new type to + support modular systems Add new types for the Nvidia modular systems MSN4800 which could be equipped with the different types of replaceable line cards. @@ -164,5 +165,5 @@ index 101333fe2b8d..49f0e15a10dd 100644 u32 reg; u32 mask; -- -2.17.1 +2.20.1 diff --git a/patch/0056-platform-x86-mlx-platform-Add-initial-support-f.patch b/patch/0056-platform-x86-mlx-platform-Add-initial-support-for-ne.patch similarity index 99% rename from patch/0056-platform-x86-mlx-platform-Add-initial-support-f.patch rename to patch/0056-platform-x86-mlx-platform-Add-initial-support-for-ne.patch index 0864b9d6f..4cadcdb7b 100644 --- a/patch/0056-platform-x86-mlx-platform-Add-initial-support-f.patch +++ b/patch/0056-platform-x86-mlx-platform-Add-initial-support-for-ne.patch @@ -1,8 +1,8 @@ -From 1fe47720483933d41d480ae51c3487a2f34e6e1a Mon Sep 17 00:00:00 2001 +From e30148789fa7c9554bfbac59e737d92301d09059 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 12 Jul 2021 16:39:11 +0000 -Subject: [PATCH backport for v5.10 56/97] platform/x86: mlx-platform: Add - initial support for new modular system +Subject: [PATCH backport 5.10 056/182] platform/x86: mlx-platform: Add initial + support for new modular system Add initial chassis management support for Nvidia modular Ethernet switch systems MSN4800, providing a high performance switching solution diff --git a/patch/0057-platform-mellanox-mlxreg-hotplug-Extend-logic-f.patch b/patch/0057-platform-mellanox-mlxreg-hotplug-Extend-logic-for-ho.patch similarity index 98% rename from patch/0057-platform-mellanox-mlxreg-hotplug-Extend-logic-f.patch rename to patch/0057-platform-mellanox-mlxreg-hotplug-Extend-logic-for-ho.patch index 134331bb7..72ea497a3 100644 --- a/patch/0057-platform-mellanox-mlxreg-hotplug-Extend-logic-f.patch +++ b/patch/0057-platform-mellanox-mlxreg-hotplug-Extend-logic-for-ho.patch @@ -1,7 +1,8 @@ +From 4a9542f7b6208956b87c310942fa47b1afc45494 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 12 Jul 2021 16:50:27 +0000 -Subject: 0057 platform/mellanox: mlxreg-hotplug: Extend logic - for hotplug devices operations +Subject: [PATCH backport 5.10 057/182] platform/mellanox: mlxreg-hotplug: + Extend logic for hotplug devices operations Extend the structure 'mlxreg_hotplug_device" with platform device field to allow transition of the register map and system interrupt line number @@ -296,5 +297,5 @@ index 49f0e15a10dd..3122d550dc00 100644 bool attached; u8 regnum; -- -2.17.1 +2.20.1 diff --git a/patch/0058-platform-x86-mlx-platform-Configure-notifier-ca.patch b/patch/0058-platform-x86-mlx-platform-Configure-notifier-callbac.patch similarity index 99% rename from patch/0058-platform-x86-mlx-platform-Configure-notifier-ca.patch rename to patch/0058-platform-x86-mlx-platform-Configure-notifier-callbac.patch index 843f0ec76..71bb34735 100644 --- a/patch/0058-platform-x86-mlx-platform-Configure-notifier-ca.patch +++ b/patch/0058-platform-x86-mlx-platform-Configure-notifier-callbac.patch @@ -1,7 +1,8 @@ +From 810957c2eed0f5e5f239a332d0367dfa02ec03f6 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 12 Jul 2021 17:25:30 +0000 -Subject: 0058 platform/x86: mlx-platform: Configure notifier - callbacks for modular system +Subject: [PATCH backport 5.10 058/182] platform/x86: mlx-platform: Configure + notifier callbacks for modular system Add event notifier callbacks for modular system line cards. These callbacks are to be passed to "mlxreg-hotplug" driver by line card @@ -502,5 +503,5 @@ index 6d14eb3dab50..8e1e298cf18b 100644 }, }; -- -2.17.1 +2.20.1 diff --git a/patch/0059-platform-mellanox-mlxreg-io-Extend-number-of-hw.patch b/patch/0059-platform-mellanox-mlxreg-io-Extend-number-of-hwmon-a.patch similarity index 82% rename from patch/0059-platform-mellanox-mlxreg-io-Extend-number-of-hw.patch rename to patch/0059-platform-mellanox-mlxreg-io-Extend-number-of-hwmon-a.patch index 2a9046263..2050b790d 100644 --- a/patch/0059-platform-mellanox-mlxreg-io-Extend-number-of-hw.patch +++ b/patch/0059-platform-mellanox-mlxreg-io-Extend-number-of-hwmon-a.patch @@ -1,7 +1,8 @@ +From 1832955f5b8d4f7dc9e20d4e860564d798f6d24c Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 25 Mar 2021 20:12:07 +0200 -Subject: 0059 platform/mellanox: mlxreg-io: Extend number of - hwmon attributes +Subject: [PATCH backport 5.10 059/182] platform/mellanox: mlxreg-io: Extend + number of hwmon attributes Extend maximum number of the attributes, exposed to 'sysfs'. It is requires in order to support modular systems, which @@ -27,5 +28,5 @@ index a916cd89cbbe..2c2686d5c2fc 100644 /** * struct mlxreg_io_priv_data - driver's private data: -- -2.17.1 +2.20.1 diff --git a/patch/0060-platform_data-mlxreg-Add-new-field-for-secured-.patch b/patch/0060-platform_data-mlxreg-Add-new-field-for-secured-acces.patch similarity index 85% rename from patch/0060-platform_data-mlxreg-Add-new-field-for-secured-.patch rename to patch/0060-platform_data-mlxreg-Add-new-field-for-secured-acces.patch index a369ace07..53ed462f7 100644 --- a/patch/0060-platform_data-mlxreg-Add-new-field-for-secured-.patch +++ b/patch/0060-platform_data-mlxreg-Add-new-field-for-secured-acces.patch @@ -1,7 +1,8 @@ +From d48bd08b57cf84861e741ef8e5a2c4d3d142401c Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 12 Jul 2021 21:39:51 +0000 -Subject: 0060 platform_data/mlxreg: Add new field for secured - access +Subject: [PATCH backport 5.10 060/182] platform_data/mlxreg: Add new field for + secured access Extend structure 'mlxreg_core_data' with the field "secured". The purpose of this field is to restrict access to some attributes, if @@ -31,5 +32,5 @@ index 3122d550dc00..40185f9d7c14 100644 /** -- -2.17.1 +2.20.1 diff --git a/patch/0061-platform-mellanox-mlxreg-lc-Add-initial-support.patch b/patch/0061-platform-mellanox-mlxreg-lc-Add-initial-support-for-.patch similarity index 98% rename from patch/0061-platform-mellanox-mlxreg-lc-Add-initial-support.patch rename to patch/0061-platform-mellanox-mlxreg-lc-Add-initial-support-for-.patch index 38c64830f..183716160 100644 --- a/patch/0061-platform-mellanox-mlxreg-lc-Add-initial-support.patch +++ b/patch/0061-platform-mellanox-mlxreg-lc-Add-initial-support-for-.patch @@ -1,7 +1,8 @@ +From e8d9090e50da28c82c3bbb7ff2db58aebd1c16ff Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 12 Jul 2021 21:40:46 +0000 -Subject: 0061 platform/mellanox: mlxreg-lc: Add initial support - for Nvidia line card devices +Subject: [PATCH backport 5.10 061/182] platform/mellanox: mlxreg-lc: Add + initial support for Nvidia line card devices Provide support for the Nvidia MSN4800-XX line cards for MSN4800 Ethernet modular switch system, providing a high performance switching @@ -83,7 +84,7 @@ index 499623ccf2fe..e47b6b064881 100644 +obj-$(CONFIG_MLXREG_LC) += mlxreg-lc.o diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c new file mode 100644 -index 000000000000..c2ccb38df693 +index 000000000000..2ddad96b154a --- /dev/null +++ b/drivers/platform/mellanox/mlxreg-lc.c @@ -0,0 +1,915 @@ @@ -566,7 +567,7 @@ index 000000000000..c2ccb38df693 + else + regval &= ~BIT(mlxreg_lc->data->slot - 1); + -+ err = 0; /*regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, regval);*/ ++ err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, regval); + + mutex_unlock(&mlxreg_lc->lock); + @@ -598,7 +599,7 @@ index 000000000000..c2ccb38df693 + else + regval &= ~BIT(mlxreg_lc->data->slot - 1); + -+ err = 0; /*regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_ena, regval);*/ ++ err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_ena, regval); + +regmap_read_fail: + mutex_unlock(&mlxreg_lc->lock); @@ -1003,5 +1004,5 @@ index 000000000000..c2ccb38df693 +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:mlxreg-lc"); -- -2.17.1 +2.20.1 diff --git a/patch/0062-Documentation-ABI-Add-new-attributes-for-mlxreg.patch b/patch/0062-Documentation-ABI-Add-new-attributes-for-mlxreg-io-s.patch similarity index 97% rename from patch/0062-Documentation-ABI-Add-new-attributes-for-mlxreg.patch rename to patch/0062-Documentation-ABI-Add-new-attributes-for-mlxreg-io-s.patch index efe4bf0c5..e611b499b 100644 --- a/patch/0062-Documentation-ABI-Add-new-attributes-for-mlxreg.patch +++ b/patch/0062-Documentation-ABI-Add-new-attributes-for-mlxreg-io-s.patch @@ -1,7 +1,8 @@ +From a47f1f27b1d6393a5a47d5de211ba36e5905b8c7 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 25 Mar 2021 20:12:05 +0200 -Subject: 0062 Documentation/ABI: Add new attributes for - mlxreg-io sysfs interfaces +Subject: [PATCH backport 5.10 062/182] Documentation/ABI: Add new attributes + for mlxreg-io sysfs interfaces Add documentation for the new attributes: - "bios_active_image"; "bios_auth_fail"; "bios_upgrade_fail"; @@ -168,5 +169,5 @@ index fd9a8045bb0c..65d87f43e618 100644 + + The file is read/write. -- -2.17.1 +2.20.1 diff --git a/patch/0063-Documentation-ABI-Add-new-line-card-attributes-.patch b/patch/0063-Documentation-ABI-Add-new-line-card-attributes-for-m.patch similarity index 96% rename from patch/0063-Documentation-ABI-Add-new-line-card-attributes-.patch rename to patch/0063-Documentation-ABI-Add-new-line-card-attributes-for-m.patch index 1ca58f0ce..902687365 100644 --- a/patch/0063-Documentation-ABI-Add-new-line-card-attributes-.patch +++ b/patch/0063-Documentation-ABI-Add-new-line-card-attributes-for-m.patch @@ -1,7 +1,8 @@ +From 999214e1026baf68ff05a734a92e4cbb4cd8a073 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 25 Mar 2021 20:12:11 +0200 -Subject: 0063 Documentation/ABI: Add new line card attributes - for mlxreg-io sysfs interfaces +Subject: [PATCH backport 5.10 063/182] Documentation/ABI: Add new line card + attributes for mlxreg-io sysfs interfaces Add documentation for the new attributes for line cards: - CPLDs versioning. @@ -127,5 +128,5 @@ index 65d87f43e618..e2f938499473 100644 + + The files are read only. -- -2.17.1 +2.20.1 diff --git a/patch/0064-hwmon-mlxreg-fan-Extend-the-maximum-number-of-t.patch b/patch/0064-hwmon-mlxreg-fan-Extend-the-maximum-number-of-tachom.patch similarity index 70% rename from patch/0064-hwmon-mlxreg-fan-Extend-the-maximum-number-of-t.patch rename to patch/0064-hwmon-mlxreg-fan-Extend-the-maximum-number-of-tachom.patch index ac50e534a..77d977c67 100644 --- a/patch/0064-hwmon-mlxreg-fan-Extend-the-maximum-number-of-t.patch +++ b/patch/0064-hwmon-mlxreg-fan-Extend-the-maximum-number-of-tachom.patch @@ -1,7 +1,8 @@ +From 0e6b16e3aefc494a1e0a4b1a2c731f8a2fb6ec33 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 12 Jul 2021 22:04:25 +0000 -Subject: 0064 hwmon: (mlxreg-fan) Extend the maximum number of - tachometers +Subject: [PATCH backport 5.10 064/182] hwmon: (mlxreg-fan) Extend the maximum + number of tachometers Extend support of maximum tachometers from 12 to 14 in order to support new systems, equipped with more fans. @@ -12,7 +13,7 @@ Signed-off-by: Vadim Pasternak 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c -index 93fb991a5f4e..35c283405df6 100644 +index 89fe7b9fe26b..0f5b109817a7 100644 --- a/drivers/hwmon/mlxreg-fan.c +++ b/drivers/hwmon/mlxreg-fan.c @@ -12,7 +12,7 @@ @@ -24,15 +25,15 @@ index 93fb991a5f4e..35c283405df6 100644 #define MLXREG_FAN_MAX_STATE 10 #define MLXREG_FAN_MIN_DUTY 51 /* 20% */ #define MLXREG_FAN_MAX_DUTY 255 /* 100% */ -@@ -255,6 +255,8 @@ mlxreg_fan_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, - - static const struct hwmon_channel_info *mlxreg_fan_hwmon_info[] = { - HWMON_CHANNEL_INFO(fan, -+ HWMON_F_INPUT | HWMON_F_FAULT, -+ HWMON_F_INPUT | HWMON_F_FAULT, +@@ -266,6 +266,8 @@ static const struct hwmon_channel_info *mlxreg_fan_hwmon_info[] = { HWMON_F_INPUT | HWMON_F_FAULT, HWMON_F_INPUT | HWMON_F_FAULT, HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_FAULT), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT), -- -2.17.1 +2.20.1 diff --git a/patch/0065-platform-x86-mlx-platform-Extend-FAN-and-LED-co.patch b/patch/0065-platform-x86-mlx-platform-Extend-FAN-and-LED-config-.patch similarity index 95% rename from patch/0065-platform-x86-mlx-platform-Extend-FAN-and-LED-co.patch rename to patch/0065-platform-x86-mlx-platform-Extend-FAN-and-LED-config-.patch index cb7b943fe..fd3177173 100644 --- a/patch/0065-platform-x86-mlx-platform-Extend-FAN-and-LED-co.patch +++ b/patch/0065-platform-x86-mlx-platform-Extend-FAN-and-LED-config-.patch @@ -1,7 +1,8 @@ +From 907562d549fefb326456b5c8c9f4e881d6379431 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 12 Jul 2021 22:20:35 +0000 -Subject: 0065 platform/x86: mlx-platform: Extend FAN and LED - config to support new MQM97xx systems +Subject: [PATCH backport 5.10 065/182] platform/x86: mlx-platform: Extend FAN + and LED config to support new MQM97xx systems Add support for new system types "MQM97xx", which is based on Mellanox Quantum-2 ASIC. It provides up to 64x400GB/s (IB) full bidirectional @@ -126,5 +127,5 @@ index 8e1e298cf18b..681b49fe4176 100644 case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET: -- -2.17.1 +2.20.1 diff --git a/patch/0066-platform-x86-mlx-platform-Add-new-attributes-fo.patch b/patch/0066-platform-x86-mlx-platform-Add-new-attributes-for-Cof.patch similarity index 91% rename from patch/0066-platform-x86-mlx-platform-Add-new-attributes-fo.patch rename to patch/0066-platform-x86-mlx-platform-Add-new-attributes-for-Cof.patch index f868b8ca4..a9568da4d 100644 --- a/patch/0066-platform-x86-mlx-platform-Add-new-attributes-fo.patch +++ b/patch/0066-platform-x86-mlx-platform-Add-new-attributes-for-Cof.patch @@ -1,7 +1,8 @@ +From 74e69c1a32afbd2496dc0597de2610e4488d7810 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Tue, 13 Jul 2021 15:20:13 +0000 -Subject: 0066 platform/x86: mlx-platform: Add new attributes for - CoffeeLake COMEx based systems +Subject: [PATCH backport 5.10 066/182] platform/x86: mlx-platform: Add new + attributes for CoffeeLake COMEx based systems Add new attributes for systems equipped with CoffeeLake COMEx module to represent various BIOS statuses: "bios_active_image", "bios_auth_fail", @@ -59,5 +60,5 @@ index 681b49fe4176..950d90e6412a 100644 .label = "voltreg_update_status", .reg = MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET, -- -2.17.1 +2.20.1 diff --git a/patch/0067-platform-mellanox-Add-dedicated-match-for-system-typ.patch b/patch/0067-platform-mellanox-Add-dedicated-match-for-system-typ.patch new file mode 100644 index 000000000..f079610ff --- /dev/null +++ b/patch/0067-platform-mellanox-Add-dedicated-match-for-system-typ.patch @@ -0,0 +1,434 @@ +From 8e3d1dbfd9cf686f9282d9b36f4ccc5ef3949ef5 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 7 Feb 2021 22:59:53 +0200 +Subject: [PATCH backport 5.10 067/182] platform/mellanox: Add dedicated match + for system type QMB8700 (downstream) + +Use dedicated match function for QMB8700 system in order to work-around +wrong CPLD register map. + +Note this is downstream kernel patch, no intention to upstream this +code. + +Signed-off-by: Oleksandr Shamray +Reviewed-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 353 ++++++++++++++++++++++++++++ + 1 file changed, 353 insertions(+) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 950d90e6412a..614b9f5c673f 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -201,6 +201,7 @@ + #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) + #define MLXPLAT_CPLD_ASIC_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(6, 0) ++#define MLXPLAT_CPLD_FAN_QMB8700_MASK GENMASK(5, 0) + #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) + #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) + #define MLXPLAT_CPLD_VOLTREG_UPD_MASK GENMASK(5, 4) +@@ -949,6 +950,57 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = { + }, + }; + ++static struct mlxreg_core_data mlxplat_mlxcpld_qmb8700_fan_items_data[] = { ++ { ++ .label = "fan1", ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = BIT(0), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(0), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "fan2", ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = BIT(1), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(1), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "fan3", ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = BIT(2), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(2), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "fan4", ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = BIT(3), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(3), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "fan5", ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = BIT(4), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(4), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "fan6", ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = BIT(5), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(5), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++}; ++ + static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = { + { + .data = mlxplat_mlxcpld_default_ng_psu_items_data, +@@ -988,6 +1040,45 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = { + }, + }; + ++static struct mlxreg_core_item mlxplat_mlxcpld_qmb8700_items[] = { ++ { ++ .data = mlxplat_mlxcpld_default_ng_psu_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = MLXPLAT_CPLD_PSU_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_ng_pwr_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = MLXPLAT_CPLD_PWR_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data), ++ .inversed = 0, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_qmb8700_fan_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = MLXPLAT_CPLD_FAN_QMB8700_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_qmb8700_fan_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_asic_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, ++ .mask = MLXPLAT_CPLD_ASIC_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), ++ .inversed = 0, ++ .health = true, ++ }, ++}; ++ + static + struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { + .items = mlxplat_mlxcpld_default_ng_items, +@@ -998,6 +1089,16 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, + }; + ++static ++struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_qmb8700_data = { ++ .items = mlxplat_mlxcpld_qmb8700_items, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_qmb8700_items), ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, ++ .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ++ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, ++}; ++ + /* Platform hotplug extended system family data */ + static struct mlxreg_core_data mlxplat_mlxcpld_ext_psu_items_data[] = { + { +@@ -2430,6 +2531,124 @@ static struct mlxreg_core_platform_data mlxplat_modular_led_data = { + .counter = ARRAY_SIZE(mlxplat_mlxcpld_modular_led_data), + }; + ++/* Platform led data for QMB8700 system */ ++static struct mlxreg_core_data mlxplat_mlxcpld_qmb8700_led_data[] = { ++ { ++ .label = "status:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ }, ++ { ++ .label = "status:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK ++ }, ++ { ++ .label = "psu:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ }, ++ { ++ .label = "psu:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ }, ++ { ++ .label = "fan1:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(0), ++ }, ++ { ++ .label = "fan1:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(0), ++ }, ++ { ++ .label = "fan2:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(1), ++ }, ++ { ++ .label = "fan2:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(1), ++ }, ++ { ++ .label = "fan3:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(2), ++ }, ++ { ++ .label = "fan3:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(2), ++ }, ++ { ++ .label = "fan4:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(3), ++ }, ++ { ++ .label = "fan4:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(3), ++ }, ++ { ++ .label = "fan5:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(4), ++ }, ++ { ++ .label = "fan5:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(4), ++ }, ++ { ++ .label = "fan6:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(5), ++ }, ++ { ++ .label = "fan6:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(5), ++ }, ++ { ++ .label = "uid:blue", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ }, ++}; ++ ++static struct mlxreg_core_platform_data mlxplat_qmb8700_led_data = { ++ .data = mlxplat_mlxcpld_qmb8700_led_data, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_qmb8700_led_data), ++}; ++ + /* Platform register access default */ + static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { + { +@@ -3592,6 +3811,107 @@ static struct mlxreg_core_platform_data mlxplat_default_fan_data = { + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + }; + ++/* Platform FAN default */ ++static struct mlxreg_core_data mlxplat_mlxcpld_qmb8700_fan_data[] = { ++ { ++ .label = "pwm1", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET, ++ }, ++ { ++ .label = "tacho1", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET, ++ .mask = GENMASK(7, 0), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, ++ .bit = BIT(0), ++ }, ++ { ++ .label = "tacho2", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET, ++ .mask = GENMASK(7, 0), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, ++ .bit = BIT(1), ++ }, ++ { ++ .label = "tacho3", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET, ++ .mask = GENMASK(7, 0), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, ++ .bit = BIT(2), ++ }, ++ { ++ .label = "tacho4", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET, ++ .mask = GENMASK(7, 0), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, ++ .bit = BIT(3), ++ }, ++ { ++ .label = "tacho5", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET, ++ .mask = GENMASK(7, 0), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, ++ .bit = BIT(4), ++ }, ++ { ++ .label = "tacho6", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET, ++ .mask = GENMASK(7, 0), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, ++ .bit = BIT(5), ++ }, ++ { ++ .label = "tacho7", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET, ++ .mask = GENMASK(7, 0), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, ++ .bit = BIT(6), ++ }, ++ { ++ .label = "tacho8", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET, ++ .mask = GENMASK(7, 0), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, ++ .bit = BIT(7), ++ }, ++ { ++ .label = "tacho9", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET, ++ .mask = GENMASK(7, 0), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET, ++ .bit = BIT(0), ++ }, ++ { ++ .label = "tacho10", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET, ++ .mask = GENMASK(7, 0), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET, ++ .bit = BIT(1), ++ }, ++ { ++ .label = "tacho11", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET, ++ .mask = GENMASK(7, 0), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET, ++ .bit = BIT(2), ++ }, ++ { ++ .label = "tacho12", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET, ++ .mask = GENMASK(7, 0), ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET, ++ .bit = BIT(3), ++ }, ++ { ++ .label = "conf", ++ .capability = MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET, ++ }, ++}; ++ ++static struct mlxreg_core_platform_data mlxplat_qmb8700_fan_data = { ++ .data = mlxplat_mlxcpld_qmb8700_fan_data, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_qmb8700_fan_data), ++}; ++ + /* Watchdog type1: hardware implementation version1 + * (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140 systems). + */ +@@ -4461,6 +4781,32 @@ static int __init mlxplat_dmi_modular_matched(const struct dmi_system_id *dmi) + return 1; + } + ++static int __init mlxplat_dmi_qmb8700_matched(const struct dmi_system_id *dmi) ++{ ++ int i; ++ ++ mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; ++ mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data); ++ mlxplat_mux_data = mlxplat_default_mux_data; ++ for (i = 0; i < mlxplat_mux_num; i++) { ++ mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; ++ mlxplat_mux_data[i].n_values = ++ ARRAY_SIZE(mlxplat_msn21xx_channels); ++ } ++ mlxplat_hotplug = &mlxplat_mlxcpld_qmb8700_data; ++ mlxplat_hotplug->deferred_nr = ++ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; ++ mlxplat_led = &mlxplat_qmb8700_led_data; ++ mlxplat_regs_io = &mlxplat_default_ng_regs_io_data; ++ mlxplat_fan = &mlxplat_qmb8700_fan_data; ++ for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) ++ mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; ++ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng; ++ ++ return 1; ++} ++ + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + { + .callback = mlxplat_dmi_default_matched, +@@ -4486,6 +4832,13 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"), + }, + }, ++ { ++ .callback = mlxplat_dmi_qmb8700_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MQM8700"), ++ }, ++ }, + { + .callback = mlxplat_dmi_qmb7xx_matched, + .matches = { +-- +2.20.1 + diff --git a/patch/0068-mlxsw-core-Initialize-switch-driver-last.patch b/patch/0068-mlxsw-core-Initialize-switch-driver-last.patch index 884c2ca16..7384e5da2 100644 --- a/patch/0068-mlxsw-core-Initialize-switch-driver-last.patch +++ b/patch/0068-mlxsw-core-Initialize-switch-driver-last.patch @@ -1,6 +1,8 @@ +From 1d25ce2427827b1c61924b0ed8e937118aaa0258 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 15 Aug 2021 14:09:51 +0300 -Subject: 0068 mlxsw: core: Initialize switch driver last +Subject: [PATCH backport 5.10 068/182] mlxsw: core: Initialize switch driver + last Commit 961cf99a074f ("mlxsw: core: Re-order initialization sequence") changed the initialization sequence so that the switch driver (e.g., @@ -87,5 +89,5 @@ index 1a86535c4968..b52bbd6b2fe4 100644 if (!reload) mlxsw_core_params_unregister(mlxsw_core); -- -2.17.1 +2.20.1 diff --git a/patch/0069-mlxsw-core-Remove-mlxsw_core_is_initialized.patch b/patch/0069-mlxsw-core-Remove-mlxsw_core_is_initialized.patch index 5cb212e45..a13416e66 100644 --- a/patch/0069-mlxsw-core-Remove-mlxsw_core_is_initialized.patch +++ b/patch/0069-mlxsw-core-Remove-mlxsw_core_is_initialized.patch @@ -1,6 +1,8 @@ +From 4c2b8360a04b6462f180b9b6793d9f511c08a808 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 15 Aug 2021 14:30:14 +0300 -Subject: 0069 mlxsw: core: Remove mlxsw_core_is_initialized() +Subject: [PATCH backport 5.10 069/182] mlxsw: core: Remove + mlxsw_core_is_initialized() After the previous patch, the switch driver is always initialized last, making this function redundant. @@ -84,5 +86,5 @@ index 3713c45cfa1e..27e721f96b3b 100644 return -EINVAL; -- -2.17.1 +2.20.1 diff --git a/patch/0070-mlxsw-core_env-Defer-handling-of-module-tempera.patch b/patch/0070-mlxsw-core_env-Defer-handling-of-module-temperature-.patch similarity index 93% rename from patch/0070-mlxsw-core_env-Defer-handling-of-module-tempera.patch rename to patch/0070-mlxsw-core_env-Defer-handling-of-module-temperature-.patch index cf8e2e6ff..6483a57ca 100644 --- a/patch/0070-mlxsw-core_env-Defer-handling-of-module-tempera.patch +++ b/patch/0070-mlxsw-core_env-Defer-handling-of-module-temperature-.patch @@ -1,7 +1,8 @@ +From a450d59b7be00520e8a2ab390b2bc1642cea34c8 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 15 Aug 2021 14:50:26 +0300 -Subject: 0070 mlxsw: core_env: Defer handling of module - temperature warning events +Subject: [PATCH backport 5.10 070/182] mlxsw: core_env: Defer handling of + module temperature warning events Module temperature events are currently handled in softIRQ context, requiring the 'module_info_lock' to be a spin lock. In future patchsets @@ -86,5 +87,5 @@ index 27e721f96b3b..27eba0a0c91c 100644 static int mlxsw_env_temp_warn_event_register(struct mlxsw_core *mlxsw_core) { -- -2.17.1 +2.20.1 diff --git a/patch/0071-mlxsw-core_env-Convert-module_info_lock-to-a-mu.patch b/patch/0071-mlxsw-core_env-Convert-module_info_lock-to-a-mutex.patch similarity index 96% rename from patch/0071-mlxsw-core_env-Convert-module_info_lock-to-a-mu.patch rename to patch/0071-mlxsw-core_env-Convert-module_info_lock-to-a-mutex.patch index b7fe1eeda..1dfeb00b4 100644 --- a/patch/0071-mlxsw-core_env-Convert-module_info_lock-to-a-mu.patch +++ b/patch/0071-mlxsw-core_env-Convert-module_info_lock-to-a-mutex.patch @@ -1,7 +1,8 @@ +From 0de1374694bd39c9d3e0a185c5da34506fd4aab9 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 15 Aug 2021 15:08:18 +0300 -Subject: 0071 mlxsw: core_env: Convert 'module_info_lock' to a - mutex +Subject: [PATCH backport 5.10 071/182] mlxsw: core_env: Convert + 'module_info_lock' to a mutex After the previous patch, the lock is always taken in process context so it can be converted to a mutex. It is needed for future changes where we @@ -118,5 +119,5 @@ index 27eba0a0c91c..543f401cb5c6 100644 kfree(env); } -- -2.17.1 +2.20.1 diff --git a/patch/0072-mlxsw-Track-per-module-port-status.patch b/patch/0072-mlxsw-Track-per-module-port-status.patch index c761b501a..efc1f9891 100644 --- a/patch/0072-mlxsw-Track-per-module-port-status.patch +++ b/patch/0072-mlxsw-Track-per-module-port-status.patch @@ -1,6 +1,7 @@ +From da6632aa3ca0d019a091e3fcb772c9eacf4127e9 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 2 Sep 2021 06:40:22 +0000 -Subject: 0072 mlxsw: Track per-module port status +Subject: [PATCH backport 5.10 072/182] mlxsw: Track per-module port status In the common port module core, track the number of logical ports that are mapped to the port module and the number of logical ports using it @@ -149,5 +150,5 @@ index a8c67b763c8b..e75b702aeb36 100644 }; -- -2.17.1 +2.20.1 diff --git a/patch/0073-mlxsw-reg-Add-fields-to-PMAOS-register.patch b/patch/0073-mlxsw-reg-Add-fields-to-PMAOS-register.patch index a611dba24..2102a1903 100644 --- a/patch/0073-mlxsw-reg-Add-fields-to-PMAOS-register.patch +++ b/patch/0073-mlxsw-reg-Add-fields-to-PMAOS-register.patch @@ -1,6 +1,8 @@ +From 1af02ef69c43c4ed19fee10181957fae8b3b3bd2 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 29 Jul 2021 15:15:23 +0300 -Subject: 0073 mlxsw: reg: Add fields to PMAOS register +Subject: [PATCH backport 5.10 073/182] mlxsw: reg: Add fields to PMAOS + register The Ports Module Administrative and Operational Status (PMAOS) register configures and retrieves the per-module status. Extend it with fields @@ -59,5 +61,5 @@ index 04f0c96c8068..dd72443c295f 100644 * Admin state update enable. * If this bit is set, admin state will be updated based on admin_state field. -- -2.17.1 +2.20.1 diff --git a/patch/0074-mlxsw-Make-PMAOS-pack-function-more-generic.patch b/patch/0074-mlxsw-Make-PMAOS-pack-function-more-generic.patch index 8cedecfbd..b0763ff2b 100644 --- a/patch/0074-mlxsw-Make-PMAOS-pack-function-more-generic.patch +++ b/patch/0074-mlxsw-Make-PMAOS-pack-function-more-generic.patch @@ -1,6 +1,8 @@ +From a09c5705bfca34abe259f3ed4d7ae262700c44f3 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 2 Aug 2021 10:12:31 +0300 -Subject: 0074 mlxsw: Make PMAOS pack function more generic +Subject: [PATCH backport 5.10 074/182] mlxsw: Make PMAOS pack function more + generic The PMAOS register has enable bits (e.g., PMAOS.ee) that allow changing only a subset of the fields, which is exactly what subsequent patches @@ -53,5 +55,5 @@ index dd72443c295f..0e18806b5834 100644 /* PPLR - Port Physical Loopback Register -- -2.17.1 +2.20.1 diff --git a/patch/0075-mlxsw-Add-support-for-transceiver-modules-reset.patch b/patch/0075-mlxsw-Add-support-for-transceiver-modules-reset.patch index ec2fbbccf..1aaf83391 100644 --- a/patch/0075-mlxsw-Add-support-for-transceiver-modules-reset.patch +++ b/patch/0075-mlxsw-Add-support-for-transceiver-modules-reset.patch @@ -1,6 +1,8 @@ +From 8d47608fe8545714121b1e9067c2431eefdb13fe Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 15 Aug 2021 18:12:37 +0300 -Subject: 0075 mlxsw: Add support for transceiver modules reset +Subject: [PATCH backport 5.10 075/182] mlxsw: Add support for transceiver + modules reset Implement support for ethtool_ops::reset in order to reset transceiver modules. The module backing the netdev is reset when the 'ETH_RESET_PHY' @@ -187,5 +189,5 @@ index e75b702aeb36..d8659ff68ffe 100644 static int -- -2.17.1 +2.20.1 diff --git a/patch/0076-ethtool-Add-ability-to-control-transceiver-modu.patch b/patch/0076-ethtool-Add-ability-to-control-transceiver-modules-p.patch similarity index 99% rename from patch/0076-ethtool-Add-ability-to-control-transceiver-modu.patch rename to patch/0076-ethtool-Add-ability-to-control-transceiver-modules-p.patch index eaccac4ca..37b649899 100644 --- a/patch/0076-ethtool-Add-ability-to-control-transceiver-modu.patch +++ b/patch/0076-ethtool-Add-ability-to-control-transceiver-modules-p.patch @@ -1,7 +1,8 @@ +From a0de9809b2d039b36f39dab066777233ce2844db Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 21 Jul 2021 17:05:31 +0300 -Subject: 0076 ethtool: Add ability to control transceiver - modules' power mode +Subject: [PATCH backport 5.10 076/182] ethtool: Add ability to control + transceiver modules' power mode Add a pair of new ethtool messages, 'ETHTOOL_MSG_MODULE_SET' and 'ETHTOOL_MSG_MODULE_GET', that can be used to control transceiver @@ -797,5 +798,5 @@ index 28dbd582c860..6c4a5b39d807 100644 #endif /* _NET_ETHTOOL_NETLINK_H */ -- -2.17.1 +2.20.1 diff --git a/patch/0077-mlxsw-reg-Add-Port-Module-Memory-Map-Properties.patch b/patch/0077-mlxsw-reg-Add-Port-Module-Memory-Map-Properties-regi.patch similarity index 93% rename from patch/0077-mlxsw-reg-Add-Port-Module-Memory-Map-Properties.patch rename to patch/0077-mlxsw-reg-Add-Port-Module-Memory-Map-Properties-regi.patch index 4f47191da..75c965524 100644 --- a/patch/0077-mlxsw-reg-Add-Port-Module-Memory-Map-Properties.patch +++ b/patch/0077-mlxsw-reg-Add-Port-Module-Memory-Map-Properties-regi.patch @@ -1,7 +1,8 @@ +From 8fdacd80f26d3ad6de5b1279981f17752e33c915 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 29 Jul 2021 15:58:12 +0300 -Subject: 0077 mlxsw: reg: Add Port Module Memory Map Properties - register +Subject: [PATCH backport 5.10 077/182] mlxsw: reg: Add Port Module Memory Map + Properties register Add the Port Module Memory Map Properties register. It will be used to set the power mode of a module in subsequent patches. @@ -80,5 +81,5 @@ index 0e18806b5834..0cc2fdaa459e 100644 MLXSW_REG(hpkt), MLXSW_REG(rgcr), -- -2.17.1 +2.20.1 diff --git a/patch/0078-mlxsw-reg-Add-Management-Cable-IO-and-Notificat.patch b/patch/0078-mlxsw-reg-Add-Management-Cable-IO-and-Notifications-.patch similarity index 93% rename from patch/0078-mlxsw-reg-Add-Management-Cable-IO-and-Notificat.patch rename to patch/0078-mlxsw-reg-Add-Management-Cable-IO-and-Notifications-.patch index a83c2420f..1846df10d 100644 --- a/patch/0078-mlxsw-reg-Add-Management-Cable-IO-and-Notificat.patch +++ b/patch/0078-mlxsw-reg-Add-Management-Cable-IO-and-Notifications-.patch @@ -1,6 +1,7 @@ +From 19ba46cee9e3610173c050667eefa3ef6609f4fc Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 30 Jul 2021 17:46:31 +0300 -Subject: 0078 mlxsw: reg: Add Management Cable IO and +Subject: [PATCH backport 5.10 078/182] mlxsw: reg: Add Management Cable IO and Notifications register Add the Management Cable IO and Notifications register. It will be used @@ -65,5 +66,5 @@ index 0cc2fdaa459e..7f9b902049db 100644 MLXSW_REG(mtutc), MLXSW_REG(mpsc), -- -2.17.1 +2.20.1 diff --git a/patch/0079-mlxsw-Add-ability-to-control-transceiver-module.patch b/patch/0079-mlxsw-Add-ability-to-control-transceiver-modules-pow.patch similarity index 98% rename from patch/0079-mlxsw-Add-ability-to-control-transceiver-module.patch rename to patch/0079-mlxsw-Add-ability-to-control-transceiver-modules-pow.patch index b321ecfcd..96af1a6dd 100644 --- a/patch/0079-mlxsw-Add-ability-to-control-transceiver-module.patch +++ b/patch/0079-mlxsw-Add-ability-to-control-transceiver-modules-pow.patch @@ -1,7 +1,8 @@ +From 7c7e9508c2bdc91c3c1cbc345b0ce816388690e6 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 16 Aug 2021 16:58:34 +0300 -Subject: 0079 mlxsw: Add ability to control transceiver modules' - power mode +Subject: [PATCH backport 5.10 079/182] mlxsw: Add ability to control + transceiver modules' power mode Implement support for ethtool_ops::.get_module_power_mode and ethtool_ops::set_module_power_mode. @@ -373,5 +374,5 @@ index d8659ff68ffe..3d07c2dcf08d 100644 static int -- -2.17.1 +2.20.1 diff --git a/patch/0080-ethtool-Add-transceiver-module-extended-states.patch b/patch/0080-ethtool-Add-transceiver-module-extended-states.patch index 7c90b505c..7a128c4b9 100644 --- a/patch/0080-ethtool-Add-transceiver-module-extended-states.patch +++ b/patch/0080-ethtool-Add-transceiver-module-extended-states.patch @@ -1,6 +1,8 @@ +From 3c154bac56bbf44419a17a431e931706550082a2 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 18 Aug 2021 10:13:47 +0300 -Subject: 0080 ethtool: Add transceiver module extended states +Subject: [PATCH backport 5.10 080/182] ethtool: Add transceiver module + extended states Add an extended state and two extended sub-states to describe link issues related to transceiver modules. @@ -86,5 +88,5 @@ index d49bad6446f9..970f1446eaf7 100644 /** -- -2.17.1 +2.20.1 diff --git a/patch/0081-platform-x86-mlx-platform-Add-support-for-multi.patch b/patch/0081-platform-x86-mlx-platform-Add-support-for-multiply-c.patch similarity index 77% rename from patch/0081-platform-x86-mlx-platform-Add-support-for-multi.patch rename to patch/0081-platform-x86-mlx-platform-Add-support-for-multiply-c.patch index 089608a4b..8f4162310 100644 --- a/patch/0081-platform-x86-mlx-platform-Add-support-for-multi.patch +++ b/patch/0081-platform-x86-mlx-platform-Add-support-for-multiply-c.patch @@ -1,7 +1,8 @@ +From 7de97d7e381e768ea11ad1f3520261d5e77c1ab4 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 19 Aug 2021 14:23:39 +0000 -Subject: 0081 platform/x86: mlx-platform: Add support for - multiply cooling devices +Subject: [PATCH backport 5.10 081/182] platform/x86: mlx-platform: Add support + for multiply cooling devices Add new registers to support systems with multiply cooling devices. Modular systems support up-to four cooling devices. This capability @@ -14,10 +15,10 @@ Reviewed-by: Michael 1 file changed, 12 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index 950d90e6412a..3d017e889ce5 100644 +index 614b9f5c673f..5c91410a649b 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c -@@ -3469,6 +3469,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { +@@ -3688,6 +3688,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { .label = "pwm1", .reg = MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET, }, @@ -37,5 +38,5 @@ index 950d90e6412a..3d017e889ce5 100644 .label = "tacho1", .reg = MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET, -- -2.17.1 +2.20.1 diff --git a/patch/0082-mlxsw-core-Extend-external-cooling-device-whitelist-.patch b/patch/0082-mlxsw-core-Extend-external-cooling-device-whitelist-.patch index 861590aba..0c752860c 100644 --- a/patch/0082-mlxsw-core-Extend-external-cooling-device-whitelist-.patch +++ b/patch/0082-mlxsw-core-Extend-external-cooling-device-whitelist-.patch @@ -1,8 +1,8 @@ -From 7ea34bd6ec1453e21f9f1d9442ea662a92423f32 Mon Sep 17 00:00:00 2001 +From 7fbd7c25c4010e8e5fbbc0d8741cff9c69bcea05 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 7 Oct 2021 19:30:05 +0000 -Subject: [PATCH backport 5.10/Alligator 1/9] mlxsw: core: Extend external - cooling device whitelist for thermal zone binding +Subject: [PATCH backport 5.10 082/182] mlxsw: core: Extend external cooling + device whitelist for thermal zone binding Allow thermal zone binding to an external cooling device of type "emc2305". @@ -17,10 +17,10 @@ Signed-off-by: Vadim Pasternak 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index f9c9ebf68..cc4cddbdb 100644 +index e1a760519097..91abc7a3f7ea 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -38,6 +38,7 @@ +@@ -30,6 +30,7 @@ /* External cooling devices, allowed for binding to mlxsw thermal zones. */ static char * const mlxsw_thermal_external_allowed_cdev[] = { "mlxreg_fan", diff --git a/patch/0083-platform_data-mlxreg-Add-field-for-notification-call.patch b/patch/0083-platform_data-mlxreg-Add-field-for-notification-call.patch index e4db5b240..14f636f17 100644 --- a/patch/0083-platform_data-mlxreg-Add-field-for-notification-call.patch +++ b/patch/0083-platform_data-mlxreg-Add-field-for-notification-call.patch @@ -1,7 +1,8 @@ -From abcebcd39fe094b68826cc04f2eca835606697f9 Mon Sep 17 00:00:00 2001 +From 2290cad212a30a34b3007c6cba5fa615d4c50a0e Mon Sep 17 00:00:00 2001 From: Michael Shych Date: Sat, 30 Apr 2022 14:58:07 +0300 -Subject: [PATCH] platform_data/mlxreg: Add field for notification callback +Subject: [PATCH backport 5.10 083/182] platform_data/mlxreg: Add field for + notification callback Add notification callback to inform caller that platform driver probing has been completed. It allows to caller to perform some initialization @@ -12,12 +13,14 @@ Reviewed-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220430115809.54565-2-michaelsh@nvidia.com Signed-off-by: Hans de Goede --- + include/linux/platform_data/mlxreg.h | 4 ++++ + 1 file changed, 4 insertions(+) diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h index 40185f9d7c14..a6bd74e29b6b 100644 --- a/include/linux/platform_data/mlxreg.h +++ b/include/linux/platform_data/mlxreg.h -@@ -216,6 +216,8 @@ +@@ -216,6 +216,8 @@ struct mlxreg_core_platform_data { * @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; @@ -26,7 +29,7 @@ index 40185f9d7c14..a6bd74e29b6b 100644 */ struct mlxreg_core_hotplug_platform_data { struct mlxreg_core_item *items; -@@ -228,6 +230,8 @@ +@@ -228,6 +230,8 @@ struct mlxreg_core_hotplug_platform_data { u32 mask_low; int deferred_nr; int shift_nr; @@ -35,3 +38,6 @@ index 40185f9d7c14..a6bd74e29b6b 100644 }; #endif /* __LINUX_PLATFORM_DATA_MLXREG_H */ +-- +2.20.1 + diff --git a/patch/0084-i2c-mlxcpld-Add-callback-to-notify-probing-completio.patch b/patch/0084-i2c-mlxcpld-Add-callback-to-notify-probing-completio.patch index 5cb708604..d21bda998 100644 --- a/patch/0084-i2c-mlxcpld-Add-callback-to-notify-probing-completio.patch +++ b/patch/0084-i2c-mlxcpld-Add-callback-to-notify-probing-completio.patch @@ -1,8 +1,8 @@ -From 81abceea27623640f0d69d1526cb6d11d964025d Mon Sep 17 00:00:00 2001 +From eea982a68f01f3e5e63e88d147f581b5c751dc81 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 7 Oct 2021 19:04:25 +0000 -Subject: [PATCH backport 5.10/Alligator 3/9] i2c: mlxcpld: Add callback to - notify probing completion +Subject: [PATCH backport 5.10 084/182] i2c: mlxcpld: Add callback to notify + probing completion Add notification to inform caller that driver probing has been completed. It allows to user, invoked platform device registration for @@ -15,7 +15,7 @@ Signed-off-by: Vadim Pasternak 1 file changed, 4 insertions(+) diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c -index 56aa424fd..fb451d42a 100644 +index 56aa424fd71d..363ea9fd66c4 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -560,6 +560,10 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) diff --git a/patch/0085-hwmon-powr1220-Upgrade-driver-to-support-hwmon-info-.patch b/patch/0085-hwmon-powr1220-Upgrade-driver-to-support-hwmon-info-.patch index 2e72be61a..499379a28 100644 --- a/patch/0085-hwmon-powr1220-Upgrade-driver-to-support-hwmon-info-.patch +++ b/patch/0085-hwmon-powr1220-Upgrade-driver-to-support-hwmon-info-.patch @@ -1,8 +1,8 @@ -From 915d4664b7158d8d0f44da810186742c69300f02 Mon Sep 17 00:00:00 2001 +From 8a3f701439798d55a93bba1f56d2a2aab4921293 Mon Sep 17 00:00:00 2001 From: Michael Shych Date: Tue, 18 Jan 2022 09:56:10 +0200 -Subject: [PATCH] hwmon: (powr1220) Upgrade driver to support hwmon info - infrastructure +Subject: [PATCH backport 5.10 085/182] hwmon: (powr1220) Upgrade driver to + support hwmon info infrastructure Reduce code by using devm_hwmon_device_register_with_groups() API by devm_hwmon_device_register_with_info() API. @@ -14,14 +14,14 @@ Reviewed-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220118075611.10665-3-michaelsh@nvidia.com Signed-off-by: Guenter Roeck --- - drivers/hwmon/powr1220.c | 207 +++++++++++++++++++++-------------------------- - 1 file changed, 92 insertions(+), 115 deletions(-) + drivers/hwmon/powr1220.c | 213 +++++++++++++++++---------------------- + 1 file changed, 95 insertions(+), 118 deletions(-) diff --git a/drivers/hwmon/powr1220.c b/drivers/hwmon/powr1220.c -index 542e4a7b0234..0fa1a136eec8 100644 +index 9e086338dcba..0fa1a136eec8 100644 --- a/drivers/hwmon/powr1220.c +++ b/drivers/hwmon/powr1220.c -@@ -111,7 +111,7 @@ +@@ -111,7 +111,7 @@ static int powr1220_read_adc(struct device *dev, int ch_num) mutex_lock(&data->update_lock); if (time_after(jiffies, data->adc_last_updated[ch_num] + HZ) || @@ -30,7 +30,7 @@ index 542e4a7b0234..0fa1a136eec8 100644 /* * figure out if we need to use the attenuator for * high inputs or inputs that we don't yet have a measurement -@@ -119,12 +119,12 @@ +@@ -119,12 +119,12 @@ static int powr1220_read_adc(struct device *dev, int ch_num) * max reading. */ if (data->adc_maxes[ch_num] > ADC_MAX_LOW_MEASUREMENT_MV || @@ -45,7 +45,7 @@ index 542e4a7b0234..0fa1a136eec8 100644 if (result) goto exit; -@@ -167,135 +167,109 @@ +@@ -167,135 +167,109 @@ static int powr1220_read_adc(struct device *dev, int ch_num) return result; } @@ -119,8 +119,7 @@ index 542e4a7b0234..0fa1a136eec8 100644 - struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct powr1220_data *data = dev_get_drvdata(dev); + int ret; - -- return sprintf(buf, "%s\n", input_names[attr->index]); ++ + switch (type) { + case hwmon_in: + switch (attr) { @@ -139,6 +138,10 @@ index 542e4a7b0234..0fa1a136eec8 100644 + break; + default: + return -EOPNOTSUPP; ++} + +- return sprintf(buf, "%s\n", input_names[attr->index]); ++ return 0; } -static SENSOR_DEVICE_ATTR_RO(in0_input, powr1220_voltage, VMON1); @@ -231,9 +234,6 @@ index 542e4a7b0234..0fa1a136eec8 100644 - &sensor_dev_attr_in11_label.dev_attr.attr, - &sensor_dev_attr_in12_label.dev_attr.attr, - &sensor_dev_attr_in13_label.dev_attr.attr, -+ return 0; -+} -+ +static const struct hwmon_channel_info *powr1220_info[] = { + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, @@ -268,7 +268,7 @@ index 542e4a7b0234..0fa1a136eec8 100644 static int powr1220_probe(struct i2c_client *client) { -@@ -312,8 +286,11 @@ +@@ -312,8 +286,11 @@ static int powr1220_probe(struct i2c_client *client) mutex_init(&data->update_lock); data->client = client; @@ -282,3 +282,6 @@ index 542e4a7b0234..0fa1a136eec8 100644 return PTR_ERR_OR_ZERO(hwmon_dev); } +-- +2.20.1 + diff --git a/patch/0086-hwmon-powr1220-Add-support-for-Lattice-s-POWR1014-po.patch b/patch/0086-hwmon-powr1220-Add-support-for-Lattice-s-POWR1014-po.patch index 39ccdcc41..949fcae0d 100644 --- a/patch/0086-hwmon-powr1220-Add-support-for-Lattice-s-POWR1014-po.patch +++ b/patch/0086-hwmon-powr1220-Add-support-for-Lattice-s-POWR1014-po.patch @@ -1,8 +1,8 @@ -From 9f93aa1005fa1b960f10e0ee3ed8c4e697526053 Mon Sep 17 00:00:00 2001 +From 6e39043862ce94cedaeabbb501feab34f7060ef5 Mon Sep 17 00:00:00 2001 From: Michael Shych Date: Tue, 18 Jan 2022 09:56:11 +0200 -Subject: [PATCH] hwmon: (powr1220) Add support for Lattice's POWR1014 power - manager IC +Subject: [PATCH backport 5.10 086/182] hwmon: (powr1220) Add support for + Lattice's POWR1014 power manager IC This patch adds support for Lattice's POWR1014 power manager IC. Read access to all the ADCs on the chip are supported through @@ -17,6 +17,8 @@ Reviewed-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220118075611.10665-4-michaelsh@nvidia.com Signed-off-by: Guenter Roeck --- + drivers/hwmon/powr1220.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/powr1220.c b/drivers/hwmon/powr1220.c index 0fa1a136eec8..f77dc6db31ac 100644 @@ -31,7 +33,7 @@ index 0fa1a136eec8..f77dc6db31ac 100644 enum powr1220_regs { VMON_STATUS0, VMON_STATUS1, -@@ -74,6 +76,7 @@ +@@ -74,6 +76,7 @@ enum powr1220_adc_values { struct powr1220_data { struct i2c_client *client; struct mutex update_lock; @@ -39,7 +41,7 @@ index 0fa1a136eec8..f77dc6db31ac 100644 bool adc_valid[MAX_POWR1220_ADC_VALUES]; /* the next value is in jiffies */ unsigned long adc_last_updated[MAX_POWR1220_ADC_VALUES]; -@@ -171,6 +174,11 @@ +@@ -171,6 +174,11 @@ static umode_t powr1220_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) { @@ -51,7 +53,7 @@ index 0fa1a136eec8..f77dc6db31ac 100644 switch (type) { case hwmon_in: switch (attr) { -@@ -271,6 +279,8 @@ +@@ -271,6 +279,8 @@ static const struct hwmon_chip_info powr1220_chip_info = { .info = powr1220_info, }; @@ -60,7 +62,7 @@ index 0fa1a136eec8..f77dc6db31ac 100644 static int powr1220_probe(struct i2c_client *client) { struct powr1220_data *data; -@@ -283,6 +293,15 @@ +@@ -283,6 +293,15 @@ static int powr1220_probe(struct i2c_client *client) if (!data) return -ENOMEM; @@ -76,7 +78,7 @@ index 0fa1a136eec8..f77dc6db31ac 100644 mutex_init(&data->update_lock); data->client = client; -@@ -296,7 +315,8 @@ +@@ -296,7 +315,8 @@ static int powr1220_probe(struct i2c_client *client) } static const struct i2c_device_id powr1220_ids[] = { @@ -86,3 +88,6 @@ index 0fa1a136eec8..f77dc6db31ac 100644 { } }; +-- +2.20.1 + diff --git a/patch/0087-hwmon-Add-support-for-EMC2305-RPM-based-PWM-Fan-Spee.patch b/patch/0087-hwmon-Add-support-for-EMC2305-RPM-based-PWM-Fan-Spee.patch index 608c96620..ddcf2b4d9 100644 --- a/patch/0087-hwmon-Add-support-for-EMC2305-RPM-based-PWM-Fan-Spee.patch +++ b/patch/0087-hwmon-Add-support-for-EMC2305-RPM-based-PWM-Fan-Spee.patch @@ -1,7 +1,7 @@ -From 9665518f7ec26d85930b57343b68da8f7524119e Mon Sep 17 00:00:00 2001 +From d439a8e75600c9919c8f1380c18a5141d271412a Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 9 Oct 2021 08:49:14 +0000 -Subject: [PATCH backport 5.10/Alligator 6/9] hwmon: Add support for EMC2305 +Subject: [PATCH backport 5.10 087/182] hwmon: Add support for EMC2305 RPM-based PWM Fan Speed Controller Introduce EMC2305 RPM-based PWM Fan Speed Controller @@ -22,12 +22,12 @@ Signed-off-by: Michael Shych --- drivers/hwmon/Kconfig | 12 + drivers/hwmon/Makefile | 1 + - drivers/hwmon/emc2305.c | 518 ++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 531 insertions(+) + drivers/hwmon/emc2305.c | 522 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 535 insertions(+) create mode 100644 drivers/hwmon/emc2305.c diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index a850e4f0e..6512c0c5b 100644 +index f741c7492ee4..93d0313aa210 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1601,6 +1601,18 @@ config SENSORS_EMC2103 @@ -50,7 +50,7 @@ index a850e4f0e..6512c0c5b 100644 tristate "SMSC EMC6W201" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index 9db2903b6..644a7e6ee 100644 +index 9db2903b61e5..644a7e6eeae6 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_SENSORS_DS620) += ds620.o @@ -63,10 +63,10 @@ index 9db2903b6..644a7e6ee 100644 obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c new file mode 100644 -index 000000000..3f98bdcd2 +index 000000000000..04bc9f658d85 --- /dev/null +++ b/drivers/hwmon/emc2305.c -@@ -0,0 +1,523 @@ +@@ -0,0 +1,522 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hardware monitoring driver for EMC2305 fan controller @@ -589,7 +589,6 @@ index 000000000..3f98bdcd2 +MODULE_AUTHOR("Claud Chang "); +MODULE_DESCRIPTION("SMSC EMC2305 fan controller driver"); +MODULE_LICENSE("GPL"); -+ --- +-- 2.20.1 diff --git a/patch/0088-dt-bindings-Add-description-for-EMC2305-for-RPM-base.patch b/patch/0088-dt-bindings-Add-description-for-EMC2305-for-RPM-base.patch deleted file mode 100644 index 372408fe2..000000000 --- a/patch/0088-dt-bindings-Add-description-for-EMC2305-for-RPM-base.patch +++ /dev/null @@ -1,69 +0,0 @@ -From f725a91ddff83408baefcb2ac7e81aeb478079f9 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Sat, 16 Oct 2021 10:52:13 +0000 -Subject: [PATCH backport 5.10/Alligator 7/9] dt-bindings: Add description for - EMC2305 for RPM-based PWM Fan Speed Controller - -Michrochip EMC2305 RPM-based PWM Fan Speed Controller. - -Signed-off-by: Michael Shych ---- - .../devicetree/bindings/hwmon/emc2305.yaml | 46 +++++++++++++++++++ - 1 file changed, 46 insertions(+) - create mode 100644 Documentation/devicetree/bindings/hwmon/emc2305.yaml - -diff --git a/Documentation/devicetree/bindings/hwmon/emc2305.yaml b/Documentation/devicetree/bindings/hwmon/emc2305.yaml -new file mode 100644 -index 000000000..8a46c02a3 ---- /dev/null -+++ b/Documentation/devicetree/bindings/hwmon/emc2305.yaml -@@ -0,0 +1,46 @@ -+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) -+%YAML 1.2 -+--- -+ -+$id: http://devicetree.org/schemas/hwmon/emc2305.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: RPM-based PWM Fan Speed Controller EMC2305 -+ -+maintainers: -+ - Claud Chang -+ -+properties: -+ compatible: -+ enum: -+ - emc2305 -+ -+ emc2305,min-pwm: -+ description: -+ Min pwm of emc2305 -+ maxItems: 1 -+ emc2305,max-pwm: -+ description: -+ Max pwm of emc2305 -+ maxItems: 1 -+ emc2305,cooling-levels: -+ description: -+ Quantity of cooling level state. -+ maxItems: 1 -+ -+required: -+ - compatible -+ - emc2305,min-pwm -+ - emc2305,max-pwm -+ - emc2305,cooling-levels -+ -+additionalProperties: false -+ -+examples: -+ - | -+ fan@1 { -+ compatible = "smsc,emc2305"; -+ emc2305,min-pwm = <0>; -+ emc2305,max-pwm = <255>; -+ emc2305,cooling-levels = <10>; -+ } --- -2.20.1 - diff --git a/patch/0089-platform-mellanox-Add-support-for-new-SN2201-system.patch b/patch/0089-platform-mellanox-Add-support-for-new-SN2201-system.patch index 4b354ae37..389047ea7 100644 --- a/patch/0089-platform-mellanox-Add-support-for-new-SN2201-system.patch +++ b/patch/0089-platform-mellanox-Add-support-for-new-SN2201-system.patch @@ -1,7 +1,8 @@ -From 662f24826f954d49d56211822bcd7b3109287961 Mon Sep 17 00:00:00 2001 +From dac063a274f4553f3ea0cf17a37dece1d9ea1207 Mon Sep 17 00:00:00 2001 From: Michael Shych Date: Sat, 30 Apr 2022 14:58:08 +0300 -Subject: [PATCH] platform/mellanox: Add support for new SN2201 system +Subject: [PATCH backport 5.10 089/182] platform/mellanox: Add support for new + SN2201 system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -38,11 +39,17 @@ Reviewed-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220430115809.54565-3-michaelsh@nvidia.com Signed-off-by: Hans de Goede --- + drivers/platform/mellanox/Kconfig | 17 + + drivers/platform/mellanox/Makefile | 1 + + drivers/platform/mellanox/nvsw-sn2201.c | 1261 +++++++++++++++++++++++ + 3 files changed, 1279 insertions(+) + create mode 100644 drivers/platform/mellanox/nvsw-sn2201.c + diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig -index d4c5c170bca0..72df4b8f4dd8 100644 +index 8f6c89f0b4ff..75e2bee17606 100644 --- a/drivers/platform/mellanox/Kconfig +++ b/drivers/platform/mellanox/Kconfig -@@ -68,4 +68,21 @@ +@@ -68,4 +68,21 @@ config MLXBF_BOOTCTL to the userspace tools, to be used in conjunction with the eMMC device driver to do necessary initial swap of the boot partition. @@ -65,17 +72,17 @@ index d4c5c170bca0..72df4b8f4dd8 100644 + endif # MELLANOX_PLATFORM diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile -index a4868366ff18..04703c0416b1 100644 +index e47b6b064881..6af37ee88861 100644 --- a/drivers/platform/mellanox/Makefile +++ b/drivers/platform/mellanox/Makefile -@@ -8,3 +8,4 @@ +@@ -8,3 +8,4 @@ obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o obj-$(CONFIG_MLXREG_LC) += mlxreg-lc.o +obj-$(CONFIG_NVSW_SN2201) += nvsw-sn2201.o diff --git a/drivers/platform/mellanox/nvsw-sn2201.c b/drivers/platform/mellanox/nvsw-sn2201.c new file mode 100644 -index 000000000000..0bcdc7c75007 +index 000000000000..51da240ce4f9 --- /dev/null +++ b/drivers/platform/mellanox/nvsw-sn2201.c @@ -0,0 +1,1261 @@ @@ -1340,3 +1347,6 @@ index 000000000000..0bcdc7c75007 +MODULE_DESCRIPTION("Nvidia sn2201 platform driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:nvsw-sn2201"); +-- +2.20.1 + diff --git a/patch/0090-Documentation-ABI-Add-new-attributes-for-mlxreg-io-s.patch b/patch/0090-Documentation-ABI-Add-new-attributes-for-mlxreg-io-s.patch index 14b729ea9..4e5fdc758 100644 --- a/patch/0090-Documentation-ABI-Add-new-attributes-for-mlxreg-io-s.patch +++ b/patch/0090-Documentation-ABI-Add-new-attributes-for-mlxreg-io-s.patch @@ -1,8 +1,8 @@ -From b1a9c69792caaac0813c9dc7806fb8654212e56c Mon Sep 17 00:00:00 2001 +From d563b6d291495af320cbbd5733933bc09855080c Mon Sep 17 00:00:00 2001 From: Michael Shych Date: Sat, 30 Apr 2022 14:58:09 +0300 -Subject: [PATCH] Documentation/ABI: Add new attributes for mlxreg-io sysfs - interfaces +Subject: [PATCH backport 5.10 090/182] Documentation/ABI: Add new attributes + for mlxreg-io sysfs interfaces Add documentation for the new attributes: - "phy_reset" - Reset PHY. @@ -14,14 +14,14 @@ Reviewed-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220430115809.54565-4-michaelsh@nvidia.com Signed-off-by: Hans de Goede --- - Documentation/ABI/stable/sysfs-driver-mlxreg-io | 36 +++++++++++++++++++++++++ + .../ABI/stable/sysfs-driver-mlxreg-io | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Documentation/ABI/stable/sysfs-driver-mlxreg-io b/Documentation/ABI/stable/sysfs-driver-mlxreg-io -index 12c3f895cd2f..b312242d4f40 100644 +index e2f938499473..0913a8daf767 100644 --- a/Documentation/ABI/stable/sysfs-driver-mlxreg-io +++ b/Documentation/ABI/stable/sysfs-driver-mlxreg-io -@@ -451,3 +451,39 @@ +@@ -451,3 +451,39 @@ Description: These files provide the maximum powered required for line card feeding and line card configuration Id. The files are read only. @@ -61,3 +61,6 @@ index 12c3f895cd2f..b312242d4f40 100644 + 0 - Power good, 1 - Not power good. + + The files are read only. +-- +2.20.1 + diff --git a/patch/0091-platform-x86-mlx-platform-Add-support-for-new-s.patch b/patch/0091-platform-x86-mlx-platform-Add-support-for-new-system.patch similarity index 90% rename from patch/0091-platform-x86-mlx-platform-Add-support-for-new-s.patch rename to patch/0091-platform-x86-mlx-platform-Add-support-for-new-system.patch index 4bdd1707f..043f348c5 100644 --- a/patch/0091-platform-x86-mlx-platform-Add-support-for-new-s.patch +++ b/patch/0091-platform-x86-mlx-platform-Add-support-for-new-system.patch @@ -1,7 +1,8 @@ +From ececae8bc325e3b01f36fd694e45a4cbbad334e4 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sat, 23 Oct 2021 12:40:22 +0300 -Subject: 0091 platform/x86: mlx-platform: Add support for new - system SGN2410 +Subject: [PATCH backport 5.10 091/182] platform/x86: mlx-platform: Add support + for new system SGN2410 Add support for new system type, which is a water-cooling flavor of the VMOD001 system class, equipped with 48xSFP28 and 8xQSFP28 @@ -20,10 +21,10 @@ Signed-off-by: Hans de Goede 1 file changed, 113 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index 3d017e889ce5..447044fdcb77 100644 +index 5c91410a649b..fac4b6dcfdc7 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c -@@ -533,6 +533,21 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = { +@@ -534,6 +534,21 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = { }, }; @@ -45,7 +46,7 @@ index 3d017e889ce5..447044fdcb77 100644 static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { { .label = "fan1", -@@ -661,6 +676,46 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { +@@ -662,6 +677,46 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, }; @@ -92,7 +93,7 @@ index 3d017e889ce5..447044fdcb77 100644 static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_comex_data = { .items = mlxplat_mlxcpld_comex_items, -@@ -2018,6 +2073,35 @@ static struct mlxreg_core_platform_data mlxplat_default_led_data = { +@@ -2119,6 +2174,35 @@ static struct mlxreg_core_platform_data mlxplat_default_led_data = { .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_data), }; @@ -128,7 +129,7 @@ index 3d017e889ce5..447044fdcb77 100644 /* Platform led MSN21xx system family data */ static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_led_data[] = { { -@@ -4311,6 +4395,28 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) +@@ -4631,6 +4715,28 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) return 1; } @@ -157,7 +158,7 @@ index 3d017e889ce5..447044fdcb77 100644 static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) { int i; -@@ -4474,6 +4580,13 @@ static int __init mlxplat_dmi_modular_matched(const struct dmi_system_id *dmi) +@@ -4820,6 +4926,13 @@ static int __init mlxplat_dmi_qmb8700_matched(const struct dmi_system_id *dmi) } static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { @@ -172,5 +173,5 @@ index 3d017e889ce5..447044fdcb77 100644 .callback = mlxplat_dmi_default_matched, .matches = { -- -2.17.1 +2.20.1 diff --git a/patch/0092-platform-mellanox-mlxreg-lc-fix-error-code-in-m.patch b/patch/0092-platform-mellanox-mlxreg-lc-fix-error-code-in-mlxreg.patch similarity index 87% rename from patch/0092-platform-mellanox-mlxreg-lc-fix-error-code-in-m.patch rename to patch/0092-platform-mellanox-mlxreg-lc-fix-error-code-in-mlxreg.patch index ab6ef6203..963dae598 100644 --- a/patch/0092-platform-mellanox-mlxreg-lc-fix-error-code-in-m.patch +++ b/patch/0092-platform-mellanox-mlxreg-lc-fix-error-code-in-mlxreg.patch @@ -1,7 +1,8 @@ +From 925c0bdeb184d3ec04cc6dd46f9e9b0c2f27ac7c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 10 Nov 2021 10:43:46 +0300 -Subject: 0092 platform/mellanox: mlxreg-lc: fix error code in - mlxreg_lc_create_static_devices() +Subject: [PATCH backport 5.10 092/182] platform/mellanox: mlxreg-lc: fix error + code in mlxreg_lc_create_static_devices() This code should be using PTR_ERR() instead of IS_ERR(). And because it's using the wrong "dev->client" pointer, the IS_ERR() check will be @@ -18,7 +19,7 @@ Signed-off-by: Hans de Goede 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c -index c2ccb38df693..244676a12d74 100644 +index 2ddad96b154a..75c28179dd07 100644 --- a/drivers/platform/mellanox/mlxreg-lc.c +++ b/drivers/platform/mellanox/mlxreg-lc.c @@ -420,7 +420,7 @@ mlxreg_lc_create_static_devices(struct mlxreg_lc *mlxreg_lc, struct mlxreg_hotpl @@ -48,5 +49,5 @@ index c2ccb38df693..244676a12d74 100644 static void -- -2.17.1 +2.20.1 diff --git a/patch/0093-hwmon-mlxreg-fan-Extend-driver-to-support-multi.patch b/patch/0093-hwmon-mlxreg-fan-Extend-driver-to-support-multiply-P.patch similarity index 96% rename from patch/0093-hwmon-mlxreg-fan-Extend-driver-to-support-multi.patch rename to patch/0093-hwmon-mlxreg-fan-Extend-driver-to-support-multiply-P.patch index 57d29b04b..611af1d0c 100644 --- a/patch/0093-hwmon-mlxreg-fan-Extend-driver-to-support-multi.patch +++ b/patch/0093-hwmon-mlxreg-fan-Extend-driver-to-support-multiply-P.patch @@ -1,7 +1,8 @@ +From fc25f37b0269b04b9853c2d62a80e0542f47506d Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 16 Sep 2021 22:47:18 +0300 -Subject: 0093 hwmon: (mlxreg-fan) Extend driver to support - multiply PWM +Subject: [PATCH backport 5.10 093/182] hwmon: (mlxreg-fan) Extend driver to + support multiply PWM Add additional PWM attributes in order to support the systems, which can be equipped with up-to four PWM controllers. System capability of @@ -16,7 +17,7 @@ Signed-off-by: Guenter Roeck 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c -index 35c283405df6..efc16ee09153 100644 +index 0f5b109817a7..1a146cc4b0fd 100644 --- a/drivers/hwmon/mlxreg-fan.c +++ b/drivers/hwmon/mlxreg-fan.c @@ -13,6 +13,8 @@ @@ -179,5 +180,5 @@ index 35c283405df6..efc16ee09153 100644 if (configured) { dev_err(fan->dev, "duplicate conf entry: %s\n", -- -2.17.1 +2.20.1 diff --git a/patch/0094-hwmon-mlxreg-fan-Extend-driver-to-support-multi.patch b/patch/0094-hwmon-mlxreg-fan-Extend-driver-to-support-multiply-c.patch similarity index 95% rename from patch/0094-hwmon-mlxreg-fan-Extend-driver-to-support-multi.patch rename to patch/0094-hwmon-mlxreg-fan-Extend-driver-to-support-multiply-c.patch index 88e9e1212..2b5c5b6cf 100644 --- a/patch/0094-hwmon-mlxreg-fan-Extend-driver-to-support-multi.patch +++ b/patch/0094-hwmon-mlxreg-fan-Extend-driver-to-support-multiply-c.patch @@ -1,7 +1,8 @@ +From 6518f8a96184e989d93b17700ac110da30ec8b53 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Fri, 17 Sep 2021 00:31:28 +0300 -Subject: 0094 hwmon: (mlxreg-fan) Extend driver to support - multiply cooling devices +Subject: [PATCH backport 5.10 094/182] hwmon: (mlxreg-fan) Extend driver to + support multiply cooling devices Add support for additional cooling devices in order to support the systems, which can be equipped with up-to four PWM controllers. @@ -13,7 +14,7 @@ Signed-off-by: Guenter Roeck 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c -index efc16ee09153..b7d9b38e1175 100644 +index 1a146cc4b0fd..35228ed112d7 100644 --- a/drivers/hwmon/mlxreg-fan.c +++ b/drivers/hwmon/mlxreg-fan.c @@ -63,6 +63,8 @@ @@ -88,7 +89,7 @@ index efc16ee09153..b7d9b38e1175 100644 int i, config = 0; u32 regval; @@ -348,11 +354,11 @@ static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev, - config = 0; /*1*/; + config = 1; state -= MLXREG_FAN_MAX_STATE; for (i = 0; i < state; i++) - fan->cooling_levels[i] = state; @@ -172,5 +173,5 @@ index efc16ee09153..b7d9b38e1175 100644 static struct platform_driver mlxreg_fan_driver = { -- -2.17.1 +2.20.1 diff --git a/patch/0095-hwmon-mlxreg-fan-Fix-out-of-bounds-read-on-arra.patch b/patch/0095-hwmon-mlxreg-fan-Fix-out-of-bounds-read-on-array-fan.patch similarity index 84% rename from patch/0095-hwmon-mlxreg-fan-Fix-out-of-bounds-read-on-arra.patch rename to patch/0095-hwmon-mlxreg-fan-Fix-out-of-bounds-read-on-array-fan.patch index 1974b6ffc..a1e16a23f 100644 --- a/patch/0095-hwmon-mlxreg-fan-Fix-out-of-bounds-read-on-arra.patch +++ b/patch/0095-hwmon-mlxreg-fan-Fix-out-of-bounds-read-on-array-fan.patch @@ -1,7 +1,8 @@ +From 3e3dcc8a418d6901578e20b081bbf75f2c7a7316 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 20 Sep 2021 19:09:21 +0100 -Subject: 0095 hwmon: (mlxreg-fan) Fix out of bounds read on - array fan->pwm +Subject: [PATCH backport 5.10 095/182] hwmon: (mlxreg-fan) Fix out of bounds + read on array fan->pwm Array fan->pwm[] is MLXREG_FAN_MAX_PWM elements in size, however the for-loop has a off-by-one error causing index i to be out of range @@ -19,7 +20,7 @@ Signed-off-by: Guenter Roeck 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c -index b7d9b38e1175..21190020172a 100644 +index 35228ed112d7..feab9ec6a6ca 100644 --- a/drivers/hwmon/mlxreg-fan.c +++ b/drivers/hwmon/mlxreg-fan.c @@ -554,7 +554,7 @@ static int mlxreg_fan_cooling_config(struct device *dev, struct mlxreg_fan *fan) @@ -32,5 +33,5 @@ index b7d9b38e1175..21190020172a 100644 if (!pwm->connected) -- -2.17.1 +2.20.1 diff --git a/patch/0096-hwmon-mlxreg-fan-Modify-PWM-connectivity-valida.patch b/patch/0096-hwmon-mlxreg-fan-Modify-PWM-connectivity-validation.patch similarity index 85% rename from patch/0096-hwmon-mlxreg-fan-Modify-PWM-connectivity-valida.patch rename to patch/0096-hwmon-mlxreg-fan-Modify-PWM-connectivity-validation.patch index 967b2f11c..1cc2fe948 100644 --- a/patch/0096-hwmon-mlxreg-fan-Modify-PWM-connectivity-valida.patch +++ b/patch/0096-hwmon-mlxreg-fan-Modify-PWM-connectivity-validation.patch @@ -1,7 +1,8 @@ +From 66cfe84c9fd69ec5f98e1ff2888898ea24d4f7ae Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 26 Sep 2021 08:35:40 +0300 -Subject: 0096 hwmon: (mlxreg-fan) Modify PWM connectivity - validation +Subject: [PATCH backport 5.10 096/182] hwmon: (mlxreg-fan) Modify PWM + connectivity validation Validate PWM connectivity only for additional PWM - "pwm1" is connected on all systems, while "pwm2" - "pwm4" are optional. Validate @@ -17,7 +18,7 @@ Signed-off-by: Guenter Roeck 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c -index 21190020172a..780ae56a59ef 100644 +index feab9ec6a6ca..8e5cd6991929 100644 --- a/drivers/hwmon/mlxreg-fan.c +++ b/drivers/hwmon/mlxreg-fan.c @@ -488,9 +488,14 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, @@ -39,5 +40,5 @@ index 21190020172a..780ae56a59ef 100644 fan->pwm[pwm_num].reg = data->reg; fan->pwm[pwm_num].connected = true; -- -2.17.1 +2.20.1 diff --git a/patch/0097-hwmon-mlxreg-fan-Support-distinctive-names-per-.patch b/patch/0097-hwmon-mlxreg-fan-Support-distinctive-names-per-diffe.patch similarity index 88% rename from patch/0097-hwmon-mlxreg-fan-Support-distinctive-names-per-.patch rename to patch/0097-hwmon-mlxreg-fan-Support-distinctive-names-per-diffe.patch index a5c4ce34f..444cf3298 100644 --- a/patch/0097-hwmon-mlxreg-fan-Support-distinctive-names-per-.patch +++ b/patch/0097-hwmon-mlxreg-fan-Support-distinctive-names-per-diffe.patch @@ -1,7 +1,8 @@ +From 9e274525918eab0b820a88cf44238aae5d1a5b75 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 26 Sep 2021 08:35:41 +0300 -Subject: 0097 hwmon: (mlxreg-fan) Support distinctive names per - different cooling devices +Subject: [PATCH backport 5.10 097/182] hwmon: (mlxreg-fan) Support distinctive + names per different cooling devices Provide different names for cooling devices registration to allow binding each cooling devices to relevant thermal zone. Thus, specific @@ -17,7 +18,7 @@ Signed-off-by: Guenter Roeck 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c -index 780ae56a59ef..acba9d6888d4 100644 +index 8e5cd6991929..4a8becdb0d58 100644 --- a/drivers/hwmon/mlxreg-fan.c +++ b/drivers/hwmon/mlxreg-fan.c @@ -263,6 +263,13 @@ mlxreg_fan_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, @@ -46,5 +47,5 @@ index 780ae56a59ef..acba9d6888d4 100644 dev_err(dev, "Failed to register cooling device\n"); return PTR_ERR(pwm->cdev); -- -2.17.1 +2.20.1 diff --git a/patch/0098-mlxsw-i2c-Prevent-transaction-execution-for.patch b/patch/0098-mlxsw-i2c-Prevent-transaction-execution-for.patch deleted file mode 100644 index 4249ad90d..000000000 --- a/patch/0098-mlxsw-i2c-Prevent-transaction-execution-for.patch +++ /dev/null @@ -1,126 +0,0 @@ -From d3e0bf403d527f717a62ea328781256f999d4f95 Mon Sep 17 00:00:00 2001 -From: Stepan Blyschak -Date: Mon, 20 Jun 2022 19:28:04 +0300 -Subject: [PATCH] mlxsw: i2c: Prevent transaction execution for special - chip states - -Do not run transaction in cases chip is in reset or in-service update -states. In such case firmware is not accessible and will reject transaction -with the relevant status "RUNNING_RESET" or "FW_ISSU_ONGOING". -In case transaction is failed do to one of these reasons, stop sending -transactions. In such case driver is about to be removed since it -cannot continue running after reset or in-service update. And -re-probed again after reset or in-service update is completed. - -Signed-off-by: Vadim Pasternak -Signed-off-by: Stepan Blyschak ---- - drivers/net/ethernet/mellanox/mlxsw/cmd.h | 4 ++++ - drivers/net/ethernet/mellanox/mlxsw/i2c.c | 29 ++++++++++++++++++++--- - 2 files changed, 30 insertions(+), 3 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/cmd.h b/drivers/net/ethernet/mellanox/mlxsw/cmd.h -index 91f68fb0b..d8ecb8c8a 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/cmd.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/cmd.h -@@ -149,6 +149,8 @@ enum mlxsw_cmd_status { - MLXSW_CMD_STATUS_BAD_NVMEM = 0x0B, - /* Device is currently running reset */ - MLXSW_CMD_STATUS_RUNNING_RESET = 0x26, -+ /* FW ISSU ongoing. */ -+ MLXSW_CMD_STATUS_FW_ISSU = 0x27, - /* Bad management packet (silently discarded). */ - MLXSW_CMD_STATUS_BAD_PKT = 0x30, - }; -@@ -180,6 +182,8 @@ static inline const char *mlxsw_cmd_status_str(u8 status) - return "BAD_NVMEM"; - case MLXSW_CMD_STATUS_RUNNING_RESET: - return "RUNNING_RESET"; -+ case MLXSW_CMD_STATUS_FW_ISSU: -+ return "FW_ISSU_ONGOING"; - case MLXSW_CMD_STATUS_BAD_PKT: - return "BAD_PKT"; - default: -diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c -index 939b692ff..3c9d2c7a0 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c -@@ -63,6 +63,7 @@ - * @core: switch core pointer; - * @bus_info: bus info block; - * @block_size: maximum block size allowed to pass to under layer; -+ * @status: status to indicate chip reset or in-service update; - */ - struct mlxsw_i2c { - struct { -@@ -76,6 +77,7 @@ struct mlxsw_i2c { - struct mlxsw_core *core; - struct mlxsw_bus_info bus_info; - u16 block_size; -+ u8 status; - }; - - #define MLXSW_I2C_READ_MSG(_client, _addr_buf, _buf, _len) { \ -@@ -222,6 +224,19 @@ static int mlxsw_i2c_write_cmd(struct i2c_client *client, - return 0; - } - -+static bool -+mlxsw_i2c_cmd_status_verify(struct device *dev, struct mlxsw_i2c *mlxsw_i2c, -+ u8 status) -+{ -+ if (status == MLXSW_CMD_STATUS_FW_ISSU || -+ status == MLXSW_CMD_STATUS_RUNNING_RESET) { -+ mlxsw_i2c->status = status; -+ dev_info(dev, "FW status=%x(%s)): Access to device is not allowed in this state\n", status, mlxsw_cmd_status_str(status)); -+ return true; -+ } -+ return false; -+} -+ - /* Routine posts initialization command to ASIC through mail box. */ - static int - mlxsw_i2c_write_init_cmd(struct i2c_client *client, -@@ -405,6 +420,10 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, - - WARN_ON(in_mbox_size % sizeof(u32) || out_mbox_size % sizeof(u32)); - -+ /* Do not run transaction if chip is in reset or in-service update state. */ -+ if (mlxsw_i2c->status) -+ return 0; -+ - if (in_mbox) { - reg_size = mlxsw_i2c_get_reg_size(in_mbox); - num = reg_size / mlxsw_i2c->block_size; -@@ -479,6 +498,8 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, - - cmd_fail: - mutex_unlock(&mlxsw_i2c->cmd.lock); -+ if (mlxsw_i2c_cmd_status_verify(&client->dev, mlxsw_i2c, *status)) -+ err = 0; - return err; - } - -@@ -608,14 +629,16 @@ static int mlxsw_i2c_probe(struct i2c_client *client, - /* Wait until go bit is cleared. */ - err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, &status); - if (err) { -- dev_err(&client->dev, "HW semaphore is not released"); -+ if (!mlxsw_i2c_cmd_status_verify(&client->dev, mlxsw_i2c, status)) -+ dev_err(&client->dev, "HW semaphore is not released"); - goto errout; - } - - /* Validate transaction completion status. */ - if (status) { -- dev_err(&client->dev, "Bad transaction completion status %x\n", -- status); -+ if (!mlxsw_i2c_cmd_status_verify(&client->dev, mlxsw_i2c, status)) -+ dev_err(&client->dev, "Bad transaction completion status %x\n", -+ status); - err = -EIO; - goto errout; - } --- -2.17.1 - diff --git a/patch/0099-mlxsw-core_hwmon-Fix-variable-names-for-hwmon-attrib.patch b/patch/0099-mlxsw-core_hwmon-Fix-variable-names-for-hwmon-attrib.patch new file mode 100644 index 000000000..34822879a --- /dev/null +++ b/patch/0099-mlxsw-core_hwmon-Fix-variable-names-for-hwmon-attrib.patch @@ -0,0 +1,256 @@ +From 320a964b80a8f9245da0515a26c2d41e035b3d10 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:41 +0200 +Subject: [PATCH backport 5.10 099/182] mlxsw: core_hwmon: Fix variable names + for hwmon attributes + +Replace all local variables 'mlwsw_hwmon_attr' by 'mlxsw_hwmon_attr'. +All variable prefixes should start with 'mlxsw' according to the naming +convention, so 'mlwsw' is changed to 'mlxsw'. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 76 +++++++++---------- + 1 file changed, 38 insertions(+), 38 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index d41afdfbd085..3788d02b5244 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -57,14 +57,14 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + int temp, index; + int err; + +- index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, ++ index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon->module_sensor_max); + mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -80,14 +80,14 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + int temp_max, index; + int err; + +- index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, ++ index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon->module_sensor_max); + mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -103,9 +103,9 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; + unsigned long val; + int index; +@@ -117,7 +117,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(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon->module_sensor_max); + + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, index); +@@ -138,13 +138,13 @@ static ssize_t mlxsw_hwmon_fan_rpm_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mfsm_pl[MLXSW_REG_MFSM_LEN]; + int err; + +- mlxsw_reg_mfsm_pack(mfsm_pl, mlwsw_hwmon_attr->type_index); ++ mlxsw_reg_mfsm_pack(mfsm_pl, mlxsw_hwmon_attr->type_index); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsm), mfsm_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query fan\n"); +@@ -157,9 +157,9 @@ static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char fore_pl[MLXSW_REG_FORE_LEN]; + bool fault; + int err; +@@ -169,7 +169,7 @@ static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev, + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query fan\n"); + return err; + } +- mlxsw_reg_fore_unpack(fore_pl, mlwsw_hwmon_attr->type_index, &fault); ++ mlxsw_reg_fore_unpack(fore_pl, mlxsw_hwmon_attr->type_index, &fault); + + return sprintf(buf, "%u\n", fault); + } +@@ -178,13 +178,13 @@ static ssize_t mlxsw_hwmon_pwm_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mfsc_pl[MLXSW_REG_MFSC_LEN]; + int err; + +- mlxsw_reg_mfsc_pack(mfsc_pl, mlwsw_hwmon_attr->type_index, 0); ++ mlxsw_reg_mfsc_pack(mfsc_pl, mlxsw_hwmon_attr->type_index, 0); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query PWM\n"); +@@ -198,9 +198,9 @@ static ssize_t mlxsw_hwmon_pwm_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mfsc_pl[MLXSW_REG_MFSC_LEN]; + unsigned long val; + int err; +@@ -211,7 +211,7 @@ static ssize_t mlxsw_hwmon_pwm_store(struct device *dev, + if (val > 255) + return -EINVAL; + +- mlxsw_reg_mfsc_pack(mfsc_pl, mlwsw_hwmon_attr->type_index, val); ++ mlxsw_reg_mfsc_pack(mfsc_pl, mlxsw_hwmon_attr->type_index, val); + err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to write PWM\n"); +@@ -224,14 +224,14 @@ static int mlxsw_hwmon_module_temp_get(struct device *dev, + struct device_attribute *attr, + int *p_temp) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + u8 module; + int err; + +- module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; + 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); +@@ -261,15 +261,15 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; + u8 module, fault; + u16 temp; + int err; + +- module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_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); +@@ -303,13 +303,13 @@ static int mlxsw_hwmon_module_temp_critical_get(struct device *dev, + struct device_attribute *attr, + int *p_temp) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + u8 module; + int err; + +- module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; + err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, + SFP_TEMP_HIGH_WARN, p_temp); + if (err) { +@@ -337,13 +337,13 @@ static int mlxsw_hwmon_module_temp_emergency_get(struct device *dev, + struct device_attribute *attr, + int *p_temp) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + u8 module; + int err; + +- module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; + err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, + SFP_TEMP_HIGH_ALARM, p_temp); + if (err) { +@@ -373,11 +373,11 @@ mlxsw_hwmon_module_temp_label_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); + + return sprintf(buf, "front panel %03u\n", +- mlwsw_hwmon_attr->type_index); ++ mlxsw_hwmon_attr->type_index); + } + + static ssize_t +@@ -385,10 +385,10 @@ mlxsw_hwmon_gbox_temp_label_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; +- int index = mlwsw_hwmon_attr->type_index - ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ int index = mlxsw_hwmon_attr->type_index - + mlxsw_hwmon->module_sensor_max + 1; + + return sprintf(buf, "gearbox %03u\n", index); +-- +2.20.1 + diff --git a/patch/0100-mlxsw-core_thermal-Rename-labels-according-to-naming.patch b/patch/0100-mlxsw-core_thermal-Rename-labels-according-to-naming.patch new file mode 100644 index 000000000..fcab6bb55 --- /dev/null +++ b/patch/0100-mlxsw-core_thermal-Rename-labels-according-to-naming.patch @@ -0,0 +1,162 @@ +From 2f12c9f7cd1d91732ee64d11611cc4cb6baf69a6 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:42 +0200 +Subject: [PATCH backport 5.10 100/182] mlxsw: core_thermal: Rename labels + according to naming convention + +Rename labels for error flow handling in order to align with naming +convention used in rest of 'mlxsw' code. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../ethernet/mellanox/mlxsw/core_thermal.c | 43 ++++++++++--------- + 1 file changed, 23 insertions(+), 20 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 91abc7a3f7ea..f471f03e0094 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -393,11 +393,11 @@ static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev, + trip->min_state, + THERMAL_WEIGHT_DEFAULT); + if (err < 0) +- goto err_bind_cooling_device; ++ goto err_thermal_zone_bind_cooling_device; + } + return 0; + +-err_bind_cooling_device: ++err_thermal_zone_bind_cooling_device: + for (j = i - 1; j >= 0; j--) + thermal_zone_unbind_cooling_device(tzdev, j, cdev); + return err; +@@ -766,7 +766,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + for (i = 0; i < thermal->tz_module_num; i++) { + err = mlxsw_thermal_module_init(dev, core, thermal, i); + if (err) +- goto err_unreg_tz_module_arr; ++ goto err_thermal_module_init; + } + + for (i = 0; i < thermal->tz_module_num; i++) { +@@ -775,12 +775,13 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + continue; + err = mlxsw_thermal_module_tz_init(module_tz); + if (err) +- goto err_unreg_tz_module_arr; ++ goto err_thermal_module_tz_init; + } + + return 0; + +-err_unreg_tz_module_arr: ++err_thermal_module_tz_init: ++err_thermal_module_init: + for (i = thermal->tz_module_num - 1; i >= 0; i--) + mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); + kfree(thermal->tz_module_arr); +@@ -871,12 +872,12 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + gearbox_tz->parent = thermal; + err = mlxsw_thermal_gearbox_tz_init(gearbox_tz); + if (err) +- goto err_unreg_tz_gearbox; ++ goto err_thermal_gearbox_tz_init; + } + + return 0; + +-err_unreg_tz_gearbox: ++err_thermal_gearbox_tz_init: + for (i--; i >= 0; i--) + mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); + kfree(thermal->tz_gearbox_arr); +@@ -920,7 +921,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl); + if (err) { + dev_err(dev, "Failed to probe PWMs\n"); +- goto err_free_thermal; ++ goto err_reg_query; + } + mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active); + +@@ -934,14 +935,14 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsl), + mfsl_pl); + if (err) +- goto err_free_thermal; ++ goto err_reg_query; + + /* set the minimal RPMs to 0 */ + mlxsw_reg_mfsl_tach_min_set(mfsl_pl, 0); + err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsl), + mfsl_pl); + if (err) +- goto err_free_thermal; ++ goto err_reg_write; + } + } + for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) { +@@ -954,7 +955,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + if (IS_ERR(cdev)) { + err = PTR_ERR(cdev); + dev_err(dev, "Failed to register cooling device\n"); +- goto err_unreg_cdevs; ++ goto err_thermal_cooling_device_register; + } + thermal->cdevs[i] = cdev; + } +@@ -978,38 +979,40 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + if (IS_ERR(thermal->tzdev)) { + err = PTR_ERR(thermal->tzdev); + dev_err(dev, "Failed to register thermal zone\n"); +- goto err_unreg_cdevs; ++ goto err_thermal_zone_device_register; + } + + err = mlxsw_thermal_modules_init(dev, core, thermal); + if (err) +- goto err_unreg_tzdev; ++ goto err_thermal_modules_init; + + err = mlxsw_thermal_gearboxes_init(dev, core, thermal); + if (err) +- goto err_unreg_modules_tzdev; ++ goto err_thermal_gearboxes_init; + + err = thermal_zone_device_enable(thermal->tzdev); + if (err) +- goto err_unreg_gearboxes; ++ goto err_thermal_zone_device_enable; + + *p_thermal = thermal; + return 0; + +-err_unreg_gearboxes: ++err_thermal_zone_device_enable: + mlxsw_thermal_gearboxes_fini(thermal); +-err_unreg_modules_tzdev: ++err_thermal_gearboxes_init: + mlxsw_thermal_modules_fini(thermal); +-err_unreg_tzdev: ++err_thermal_modules_init: + if (thermal->tzdev) { + thermal_zone_device_unregister(thermal->tzdev); + thermal->tzdev = NULL; + } +-err_unreg_cdevs: ++err_thermal_zone_device_register: ++err_thermal_cooling_device_register: + for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) + if (thermal->cdevs[i]) + thermal_cooling_device_unregister(thermal->cdevs[i]); +-err_free_thermal: ++err_reg_write: ++err_reg_query: + devm_kfree(dev, thermal); + return err; + } +-- +2.20.1 + diff --git a/patch/0101-mlxsw-core_thermal-Remove-obsolete-API-for-query-res.patch b/patch/0101-mlxsw-core_thermal-Remove-obsolete-API-for-query-res.patch new file mode 100644 index 000000000..f1edc13f6 --- /dev/null +++ b/patch/0101-mlxsw-core_thermal-Remove-obsolete-API-for-query-res.patch @@ -0,0 +1,111 @@ +From d0a94e237cb6d2020a0a1c27f357a9c3bfc0b1d5 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:43 +0200 +Subject: [PATCH backport 5.10 101/182] mlxsw: core_thermal: Remove obsolete + API for query resource + +Remove obsolete API mlxsw_core_res_query_enabled(), which is only +relevant for end-of-life SwitchX-2 ASICs. Support for these ASICs was +removed in commit b0d80c013b04 ("mlxsw: Remove Mellanox SwitchX-2 ASIC +support"). + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 6 ------ + drivers/net/ethernet/mellanox/mlxsw/core.h | 2 -- + drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 3 --- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 12 ------------ + 4 files changed, 23 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 7938bad70e37..0b1888318ef1 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -129,12 +129,6 @@ 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); +- + bool mlxsw_core_temp_warn_enabled(const struct mlxsw_core *mlxsw_core) + { + return mlxsw_core->driver->temp_warn_enabled; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 56efb8e48022..0ceb7dae95f6 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -30,8 +30,6 @@ 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); +- + bool mlxsw_core_temp_warn_enabled(const struct mlxsw_core *mlxsw_core); + + bool +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 3788d02b5244..8b170ad92302 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -655,9 +655,6 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + u8 module_sensor_max; + int i, err; + +- if (!mlxsw_core_res_query_enabled(mlxsw_hwmon->core)) +- return 0; +- + mlxsw_reg_mgpir_pack(mgpir_pl); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index f471f03e0094..80942c78d9e5 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -746,9 +746,6 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + int i, err; + +- if (!mlxsw_core_res_query_enabled(core)) +- return 0; +- + mlxsw_reg_mgpir_pack(mgpir_pl); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) +@@ -793,9 +790,6 @@ mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal) + { + int i; + +- if (!mlxsw_core_res_query_enabled(thermal->core)) +- return; +- + for (i = thermal->tz_module_num - 1; i >= 0; i--) + mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); + kfree(thermal->tz_module_arr); +@@ -843,9 +837,6 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + int i; + int err; + +- if (!mlxsw_core_res_query_enabled(core)) +- return 0; +- + mlxsw_reg_mgpir_pack(mgpir_pl); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) +@@ -889,9 +880,6 @@ mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal) + { + int i; + +- if (!mlxsw_core_res_query_enabled(thermal->core)) +- return; +- + for (i = thermal->tz_gearbox_num - 1; i >= 0; i--) + mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); + kfree(thermal->tz_gearbox_arr); +-- +2.20.1 + diff --git a/patch/0102-mlxsw-reg-Add-mgpir_-prefix-to-MGPIR-fields-comments.patch b/patch/0102-mlxsw-reg-Add-mgpir_-prefix-to-MGPIR-fields-comments.patch new file mode 100644 index 000000000..197eb7843 --- /dev/null +++ b/patch/0102-mlxsw-reg-Add-mgpir_-prefix-to-MGPIR-fields-comments.patch @@ -0,0 +1,52 @@ +From 2e6cd3d593c0bf1cc38093a73ec7777a5b806bfe Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:44 +0200 +Subject: [PATCH backport 5.10 102/182] mlxsw: reg: Add "mgpir_" prefix to + MGPIR fields comments + +Do the same as for other registers and have "mgpir_" prefix for the +MGPIR fields. + +Signed-off-by: Jiri Pirko +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 7f9b902049db..c3fb2e4d4458 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10130,24 +10130,24 @@ enum mlxsw_reg_mgpir_device_type { + MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE, + }; + +-/* device_type ++/* mgpir_device_type + * Access: RO + */ + MLXSW_ITEM32(reg, mgpir, device_type, 0x00, 24, 4); + +-/* devices_per_flash ++/* mgpir_devices_per_flash + * Number of devices of device_type per flash (can be shared by few devices). + * Access: RO + */ + MLXSW_ITEM32(reg, mgpir, devices_per_flash, 0x00, 16, 8); + +-/* num_of_devices ++/* mgpir_num_of_devices + * Number of devices of device_type. + * Access: RO + */ + MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8); + +-/* num_of_modules ++/* mgpir_num_of_modules + * Number of modules. + * Access: RO + */ +-- +2.20.1 + diff --git a/patch/0103-mlxsw-core-Remove-unnecessary-asserts.patch b/patch/0103-mlxsw-core-Remove-unnecessary-asserts.patch new file mode 100644 index 000000000..438d496fb --- /dev/null +++ b/patch/0103-mlxsw-core-Remove-unnecessary-asserts.patch @@ -0,0 +1,102 @@ +From 7b7f5f88374c3377fc28e48a0bc77ae4aa783fda Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 7 Dec 2021 16:07:31 +0200 +Subject: [PATCH backport 5.10 103/182] mlxsw: core: Remove unnecessary asserts + +Remove unnecessary asserts for module index validation. Leave only one +that is actually necessary in mlxsw_env_pmpe_listener_func() where the +module index is directly read from the firmware event. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 24 ------------------- + 1 file changed, 24 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 6dd4ae2f45f4..c1d51b4b6b36 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -414,9 +414,6 @@ int mlxsw_env_reset_module(struct net_device *netdev, + !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) + return 0; + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return -EINVAL; +- + mutex_lock(&mlxsw_env->module_info_lock); + + if (mlxsw_env->module_info[module].num_ports_up) { +@@ -456,9 +453,6 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + u32 status_bits; + int err; + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return -EINVAL; +- + mutex_lock(&mlxsw_env->module_info_lock); + + params->policy = mlxsw_env->module_info[module].power_mode_policy; +@@ -560,9 +554,6 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + bool low_power; + int err = 0; + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return -EINVAL; +- + if (policy != ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH && + policy != ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) { + NL_SET_ERR_MSG_MOD(extack, "Unsupported power mode policy"); +@@ -901,9 +892,6 @@ mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module, + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return -EINVAL; +- + mutex_lock(&mlxsw_env->module_info_lock); + *p_counter = mlxsw_env->module_info[module].module_overheat_counter; + mutex_unlock(&mlxsw_env->module_info_lock); +@@ -916,9 +904,6 @@ void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return; +- + mutex_lock(&mlxsw_env->module_info_lock); + mlxsw_env->module_info[module].num_ports_mapped++; + mutex_unlock(&mlxsw_env->module_info_lock); +@@ -929,9 +914,6 @@ void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return; +- + mutex_lock(&mlxsw_env->module_info_lock); + mlxsw_env->module_info[module].num_ports_mapped--; + mutex_unlock(&mlxsw_env->module_info_lock); +@@ -943,9 +925,6 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module) + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + int err = 0; + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return -EINVAL; +- + mutex_lock(&mlxsw_env->module_info_lock); + + if (mlxsw_env->module_info[module].power_mode_policy != +@@ -975,9 +954,6 @@ void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return; +- + mutex_lock(&mlxsw_env->module_info_lock); + + mlxsw_env->module_info[module].num_ports_up--; +-- +2.20.1 + diff --git a/patch/0104-mlxsw-reg-Extend-MTMP-register-with-new-slot-number-.patch b/patch/0104-mlxsw-reg-Extend-MTMP-register-with-new-slot-number-.patch new file mode 100644 index 000000000..97ee7b411 --- /dev/null +++ b/patch/0104-mlxsw-reg-Extend-MTMP-register-with-new-slot-number-.patch @@ -0,0 +1,147 @@ +From 58426cf3ccba63cbc0b9ddc2abfc1173ca8ba368 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:45 +0200 +Subject: [PATCH backport 5.10 104/182] mlxsw: reg: Extend MTMP register with + new slot number field + +Extend MTMP (Management Temperature Register) with new field specifying +the slot index. The purpose of this field is to support access to MTMP +register for reading temperature sensors on modular systems. +For non-modular systems the 'sensor_index' uniquely identifies the cage +sensors, while 'slot_index' is always 0. For modular systems the +sensors are identified by: +- 'slot_index', specifying the slot index, where line card is located; +- 'sensor_index', specifying cage sensor within the line card. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 11 ++++++----- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 6 +++--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 11 +++++++++-- + 4 files changed, 19 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index c1d51b4b6b36..32faedfd2ea8 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -142,7 +142,7 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, + int page; + int err; + +- mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, + false, false); + err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); + if (err) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 8b170ad92302..71ca3b561e62 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -66,7 +66,7 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon->module_sensor_max); +- mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); +@@ -89,7 +89,7 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon->module_sensor_max); +- mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); +@@ -232,8 +232,9 @@ static int mlxsw_hwmon_module_temp_get(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +- mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, +- false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, ++ MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, false, ++ false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + dev_err(dev, "Failed to query module temperature\n"); +@@ -721,7 +722,7 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) + while (index < max_index) { + sensor_index = index % mlxsw_hwmon->module_sensor_max + + MLXSW_REG_MTMP_GBOX_INDEX_MIN; +- mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, true, true); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, sensor_index, true, true); + err = mlxsw_reg_write(mlxsw_hwmon->core, + MLXSW_REG(mtmp), mtmp_pl); + if (err) { +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 80942c78d9e5..f4f0f8ce8597 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -272,7 +272,7 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, + int temp; + int err; + +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, 0, false, false); + + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { +@@ -432,7 +432,7 @@ mlxsw_thermal_module_temp_and_thresholds_get(struct mlxsw_core *core, + int err; + + /* Read module temperature and thresholds. */ +- mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, sensor_index, false, false); + err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + /* Set temperature and thresholds to zero to avoid passing +@@ -577,7 +577,7 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, + int err; + + index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module; +- mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); + + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index c3fb2e4d4458..0428904b99d2 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -8541,6 +8541,12 @@ MLXSW_ITEM32(reg, mtcap, sensor_count, 0x00, 0, 7); + + MLXSW_REG_DEFINE(mtmp, MLXSW_REG_MTMP_ID, MLXSW_REG_MTMP_LEN); + ++/* reg_mtmp_slot_index ++ * Slot index (0: Main board). ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mtmp, slot_index, 0x00, 16, 4); ++ + #define MLXSW_REG_MTMP_MODULE_INDEX_MIN 64 + #define MLXSW_REG_MTMP_GBOX_INDEX_MIN 256 + /* reg_mtmp_sensor_index +@@ -8630,11 +8636,12 @@ MLXSW_ITEM32(reg, mtmp, temperature_threshold_lo, 0x10, 0, 16); + */ + MLXSW_ITEM_BUF(reg, mtmp, sensor_name, 0x18, MLXSW_REG_MTMP_SENSOR_NAME_SIZE); + +-static inline void mlxsw_reg_mtmp_pack(char *payload, u16 sensor_index, +- bool max_temp_enable, ++static inline void mlxsw_reg_mtmp_pack(char *payload, u8 slot_index, ++ u16 sensor_index, bool max_temp_enable, + bool max_temp_reset) + { + MLXSW_REG_ZERO(mtmp, payload); ++ mlxsw_reg_mtmp_slot_index_set(payload, slot_index); + mlxsw_reg_mtmp_sensor_index_set(payload, sensor_index); + mlxsw_reg_mtmp_mte_set(payload, max_temp_enable); + mlxsw_reg_mtmp_mtr_set(payload, max_temp_reset); +-- +2.20.1 + diff --git a/patch/0105-mlxsw-reg-Extend-MTBR-register-with-new-slot-number-.patch b/patch/0105-mlxsw-reg-Extend-MTBR-register-with-new-slot-number-.patch new file mode 100644 index 000000000..c5412a8dd --- /dev/null +++ b/patch/0105-mlxsw-reg-Extend-MTBR-register-with-new-slot-number-.patch @@ -0,0 +1,88 @@ +From c9c07da3e3dadf102a25e27f49d0ce4f414c096c Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:46 +0200 +Subject: [PATCH backport 5.10 105/182] mlxsw: reg: Extend MTBR register with + new slot number field + +Extend MTBR (Management Temperature Bulk Register) with new field +specifying the slot number. The purpose of this field is to support +access to MTBR register for reading temperature sensors on modular +system. For non-modular systems the 'sensor_index' uniquely identifies +the cage sensors. For modular systems the sensors are identified by two +indexes: +- 'slot_index', specifying the slot number, where line card is located; +- 'sensor_index', specifying cage sensor within the line card. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 4 ++-- + drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 4 ++-- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 11 +++++++++-- + 3 files changed, 13 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 32faedfd2ea8..c2aa05be5bcc 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -591,8 +591,8 @@ static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core, + u16 temp; + int err; + +- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, +- 1); ++ mlxsw_reg_mtbr_pack(mtbr_pl, 0, ++ MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 1); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtbr), mtbr_pl); + if (err) + return err; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 71ca3b561e62..f4bc711a16cf 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -271,8 +271,8 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, +- 1); ++ mlxsw_reg_mtbr_pack(mtbr_pl, 0, ++ 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"); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 0428904b99d2..df210bd9a29c 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -8707,6 +8707,12 @@ MLXSW_ITEM_BIT_ARRAY(reg, mtwe, sensor_warning, 0x0, 0x10, 1); + + MLXSW_REG_DEFINE(mtbr, MLXSW_REG_MTBR_ID, MLXSW_REG_MTBR_LEN); + ++/* reg_mtbr_slot_index ++ * Slot index (0: Main board). ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mtbr, slot_index, 0x00, 16, 4); ++ + /* reg_mtbr_base_sensor_index + * Base sensors index to access (0 - ASIC sensor, 1-63 - ambient sensors, + * 64-127 are mapped to the SFP+/QSFP modules sequentially). +@@ -8739,10 +8745,11 @@ MLXSW_ITEM32_INDEXED(reg, mtbr, rec_max_temp, MLXSW_REG_MTBR_BASE_LEN, 16, + MLXSW_ITEM32_INDEXED(reg, mtbr, rec_temp, MLXSW_REG_MTBR_BASE_LEN, 0, 16, + MLXSW_REG_MTBR_REC_LEN, 0x00, false); + +-static inline void mlxsw_reg_mtbr_pack(char *payload, u16 base_sensor_index, +- u8 num_rec) ++static inline void mlxsw_reg_mtbr_pack(char *payload, u8 slot_index, ++ u16 base_sensor_index, u8 num_rec) + { + MLXSW_REG_ZERO(mtbr, payload); ++ mlxsw_reg_mtbr_slot_index_set(payload, slot_index); + mlxsw_reg_mtbr_base_sensor_index_set(payload, base_sensor_index); + mlxsw_reg_mtbr_num_rec_set(payload, num_rec); + } +-- +2.20.1 + diff --git a/patch/0106-mlxsw-reg-Extend-MCIA-register-with-new-slot-number-.patch b/patch/0106-mlxsw-reg-Extend-MCIA-register-with-new-slot-number-.patch new file mode 100644 index 000000000..56fe2c80c --- /dev/null +++ b/patch/0106-mlxsw-reg-Extend-MCIA-register-with-new-slot-number-.patch @@ -0,0 +1,109 @@ +From 4f10b61f33bdaee774b31b7fe37a76058b755561 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:47 +0200 +Subject: [PATCH backport 5.10 106/182] mlxsw: reg: Extend MCIA register with + new slot number field + +Extend MCIA (Management Cable Info Access Register) with new field +specifying the slot number. The purpose of this field is to support +access to MCIA register for reading cage cable information on modular +system. For non-modular systems the 'module' number uniquely identifies +the transceiver location. For modular systems the transceivers are +identified by two indexes: +- 'slot_index', specifying the slot number, where line card is located; +- 'module', specifying cage transceiver within the line card. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 13 +++++++------ + drivers/net/ethernet/mellanox/mlxsw/reg.h | 14 +++++++++++--- + 2 files changed, 18 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index c2aa05be5bcc..a516c04ad19b 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -35,8 +35,8 @@ static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id, + u8 ident; + int err; + +- mlxsw_reg_mcia_pack(mcia_pl, id, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1, +- MLXSW_REG_MCIA_I2C_ADDR_LOW); ++ mlxsw_reg_mcia_pack(mcia_pl, 0, id, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, ++ 1, MLXSW_REG_MCIA_I2C_ADDR_LOW); + err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); + if (err) + return err; +@@ -110,7 +110,8 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, + } + } + +- mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, offset, size, i2c_addr); ++ mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, page, offset, size, ++ i2c_addr); + + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); + if (err) +@@ -184,12 +185,12 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, + page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM; + else + page = MLXSW_REG_MCIA_TH_PAGE_NUM; +- mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, ++ mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, page, + MLXSW_REG_MCIA_TH_PAGE_OFF + off, + MLXSW_REG_MCIA_TH_ITEM_SIZE, + MLXSW_REG_MCIA_I2C_ADDR_LOW); + } else { +- mlxsw_reg_mcia_pack(mcia_pl, module, 0, ++ mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, + MLXSW_REG_MCIA_PAGE0_LO, + off, MLXSW_REG_MCIA_TH_ITEM_SIZE, + MLXSW_REG_MCIA_I2C_ADDR_HIGH); +@@ -369,7 +370,7 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module, + size = min_t(u8, page->length - bytes_read, + MLXSW_REG_MCIA_EEPROM_SIZE); + +- mlxsw_reg_mcia_pack(mcia_pl, module, 0, page->page, ++ mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, page->page, + device_addr + bytes_read, size, + page->i2c_address); + mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index df210bd9a29c..bdbe198a9053 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -8798,6 +8798,12 @@ MLXSW_ITEM32(reg, mcia, l, 0x00, 31, 1); + */ + MLXSW_ITEM32(reg, mcia, module, 0x00, 16, 8); + ++/* reg_mcia_slot_index ++ * Slot index (0: Main board) ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mcia, slot, 0x00, 12, 4); ++ + enum { + MLXSW_REG_MCIA_STATUS_GOOD = 0, + /* No response from module's EEPROM. */ +@@ -8896,11 +8902,13 @@ MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE); + MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) / \ + MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH + 1) + +-static inline void mlxsw_reg_mcia_pack(char *payload, u8 module, u8 lock, +- u8 page_number, u16 device_addr, +- u8 size, u8 i2c_device_addr) ++static inline void mlxsw_reg_mcia_pack(char *payload, u8 slot_index, u8 module, ++ u8 lock, u8 page_number, ++ u16 device_addr, u8 size, ++ u8 i2c_device_addr) + { + MLXSW_REG_ZERO(mcia, payload); ++ mlxsw_reg_mcia_slot_set(payload, slot_index); + mlxsw_reg_mcia_module_set(payload, module); + mlxsw_reg_mcia_l_set(payload, lock); + mlxsw_reg_mcia_page_number_set(payload, page_number); +-- +2.20.1 + diff --git a/patch/0107-mlxsw-reg-Extend-MCION-register-with-new-slot-number.patch b/patch/0107-mlxsw-reg-Extend-MCION-register-with-new-slot-number.patch new file mode 100644 index 000000000..d03711b1c --- /dev/null +++ b/patch/0107-mlxsw-reg-Extend-MCION-register-with-new-slot-number.patch @@ -0,0 +1,69 @@ +From aba06998f55ba715e6161a427356fccc17b466fc Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:50 +0200 +Subject: [PATCH backport 5.10 107/182] mlxsw: reg: Extend MCION register with + new slot number field + +Extend MCION (Management Cable IO and Notifications Register) with new +field specifying the slot number. The purpose of this field is to +support access to MCION register for query cage transceiver on modular +system. + +For non-modular systems the 'module' number uniquely identifies the +transceiver location. For modular systems the transceivers are +identified by two indexes: +- 'slot_index', specifying the slot number, where line card is located; +- 'module', specifying cage transceiver within the line card. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 9 ++++++++- + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index a516c04ad19b..2ac8444aa8b2 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -458,7 +458,7 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + + params->policy = mlxsw_env->module_info[module].power_mode_policy; + +- mlxsw_reg_mcion_pack(mcion_pl, module); ++ mlxsw_reg_mcion_pack(mcion_pl, 0, module); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Failed to retrieve module's power mode"); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index bdbe198a9053..acde0cd00944 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -9327,6 +9327,12 @@ MLXSW_REG_DEFINE(mcion, MLXSW_REG_MCION_ID, MLXSW_REG_MCION_LEN); + */ + MLXSW_ITEM32(reg, mcion, module, 0x00, 16, 8); + ++/* reg_mcion_slot_index ++ * Slot index. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mcion, slot_index, 0x00, 12, 4); ++ + enum { + MLXSW_REG_MCION_MODULE_STATUS_BITS_PRESENT_MASK = BIT(0), + MLXSW_REG_MCION_MODULE_STATUS_BITS_LOW_POWER_MASK = BIT(8), +@@ -9338,9 +9344,10 @@ enum { + */ + MLXSW_ITEM32(reg, mcion, module_status_bits, 0x04, 0, 16); + +-static inline void mlxsw_reg_mcion_pack(char *payload, u8 module) ++static inline void mlxsw_reg_mcion_pack(char *payload, u8 slot_index, u8 module) + { + MLXSW_REG_ZERO(mcion, payload); ++ mlxsw_reg_mcion_slot_index_set(payload, slot_index); + mlxsw_reg_mcion_module_set(payload, module); + } + +-- +2.20.1 + diff --git a/patch/0108-mlxsw-reg-Extend-PMMP-register-with-new-slot-number-.patch b/patch/0108-mlxsw-reg-Extend-PMMP-register-with-new-slot-number-.patch new file mode 100644 index 000000000..721b79aa4 --- /dev/null +++ b/patch/0108-mlxsw-reg-Extend-PMMP-register-with-new-slot-number-.patch @@ -0,0 +1,68 @@ +From 0aebe300b70a084161c12e813396025b255d91d7 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:51 +0200 +Subject: [PATCH backport 5.10 108/182] mlxsw: reg: Extend PMMP register with + new slot number field + +Extend PMMP (Port Module Memory Map Properties Register) with new +field specifying the slot number. The purpose of this field is to +enable overriding the cable/module memory map advertisement. + +For non-modular systems the 'module' number uniquely identifies the +transceiver location. For modular systems the transceivers are +identified by two indexes: +- 'slot_index', specifying the slot number, where line card is located; +- 'module', specifying cage transceiver within the line card. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 9 ++++++++- + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 2ac8444aa8b2..ad27a1c90f92 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -501,7 +501,7 @@ static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core, + u16 eeprom_override_mask, eeprom_override; + char pmmp_pl[MLXSW_REG_PMMP_LEN]; + +- mlxsw_reg_pmmp_pack(pmmp_pl, module); ++ mlxsw_reg_pmmp_pack(pmmp_pl, 0, module); + mlxsw_reg_pmmp_sticky_set(pmmp_pl, true); + /* Mask all the bits except low power mode. */ + eeprom_override_mask = ~MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index acde0cd00944..aad0cb1497aa 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -5633,6 +5633,12 @@ MLXSW_REG_DEFINE(pmmp, MLXSW_REG_PMMP_ID, MLXSW_REG_PMMP_LEN); + */ + MLXSW_ITEM32(reg, pmmp, module, 0x00, 16, 8); + ++/* reg_pmmp_slot_index ++ * Slot index. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, pmmp, slot_index, 0x00, 24, 4); ++ + /* reg_pmmp_sticky + * When set, will keep eeprom_override values after plug-out event. + * Access: OP +@@ -5660,9 +5666,10 @@ enum { + */ + MLXSW_ITEM32(reg, pmmp, eeprom_override, 0x04, 0, 16); + +-static inline void mlxsw_reg_pmmp_pack(char *payload, u8 module) ++static inline void mlxsw_reg_pmmp_pack(char *payload, u8 slot_index, u8 module) + { + MLXSW_REG_ZERO(pmmp, payload); ++ mlxsw_reg_pmmp_slot_index_set(payload, slot_index); + mlxsw_reg_pmmp_module_set(payload, module); + } + +-- +2.20.1 + diff --git a/patch/0109-mlxsw-reg-Extend-MGPIR-register-with-new-slot-fields.patch b/patch/0109-mlxsw-reg-Extend-MGPIR-register-with-new-slot-fields.patch new file mode 100644 index 000000000..acd11709c --- /dev/null +++ b/patch/0109-mlxsw-reg-Extend-MGPIR-register-with-new-slot-fields.patch @@ -0,0 +1,199 @@ +From 441a7861ef61f4d0d55dee542d4704487694f68c Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 22 Dec 2021 06:11:50 +0000 +Subject: [PATCH backport 5.10 109/182] mlxsw: reg: Extend MGPIR register with + new slot fields + +Extend MGPIR (Management General Peripheral Information Register) with +new fields specifying the slot number and number of the slots available +on system. The purpose of these fields is: +- to support access to MPGIR register on modular system for getting the + number of cages, equipped on the line card, inserted at specified + slot. In case slot number is set zero, MGPIR will provide the + information for the main board. For Top of the Rack (non-modular) + system it will provide the same as before. +- to provide the number of slots supported by system. This data is + relevant only in case slot number is set zero. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 4 ++-- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 9 +++++---- + .../ethernet/mellanox/mlxsw/core_thermal.c | 8 ++++---- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 4 ++-- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 20 +++++++++++++++++-- + 5 files changed, 31 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index ad27a1c90f92..8ab15d5bd7f5 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -983,12 +983,12 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + u8 module_count; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl); ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + +- mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count); ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count, NULL); + + env = kzalloc(struct_size(env, module_info, module_count), GFP_KERNEL); + if (!env) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index f4bc711a16cf..2bc4c4556895 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -656,13 +656,13 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + u8 module_sensor_max; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl); ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, +- &module_sensor_max); ++ &module_sensor_max, NULL); + + /* Add extra attributes for module temperature. Sensor index is + * assigned to sensor_count value, while all indexed before +@@ -707,12 +707,13 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) + u8 gbox_num; + int err; + +- mlxsw_reg_mgpir_pack(mgpir_pl); ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + +- mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, NULL); ++ mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, NULL, ++ NULL); + if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || + !gbox_num) + return 0; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index f4f0f8ce8597..21a7415c8ef5 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -746,13 +746,13 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl); ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, +- &thermal->tz_module_num); ++ &thermal->tz_module_num, NULL); + + thermal->tz_module_arr = kcalloc(thermal->tz_module_num, + sizeof(*thermal->tz_module_arr), +@@ -837,13 +837,13 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + int i; + int err; + +- mlxsw_reg_mgpir_pack(mgpir_pl); ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, +- NULL); ++ NULL, NULL); + if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || + !gbox_num) + return 0; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 3d07c2dcf08d..b2ffcfda8374 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -280,13 +280,13 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl); ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, +- &mlxsw_m->max_ports); ++ &mlxsw_m->max_ports, NULL); + if (!mlxsw_m->max_ports) + return 0; + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index aad0cb1497aa..a5fa25d4bd8f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10166,6 +10166,12 @@ enum mlxsw_reg_mgpir_device_type { + MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE, + }; + ++/* mgpir_slot_index ++ * Slot index (0: Main board). ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mgpir, slot_index, 0x00, 28, 4); ++ + /* mgpir_device_type + * Access: RO + */ +@@ -10183,21 +10189,29 @@ MLXSW_ITEM32(reg, mgpir, devices_per_flash, 0x00, 16, 8); + */ + MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8); + ++/* mgpir_num_of_slots ++ * Number of slots in the system. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mgpir, num_of_slots, 0x04, 8, 8); ++ + /* mgpir_num_of_modules + * Number of modules. + * Access: RO + */ + MLXSW_ITEM32(reg, mgpir, num_of_modules, 0x04, 0, 8); + +-static inline void mlxsw_reg_mgpir_pack(char *payload) ++static inline void mlxsw_reg_mgpir_pack(char *payload, u8 slot_index) + { + MLXSW_REG_ZERO(mgpir, payload); ++ mlxsw_reg_mgpir_slot_index_set(payload, slot_index); + } + + static inline void + mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, + enum mlxsw_reg_mgpir_device_type *device_type, +- u8 *devices_per_flash, u8 *num_of_modules) ++ u8 *devices_per_flash, u8 *num_of_modules, ++ u8 *num_of_slots) + { + if (num_of_devices) + *num_of_devices = mlxsw_reg_mgpir_num_of_devices_get(payload); +@@ -10208,6 +10222,8 @@ mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, + mlxsw_reg_mgpir_devices_per_flash_get(payload); + if (num_of_modules) + *num_of_modules = mlxsw_reg_mgpir_num_of_modules_get(payload); ++ if (num_of_slots) ++ *num_of_slots = mlxsw_reg_mgpir_num_of_slots_get(payload); + } + + /* MFDE - Monitoring FW Debug Register +-- +2.20.1 + diff --git a/patch/0110-mlxsw-core_env-Pass-slot-index-during-PMAOS-register.patch b/patch/0110-mlxsw-core_env-Pass-slot-index-during-PMAOS-register.patch new file mode 100644 index 000000000..110f94ebe --- /dev/null +++ b/patch/0110-mlxsw-core_env-Pass-slot-index-during-PMAOS-register.patch @@ -0,0 +1,66 @@ +From 7c2049bccef11b265fd4a4458b92277ea8ea97fc Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:52 +0200 +Subject: [PATCH backport 5.10 110/182] mlxsw: core_env: Pass slot index during + PMAOS register write call + +Pass the slot index down to PMAOS pack helper alongside with the module. + +Signed-off-by: Jiri Pirko +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 6 +++--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 3 ++- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 8ab15d5bd7f5..b7c1fd3dbf45 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -398,7 +398,7 @@ static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 module) + { + char pmaos_pl[MLXSW_REG_PMAOS_LEN]; + +- mlxsw_reg_pmaos_pack(pmaos_pl, module); ++ mlxsw_reg_pmaos_pack(pmaos_pl, 0, module); + mlxsw_reg_pmaos_rst_set(pmaos_pl, true); + + return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl); +@@ -486,7 +486,7 @@ static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core, + enum mlxsw_reg_pmaos_admin_status admin_status; + char pmaos_pl[MLXSW_REG_PMAOS_LEN]; + +- mlxsw_reg_pmaos_pack(pmaos_pl, module); ++ mlxsw_reg_pmaos_pack(pmaos_pl, 0, module); + admin_status = enable ? MLXSW_REG_PMAOS_ADMIN_STATUS_ENABLED : + MLXSW_REG_PMAOS_ADMIN_STATUS_DISABLED; + mlxsw_reg_pmaos_admin_status_set(pmaos_pl, admin_status); +@@ -876,7 +876,7 @@ mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core, + for (i = 0; i < module_count; i++) { + char pmaos_pl[MLXSW_REG_PMAOS_LEN]; + +- mlxsw_reg_pmaos_pack(pmaos_pl, i); ++ mlxsw_reg_pmaos_pack(pmaos_pl, 0, i); + mlxsw_reg_pmaos_e_set(pmaos_pl, + MLXSW_REG_PMAOS_E_GENERATE_EVENT); + mlxsw_reg_pmaos_ee_set(pmaos_pl, true); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index a5fa25d4bd8f..07f68fd1a4e5 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -5481,9 +5481,10 @@ enum mlxsw_reg_pmaos_e { + */ + MLXSW_ITEM32(reg, pmaos, e, 0x04, 0, 2); + +-static inline void mlxsw_reg_pmaos_pack(char *payload, u8 module) ++static inline void mlxsw_reg_pmaos_pack(char *payload, u8 slot_index, u8 module) + { + MLXSW_REG_ZERO(pmaos, payload); ++ mlxsw_reg_pmaos_slot_index_set(payload, slot_index); + mlxsw_reg_pmaos_module_set(payload, module); + } + +-- +2.20.1 + diff --git a/patch/0111-mlxsw-reg-Add-new-field-to-Management-General-Periph.patch b/patch/0111-mlxsw-reg-Add-new-field-to-Management-General-Periph.patch new file mode 100644 index 000000000..d73ec6067 --- /dev/null +++ b/patch/0111-mlxsw-reg-Add-new-field-to-Management-General-Periph.patch @@ -0,0 +1,38 @@ +From 4b630e780a6fa8b387e79e252169d5743faf5321 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:49 +0200 +Subject: [PATCH backport 5.10 111/182] mlxsw: reg: Add new field to Management + General Peripheral Information Register + +Add new field 'max_modules_per_slot' to provide maximum number of +modules that can be connected per slot. This field will always be zero, +if 'slot_index' in query request is set to non-zero value, otherwise +value in this field will provide maximum modules number, which can be +equipped on device inserted at any slot. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 07f68fd1a4e5..98c627ffe039 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10190,6 +10190,12 @@ MLXSW_ITEM32(reg, mgpir, devices_per_flash, 0x00, 16, 8); + */ + MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8); + ++/* max_modules_per_slot ++ * Maximum number of modules that can be connected per slot. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mgpir, max_modules_per_slot, 0x04, 16, 8); ++ + /* mgpir_num_of_slots + * Number of slots in the system. + * Access: RO +-- +2.20.1 + diff --git a/patch/0112-mlxsw-core-Extend-interfaces-for-cable-info-access-w.patch b/patch/0112-mlxsw-core-Extend-interfaces-for-cable-info-access-w.patch new file mode 100644 index 000000000..5e44880f2 --- /dev/null +++ b/patch/0112-mlxsw-core-Extend-interfaces-for-cable-info-access-w.patch @@ -0,0 +1,828 @@ +From 0b0f4813bdd0b4ed70074d616f68bb6c774662bc Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:53 +0200 +Subject: [PATCH backport 5.10 112/182] mlxsw: core: Extend interfaces for + cable info access with slot argument + +Extend all cable info APIs with 'slot_index' argument. + +For main board, slot will always be set to zero and these APIs will work +as before. If reading cable information is required from cages located +on line cards, slot should be set to the physical slot number, where +line card is located in modular systems. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 172 +++++++++++------- + .../net/ethernet/mellanox/mlxsw/core_env.h | 43 +++-- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 10 +- + .../ethernet/mellanox/mlxsw/core_thermal.c | 4 +- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 21 ++- + .../net/ethernet/mellanox/mlxsw/spectrum.c | 2 +- + .../mellanox/mlxsw/spectrum_ethtool.c | 10 +- + 7 files changed, 155 insertions(+), 107 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index b7c1fd3dbf45..fc4468a6b0f6 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -27,16 +27,18 @@ struct mlxsw_env { + struct mlxsw_env_module_info module_info[]; + }; + +-static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id, +- bool *qsfp, bool *cmis) ++static int ++mlxsw_env_validate_cable_ident(struct mlxsw_core *core, u8 slot_index, int id, ++ bool *qsfp, bool *cmis) + { + char mcia_pl[MLXSW_REG_MCIA_LEN]; + char *eeprom_tmp; + u8 ident; + int err; + +- mlxsw_reg_mcia_pack(mcia_pl, 0, id, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, +- 1, MLXSW_REG_MCIA_I2C_ADDR_LOW); ++ mlxsw_reg_mcia_pack(mcia_pl, slot_index, id, 0, ++ MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1, ++ MLXSW_REG_MCIA_I2C_ADDR_LOW); + err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); + if (err) + return err; +@@ -64,8 +66,8 @@ static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id, + } + + static int +-mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, +- u16 offset, u16 size, void *data, ++mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ int module, u16 offset, u16 size, void *data, + bool qsfp, unsigned int *p_read_size) + { + char mcia_pl[MLXSW_REG_MCIA_LEN]; +@@ -110,7 +112,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, + } + } + +- mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, page, offset, size, ++ mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page, offset, size, + i2c_addr); + + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); +@@ -128,8 +130,9 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, + return 0; + } + +-int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, +- int off, int *temp) ++int ++mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, u8 slot_index, ++ int module, int off, int *temp) + { + unsigned int module_temp, module_crit, module_emerg; + union { +@@ -143,8 +146,9 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, + int page; + int err; + +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, +- false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, slot_index, ++ MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, false, ++ false); + err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); + if (err) + return err; +@@ -173,7 +177,8 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, + */ + + /* Validate module identifier value. */ +- err = mlxsw_env_validate_cable_ident(core, module, &qsfp, &cmis); ++ err = mlxsw_env_validate_cable_ident(core, slot_index, module, &qsfp, ++ &cmis); + if (err) + return err; + +@@ -185,12 +190,12 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, + page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM; + else + page = MLXSW_REG_MCIA_TH_PAGE_NUM; +- mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, page, ++ mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page, + MLXSW_REG_MCIA_TH_PAGE_OFF + off, + MLXSW_REG_MCIA_TH_ITEM_SIZE, + MLXSW_REG_MCIA_I2C_ADDR_LOW); + } else { +- mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, ++ mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, + MLXSW_REG_MCIA_PAGE0_LO, + off, MLXSW_REG_MCIA_TH_ITEM_SIZE, + MLXSW_REG_MCIA_I2C_ADDR_HIGH); +@@ -207,8 +212,8 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, + return 0; + } + +-int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, +- struct ethtool_modinfo *modinfo) ++int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ int module, struct ethtool_modinfo *modinfo) + { + u8 module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE]; + u16 offset = MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE; +@@ -216,8 +221,9 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, + unsigned int read_size; + int err; + +- err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset, +- module_info, false, &read_size); ++ err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index, module, 0, ++ offset, module_info, false, ++ &read_size); + if (err) + return err; + +@@ -246,9 +252,10 @@ 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 diagnostic monitoring page */ +- err = mlxsw_env_query_module_eeprom(mlxsw_core, module, +- SFP_DIAGMON, 1, &diag_mon, +- false, &read_size); ++ err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index, ++ module, SFP_DIAGMON, 1, ++ &diag_mon, false, ++ &read_size); + if (err) + return err; + +@@ -286,8 +293,9 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, + EXPORT_SYMBOL(mlxsw_env_get_module_info); + + int mlxsw_env_get_module_eeprom(struct net_device *netdev, +- struct mlxsw_core *mlxsw_core, int module, +- struct ethtool_eeprom *ee, u8 *data) ++ struct mlxsw_core *mlxsw_core, u8 slot_index, ++ int module, struct ethtool_eeprom *ee, ++ u8 *data) + { + int offset = ee->offset; + unsigned int read_size; +@@ -300,12 +308,14 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev, + + memset(data, 0, ee->len); + /* Validate module identifier value. */ +- err = mlxsw_env_validate_cable_ident(mlxsw_core, module, &qsfp, &cmis); ++ err = mlxsw_env_validate_cable_ident(mlxsw_core, slot_index, module, ++ &qsfp, &cmis); + if (err) + return err; + + while (i < ee->len) { +- err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset, ++ err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index, ++ module, offset, + ee->len - i, data + i, + qsfp, &read_size); + if (err) { +@@ -351,7 +361,8 @@ static int mlxsw_env_mcia_status_process(const char *mcia_pl, + } + + int +-mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module, ++mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, ++ u8 slot_index, u8 module, + const struct ethtool_module_eeprom *page, + struct netlink_ext_ack *extack) + { +@@ -370,7 +381,7 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module, + size = min_t(u8, page->length - bytes_read, + MLXSW_REG_MCIA_EEPROM_SIZE); + +- mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, page->page, ++ mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page->page, + device_addr + bytes_read, size, + page->i2c_address); + mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank); +@@ -394,18 +405,20 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module, + } + EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page); + +-static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 module) ++static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module) + { + char pmaos_pl[MLXSW_REG_PMAOS_LEN]; + +- mlxsw_reg_pmaos_pack(pmaos_pl, 0, module); ++ mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, module); + mlxsw_reg_pmaos_rst_set(pmaos_pl, true); + + return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl); + } + + int mlxsw_env_reset_module(struct net_device *netdev, +- struct mlxsw_core *mlxsw_core, u8 module, u32 *flags) ++ struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, u32 *flags) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + u32 req = *flags; +@@ -430,7 +443,7 @@ int mlxsw_env_reset_module(struct net_device *netdev, + goto out; + } + +- err = mlxsw_env_module_reset(mlxsw_core, module); ++ err = mlxsw_env_module_reset(mlxsw_core, slot_index, module); + if (err) { + netdev_err(netdev, "Failed to reset module\n"); + goto out; +@@ -445,7 +458,8 @@ int mlxsw_env_reset_module(struct net_device *netdev, + EXPORT_SYMBOL(mlxsw_env_reset_module); + + int +-mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, ++mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, + struct ethtool_module_power_mode_params *params, + struct netlink_ext_ack *extack) + { +@@ -458,7 +472,7 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + + params->policy = mlxsw_env->module_info[module].power_mode_policy; + +- mlxsw_reg_mcion_pack(mcion_pl, 0, module); ++ mlxsw_reg_mcion_pack(mcion_pl, slot_index, module); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Failed to retrieve module's power mode"); +@@ -481,12 +495,12 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + EXPORT_SYMBOL(mlxsw_env_get_module_power_mode); + + static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core, +- u8 module, bool enable) ++ u8 slot_index, u8 module, bool enable) + { + enum mlxsw_reg_pmaos_admin_status admin_status; + char pmaos_pl[MLXSW_REG_PMAOS_LEN]; + +- mlxsw_reg_pmaos_pack(pmaos_pl, 0, module); ++ mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, module); + admin_status = enable ? MLXSW_REG_PMAOS_ADMIN_STATUS_ENABLED : + MLXSW_REG_PMAOS_ADMIN_STATUS_DISABLED; + mlxsw_reg_pmaos_admin_status_set(pmaos_pl, admin_status); +@@ -496,12 +510,13 @@ static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core, + } + + static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core, +- u8 module, bool low_power) ++ u8 slot_index, u8 module, ++ bool low_power) + { + u16 eeprom_override_mask, eeprom_override; + char pmmp_pl[MLXSW_REG_PMMP_LEN]; + +- mlxsw_reg_pmmp_pack(pmmp_pl, 0, module); ++ mlxsw_reg_pmmp_pack(pmmp_pl, slot_index, module); + mlxsw_reg_pmmp_sticky_set(pmmp_pl, true); + /* Mask all the bits except low power mode. */ + eeprom_override_mask = ~MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK; +@@ -514,24 +529,26 @@ static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core, + } + + static int __mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, +- u8 module, bool low_power, ++ u8 slot_index, u8 module, ++ bool low_power, + struct netlink_ext_ack *extack) + { + int err; + +- err = mlxsw_env_module_enable_set(mlxsw_core, module, false); ++ err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, false); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Failed to disable module"); + return err; + } + +- err = mlxsw_env_module_low_power_set(mlxsw_core, module, low_power); ++ err = mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module, ++ low_power); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Failed to set module's power mode"); + goto err_module_low_power_set; + } + +- err = mlxsw_env_module_enable_set(mlxsw_core, module, true); ++ err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Failed to enable module"); + goto err_module_enable_set; +@@ -540,14 +557,16 @@ static int __mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, + return 0; + + err_module_enable_set: +- mlxsw_env_module_low_power_set(mlxsw_core, module, !low_power); ++ mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module, ++ !low_power); + err_module_low_power_set: +- mlxsw_env_module_enable_set(mlxsw_core, module, true); ++ mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true); + return err; + } + + int +-mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, ++mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, + enum ethtool_module_power_mode_policy policy, + struct netlink_ext_ack *extack) + { +@@ -571,8 +590,8 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + goto out_set_policy; + + low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO; +- err = __mlxsw_env_set_module_power_mode(mlxsw_core, module, low_power, +- extack); ++ err = __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, ++ low_power, extack); + if (err) + goto out; + +@@ -585,14 +604,14 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + EXPORT_SYMBOL(mlxsw_env_set_module_power_mode); + + static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core, +- u8 module, ++ u8 slot_index, u8 module, + bool *p_has_temp_sensor) + { + char mtbr_pl[MLXSW_REG_MTBR_LEN]; + u16 temp; + int err; + +- mlxsw_reg_mtbr_pack(mtbr_pl, 0, ++ mlxsw_reg_mtbr_pack(mtbr_pl, slot_index, + MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 1); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtbr), mtbr_pl); + if (err) +@@ -613,13 +632,15 @@ static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core, + return 0; + } + +-static int mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, +- u16 sensor_index, bool enable) ++static int ++mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u16 sensor_index, bool enable) + { + char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; + enum mlxsw_reg_mtmp_tee tee; + int err, threshold_hi; + ++ mlxsw_reg_mtmp_slot_index_set(mtmp_pl, slot_index); + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, sensor_index); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl); + if (err) +@@ -627,6 +648,7 @@ static int mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, + + if (enable) { + err = mlxsw_env_module_temp_thresholds_get(mlxsw_core, ++ slot_index, + sensor_index - + MLXSW_REG_MTMP_MODULE_INDEX_MIN, + SFP_TEMP_HIGH_WARN, +@@ -654,14 +676,14 @@ static int mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, + } + + static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core, +- u8 module_count) ++ u8 slot_index, u8 module_count) + { + int i, err, sensor_index; + bool has_temp_sensor; + + for (i = 0; i < module_count; i++) { +- err = mlxsw_env_module_has_temp_sensor(mlxsw_core, i, +- &has_temp_sensor); ++ err = mlxsw_env_module_has_temp_sensor(mlxsw_core, slot_index, ++ i, &has_temp_sensor); + if (err) + return err; + +@@ -669,7 +691,8 @@ static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core, + continue; + + sensor_index = i + MLXSW_REG_MTMP_MODULE_INDEX_MIN; +- err = mlxsw_env_temp_event_set(mlxsw_core, sensor_index, true); ++ err = mlxsw_env_temp_event_set(mlxsw_core, slot_index, ++ sensor_index, true); + if (err) + return err; + } +@@ -776,6 +799,7 @@ static void mlxsw_env_temp_warn_event_unregister(struct mlxsw_env *mlxsw_env) + + struct mlxsw_env_module_plug_unplug_event { + struct mlxsw_env *mlxsw_env; ++ u8 slot_index; + u8 module; + struct work_struct work; + }; +@@ -796,7 +820,9 @@ static void mlxsw_env_pmpe_event_work(struct work_struct *work) + mlxsw_env->module_info[event->module].is_overheat = false; + mutex_unlock(&mlxsw_env->module_info_lock); + +- err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, event->module, ++ err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, ++ event->slot_index, ++ event->module, + &has_temp_sensor); + /* Do not disable events on modules without sensors or faulty sensors + * because FW returns errors. +@@ -808,7 +834,8 @@ static void mlxsw_env_pmpe_event_work(struct work_struct *work) + goto out; + + sensor_index = event->module + MLXSW_REG_MTMP_MODULE_INDEX_MIN; +- mlxsw_env_temp_event_set(mlxsw_env->core, sensor_index, true); ++ mlxsw_env_temp_event_set(mlxsw_env->core, event->slot_index, ++ sensor_index, true); + + out: + kfree(event); +@@ -835,6 +862,7 @@ mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl, + return; + + event->mlxsw_env = mlxsw_env; ++ event->slot_index = 0; + event->module = module; + INIT_WORK(&event->work, mlxsw_env_pmpe_event_work); + mlxsw_core_schedule_work(&event->work); +@@ -869,14 +897,14 @@ mlxsw_env_module_plug_event_unregister(struct mlxsw_env *mlxsw_env) + + static int + mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core, +- u8 module_count) ++ u8 slot_index, u8 module_count) + { + int i, err; + + for (i = 0; i < module_count; i++) { + char pmaos_pl[MLXSW_REG_PMAOS_LEN]; + +- mlxsw_reg_pmaos_pack(pmaos_pl, 0, i); ++ mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, i); + mlxsw_reg_pmaos_e_set(pmaos_pl, + MLXSW_REG_PMAOS_E_GENERATE_EVENT); + mlxsw_reg_pmaos_ee_set(pmaos_pl, true); +@@ -888,8 +916,8 @@ mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core, + } + + int +-mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module, +- u64 *p_counter) ++mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, u64 *p_counter) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +@@ -901,7 +929,8 @@ mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module, + } + EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get); + +-void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module) ++void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +@@ -911,7 +940,8 @@ void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module) + } + EXPORT_SYMBOL(mlxsw_env_module_port_map); + +-void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module) ++void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +@@ -921,7 +951,8 @@ void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module) + } + EXPORT_SYMBOL(mlxsw_env_module_port_unmap); + +-int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module) ++int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + int err = 0; +@@ -938,8 +969,8 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module) + /* Transition to high power mode following first port using the module + * being put administratively up. + */ +- err = __mlxsw_env_set_module_power_mode(mlxsw_core, module, false, +- NULL); ++ err = __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, ++ false, NULL); + if (err) + goto out_unlock; + +@@ -951,7 +982,8 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module) + } + EXPORT_SYMBOL(mlxsw_env_module_port_up); + +-void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module) ++void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +@@ -969,7 +1001,8 @@ void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module) + /* Transition to low power mode following last port using the module + * being put administratively down. + */ +- __mlxsw_env_set_module_power_mode(mlxsw_core, module, true, NULL); ++ __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, true, ++ NULL); + + out_unlock: + mutex_unlock(&mlxsw_env->module_info_lock); +@@ -1014,12 +1047,13 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + if (err) + goto err_module_plug_event_register; + +- err = mlxsw_env_module_oper_state_event_enable(mlxsw_core, ++ err = mlxsw_env_module_oper_state_event_enable(mlxsw_core, 0, + env->module_count); + if (err) + goto err_oper_state_event_enable; + +- err = mlxsw_env_module_temp_event_enable(mlxsw_core, env->module_count); ++ err = mlxsw_env_module_temp_event_enable(mlxsw_core, 0, ++ env->module_count); + if (err) + goto err_temp_event_enable; + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.h b/drivers/net/ethernet/mellanox/mlxsw/core_env.h +index da121b1a84b4..03d027870d65 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.h +@@ -9,46 +9,55 @@ + struct ethtool_modinfo; + struct ethtool_eeprom; + +-int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, +- int off, int *temp); ++int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, ++ u8 slot_index, int module, int off, ++ int *temp); + +-int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, +- struct ethtool_modinfo *modinfo); ++int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ int module, struct ethtool_modinfo *modinfo); + + int mlxsw_env_get_module_eeprom(struct net_device *netdev, +- struct mlxsw_core *mlxsw_core, int module, +- struct ethtool_eeprom *ee, u8 *data); ++ struct mlxsw_core *mlxsw_core, u8 slot_index, ++ int module, struct ethtool_eeprom *ee, ++ u8 *data); + + int +-mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module, ++mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, ++ u8 slot_index, u8 module, + const struct ethtool_module_eeprom *page, + struct netlink_ext_ack *extack); + + int mlxsw_env_reset_module(struct net_device *netdev, +- struct mlxsw_core *mlxsw_core, u8 module, +- u32 *flags); ++ struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, u32 *flags); + + int +-mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, ++mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, + struct ethtool_module_power_mode_params *params, + struct netlink_ext_ack *extack); + + int +-mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, ++mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, + enum ethtool_module_power_mode_policy policy, + struct netlink_ext_ack *extack); + + int +-mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module, +- u64 *p_counter); ++mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, u64 *p_counter); + +-void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module); ++void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module); + +-void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module); ++void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module); + +-int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module); ++int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module); + +-void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module); ++void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module); + + int mlxsw_env_init(struct mlxsw_core *core, struct mlxsw_env **p_env); + void mlxsw_env_fini(struct mlxsw_env *env); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 2bc4c4556895..5df54a5bf292 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -311,8 +311,9 @@ static int mlxsw_hwmon_module_temp_critical_get(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +- err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, +- SFP_TEMP_HIGH_WARN, p_temp); ++ err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0, ++ module, SFP_TEMP_HIGH_WARN, ++ p_temp); + if (err) { + dev_err(dev, "Failed to query module temperature thresholds\n"); + return err; +@@ -345,8 +346,9 @@ static int mlxsw_hwmon_module_temp_emergency_get(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +- err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, +- SFP_TEMP_HIGH_ALARM, p_temp); ++ err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0, ++ module, SFP_TEMP_HIGH_ALARM, ++ p_temp); + if (err) { + dev_err(dev, "Failed to query module temperature thresholds\n"); + return err; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 21a7415c8ef5..4f84c4bb66af 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -151,13 +151,13 @@ mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core, + * EEPROM if we got valid thresholds from MTMP. + */ + if (!emerg_temp || !crit_temp) { +- err = mlxsw_env_module_temp_thresholds_get(core, tz->module, ++ err = mlxsw_env_module_temp_thresholds_get(core, 0, tz->module, + SFP_TEMP_HIGH_WARN, + &crit_temp); + if (err) + return err; + +- err = mlxsw_env_module_temp_thresholds_get(core, tz->module, ++ err = mlxsw_env_module_temp_thresholds_get(core, 0, tz->module, + SFP_TEMP_HIGH_ALARM, + &emerg_temp); + if (err) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index b2ffcfda8374..104f1ba0242f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -59,7 +59,8 @@ static int mlxsw_m_port_open(struct net_device *dev) + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev); + struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; + +- return mlxsw_env_module_port_up(mlxsw_m->core, mlxsw_m_port->module); ++ return mlxsw_env_module_port_up(mlxsw_m->core, 0, ++ mlxsw_m_port->module); + } + + static int mlxsw_m_port_stop(struct net_device *dev) +@@ -67,7 +68,7 @@ static int mlxsw_m_port_stop(struct net_device *dev) + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev); + struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; + +- mlxsw_env_module_port_down(mlxsw_m->core, mlxsw_m_port->module); ++ mlxsw_env_module_port_down(mlxsw_m->core, 0, mlxsw_m_port->module); + return 0; + } + +@@ -110,7 +111,8 @@ static int mlxsw_m_get_module_info(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_info(core, mlxsw_m_port->module, modinfo); ++ return mlxsw_env_get_module_info(core, 0, mlxsw_m_port->module, ++ modinfo); + } + + static int +@@ -120,8 +122,8 @@ mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_eeprom(netdev, core, mlxsw_m_port->module, +- ee, data); ++ return mlxsw_env_get_module_eeprom(netdev, core, 0, ++ mlxsw_m_port->module, ee, data); + } + + static int +@@ -132,7 +134,8 @@ mlxsw_m_get_module_eeprom_by_page(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_eeprom_by_page(core, mlxsw_m_port->module, ++ return mlxsw_env_get_module_eeprom_by_page(core, 0, ++ mlxsw_m_port->module, + page, extack); + } + +@@ -141,7 +144,7 @@ static int mlxsw_m_reset(struct net_device *netdev, u32 *flags) + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_reset_module(netdev, core, mlxsw_m_port->module, ++ return mlxsw_env_reset_module(netdev, core, 0, mlxsw_m_port->module, + flags); + } + +@@ -153,7 +156,7 @@ mlxsw_m_get_module_power_mode(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_power_mode(core, mlxsw_m_port->module, ++ return mlxsw_env_get_module_power_mode(core, 0, mlxsw_m_port->module, + params, extack); + } + +@@ -165,7 +168,7 @@ mlxsw_m_set_module_power_mode(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_set_module_power_mode(core, mlxsw_m_port->module, ++ return mlxsw_env_set_module_power_mode(core, 0, mlxsw_m_port->module, + params->policy, extack); + } + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +index 4110e15c22c7..e0424f490c6f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -1377,7 +1377,7 @@ static int mlxsw_sp_port_overheat_init_val_set(struct mlxsw_sp_port *mlxsw_sp_po + u64 overheat_counter; + int err; + +- err = mlxsw_env_module_overheat_counter_get(mlxsw_sp->core, module, ++ err = mlxsw_env_module_overheat_counter_get(mlxsw_sp->core, 0, module, + &overheat_counter); + if (err) + return err; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c +index 369b9d0dc5d4..c9298b236182 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c +@@ -566,7 +566,7 @@ mlxsw_sp_port_get_transceiver_overheat_stats(struct mlxsw_sp_port *mlxsw_sp_port + u64 stats; + int err; + +- err = mlxsw_env_module_overheat_counter_get(mlxsw_core, ++ err = mlxsw_env_module_overheat_counter_get(mlxsw_core, 0, + port_mapping.module, + &stats); + if (err) +@@ -1032,7 +1032,7 @@ static int mlxsw_sp_get_module_info(struct net_device *netdev, + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + int err; + +- err = mlxsw_env_get_module_info(mlxsw_sp->core, ++ err = mlxsw_env_get_module_info(mlxsw_sp->core, 0, + mlxsw_sp_port->mapping.module, + modinfo); + +@@ -1046,7 +1046,7 @@ static int mlxsw_sp_get_module_eeprom(struct net_device *netdev, + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + int err; + +- err = mlxsw_env_get_module_eeprom(netdev, mlxsw_sp->core, ++ err = mlxsw_env_get_module_eeprom(netdev, mlxsw_sp->core, 0, + mlxsw_sp_port->mapping.module, ee, + data); + +@@ -1062,8 +1062,8 @@ mlxsw_sp_get_module_eeprom_by_page(struct net_device *dev, + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 module = mlxsw_sp_port->mapping.module; + +- return mlxsw_env_get_module_eeprom_by_page(mlxsw_sp->core, module, page, +- extack); ++ return mlxsw_env_get_module_eeprom_by_page(mlxsw_sp->core, 0, module, ++ page, extack); + } + + static int +-- +2.20.1 + diff --git a/patch/0113-mlxsw-core-Extend-port-module-data-structures-for-li.patch b/patch/0113-mlxsw-core-Extend-port-module-data-structures-for-li.patch new file mode 100644 index 000000000..ad8bd09c4 --- /dev/null +++ b/patch/0113-mlxsw-core-Extend-port-module-data-structures-for-li.patch @@ -0,0 +1,520 @@ +From fe0bf4454c709fa1ddb5fa105e88f2d57cb5ef5a Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:27 +0200 +Subject: [PATCH backport 5.10 113/182] mlxsw: core: Extend port module data + structures for line cards + +The port module core is tasked with module operations such as setting +power mode policy and reset. The per-module information is currently +stored in one large array suited for non-modular systems where only the +main board is present (i.e., slot index 0). + +As a preparation for line cards support, allocate a per line card array +according to the queried number of slots in the system. For each line +card, allocate a module array according to the queried maximum number of +modules per-slot. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 223 ++++++++++++------ + 1 file changed, 157 insertions(+), 66 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index fc4468a6b0f6..606d89b6f50f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -20,13 +20,19 @@ struct mlxsw_env_module_info { + enum ethtool_module_power_mode_policy power_mode_policy; + }; + +-struct mlxsw_env { +- struct mlxsw_core *core; ++struct mlxsw_env_module_line_cards { + u8 module_count; +- struct mutex module_info_lock; /* Protects 'module_info'. */ + struct mlxsw_env_module_info module_info[]; + }; + ++struct mlxsw_env { ++ struct mlxsw_core *core; ++ u8 max_module_count; /* Maximum number of modules per-slot. */ ++ u8 num_of_slots; /* Including the main board. */ ++ struct mutex line_cards_lock; /* Protects line cards. */ ++ struct mlxsw_env_module_line_cards *line_cards[]; ++}; ++ + static int + mlxsw_env_validate_cable_ident(struct mlxsw_core *core, u8 slot_index, int id, + bool *qsfp, bool *cmis) +@@ -405,6 +411,15 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, + } + EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page); + ++static struct ++mlxsw_env_module_info *mlxsw_env_module_info_get(struct mlxsw_core *mlxsw_core, ++ u8 slot_index, u8 module) ++{ ++ struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ ++ return &mlxsw_env->line_cards[slot_index]->module_info[module]; ++} ++ + static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 slot_index, + u8 module) + { +@@ -421,6 +436,7 @@ int mlxsw_env_reset_module(struct net_device *netdev, + u8 module, u32 *flags) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + u32 req = *flags; + int err; + +@@ -428,15 +444,16 @@ int mlxsw_env_reset_module(struct net_device *netdev, + !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) + return 0; + +- mutex_lock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); + +- if (mlxsw_env->module_info[module].num_ports_up) { ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ if (module_info->num_ports_up) { + netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n"); + err = -EINVAL; + goto out; + } + +- if (mlxsw_env->module_info[module].num_ports_mapped > 1 && ++ if (module_info->num_ports_mapped > 1 && + !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) { + netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n"); + err = -EINVAL; +@@ -452,7 +469,7 @@ int mlxsw_env_reset_module(struct net_device *netdev, + *flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)); + + out: +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_unlock(&mlxsw_env->line_cards_lock); + return err; + } + EXPORT_SYMBOL(mlxsw_env_reset_module); +@@ -464,13 +481,15 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, + struct netlink_ext_ack *extack) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + char mcion_pl[MLXSW_REG_MCION_LEN]; + u32 status_bits; + int err; + +- mutex_lock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); + +- params->policy = mlxsw_env->module_info[module].power_mode_policy; ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ params->policy = module_info->power_mode_policy; + + mlxsw_reg_mcion_pack(mcion_pl, slot_index, module); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl); +@@ -489,7 +508,7 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, + params->mode = ETHTOOL_MODULE_POWER_MODE_HIGH; + + out: +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_unlock(&mlxsw_env->line_cards_lock); + return err; + } + EXPORT_SYMBOL(mlxsw_env_get_module_power_mode); +@@ -571,6 +590,7 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, + struct netlink_ext_ack *extack) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + bool low_power; + int err = 0; + +@@ -580,13 +600,14 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, + return -EOPNOTSUPP; + } + +- mutex_lock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); + +- if (mlxsw_env->module_info[module].power_mode_policy == policy) ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ if (module_info->power_mode_policy == policy) + goto out; + + /* If any ports are up, we are already in high power mode. */ +- if (mlxsw_env->module_info[module].num_ports_up) ++ if (module_info->num_ports_up) + goto out_set_policy; + + low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO; +@@ -596,9 +617,9 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, + goto out; + + out_set_policy: +- mlxsw_env->module_info[module].power_mode_policy = policy; ++ module_info->power_mode_policy = policy; + out: +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_unlock(&mlxsw_env->line_cards_lock); + return err; + } + EXPORT_SYMBOL(mlxsw_env_set_module_power_mode); +@@ -709,6 +730,7 @@ struct mlxsw_env_module_temp_warn_event { + static void mlxsw_env_mtwe_event_work(struct work_struct *work) + { + struct mlxsw_env_module_temp_warn_event *event; ++ struct mlxsw_env_module_info *module_info; + struct mlxsw_env *mlxsw_env; + int i, sensor_warning; + bool is_overheat; +@@ -717,7 +739,7 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work) + work); + mlxsw_env = event->mlxsw_env; + +- for (i = 0; i < mlxsw_env->module_count; i++) { ++ for (i = 0; i < mlxsw_env->max_module_count; i++) { + /* 64-127 of sensor_index are mapped to the port modules + * sequentially (module 0 is mapped to sensor_index 64, + * module 1 to sensor_index 65 and so on) +@@ -725,9 +747,10 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work) + sensor_warning = + mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl, + i + MLXSW_REG_MTMP_MODULE_INDEX_MIN); +- mutex_lock(&mlxsw_env->module_info_lock); +- is_overheat = +- mlxsw_env->module_info[i].is_overheat; ++ mutex_lock(&mlxsw_env->line_cards_lock); ++ /* MTWE only supports main board. */ ++ module_info = mlxsw_env_module_info_get(mlxsw_env->core, 0, i); ++ is_overheat = module_info->is_overheat; + + if ((is_overheat && sensor_warning) || + (!is_overheat && !sensor_warning)) { +@@ -735,21 +758,21 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work) + * warning OR current state in "no warning" and MTWE + * does not report warning. + */ +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_unlock(&mlxsw_env->line_cards_lock); + continue; + } else if (is_overheat && !sensor_warning) { + /* MTWE reports "no warning", turn is_overheat off. + */ +- mlxsw_env->module_info[i].is_overheat = false; +- mutex_unlock(&mlxsw_env->module_info_lock); ++ module_info->is_overheat = false; ++ mutex_unlock(&mlxsw_env->line_cards_lock); + } else { + /* Current state is "no warning" and MTWE reports + * "warning", increase the counter and turn is_overheat + * on. + */ +- mlxsw_env->module_info[i].is_overheat = true; +- mlxsw_env->module_info[i].module_overheat_counter++; +- mutex_unlock(&mlxsw_env->module_info_lock); ++ module_info->is_overheat = true; ++ module_info->module_overheat_counter++; ++ mutex_unlock(&mlxsw_env->line_cards_lock); + } + } + +@@ -807,6 +830,7 @@ struct mlxsw_env_module_plug_unplug_event { + static void mlxsw_env_pmpe_event_work(struct work_struct *work) + { + struct mlxsw_env_module_plug_unplug_event *event; ++ struct mlxsw_env_module_info *module_info; + struct mlxsw_env *mlxsw_env; + bool has_temp_sensor; + u16 sensor_index; +@@ -816,9 +840,12 @@ static void mlxsw_env_pmpe_event_work(struct work_struct *work) + work); + mlxsw_env = event->mlxsw_env; + +- mutex_lock(&mlxsw_env->module_info_lock); +- mlxsw_env->module_info[event->module].is_overheat = false; +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); ++ module_info = mlxsw_env_module_info_get(mlxsw_env->core, ++ event->slot_index, ++ event->module); ++ module_info->is_overheat = false; ++ mutex_unlock(&mlxsw_env->line_cards_lock); + + err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, + event->slot_index, +@@ -845,12 +872,14 @@ static void + mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl, + void *priv) + { ++ u8 slot_index = mlxsw_reg_pmpe_slot_index_get(pmpe_pl); + struct mlxsw_env_module_plug_unplug_event *event; + enum mlxsw_reg_pmpe_module_status module_status; + u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl); + struct mlxsw_env *mlxsw_env = priv; + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) ++ if (WARN_ON_ONCE(module >= mlxsw_env->max_module_count || ++ slot_index >= mlxsw_env->num_of_slots)) + return; + + module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl); +@@ -862,7 +891,7 @@ mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl, + return; + + event->mlxsw_env = mlxsw_env; +- event->slot_index = 0; ++ event->slot_index = slot_index; + event->module = module; + INIT_WORK(&event->work, mlxsw_env_pmpe_event_work); + mlxsw_core_schedule_work(&event->work); +@@ -920,10 +949,12 @@ mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 slot_ind + u8 module, u64 *p_counter) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + +- mutex_lock(&mlxsw_env->module_info_lock); +- *p_counter = mlxsw_env->module_info[module].module_overheat_counter; +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ *p_counter = module_info->module_overheat_counter; ++ mutex_unlock(&mlxsw_env->line_cards_lock); + + return 0; + } +@@ -933,10 +964,12 @@ void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 slot_index, + u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + +- mutex_lock(&mlxsw_env->module_info_lock); +- mlxsw_env->module_info[module].num_ports_mapped++; +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ module_info->num_ports_mapped++; ++ mutex_unlock(&mlxsw_env->line_cards_lock); + } + EXPORT_SYMBOL(mlxsw_env_module_port_map); + +@@ -944,10 +977,12 @@ void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 slot_index, + u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + +- mutex_lock(&mlxsw_env->module_info_lock); +- mlxsw_env->module_info[module].num_ports_mapped--; +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ module_info->num_ports_mapped--; ++ mutex_unlock(&mlxsw_env->line_cards_lock); + } + EXPORT_SYMBOL(mlxsw_env_module_port_unmap); + +@@ -955,15 +990,17 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index, + u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + int err = 0; + +- mutex_lock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); + +- if (mlxsw_env->module_info[module].power_mode_policy != ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ if (module_info->power_mode_policy != + ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) + goto out_inc; + +- if (mlxsw_env->module_info[module].num_ports_up != 0) ++ if (module_info->num_ports_up != 0) + goto out_inc; + + /* Transition to high power mode following first port using the module +@@ -975,9 +1012,9 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index, + goto out_unlock; + + out_inc: +- mlxsw_env->module_info[module].num_ports_up++; ++ module_info->num_ports_up++; + out_unlock: +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_unlock(&mlxsw_env->line_cards_lock); + return err; + } + EXPORT_SYMBOL(mlxsw_env_module_port_up); +@@ -986,16 +1023,18 @@ void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index, + u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + +- mutex_lock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); + +- mlxsw_env->module_info[module].num_ports_up--; ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ module_info->num_ports_up--; + +- if (mlxsw_env->module_info[module].power_mode_policy != ++ if (module_info->power_mode_policy != + ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) + goto out_unlock; + +- if (mlxsw_env->module_info[module].num_ports_up != 0) ++ if (module_info->num_ports_up != 0) + goto out_unlock; + + /* Transition to low power mode following last port using the module +@@ -1005,38 +1044,83 @@ void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index, + NULL); + + out_unlock: +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_unlock(&mlxsw_env->line_cards_lock); + } + EXPORT_SYMBOL(mlxsw_env_module_port_down); + ++static int mlxsw_env_line_cards_alloc(struct mlxsw_env *env) ++{ ++ struct mlxsw_env_module_info *module_info; ++ int i, j; ++ ++ for (i = 0; i < env->num_of_slots; i++) { ++ env->line_cards[i] = kzalloc(struct_size(env->line_cards[i], ++ module_info, ++ env->max_module_count), ++ GFP_KERNEL); ++ if (!env->line_cards[i]) ++ goto kzalloc_err; ++ ++ /* Firmware defaults to high power mode policy where modules ++ * are transitioned to high power mode following plug-in. ++ */ ++ for (j = 0; j < env->max_module_count; j++) { ++ module_info = &env->line_cards[i]->module_info[j]; ++ module_info->power_mode_policy = ++ ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH; ++ } ++ } ++ ++ return 0; ++ ++kzalloc_err: ++ for (i--; i >= 0; i--) ++ kfree(env->line_cards[i]); ++ return -ENOMEM; ++} ++ ++static void mlxsw_env_line_cards_free(struct mlxsw_env *env) ++{ ++ int i = env->num_of_slots; ++ ++ for (i--; i >= 0; i--) ++ kfree(env->line_cards[i]); ++} ++ + int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + { ++ u8 module_count, num_of_slots, max_module_count; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + struct mlxsw_env *env; +- u8 module_count; +- int i, err; ++ int err; + + mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + +- mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count, NULL); ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count, ++ &num_of_slots); ++ /* If the system is modular, get the maximum number of modules per-slot. ++ * Otherwise, get the maximum number of modules on the main board. ++ */ ++ max_module_count = num_of_slots ? ++ mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl) : ++ module_count; + +- env = kzalloc(struct_size(env, module_info, module_count), GFP_KERNEL); ++ env = kzalloc(struct_size(env, line_cards, num_of_slots + 1), ++ GFP_KERNEL); + if (!env) + return -ENOMEM; + +- /* Firmware defaults to high power mode policy where modules are +- * transitioned to high power mode following plug-in. +- */ +- for (i = 0; i < module_count; i++) +- env->module_info[i].power_mode_policy = +- ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH; +- +- mutex_init(&env->module_info_lock); + env->core = mlxsw_core; +- env->module_count = module_count; ++ env->num_of_slots = num_of_slots + 1; ++ env->max_module_count = max_module_count; ++ err = mlxsw_env_line_cards_alloc(env); ++ if (err) ++ goto err_mlxsw_env_line_cards_alloc; ++ ++ mutex_init(&env->line_cards_lock); + *p_env = env; + + err = mlxsw_env_temp_warn_event_register(mlxsw_core); +@@ -1047,13 +1131,17 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + if (err) + goto err_module_plug_event_register; + ++ /* Set 'module_count' only for main board. Actual count for line card ++ * is to be set after line card is activated. ++ */ ++ env->line_cards[0]->module_count = num_of_slots ? 0 : module_count; + err = mlxsw_env_module_oper_state_event_enable(mlxsw_core, 0, +- env->module_count); ++ module_count); + if (err) + goto err_oper_state_event_enable; + + err = mlxsw_env_module_temp_event_enable(mlxsw_core, 0, +- env->module_count); ++ module_count); + if (err) + goto err_temp_event_enable; + +@@ -1065,7 +1153,9 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + err_module_plug_event_register: + mlxsw_env_temp_warn_event_unregister(env); + err_temp_warn_event_register: +- mutex_destroy(&env->module_info_lock); ++ mutex_destroy(&env->line_cards_lock); ++ mlxsw_env_line_cards_free(env); ++err_mlxsw_env_line_cards_alloc: + kfree(env); + return err; + } +@@ -1076,6 +1166,7 @@ void mlxsw_env_fini(struct mlxsw_env *env) + /* Make sure there is no more event work scheduled. */ + mlxsw_core_flush_owq(); + mlxsw_env_temp_warn_event_unregister(env); +- mutex_destroy(&env->module_info_lock); ++ mutex_destroy(&env->line_cards_lock); ++ mlxsw_env_line_cards_free(env); + kfree(env); + } +-- +2.20.1 + diff --git a/patch/0114-mlxsw-core-Move-port-module-events-enablement-to-a-s.patch b/patch/0114-mlxsw-core-Move-port-module-events-enablement-to-a-s.patch new file mode 100644 index 000000000..d8e3d30a4 --- /dev/null +++ b/patch/0114-mlxsw-core-Move-port-module-events-enablement-to-a-s.patch @@ -0,0 +1,92 @@ +From 3c3be37747cb938fff1178f88d611eb00159297b Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:28 +0200 +Subject: [PATCH backport 5.10 114/182] mlxsw: core: Move port module events + enablement to a separate function + +Use a separate function for enablement of port module events such +plug/unplug and temperature threshold crossing. The motivation is to +reuse the function for line cards. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 44 ++++++++++++++----- + 1 file changed, 34 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 606d89b6f50f..4553dfa68f96 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -1087,6 +1087,32 @@ static void mlxsw_env_line_cards_free(struct mlxsw_env *env) + kfree(env->line_cards[i]); + } + ++static int ++mlxsw_env_module_event_enable(struct mlxsw_env *mlxsw_env, u8 slot_index) ++{ ++ u8 module_count; ++ int err; ++ ++ module_count = mlxsw_env->line_cards[slot_index]->module_count; ++ err = mlxsw_env_module_oper_state_event_enable(mlxsw_env->core, ++ slot_index, ++ module_count); ++ if (err) ++ return err; ++ ++ err = mlxsw_env_module_temp_event_enable(mlxsw_env->core, slot_index, ++ module_count); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++static void ++mlxsw_env_module_event_disable(struct mlxsw_env *mlxsw_env, u8 slot_index) ++{ ++} ++ + int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + { + u8 module_count, num_of_slots, max_module_count; +@@ -1135,20 +1161,17 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + * is to be set after line card is activated. + */ + env->line_cards[0]->module_count = num_of_slots ? 0 : module_count; +- err = mlxsw_env_module_oper_state_event_enable(mlxsw_core, 0, +- module_count); +- if (err) +- goto err_oper_state_event_enable; +- +- err = mlxsw_env_module_temp_event_enable(mlxsw_core, 0, +- module_count); ++ /* Enable events only for main board. Line card events are to be ++ * configured only after line card is activated. Before that, access to ++ * modules on line cards is not allowed. ++ */ ++ err = mlxsw_env_module_event_enable(env, 0); + if (err) +- goto err_temp_event_enable; ++ goto err_mlxsw_env_module_event_enable; + + return 0; + +-err_temp_event_enable: +-err_oper_state_event_enable: ++err_mlxsw_env_module_event_enable: + mlxsw_env_module_plug_event_unregister(env); + err_module_plug_event_register: + mlxsw_env_temp_warn_event_unregister(env); +@@ -1162,6 +1185,7 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + + void mlxsw_env_fini(struct mlxsw_env *env) + { ++ mlxsw_env_module_event_disable(env, 0); + mlxsw_env_module_plug_event_unregister(env); + /* Make sure there is no more event work scheduled. */ + mlxsw_core_flush_owq(); +-- +2.20.1 + diff --git a/patch/0115-mlxsw-core_hwmon-Split-gearbox-initialization.patch b/patch/0115-mlxsw-core_hwmon-Split-gearbox-initialization.patch new file mode 100644 index 000000000..b5876fa61 --- /dev/null +++ b/patch/0115-mlxsw-core_hwmon-Split-gearbox-initialization.patch @@ -0,0 +1,122 @@ +From 1a451b46c16494cfa38bb47495ad632626502681 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:29 +0200 +Subject: [PATCH backport 5.10 115/182] mlxsw: core_hwmon: Split gearbox + initialization + +Split gearbox initialization in two functions - the first one is to be +used for gearbox configuration validation, the second for creation of +gearbox related hwmon attributes, if any. + +Currently, mlxsw supports gearbox hwmon attributes corresponding to the +objects discovered on the main board. Same hwmon attributes could be +also discovered on line cards. While the initialization flow for main +board and for line cards is the same, the configuration flow is +different. + +The purpose of this patch is to allow reusing of initialization flow by +main board and line cards. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 43 ++++++++++++++----- + 1 file changed, 33 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 5df54a5bf292..7061c18b7edc 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -700,13 +700,11 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + return 0; + } + +-static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) ++static int ++mlxsw_hwmon_gearbox_main_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 *gbox_num) + { + enum mlxsw_reg_mgpir_device_type device_type; +- int index, max_index, sensor_index; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; +- char mtmp_pl[MLXSW_REG_MTMP_LEN]; +- u8 gbox_num; + int err; + + mlxsw_reg_mgpir_pack(mgpir_pl, 0); +@@ -714,10 +712,27 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) + if (err) + return err; + +- mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, NULL, ++ mlxsw_reg_mgpir_unpack(mgpir_pl, gbox_num, &device_type, NULL, NULL, + NULL); +- if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || +- !gbox_num) ++ if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE) ++ *gbox_num = 0; ++ ++ return 0; ++} ++ ++static void ++mlxsw_hwmon_gearbox_main_fini(struct mlxsw_hwmon *mlxsw_hwmon) ++{ ++} ++ ++static int ++mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 gbox_num) ++{ ++ int index, max_index, sensor_index; ++ char mtmp_pl[MLXSW_REG_MTMP_LEN]; ++ int err; ++ ++ if (!gbox_num) + return 0; + + index = mlxsw_hwmon->module_sensor_max; +@@ -756,6 +771,7 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + { + struct mlxsw_hwmon *mlxsw_hwmon; + struct device *hwmon_dev; ++ u8 gbox_num; + int err; + + mlxsw_hwmon = kzalloc(sizeof(*mlxsw_hwmon), GFP_KERNEL); +@@ -776,9 +792,13 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + if (err) + goto err_temp_module_init; + +- err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon); ++ err = mlxsw_hwmon_gearbox_main_init(mlxsw_hwmon, &gbox_num); ++ if (err) ++ goto err_gearbox_main_init; ++ ++ err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon, gbox_num); + if (err) +- goto err_temp_gearbox_init; ++ goto err_gearbox_init; + + mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group; + mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs; +@@ -796,7 +816,9 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + return 0; + + err_hwmon_register: +-err_temp_gearbox_init: ++err_gearbox_init: ++ mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon); ++err_gearbox_main_init: + err_temp_module_init: + err_fans_init: + err_temp_init: +@@ -807,5 +829,6 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon) + { + hwmon_device_unregister(mlxsw_hwmon->hwmon_dev); ++ mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon); + kfree(mlxsw_hwmon); + } +-- +2.20.1 + diff --git a/patch/0116-mlxsw-core_hwmon-Extend-internal-structures-to-suppo.patch b/patch/0116-mlxsw-core_hwmon-Extend-internal-structures-to-suppo.patch new file mode 100644 index 000000000..7c37fc22b --- /dev/null +++ b/patch/0116-mlxsw-core_hwmon-Extend-internal-structures-to-suppo.patch @@ -0,0 +1,541 @@ +From a18e5112ed12150e245e275e187ecd6d87d66b0e Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:30 +0200 +Subject: [PATCH backport 5.10 116/182] mlxsw: core_hwmon: Extend internal + structures to support multi hwmon objects + +Currently, mlxsw supports a single hwmon device and registers it with +attributes corresponding to the various objects found on the main +board such as fans and gearboxes. + +Line cards can have the same objects, but unlike the main board they +can be added and removed while the system is running. The various +hwmon objects found on these line cards should be created when the +line card becomes available and destroyed when the line card becomes +unavailable. + +The above can be achieved by representing each line card as a +different hwmon device and registering / unregistering it when the +line card becomes available / unavailable. + +Prepare for multi hwmon device support by splitting +'struct mlxsw_hwmon' into 'struct mlxsw_hwmon' and +'struct mlxsw_hwmon_dev'. The first will hold information relevant to +all hwmon devices, whereas the second will hold per-hwmon device +information. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 192 ++++++++++-------- + 1 file changed, 112 insertions(+), 80 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 7061c18b7edc..31b370862131 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -27,7 +27,7 @@ + + struct mlxsw_hwmon_attr { + struct device_attribute dev_attr; +- struct mlxsw_hwmon *hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev; + unsigned int type_index; + char name[32]; + }; +@@ -40,9 +40,8 @@ static int mlxsw_hwmon_get_attr_index(int index, int count) + return index; + } + +-struct mlxsw_hwmon { +- struct mlxsw_core *core; +- const struct mlxsw_bus_info *bus_info; ++struct mlxsw_hwmon_dev { ++ struct mlxsw_hwmon *hwmon; + struct device *hwmon_dev; + struct attribute_group group; + const struct attribute_group *groups[2]; +@@ -53,19 +52,26 @@ struct mlxsw_hwmon { + u8 module_sensor_max; + }; + ++struct mlxsw_hwmon { ++ struct mlxsw_core *core; ++ const struct mlxsw_bus_info *bus_info; ++ struct mlxsw_hwmon_dev *main; ++}; ++ + static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + int temp, index; + int err; + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, +- mlxsw_hwmon->module_sensor_max); ++ mlxsw_hwmon_dev->module_sensor_max); + mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { +@@ -82,13 +88,14 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + int temp_max, index; + int err; + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, +- mlxsw_hwmon->module_sensor_max); ++ mlxsw_hwmon_dev->module_sensor_max); + mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { +@@ -105,8 +112,9 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; +- char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; ++ char mtmp_pl[MLXSW_REG_MTMP_LEN]; + unsigned long val; + int index; + int err; +@@ -118,7 +126,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + return -EINVAL; + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, +- mlxsw_hwmon->module_sensor_max); ++ mlxsw_hwmon_dev->module_sensor_max); + + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, index); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -140,7 +148,8 @@ static ssize_t mlxsw_hwmon_fan_rpm_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mfsm_pl[MLXSW_REG_MFSM_LEN]; + int err; + +@@ -159,7 +168,8 @@ static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char fore_pl[MLXSW_REG_FORE_LEN]; + bool fault; + int err; +@@ -180,7 +190,8 @@ static ssize_t mlxsw_hwmon_pwm_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mfsc_pl[MLXSW_REG_MFSC_LEN]; + int err; + +@@ -200,7 +211,8 @@ static ssize_t mlxsw_hwmon_pwm_store(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mfsc_pl[MLXSW_REG_MFSC_LEN]; + unsigned long val; + int err; +@@ -226,12 +238,13 @@ static int mlxsw_hwmon_module_temp_get(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + u8 module; + int err; + +- module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; + mlxsw_reg_mtmp_pack(mtmp_pl, 0, + MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, false, + false); +@@ -264,15 +277,16 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; + u8 module, fault; + u16 temp; + int err; + +- module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +- mlxsw_reg_mtbr_pack(mtbr_pl, 0, +- MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 1); ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; ++ mlxsw_reg_mtbr_pack(mtbr_pl, 0, 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"); +@@ -306,11 +320,12 @@ static int mlxsw_hwmon_module_temp_critical_get(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + u8 module; + int err; + +- module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; + err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0, + module, SFP_TEMP_HIGH_WARN, + p_temp); +@@ -341,11 +356,12 @@ static int mlxsw_hwmon_module_temp_emergency_get(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + u8 module; + int err; + +- module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; + err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0, + module, SFP_TEMP_HIGH_ALARM, + p_temp); +@@ -390,9 +406,9 @@ mlxsw_hwmon_gbox_temp_label_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; + int index = mlxsw_hwmon_attr->type_index - +- mlxsw_hwmon->module_sensor_max + 1; ++ mlxsw_hwmon_dev->module_sensor_max + 1; + + return sprintf(buf, "gearbox %03u\n", index); + } +@@ -461,14 +477,15 @@ enum mlxsw_hwmon_attr_type { + MLXSW_HWMON_ATTR_TYPE_TEMP_EMERGENCY_ALARM, + }; + +-static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon, ++static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, + enum mlxsw_hwmon_attr_type attr_type, +- unsigned int type_index, unsigned int num) { ++ unsigned int type_index, unsigned int num) ++{ + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr; + unsigned int attr_index; + +- attr_index = mlxsw_hwmon->attrs_count; +- mlxsw_hwmon_attr = &mlxsw_hwmon->hwmon_attrs[attr_index]; ++ attr_index = mlxsw_hwmon_dev->attrs_count; ++ mlxsw_hwmon_attr = &mlxsw_hwmon_dev->hwmon_attrs[attr_index]; + + switch (attr_type) { + case MLXSW_HWMON_ATTR_TYPE_TEMP: +@@ -568,16 +585,17 @@ static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon, + } + + mlxsw_hwmon_attr->type_index = type_index; +- mlxsw_hwmon_attr->hwmon = mlxsw_hwmon; ++ mlxsw_hwmon_attr->mlxsw_hwmon_dev = mlxsw_hwmon_dev; + mlxsw_hwmon_attr->dev_attr.attr.name = mlxsw_hwmon_attr->name; + sysfs_attr_init(&mlxsw_hwmon_attr->dev_attr.attr); + +- mlxsw_hwmon->attrs[attr_index] = &mlxsw_hwmon_attr->dev_attr.attr; +- mlxsw_hwmon->attrs_count++; ++ mlxsw_hwmon_dev->attrs[attr_index] = &mlxsw_hwmon_attr->dev_attr.attr; ++ mlxsw_hwmon_dev->attrs_count++; + } + +-static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon) ++static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + { ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0}; + int i; + int err; +@@ -587,8 +605,8 @@ static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon) + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get number of temp sensors\n"); + return err; + } +- mlxsw_hwmon->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl); +- for (i = 0; i < mlxsw_hwmon->sensor_count; i++) { ++ mlxsw_hwmon_dev->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl); ++ for (i = 0; i < mlxsw_hwmon_dev->sensor_count; i++) { + char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; + + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, i); +@@ -605,18 +623,19 @@ static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon) + i); + return err; + } +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP, i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_RST, i, i); + } + return 0; + } + +-static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) ++static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + { ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mfcr_pl[MLXSW_REG_MFCR_LEN] = {0}; + enum mlxsw_reg_mfcr_pwm_frequency freq; + unsigned int type_index; +@@ -634,10 +653,10 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) + num = 0; + for (type_index = 0; type_index < MLXSW_MFCR_TACHOS_MAX; type_index++) { + if (tacho_active & BIT(type_index)) { +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_FAN_RPM, + type_index, num); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_FAN_FAULT, + type_index, num++); + } +@@ -645,15 +664,16 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) + num = 0; + for (type_index = 0; type_index < MLXSW_MFCR_PWMS_MAX; type_index++) { + if (pwm_active & BIT(type_index)) +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_PWM, + type_index, num++); + } + return 0; + } + +-static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) ++static int mlxsw_hwmon_module_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + { ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + u8 module_sensor_max; + int i, err; +@@ -671,28 +691,28 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + * sensor_count are already utilized by the sensors connected through + * mtmp register by mlxsw_hwmon_temp_init(). + */ +- mlxsw_hwmon->module_sensor_max = mlxsw_hwmon->sensor_count + +- module_sensor_max; +- for (i = mlxsw_hwmon->sensor_count; +- i < mlxsw_hwmon->module_sensor_max; i++) { +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_dev->module_sensor_max = mlxsw_hwmon_dev->sensor_count + ++ module_sensor_max; ++ for (i = mlxsw_hwmon_dev->sensor_count; ++ i < mlxsw_hwmon_dev->module_sensor_max; i++) { ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT, + i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, i, + i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG, + i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL, + i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_CRIT_ALARM, + i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_EMERGENCY_ALARM, + i, i); + } +@@ -701,8 +721,10 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + } + + static int +-mlxsw_hwmon_gearbox_main_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 *gbox_num) ++mlxsw_hwmon_gearbox_main_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, ++ u8 *gbox_num) + { ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + enum mlxsw_reg_mgpir_device_type device_type; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + int err; +@@ -721,13 +743,14 @@ mlxsw_hwmon_gearbox_main_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 *gbox_num) + } + + static void +-mlxsw_hwmon_gearbox_main_fini(struct mlxsw_hwmon *mlxsw_hwmon) ++mlxsw_hwmon_gearbox_main_fini(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + { + } + + static int +-mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 gbox_num) ++mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, u8 gbox_num) + { ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + int index, max_index, sensor_index; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + int err; +@@ -735,10 +758,10 @@ mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 gbox_num) + if (!gbox_num) + return 0; + +- index = mlxsw_hwmon->module_sensor_max; +- max_index = mlxsw_hwmon->module_sensor_max + gbox_num; ++ index = mlxsw_hwmon_dev->module_sensor_max; ++ max_index = mlxsw_hwmon_dev->module_sensor_max + gbox_num; + while (index < max_index) { +- sensor_index = index % mlxsw_hwmon->module_sensor_max + ++ sensor_index = index % mlxsw_hwmon_dev->module_sensor_max + + MLXSW_REG_MTMP_GBOX_INDEX_MIN; + mlxsw_reg_mtmp_pack(mtmp_pl, 0, sensor_index, true, true); + err = mlxsw_reg_write(mlxsw_hwmon->core, +@@ -748,15 +771,15 @@ mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 gbox_num) + sensor_index); + return err; + } +- mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP, +- index, index); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, ++ MLXSW_HWMON_ATTR_TYPE_TEMP, index, index); ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, index, + index); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_RST, index, + index); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL, + index, index); + index++; +@@ -777,58 +800,67 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + mlxsw_hwmon = kzalloc(sizeof(*mlxsw_hwmon), GFP_KERNEL); + if (!mlxsw_hwmon) + return -ENOMEM; ++ mlxsw_hwmon->main = kzalloc(sizeof(*mlxsw_hwmon->main), GFP_KERNEL); ++ if (!mlxsw_hwmon->main) { ++ err = -ENOMEM; ++ goto err_hwmon_main_init; ++ } + mlxsw_hwmon->core = mlxsw_core; + mlxsw_hwmon->bus_info = mlxsw_bus_info; ++ mlxsw_hwmon->main->hwmon = mlxsw_hwmon; + +- err = mlxsw_hwmon_temp_init(mlxsw_hwmon); ++ err = mlxsw_hwmon_temp_init(mlxsw_hwmon->main); + if (err) + goto err_temp_init; + +- err = mlxsw_hwmon_fans_init(mlxsw_hwmon); ++ err = mlxsw_hwmon_fans_init(mlxsw_hwmon->main); + if (err) + goto err_fans_init; + +- err = mlxsw_hwmon_module_init(mlxsw_hwmon); ++ err = mlxsw_hwmon_module_init(mlxsw_hwmon->main); + if (err) + goto err_temp_module_init; + +- err = mlxsw_hwmon_gearbox_main_init(mlxsw_hwmon, &gbox_num); ++ err = mlxsw_hwmon_gearbox_main_init(mlxsw_hwmon->main, &gbox_num); + if (err) + goto err_gearbox_main_init; + +- err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon, gbox_num); ++ err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon->main, gbox_num); + if (err) + goto err_gearbox_init; + +- mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group; +- mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs; ++ mlxsw_hwmon->main->groups[0] = &mlxsw_hwmon->main->group; ++ mlxsw_hwmon->main->group.attrs = mlxsw_hwmon->main->attrs; + + hwmon_dev = hwmon_device_register_with_groups(mlxsw_bus_info->dev, +- "mlxsw", mlxsw_hwmon, +- mlxsw_hwmon->groups); ++ "mlxsw", mlxsw_hwmon->main, ++ mlxsw_hwmon->main->groups); + if (IS_ERR(hwmon_dev)) { + err = PTR_ERR(hwmon_dev); + goto err_hwmon_register; + } + +- mlxsw_hwmon->hwmon_dev = hwmon_dev; ++ mlxsw_hwmon->main->hwmon_dev = hwmon_dev; + *p_hwmon = mlxsw_hwmon; + return 0; + + err_hwmon_register: + err_gearbox_init: +- mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon); ++ mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon->main); + err_gearbox_main_init: + err_temp_module_init: + err_fans_init: + err_temp_init: ++ kfree(mlxsw_hwmon->main); ++err_hwmon_main_init: + kfree(mlxsw_hwmon); + return err; + } + + void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon) + { +- hwmon_device_unregister(mlxsw_hwmon->hwmon_dev); +- mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon); ++ hwmon_device_unregister(mlxsw_hwmon->main->hwmon_dev); ++ mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon->main); ++ kfree(mlxsw_hwmon->main); + kfree(mlxsw_hwmon); + } +-- +2.20.1 + diff --git a/patch/0117-mlxsw-core_hwmon-Introduce-slot-parameter-in-hwmon-i.patch b/patch/0117-mlxsw-core_hwmon-Introduce-slot-parameter-in-hwmon-i.patch new file mode 100644 index 000000000..bc0bc548a --- /dev/null +++ b/patch/0117-mlxsw-core_hwmon-Introduce-slot-parameter-in-hwmon-i.patch @@ -0,0 +1,129 @@ +From 15f2f79bffb77324a389b7e174f32406924d3a3a Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:31 +0200 +Subject: [PATCH backport 5.10 117/182] mlxsw: core_hwmon: Introduce slot + parameter in hwmon interfaces + +Add 'slot' parameter to 'mlxsw_hwmon_dev' structure. Use this parameter +in mlxsw_reg_mtmp_pack(), mlxsw_reg_mtbr_pack() and +Use mlxsw_reg_mtmp_slot_index_set() routines. +For main board it'll always be zero, for line cards it'll be set to +the physical slot number in modular systems. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 26 +++++++++++++------ + 1 file changed, 18 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 31b370862131..0d7edabf19a4 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -50,6 +50,7 @@ struct mlxsw_hwmon_dev { + unsigned int attrs_count; + u8 sensor_count; + u8 module_sensor_max; ++ u8 slot_index; + }; + + struct mlxsw_hwmon { +@@ -72,7 +73,8 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon_dev->module_sensor_max); +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, index, false, ++ false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); +@@ -96,7 +98,8 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon_dev->module_sensor_max); +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, index, false, ++ false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); +@@ -128,6 +131,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon_dev->module_sensor_max); + ++ mlxsw_reg_mtmp_slot_index_set(mtmp_pl, mlxsw_hwmon_dev->slot_index); + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, index); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) +@@ -245,7 +249,7 @@ static int mlxsw_hwmon_module_temp_get(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, ++ mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, + MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, false, + false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -285,8 +289,8 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; +- mlxsw_reg_mtbr_pack(mtbr_pl, 0, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, +- 1); ++ mlxsw_reg_mtbr_pack(mtbr_pl, mlxsw_hwmon_dev->slot_index, ++ 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"); +@@ -326,7 +330,8 @@ static int mlxsw_hwmon_module_temp_critical_get(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; +- err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0, ++ err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, ++ mlxsw_hwmon_dev->slot_index, + module, SFP_TEMP_HIGH_WARN, + p_temp); + if (err) { +@@ -362,7 +367,8 @@ static int mlxsw_hwmon_module_temp_emergency_get(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; +- err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0, ++ err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, ++ mlxsw_hwmon_dev->slot_index, + module, SFP_TEMP_HIGH_ALARM, + p_temp); + if (err) { +@@ -609,6 +615,8 @@ static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + for (i = 0; i < mlxsw_hwmon_dev->sensor_count; i++) { + char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; + ++ mlxsw_reg_mtmp_slot_index_set(mtmp_pl, ++ mlxsw_hwmon_dev->slot_index); + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, i); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), + mtmp_pl); +@@ -763,7 +771,8 @@ mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, u8 gbox_num) + while (index < max_index) { + sensor_index = index % mlxsw_hwmon_dev->module_sensor_max + + MLXSW_REG_MTMP_GBOX_INDEX_MIN; +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, sensor_index, true, true); ++ mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, ++ sensor_index, true, true); + err = mlxsw_reg_write(mlxsw_hwmon->core, + MLXSW_REG(mtmp), mtmp_pl); + if (err) { +@@ -808,6 +817,7 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + mlxsw_hwmon->core = mlxsw_core; + mlxsw_hwmon->bus_info = mlxsw_bus_info; + mlxsw_hwmon->main->hwmon = mlxsw_hwmon; ++ mlxsw_hwmon->main->slot_index = 0; + + err = mlxsw_hwmon_temp_init(mlxsw_hwmon->main); + if (err) +-- +2.20.1 + diff --git a/patch/0118-mlxsw-core_hwmon-Extend-hwmon-device-with-gearbox-ma.patch b/patch/0118-mlxsw-core_hwmon-Extend-hwmon-device-with-gearbox-ma.patch new file mode 100644 index 000000000..7d0491b84 --- /dev/null +++ b/patch/0118-mlxsw-core_hwmon-Extend-hwmon-device-with-gearbox-ma.patch @@ -0,0 +1,136 @@ +From c627292817e68e29abdf5fd9be93340251d71f7a Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:32 +0200 +Subject: [PATCH backport 5.10 118/182] mlxsw: core_hwmon: Extend hwmon device + with gearbox mapping field + +Add gearbox mapping field to 'mlxsw_hwmon_dev' structure. It should +provide the mapping for gearbox sensor indexes, given gearbox number. +For main board mapping is supposed to be always sequential, while for +line cards on modular system it could be non-sequential. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 40 ++++++++++++++----- + 1 file changed, 31 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 0d7edabf19a4..6af23f4724e4 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -32,10 +32,11 @@ struct mlxsw_hwmon_attr { + char name[32]; + }; + +-static int mlxsw_hwmon_get_attr_index(int index, int count) ++static int ++mlxsw_hwmon_get_attr_index(int index, int count, u16 *gearbox_sensor_map) + { + if (index >= count) +- return index % count + MLXSW_REG_MTMP_GBOX_INDEX_MIN; ++ return gearbox_sensor_map[index % count]; + + return index; + } +@@ -50,6 +51,7 @@ struct mlxsw_hwmon_dev { + unsigned int attrs_count; + u8 sensor_count; + u8 module_sensor_max; ++ u16 *gearbox_sensor_map; + u8 slot_index; + }; + +@@ -72,7 +74,8 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + int err; + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, +- mlxsw_hwmon_dev->module_sensor_max); ++ mlxsw_hwmon_dev->module_sensor_max, ++ mlxsw_hwmon_dev->gearbox_sensor_map); + mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, index, false, + false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -97,7 +100,8 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + int err; + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, +- mlxsw_hwmon_dev->module_sensor_max); ++ mlxsw_hwmon_dev->module_sensor_max, ++ mlxsw_hwmon_dev->gearbox_sensor_map); + mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, index, false, + false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -129,7 +133,8 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + return -EINVAL; + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, +- mlxsw_hwmon_dev->module_sensor_max); ++ mlxsw_hwmon_dev->module_sensor_max, ++ mlxsw_hwmon_dev->gearbox_sensor_map); + + mlxsw_reg_mtmp_slot_index_set(mtmp_pl, mlxsw_hwmon_dev->slot_index); + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, index); +@@ -735,7 +740,7 @@ mlxsw_hwmon_gearbox_main_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, + struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + enum mlxsw_reg_mgpir_device_type device_type; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; +- int err; ++ int i, err; + + mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); +@@ -747,12 +752,30 @@ mlxsw_hwmon_gearbox_main_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, + if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE) + *gbox_num = 0; + ++ /* Skip gearbox sensor mapping array allocation, if no gearboxes are ++ * available. ++ */ ++ if (!*gbox_num) ++ return 0; ++ ++ mlxsw_hwmon_dev->gearbox_sensor_map = kmalloc_array(*gbox_num, ++ sizeof(u16), ++ GFP_KERNEL); ++ if (!mlxsw_hwmon_dev->gearbox_sensor_map) ++ return -ENOMEM; ++ ++ /* Fill out gearbox sensor mapping array. */ ++ for (i = 0; i < *gbox_num; i++) ++ mlxsw_hwmon_dev->gearbox_sensor_map[i] = ++ MLXSW_REG_MTMP_GBOX_INDEX_MIN + i; ++ + return 0; + } + + static void + mlxsw_hwmon_gearbox_main_fini(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + { ++ kfree(mlxsw_hwmon_dev->gearbox_sensor_map); + } + + static int +@@ -761,7 +784,7 @@ mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, u8 gbox_num) + struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + int index, max_index, sensor_index; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; +- int err; ++ int i = 0, err; + + if (!gbox_num) + return 0; +@@ -769,8 +792,7 @@ mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, u8 gbox_num) + index = mlxsw_hwmon_dev->module_sensor_max; + max_index = mlxsw_hwmon_dev->module_sensor_max + gbox_num; + while (index < max_index) { +- sensor_index = index % mlxsw_hwmon_dev->module_sensor_max + +- MLXSW_REG_MTMP_GBOX_INDEX_MIN; ++ sensor_index = mlxsw_hwmon_dev->gearbox_sensor_map[i++]; + mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, + sensor_index, true, true); + err = mlxsw_reg_write(mlxsw_hwmon->core, +-- +2.20.1 + diff --git a/patch/0119-mlxsw-core_thermal-Extend-internal-structures-to-sup.patch b/patch/0119-mlxsw-core_thermal-Extend-internal-structures-to-sup.patch new file mode 100644 index 000000000..0ff18202c --- /dev/null +++ b/patch/0119-mlxsw-core_thermal-Extend-internal-structures-to-sup.patch @@ -0,0 +1,367 @@ +From 8851888004e82e73629f031e8af592c36b12c469 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:33 +0200 +Subject: [PATCH backport 5.10 119/182] mlxsw: core_thermal: Extend internal + structures to support multi thermal areas + +Introduce intermediate level for thermal zones areas. +Currently all thermal zones are associated with thermal objects located +within the main board. Such objects are created during driver +initialization and removed during driver de-initialization. + +For line cards in modular system the thermal zones are to be associated +with the specific line card. They should be created whenever new line +card is available (inserted, validated, powered and enabled) and +removed, when line card is getting unavailable. +The thermal objects found on the line card #n are accessed by setting +slot index to #n, while for access to objects found on the main board +slot index should be set to default value zero. + +Each thermal area contains the set of thermal zones associated with +particular slot index. +Thus introduction of thermal zone areas allows to use the same APIs for +the main board and line cards, by adding slot index argument. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + .../ethernet/mellanox/mlxsw/core_thermal.c | 134 +++++++++++------- + 1 file changed, 83 insertions(+), 51 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 4f84c4bb66af..5f8b1e92475b 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -83,6 +83,15 @@ struct mlxsw_thermal_module { + struct thermal_zone_device *tzdev; + struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; + int module; /* Module or gearbox number */ ++ u8 slot_index; ++}; ++ ++struct mlxsw_thermal_area { ++ struct mlxsw_thermal_module *tz_module_arr; ++ u8 tz_module_num; ++ struct mlxsw_thermal_module *tz_gearbox_arr; ++ u8 tz_gearbox_num; ++ u8 slot_index; + }; + + struct mlxsw_thermal { +@@ -93,10 +102,7 @@ struct mlxsw_thermal { + struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX]; + u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1]; + struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; +- struct mlxsw_thermal_module *tz_module_arr; +- u8 tz_module_num; +- struct mlxsw_thermal_module *tz_gearbox_arr; +- u8 tz_gearbox_num; ++ struct mlxsw_thermal_area *main; + unsigned int tz_highest_score; + struct thermal_zone_device *tz_highest_dev; + }; +@@ -151,13 +157,15 @@ mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core, + * EEPROM if we got valid thresholds from MTMP. + */ + if (!emerg_temp || !crit_temp) { +- err = mlxsw_env_module_temp_thresholds_get(core, 0, tz->module, ++ err = mlxsw_env_module_temp_thresholds_get(core, tz->slot_index, ++ tz->module, + SFP_TEMP_HIGH_WARN, + &crit_temp); + if (err) + return err; + +- err = mlxsw_env_module_temp_thresholds_get(core, 0, tz->module, ++ err = mlxsw_env_module_temp_thresholds_get(core, tz->slot_index, ++ tz->module, + SFP_TEMP_HIGH_ALARM, + &emerg_temp); + if (err) +@@ -424,15 +432,16 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev, + + static void + mlxsw_thermal_module_temp_and_thresholds_get(struct mlxsw_core *core, +- u16 sensor_index, int *p_temp, +- int *p_crit_temp, ++ u8 slot_index, u16 sensor_index, ++ int *p_temp, int *p_crit_temp, + int *p_emerg_temp) + { + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + int err; + + /* Read module temperature and thresholds. */ +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, sensor_index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, slot_index, sensor_index, ++ false, false); + err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + /* Set temperature and thresholds to zero to avoid passing +@@ -463,6 +472,7 @@ static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, + + /* Read module temperature and thresholds. */ + mlxsw_thermal_module_temp_and_thresholds_get(thermal->core, ++ tz->slot_index, + sensor_index, &temp, + &crit_temp, &emerg_temp); + *p_temp = temp; +@@ -577,7 +587,7 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, + int err; + + index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module; +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, tz->slot_index, index, false, false); + + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) +@@ -704,25 +714,28 @@ static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev) + + static int + mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, +- struct mlxsw_thermal *thermal, u8 module) ++ struct mlxsw_thermal *thermal, ++ struct mlxsw_thermal_area *area, u8 module) + { + struct mlxsw_thermal_module *module_tz; + int dummy_temp, crit_temp, emerg_temp; + u16 sensor_index; + + sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + module; +- module_tz = &thermal->tz_module_arr[module]; ++ module_tz = &area->tz_module_arr[module]; + /* Skip if parent is already set (case of port split). */ + if (module_tz->parent) + return 0; + module_tz->module = module; ++ module_tz->slot_index = area->slot_index; + module_tz->parent = thermal; + memcpy(module_tz->trips, default_thermal_trips, + sizeof(thermal->trips)); + /* Initialize all trip point. */ + mlxsw_thermal_module_trips_reset(module_tz); + /* Read module temperature and thresholds. */ +- mlxsw_thermal_module_temp_and_thresholds_get(core, sensor_index, &dummy_temp, ++ mlxsw_thermal_module_temp_and_thresholds_get(core, area->slot_index, ++ sensor_index, &dummy_temp, + &crit_temp, &emerg_temp); + /* Update trip point according to the module data. */ + return mlxsw_thermal_module_trips_update(dev, core, module_tz, +@@ -740,34 +753,39 @@ static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz) + + static int + mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, +- struct mlxsw_thermal *thermal) ++ struct mlxsw_thermal *thermal, ++ struct mlxsw_thermal_area *area) + { + struct mlxsw_thermal_module *module_tz; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl, 0); ++ mlxsw_reg_mgpir_pack(mgpir_pl, area->slot_index); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, +- &thermal->tz_module_num, NULL); ++ &area->tz_module_num, NULL); + +- thermal->tz_module_arr = kcalloc(thermal->tz_module_num, +- sizeof(*thermal->tz_module_arr), +- GFP_KERNEL); +- if (!thermal->tz_module_arr) ++ /* For modular system module counter could be zero. */ ++ if (!area->tz_module_num) ++ return 0; ++ ++ area->tz_module_arr = kcalloc(area->tz_module_num, ++ sizeof(*area->tz_module_arr), ++ GFP_KERNEL); ++ if (!area->tz_module_arr) + return -ENOMEM; + +- for (i = 0; i < thermal->tz_module_num; i++) { +- err = mlxsw_thermal_module_init(dev, core, thermal, i); ++ for (i = 0; i < area->tz_module_num; i++) { ++ err = mlxsw_thermal_module_init(dev, core, thermal, area, i); + if (err) + goto err_thermal_module_init; + } + +- for (i = 0; i < thermal->tz_module_num; i++) { +- module_tz = &thermal->tz_module_arr[i]; ++ for (i = 0; i < area->tz_module_num; i++) { ++ module_tz = &area->tz_module_arr[i]; + if (!module_tz->parent) + continue; + err = mlxsw_thermal_module_tz_init(module_tz); +@@ -779,20 +797,21 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + + err_thermal_module_tz_init: + err_thermal_module_init: +- for (i = thermal->tz_module_num - 1; i >= 0; i--) +- mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); +- kfree(thermal->tz_module_arr); ++ for (i = area->tz_module_num - 1; i >= 0; i--) ++ mlxsw_thermal_module_fini(&area->tz_module_arr[i]); ++ kfree(area->tz_module_arr); + return err; + } + + static void +-mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal) ++mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal, ++ struct mlxsw_thermal_area *area) + { + int i; + +- for (i = thermal->tz_module_num - 1; i >= 0; i--) +- mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); +- kfree(thermal->tz_module_arr); ++ for (i = area->tz_module_num - 1; i >= 0; i--) ++ mlxsw_thermal_module_fini(&area->tz_module_arr[i]); ++ kfree(area->tz_module_arr); + } + + static int +@@ -828,7 +847,8 @@ mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz) + + static int + mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, +- struct mlxsw_thermal *thermal) ++ struct mlxsw_thermal *thermal, ++ struct mlxsw_thermal_area *area) + { + enum mlxsw_reg_mgpir_device_type device_type; + struct mlxsw_thermal_module *gearbox_tz; +@@ -848,19 +868,20 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + !gbox_num) + return 0; + +- thermal->tz_gearbox_num = gbox_num; +- thermal->tz_gearbox_arr = kcalloc(thermal->tz_gearbox_num, +- sizeof(*thermal->tz_gearbox_arr), +- GFP_KERNEL); +- if (!thermal->tz_gearbox_arr) ++ area->tz_gearbox_num = gbox_num; ++ area->tz_gearbox_arr = kcalloc(area->tz_gearbox_num, ++ sizeof(*area->tz_gearbox_arr), ++ GFP_KERNEL); ++ if (!area->tz_gearbox_arr) + return -ENOMEM; + +- for (i = 0; i < thermal->tz_gearbox_num; i++) { +- gearbox_tz = &thermal->tz_gearbox_arr[i]; ++ for (i = 0; i < area->tz_gearbox_num; i++) { ++ gearbox_tz = &area->tz_gearbox_arr[i]; + memcpy(gearbox_tz->trips, default_thermal_trips, + sizeof(thermal->trips)); + gearbox_tz->module = i; + gearbox_tz->parent = thermal; ++ gearbox_tz->slot_index = area->slot_index; + err = mlxsw_thermal_gearbox_tz_init(gearbox_tz); + if (err) + goto err_thermal_gearbox_tz_init; +@@ -870,19 +891,20 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + + err_thermal_gearbox_tz_init: + for (i--; i >= 0; i--) +- mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); +- kfree(thermal->tz_gearbox_arr); ++ mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]); ++ kfree(area->tz_gearbox_arr); + return err; + } + + static void +-mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal) ++mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal, ++ struct mlxsw_thermal_area *area) + { + int i; + +- for (i = thermal->tz_gearbox_num - 1; i >= 0; i--) +- mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); +- kfree(thermal->tz_gearbox_arr); ++ for (i = area->tz_gearbox_num - 1; i >= 0; i--) ++ mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]); ++ kfree(area->tz_gearbox_arr); + } + + int mlxsw_thermal_init(struct mlxsw_core *core, +@@ -902,9 +924,16 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + if (!thermal) + return -ENOMEM; + ++ thermal->main = devm_kzalloc(dev, sizeof(*thermal->main), GFP_KERNEL); ++ if (!thermal->main) { ++ err = -ENOMEM; ++ goto err_devm_kzalloc; ++ } ++ + thermal->core = core; + thermal->bus_info = bus_info; + memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips)); ++ thermal->main->slot_index = 0; + + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl); + if (err) { +@@ -970,11 +999,11 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + goto err_thermal_zone_device_register; + } + +- err = mlxsw_thermal_modules_init(dev, core, thermal); ++ err = mlxsw_thermal_modules_init(dev, core, thermal, thermal->main); + if (err) + goto err_thermal_modules_init; + +- err = mlxsw_thermal_gearboxes_init(dev, core, thermal); ++ err = mlxsw_thermal_gearboxes_init(dev, core, thermal, thermal->main); + if (err) + goto err_thermal_gearboxes_init; + +@@ -986,9 +1015,9 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + return 0; + + err_thermal_zone_device_enable: +- mlxsw_thermal_gearboxes_fini(thermal); ++ mlxsw_thermal_gearboxes_fini(thermal, thermal->main); + err_thermal_gearboxes_init: +- mlxsw_thermal_modules_fini(thermal); ++ mlxsw_thermal_modules_fini(thermal, thermal->main); + err_thermal_modules_init: + if (thermal->tzdev) { + thermal_zone_device_unregister(thermal->tzdev); +@@ -1001,6 +1030,8 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + thermal_cooling_device_unregister(thermal->cdevs[i]); + err_reg_write: + err_reg_query: ++ devm_kfree(dev, thermal->main); ++err_devm_kzalloc: + devm_kfree(dev, thermal); + return err; + } +@@ -1009,8 +1040,8 @@ void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) + { + int i; + +- mlxsw_thermal_gearboxes_fini(thermal); +- mlxsw_thermal_modules_fini(thermal); ++ mlxsw_thermal_gearboxes_fini(thermal, thermal->main); ++ mlxsw_thermal_modules_fini(thermal, thermal->main); + if (thermal->tzdev) { + thermal_zone_device_unregister(thermal->tzdev); + thermal->tzdev = NULL; +@@ -1023,5 +1054,6 @@ void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) + } + } + ++ devm_kfree(thermal->bus_info->dev, thermal->main); + devm_kfree(thermal->bus_info->dev, thermal); + } +-- +2.20.1 + diff --git a/patch/0120-mlxsw-core_thermal-Split-gearbox-initialization.patch b/patch/0120-mlxsw-core_thermal-Split-gearbox-initialization.patch new file mode 100644 index 000000000..b0cb21b8a --- /dev/null +++ b/patch/0120-mlxsw-core_thermal-Split-gearbox-initialization.patch @@ -0,0 +1,138 @@ +From ed83386ce79974230c5fa59245efe760046d944c Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:34 +0200 +Subject: [PATCH backport 5.10 120/182] mlxsw: core_thermal: Split gearbox + initialization + +Split gearbox initialization in two routines - the first one is to be +used for gearbox configuration validation, the second for creation of +gearbox related thermal zones if any. + +Currently, mlxsw supports gearbox thermal zones corresponding to the +main board. For system equipped with the line cards assembled with the +gearboxes, thermal zones will be associated with the gearboxes found on +those line cards. + +While the initialization flow for main board and for line cards is the +same, the configuration flow is different. + +The purpose of this patch is to allow reusing of initialization flow by +main board and line cards. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../ethernet/mellanox/mlxsw/core_thermal.c | 43 +++++++++++++++---- + 1 file changed, 34 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 5f8b1e92475b..313856b88f6c 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -846,15 +846,12 @@ mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz) + } + + static int +-mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, +- struct mlxsw_thermal *thermal, +- struct mlxsw_thermal_area *area) ++mlxsw_thermal_gearboxes_main_init(struct device *dev, struct mlxsw_core *core, ++ struct mlxsw_thermal_area *area) + { + enum mlxsw_reg_mgpir_device_type device_type; +- struct mlxsw_thermal_module *gearbox_tz; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + u8 gbox_num; +- int i; + int err; + + mlxsw_reg_mgpir_pack(mgpir_pl, 0); +@@ -864,8 +861,11 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + + mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, + NULL, NULL); +- if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || +- !gbox_num) ++ if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE) ++ gbox_num = 0; ++ ++ /* Skip gearbox sensor array allocation, if no gearboxes are available. */ ++ if (!gbox_num) + return 0; + + area->tz_gearbox_num = gbox_num; +@@ -875,6 +875,26 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + if (!area->tz_gearbox_arr) + return -ENOMEM; + ++ return 0; ++} ++ ++static void ++mlxsw_thermal_gearboxes_main_fini(struct mlxsw_thermal_area *area) ++{ ++ kfree(area->tz_gearbox_arr); ++} ++ ++static int ++mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, ++ struct mlxsw_thermal *thermal, ++ struct mlxsw_thermal_area *area) ++{ ++ struct mlxsw_thermal_module *gearbox_tz; ++ int i, err; ++ ++ if (!area->tz_gearbox_num) ++ return 0; ++ + for (i = 0; i < area->tz_gearbox_num; i++) { + gearbox_tz = &area->tz_gearbox_arr[i]; + memcpy(gearbox_tz->trips, default_thermal_trips, +@@ -892,7 +912,6 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + err_thermal_gearbox_tz_init: + for (i--; i >= 0; i--) + mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]); +- kfree(area->tz_gearbox_arr); + return err; + } + +@@ -904,7 +923,6 @@ mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal, + + for (i = area->tz_gearbox_num - 1; i >= 0; i--) + mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]); +- kfree(area->tz_gearbox_arr); + } + + int mlxsw_thermal_init(struct mlxsw_core *core, +@@ -1003,6 +1021,10 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + if (err) + goto err_thermal_modules_init; + ++ err = mlxsw_thermal_gearboxes_main_init(dev, core, thermal->main); ++ if (err) ++ goto err_thermal_gearboxes_main_init; ++ + err = mlxsw_thermal_gearboxes_init(dev, core, thermal, thermal->main); + if (err) + goto err_thermal_gearboxes_init; +@@ -1017,6 +1039,8 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + err_thermal_zone_device_enable: + mlxsw_thermal_gearboxes_fini(thermal, thermal->main); + err_thermal_gearboxes_init: ++ mlxsw_thermal_gearboxes_main_fini(thermal->main); ++err_thermal_gearboxes_main_init: + mlxsw_thermal_modules_fini(thermal, thermal->main); + err_thermal_modules_init: + if (thermal->tzdev) { +@@ -1041,6 +1065,7 @@ void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) + int i; + + mlxsw_thermal_gearboxes_fini(thermal, thermal->main); ++ mlxsw_thermal_gearboxes_main_fini(thermal->main); + mlxsw_thermal_modules_fini(thermal, thermal->main); + if (thermal->tzdev) { + thermal_zone_device_unregister(thermal->tzdev); +-- +2.20.1 + diff --git a/patch/0121-mlxsw-core_thermal-Extend-thermal-area-with-gearbox-.patch b/patch/0121-mlxsw-core_thermal-Extend-thermal-area-with-gearbox-.patch new file mode 100644 index 000000000..8e9d6e621 --- /dev/null +++ b/patch/0121-mlxsw-core_thermal-Extend-thermal-area-with-gearbox-.patch @@ -0,0 +1,127 @@ +From 13a7ef7fcdc09def9d9756510f49da82283d78df Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:35 +0200 +Subject: [PATCH backport 5.10 121/182] mlxsw: core_thermal: Extend thermal + area with gearbox mapping field + +Add gearbox mapping field 'gearbox_sensor_map' to +'mlxsw_thermal_module' structure. It should provide the mapping for +gearbox sensor indexes, given gearbox number. For main board mapping is +supposed to be always sequential, while for line cards on modular +system it could be non-sequential. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../ethernet/mellanox/mlxsw/core_thermal.c | 33 ++++++++++++++----- + 1 file changed, 25 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 313856b88f6c..bde5489d9240 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -77,9 +77,11 @@ static const struct mlxsw_thermal_trip default_thermal_trips[] = { + #define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1) + + struct mlxsw_thermal; ++struct mlxsw_thermal_area; + + struct mlxsw_thermal_module { + struct mlxsw_thermal *parent; ++ struct mlxsw_thermal_area *area; + struct thermal_zone_device *tzdev; + struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; + int module; /* Module or gearbox number */ +@@ -92,6 +94,7 @@ struct mlxsw_thermal_area { + struct mlxsw_thermal_module *tz_gearbox_arr; + u8 tz_gearbox_num; + u8 slot_index; ++ u16 *gearbox_sensor_map; + }; + + struct mlxsw_thermal { +@@ -586,7 +589,7 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, + int temp; + int err; + +- index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module; ++ index = tz->area->gearbox_sensor_map[tz->module]; + mlxsw_reg_mtmp_pack(mtmp_pl, tz->slot_index, index, false, false); + + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -727,6 +730,7 @@ mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, + if (module_tz->parent) + return 0; + module_tz->module = module; ++ module_tz->area = area; + module_tz->slot_index = area->slot_index; + module_tz->parent = thermal; + memcpy(module_tz->trips, default_thermal_trips, +@@ -851,36 +855,48 @@ mlxsw_thermal_gearboxes_main_init(struct device *dev, struct mlxsw_core *core, + { + enum mlxsw_reg_mgpir_device_type device_type; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; +- u8 gbox_num; +- int err; ++ int i = 0, err; + + mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + +- mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, +- NULL, NULL); ++ mlxsw_reg_mgpir_unpack(mgpir_pl, &area->tz_gearbox_num, &device_type, ++ NULL, NULL, NULL); + if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE) +- gbox_num = 0; ++ area->tz_gearbox_num = 0; + + /* Skip gearbox sensor array allocation, if no gearboxes are available. */ +- if (!gbox_num) ++ if (!area->tz_gearbox_num) + return 0; + +- area->tz_gearbox_num = gbox_num; + area->tz_gearbox_arr = kcalloc(area->tz_gearbox_num, + sizeof(*area->tz_gearbox_arr), + GFP_KERNEL); + if (!area->tz_gearbox_arr) + return -ENOMEM; + ++ area->gearbox_sensor_map = kmalloc_array(area->tz_gearbox_num, ++ sizeof(u16), GFP_KERNEL); ++ if (!area->gearbox_sensor_map) ++ goto mlxsw_thermal_gearbox_sensor_map; ++ ++ /* Fill out gearbox sensor mapping array. */ ++ for (i = 0; i < area->tz_gearbox_num; i++) ++ area->gearbox_sensor_map[i] = MLXSW_REG_MTMP_GBOX_INDEX_MIN + i; ++ + return 0; ++ ++mlxsw_thermal_gearbox_sensor_map: ++ kfree(area->tz_gearbox_arr); ++ return err; + } + + static void + mlxsw_thermal_gearboxes_main_fini(struct mlxsw_thermal_area *area) + { ++ kfree(area->gearbox_sensor_map); + kfree(area->tz_gearbox_arr); + } + +@@ -901,6 +917,7 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + sizeof(thermal->trips)); + gearbox_tz->module = i; + gearbox_tz->parent = thermal; ++ gearbox_tz->area = area; + gearbox_tz->slot_index = area->slot_index; + err = mlxsw_thermal_gearbox_tz_init(gearbox_tz); + if (err) +-- +2.20.1 + diff --git a/patch/0122-mlxsw-core_thermal-Add-line-card-id-prefix-to-line-c.patch b/patch/0122-mlxsw-core_thermal-Add-line-card-id-prefix-to-line-c.patch new file mode 100644 index 000000000..c08ac6d23 --- /dev/null +++ b/patch/0122-mlxsw-core_thermal-Add-line-card-id-prefix-to-line-c.patch @@ -0,0 +1,59 @@ +From 901e0ed6354f716b23854ad2f8e4eeb9a74414ab Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:36 +0200 +Subject: [PATCH backport 5.10 122/182] mlxsw: core_thermal: Add line card id + prefix to line card thermal zone name + +Add prefix "lc#n" to thermal zones associated with the thermal objects +found on line cards. + +For example thermal zone for module #9 located at line card #7 will +have type: +mlxsw-lc7-module9. +And thermal zone for gearbox #3 located at line card #5 will have type: +mlxsw-lc5-gearbox3. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_thermal.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index bde5489d9240..4964c9164c2d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -689,8 +689,12 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz) + char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; + int err; + +- snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d", +- module_tz->module + 1); ++ if (module_tz->slot_index) ++ snprintf(tz_name, sizeof(tz_name), "mlxsw-lc%d-module%d", ++ module_tz->slot_index, module_tz->module + 1); ++ else ++ 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, +@@ -824,8 +828,12 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) + char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; + int ret; + +- snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d", +- gearbox_tz->module + 1); ++ if (gearbox_tz->slot_index) ++ snprintf(tz_name, sizeof(tz_name), "mlxsw-lc%d-gearbox%d", ++ gearbox_tz->slot_index, gearbox_tz->module + 1); ++ else ++ snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d", ++ gearbox_tz->module + 1); + gearbox_tz->tzdev = thermal_zone_device_register(tz_name, + MLXSW_THERMAL_NUM_TRIPS, + MLXSW_THERMAL_TRIP_MASK, +-- +2.20.1 + diff --git a/patch/0123-mlxsw-core_thermal-Use-exact-name-of-cooling-devices.patch b/patch/0123-mlxsw-core_thermal-Use-exact-name-of-cooling-devices.patch new file mode 100644 index 000000000..ebe8c96cf --- /dev/null +++ b/patch/0123-mlxsw-core_thermal-Use-exact-name-of-cooling-devices.patch @@ -0,0 +1,35 @@ +From 7e5f922bac5153137a8b1f486728d9d95b4922bc Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:37 +0200 +Subject: [PATCH backport 5.10 123/182] mlxsw: core_thermal: Use exact name of + cooling devices for binding + +Modular system supports additional cooling devices "mlxreg_fan1", +"mlxreg_fan2", etcetera. Thermal zones in "mlxsw" driver should be +bound to the same device as before called "mlxreg_fan". Used exact +match for cooling device name to avoid binding to new additional +cooling devices. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 4964c9164c2d..64c6a78f3aa0 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -133,8 +133,7 @@ static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal, + + /* Allow mlxsw thermal zone binding to an external cooling device */ + for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) { +- if (strnstr(cdev->type, mlxsw_thermal_external_allowed_cdev[i], +- strlen(cdev->type))) ++ if (!strcmp(cdev->type, mlxsw_thermal_external_allowed_cdev[i])) + return 0; + } + +-- +2.20.1 + diff --git a/patch/0124-mlxsw-core_thermal-Use-common-define-for-thermal-zon.patch b/patch/0124-mlxsw-core_thermal-Use-common-define-for-thermal-zon.patch new file mode 100644 index 000000000..624ab7170 --- /dev/null +++ b/patch/0124-mlxsw-core_thermal-Use-common-define-for-thermal-zon.patch @@ -0,0 +1,49 @@ +From 8d06868f51917926f99299eaac26d6f86eff3593 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 13 Apr 2022 18:17:33 +0300 +Subject: [PATCH backport 5.10 124/182] mlxsw: core_thermal: Use common define + for thermal zone name length + +Replace internal define 'MLXSW_THERMAL_ZONE_MAX_NAME' by common +'THERMAL_NAME_LENGTH'. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 64c6a78f3aa0..b9253c9f70d9 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -21,7 +21,6 @@ + #define MLXSW_THERMAL_ASIC_TEMP_HOT 105000 /* 105C */ + #define MLXSW_THERMAL_HYSTERESIS_TEMP 5000 /* 5C */ + #define MLXSW_THERMAL_MODULE_TEMP_SHIFT (MLXSW_THERMAL_HYSTERESIS_TEMP * 2) +-#define MLXSW_THERMAL_ZONE_MAX_NAME 16 + #define MLXSW_THERMAL_TEMP_SCORE_MAX GENMASK(31, 0) + #define MLXSW_THERMAL_MAX_STATE 10 + #define MLXSW_THERMAL_MIN_STATE 2 +@@ -685,7 +684,7 @@ static const struct thermal_cooling_device_ops mlxsw_cooling_ops = { + static int + mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz) + { +- char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; ++ char tz_name[THERMAL_NAME_LENGTH]; + int err; + + if (module_tz->slot_index) +@@ -824,7 +823,7 @@ mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal, + static int + mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) + { +- char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; ++ char tz_name[THERMAL_NAME_LENGTH]; + int ret; + + if (gearbox_tz->slot_index) +-- +2.20.1 + diff --git a/patch/0125-devlink-add-support-to-create-line-card-and-expose-t.patch b/patch/0125-devlink-add-support-to-create-line-card-and-expose-t.patch new file mode 100644 index 000000000..13d23671a --- /dev/null +++ b/patch/0125-devlink-add-support-to-create-line-card-and-expose-t.patch @@ -0,0 +1,532 @@ +From 36a2e4e93d7d1ca2ed670b4cf827400ba367e290 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 22 Dec 2021 08:57:27 +0000 +Subject: [PATCH backport 5.10 125/182] devlink: add support to create line + card and expose to user + +Extend the devlink API so the driver is going to be able to create and +destroy linecard instances. There can be multiple line cards per devlink +device. Expose this new type of object over devlink netlink API to the +userspace, with notifications. + +Signed-off-by: Jiri Pirko +--- + include/net/devlink.h | 15 ++ + include/uapi/linux/devlink.h | 22 +++ + net/core/devlink.c | 303 ++++++++++++++++++++++++++++++++++- + 3 files changed, 339 insertions(+), 1 deletion(-) + +diff --git a/include/net/devlink.h b/include/net/devlink.h +index b01bb9bca5a2..e8f046590579 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -31,6 +31,7 @@ struct devlink_dev_stats { + struct devlink_ops; + + struct devlink { ++ u32 index; + struct list_head list; + struct list_head port_list; + struct list_head sb_list; +@@ -44,6 +45,8 @@ struct devlink { + struct list_head trap_list; + struct list_head trap_group_list; + struct list_head trap_policer_list; ++ struct list_head linecard_list; ++ struct mutex linecards_lock; /* protects linecard_list */ + const struct devlink_ops *ops; + struct xarray snapshot_ids; + struct devlink_dev_stats stats; +@@ -55,6 +58,8 @@ struct devlink { + u8 reload_failed:1, + reload_enabled:1, + registered:1; ++ refcount_t refcount; ++ struct completion comp; + char priv[0] __aligned(NETDEV_ALIGN); + }; + +@@ -137,6 +142,13 @@ struct devlink_port { + struct mutex reporters_lock; /* Protects reporter_list */ + }; + ++struct devlink_linecard { ++ struct list_head list; ++ struct devlink *devlink; ++ unsigned int index; ++ refcount_t refcount; ++}; ++ + struct devlink_sb_pool_info { + enum devlink_sb_pool_type pool_type; + u32 size; +@@ -1401,6 +1413,9 @@ void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 contro + u16 pf, bool external); + void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller, + u16 pf, u16 vf, bool external); ++struct devlink_linecard *devlink_linecard_create(struct devlink *devlink, ++ unsigned int linecard_index); ++void devlink_linecard_destroy(struct devlink_linecard *linecard); + int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, +diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h +index cf89c318f2ac..ff07ad596035 100644 +--- a/include/uapi/linux/devlink.h ++++ b/include/uapi/linux/devlink.h +@@ -126,6 +126,16 @@ enum devlink_command { + + DEVLINK_CMD_HEALTH_REPORTER_TEST, + ++ DEVLINK_CMD_RATE_GET, /* can dump */ ++ DEVLINK_CMD_RATE_SET, ++ DEVLINK_CMD_RATE_NEW, ++ DEVLINK_CMD_RATE_DEL, ++ ++ DEVLINK_CMD_LINECARD_GET, /* can dump */ ++ DEVLINK_CMD_LINECARD_SET, ++ DEVLINK_CMD_LINECARD_NEW, ++ DEVLINK_CMD_LINECARD_DEL, ++ + /* add new commands above here */ + __DEVLINK_CMD_MAX, + DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1 +@@ -529,6 +539,18 @@ enum devlink_attr { + DEVLINK_ATTR_RELOAD_ACTION_INFO, /* nested */ + DEVLINK_ATTR_RELOAD_ACTION_STATS, /* nested */ + ++ DEVLINK_ATTR_PORT_PCI_SF_NUMBER, /* u32 */ ++ ++ DEVLINK_ATTR_RATE_TYPE, /* u16 */ ++ DEVLINK_ATTR_RATE_TX_SHARE, /* u64 */ ++ DEVLINK_ATTR_RATE_TX_MAX, /* u64 */ ++ DEVLINK_ATTR_RATE_NODE_NAME, /* string */ ++ DEVLINK_ATTR_RATE_PARENT_NODE_NAME, /* string */ ++ ++ DEVLINK_ATTR_REGION_MAX_SNAPSHOTS, /* u32 */ ++ ++ DEVLINK_ATTR_LINECARD_INDEX, /* u32 */ ++ + /* add new attributes above here, update the policy in devlink.c */ + + __DEVLINK_ATTR_MAX, +diff --git a/net/core/devlink.c b/net/core/devlink.c +index 72047750dcd9..645fe0612b53 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -91,6 +91,25 @@ static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_ + + static LIST_HEAD(devlink_list); + ++static DEFINE_XARRAY_FLAGS(devlinks, XA_FLAGS_ALLOC); ++#define DEVLINK_REGISTERED XA_MARK_1 ++ ++/* devlink instances are open to the access from the user space after ++ * devlink_register() call. Such logical barrier allows us to have certain ++ * expectations related to locking. ++ * ++ * Before *_register() - we are in initialization stage and no parallel ++ * access possible to the devlink instance. All drivers perform that phase ++ * by implicitly holding device_lock. ++ * ++ * After *_register() - users and driver can access devlink instance at ++ * the same time. ++ */ ++#define ASSERT_DEVLINK_REGISTERED(d) \ ++ WARN_ON_ONCE(!xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED)) ++#define ASSERT_DEVLINK_NOT_REGISTERED(d) \ ++ WARN_ON_ONCE(xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED)) ++ + /* devlink_mutex + * + * An overall lock guarding every operation coming from userspace. +@@ -105,6 +124,19 @@ struct net *devlink_net(const struct devlink *devlink) + } + EXPORT_SYMBOL_GPL(devlink_net); + ++void devlink_put(struct devlink *devlink) ++{ ++ if (refcount_dec_and_test(&devlink->refcount)) ++ complete(&devlink->comp); ++} ++ ++struct devlink *__must_check devlink_try_get(struct devlink *devlink) ++{ ++ if (refcount_inc_not_zero(&devlink->refcount)) ++ return devlink; ++ return NULL; ++} ++ + static void __devlink_net_set(struct devlink *devlink, struct net *net) + { + write_pnet(&devlink->_net, net); +@@ -187,6 +219,56 @@ static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink, + return devlink_port_get_from_attrs(devlink, info->attrs); + } + ++static struct devlink_linecard * ++devlink_linecard_get_by_index(struct devlink *devlink, ++ unsigned int linecard_index) ++{ ++ struct devlink_linecard *devlink_linecard; ++ ++ list_for_each_entry(devlink_linecard, &devlink->linecard_list, list) { ++ if (devlink_linecard->index == linecard_index) ++ return devlink_linecard; ++ } ++ return NULL; ++} ++ ++static bool devlink_linecard_index_exists(struct devlink *devlink, ++ unsigned int linecard_index) ++{ ++ return devlink_linecard_get_by_index(devlink, linecard_index); ++} ++ ++static struct devlink_linecard * ++devlink_linecard_get_from_attrs(struct devlink *devlink, struct nlattr **attrs) ++{ ++ if (attrs[DEVLINK_ATTR_LINECARD_INDEX]) { ++ u32 linecard_index = nla_get_u32(attrs[DEVLINK_ATTR_LINECARD_INDEX]); ++ struct devlink_linecard *linecard; ++ ++ mutex_lock(&devlink->linecards_lock); ++ linecard = devlink_linecard_get_by_index(devlink, linecard_index); ++ if (linecard) ++ refcount_inc(&linecard->refcount); ++ mutex_unlock(&devlink->linecards_lock); ++ if (!linecard) ++ return ERR_PTR(-ENODEV); ++ return linecard; ++ } ++ return ERR_PTR(-EINVAL); ++} ++ ++static struct devlink_linecard * ++devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info) ++{ ++ return devlink_linecard_get_from_attrs(devlink, info->attrs); ++} ++ ++static void devlink_linecard_put(struct devlink_linecard *linecard) ++{ ++ if (refcount_dec_and_test(&linecard->refcount)) ++ kfree(linecard); ++} ++ + struct devlink_sb { + struct list_head list; + unsigned int index; +@@ -405,16 +487,20 @@ devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id) + + #define DEVLINK_NL_FLAG_NEED_PORT BIT(0) + #define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1) ++#define DEVLINK_NL_FLAG_NEED_RATE BIT(2) ++#define DEVLINK_NL_FLAG_NEED_RATE_NODE BIT(3) ++#define DEVLINK_NL_FLAG_NEED_LINECARD BIT(4) + + /* The per devlink instance lock is taken by default in the pre-doit + * operation, yet several commands do not require this. The global + * devlink lock is taken and protects from disruption by user-calls. + */ +-#define DEVLINK_NL_FLAG_NO_LOCK BIT(2) ++#define DEVLINK_NL_FLAG_NO_LOCK BIT(5) + + static int devlink_nl_pre_doit(const struct genl_ops *ops, + struct sk_buff *skb, struct genl_info *info) + { ++ struct devlink_linecard *linecard; + struct devlink_port *devlink_port; + struct devlink *devlink; + int err; +@@ -439,6 +525,13 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops, + devlink_port = devlink_port_get_from_info(devlink, info); + if (!IS_ERR(devlink_port)) + info->user_ptr[1] = devlink_port; ++ } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_LINECARD) { ++ linecard = devlink_linecard_get_from_info(devlink, info); ++ if (IS_ERR(linecard)) { ++ err = PTR_ERR(linecard); ++ goto unlock; ++ } ++ info->user_ptr[1] = linecard; + } + return 0; + +@@ -452,9 +545,14 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops, + static void devlink_nl_post_doit(const struct genl_ops *ops, + struct sk_buff *skb, struct genl_info *info) + { ++ struct devlink_linecard *linecard; + struct devlink *devlink; + + devlink = info->user_ptr[0]; ++ if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_LINECARD) { ++ linecard = info->user_ptr[1]; ++ devlink_linecard_put(linecard); ++ } + if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK) + mutex_unlock(&devlink->lock); + mutex_unlock(&devlink_mutex); +@@ -1135,6 +1233,132 @@ static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb, + return devlink_port_unsplit(devlink, port_index, info->extack); + } + ++static int devlink_nl_linecard_fill(struct sk_buff *msg, ++ struct devlink *devlink, ++ struct devlink_linecard *linecard, ++ enum devlink_command cmd, u32 portid, ++ u32 seq, int flags, ++ struct netlink_ext_ack *extack) ++{ ++ void *hdr; ++ ++ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); ++ if (!hdr) ++ return -EMSGSIZE; ++ ++ if (devlink_nl_put_handle(msg, devlink)) ++ goto nla_put_failure; ++ if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index)) ++ goto nla_put_failure; ++ ++ genlmsg_end(msg, hdr); ++ return 0; ++ ++nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ return -EMSGSIZE; ++} ++ ++static void devlink_linecard_notify(struct devlink_linecard *linecard, ++ enum devlink_command cmd) ++{ ++ struct devlink *devlink = linecard->devlink; ++ struct sk_buff *msg; ++ int err; ++ ++ WARN_ON(cmd != DEVLINK_CMD_LINECARD_NEW && ++ cmd != DEVLINK_CMD_LINECARD_DEL); ++ ++ if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED)) ++ return; ++ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!msg) ++ return; ++ ++ err = devlink_nl_linecard_fill(msg, devlink, linecard, cmd, 0, 0, 0, ++ NULL); ++ if (err) { ++ nlmsg_free(msg); ++ return; ++ } ++ ++ genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), ++ msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); ++} ++ ++static int devlink_nl_cmd_linecard_get_doit(struct sk_buff *skb, ++ struct genl_info *info) ++{ ++ struct devlink_linecard *linecard = info->user_ptr[1]; ++ struct devlink *devlink = linecard->devlink; ++ struct sk_buff *msg; ++ int err; ++ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!msg) ++ return -ENOMEM; ++ ++ err = devlink_nl_linecard_fill(msg, devlink, linecard, ++ DEVLINK_CMD_LINECARD_NEW, ++ info->snd_portid, info->snd_seq, 0, ++ info->extack); ++ if (err) { ++ nlmsg_free(msg); ++ return err; ++ } ++ ++ return genlmsg_reply(msg, info); ++} ++ ++static int devlink_nl_cmd_linecard_get_dumpit(struct sk_buff *msg, ++ struct netlink_callback *cb) ++{ ++ struct devlink_linecard *linecard; ++ struct devlink *devlink; ++ int start = cb->args[0]; ++ unsigned long index; ++ int idx = 0; ++ int err; ++ ++ mutex_lock(&devlink_mutex); ++ xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { ++ if (!devlink_try_get(devlink)) ++ continue; ++ ++ if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) ++ goto retry; ++ ++ mutex_lock(&devlink->linecards_lock); ++ list_for_each_entry(linecard, &devlink->linecard_list, list) { ++ if (idx < start) { ++ idx++; ++ continue; ++ } ++ err = devlink_nl_linecard_fill(msg, devlink, linecard, ++ DEVLINK_CMD_LINECARD_NEW, ++ NETLINK_CB(cb->skb).portid, ++ cb->nlh->nlmsg_seq, ++ NLM_F_MULTI, ++ cb->extack); ++ if (err) { ++ mutex_unlock(&devlink->linecards_lock); ++ devlink_put(devlink); ++ goto out; ++ } ++ idx++; ++ } ++ mutex_unlock(&devlink->linecards_lock); ++retry: ++ devlink_put(devlink); ++ } ++out: ++ mutex_unlock(&devlink_mutex); ++ ++ cb->args[0] = idx; ++ return msg->len; ++} ++ + static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink, + struct devlink_sb *devlink_sb, + enum devlink_command cmd, u32 portid, +@@ -7594,6 +7818,19 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT, + DEVLINK_RELOAD_ACTION_MAX), + [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK), ++//<<<<<<< HEAD ++//======= ++ [DEVLINK_ATTR_PORT_FLAVOUR] = { .type = NLA_U16 }, ++ [DEVLINK_ATTR_PORT_PCI_PF_NUMBER] = { .type = NLA_U16 }, ++ [DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .type = NLA_U32 }, ++ [DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .type = NLA_U32 }, ++ [DEVLINK_ATTR_RATE_TYPE] = { .type = NLA_U16 }, ++ [DEVLINK_ATTR_RATE_TX_SHARE] = { .type = NLA_U64 }, ++ [DEVLINK_ATTR_RATE_TX_MAX] = { .type = NLA_U64 }, ++ [DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING }, ++ [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING }, ++ [DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 }, ++//>>>>>>> 1180815a3831... devlink: add support to create line card and expose to user + }; + + static const struct genl_small_ops devlink_nl_ops[] = { +@@ -7633,6 +7870,14 @@ static const struct genl_small_ops devlink_nl_ops[] = { + .flags = GENL_ADMIN_PERM, + .internal_flags = DEVLINK_NL_FLAG_NO_LOCK, + }, ++ { ++ .cmd = DEVLINK_CMD_LINECARD_GET, ++ .doit = devlink_nl_cmd_linecard_get_doit, ++ .dumpit = devlink_nl_cmd_linecard_get_dumpit, ++ .internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD | ++ DEVLINK_NL_FLAG_NO_LOCK, ++ /* can be retrieved by unprivileged users */ ++ }, + { + .cmd = DEVLINK_CMD_SB_GET, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, +@@ -7980,6 +8225,7 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size) + xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC); + __devlink_net_set(devlink, &init_net); + INIT_LIST_HEAD(&devlink->port_list); ++ INIT_LIST_HEAD(&devlink->linecard_list); + INIT_LIST_HEAD(&devlink->sb_list); + INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list); + INIT_LIST_HEAD(&devlink->resource_list); +@@ -7991,6 +8237,8 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size) + INIT_LIST_HEAD(&devlink->trap_policer_list); + mutex_init(&devlink->lock); + mutex_init(&devlink->reporters_lock); ++ mutex_init(&devlink->linecards_lock); ++ + return devlink; + } + EXPORT_SYMBOL_GPL(devlink_alloc); +@@ -8071,6 +8319,7 @@ EXPORT_SYMBOL_GPL(devlink_reload_disable); + */ + void devlink_free(struct devlink *devlink) + { ++ mutex_destroy(&devlink->linecards_lock); + mutex_destroy(&devlink->reporters_lock); + mutex_destroy(&devlink->lock); + WARN_ON(!list_empty(&devlink->trap_policer_list)); +@@ -8082,6 +8331,7 @@ void devlink_free(struct devlink *devlink) + WARN_ON(!list_empty(&devlink->resource_list)); + WARN_ON(!list_empty(&devlink->dpipe_table_list)); + WARN_ON(!list_empty(&devlink->sb_list)); ++ WARN_ON(!list_empty(&devlink->linecard_list)); + WARN_ON(!list_empty(&devlink->port_list)); + + xa_destroy(&devlink->snapshot_ids); +@@ -8427,6 +8677,57 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, + return 0; + } + ++/** ++ * devlink_linecard_create - Create devlink linecard ++ * ++ * @devlink: devlink ++ * @linecard_index: driver-specific numerical identifier of the linecard ++ * ++ * Create devlink linecard instance with provided linecard index. ++ * Caller can use any indexing, even hw-related one. ++ */ ++struct devlink_linecard *devlink_linecard_create(struct devlink *devlink, ++ unsigned int linecard_index) ++{ ++ struct devlink_linecard *linecard; ++ ++ mutex_lock(&devlink->linecards_lock); ++ if (devlink_linecard_index_exists(devlink, linecard_index)) { ++ mutex_unlock(&devlink->linecards_lock); ++ return ERR_PTR(-EEXIST); ++ } ++ ++ linecard = kzalloc(sizeof(*linecard), GFP_KERNEL); ++ if (!linecard) ++ return ERR_PTR(-ENOMEM); ++ ++ linecard->devlink = devlink; ++ linecard->index = linecard_index; ++ list_add_tail(&linecard->list, &devlink->linecard_list); ++ refcount_set(&linecard->refcount, 1); ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&devlink->linecards_lock); ++ return linecard; ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_create); ++ ++/** ++ * devlink_linecard_destroy - Destroy devlink linecard ++ * ++ * @linecard: devlink linecard ++ */ ++void devlink_linecard_destroy(struct devlink_linecard *linecard) ++{ ++ struct devlink *devlink = linecard->devlink; ++ ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL); ++ mutex_lock(&devlink->linecards_lock); ++ list_del(&linecard->list); ++ mutex_unlock(&devlink->linecards_lock); ++ devlink_linecard_put(linecard); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_destroy); ++ + int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, +-- +2.20.1 + diff --git a/patch/0126-devlink-implement-line-card-provisioning.patch b/patch/0126-devlink-implement-line-card-provisioning.patch new file mode 100644 index 000000000..d95308aca --- /dev/null +++ b/patch/0126-devlink-implement-line-card-provisioning.patch @@ -0,0 +1,555 @@ +From 37d223fa389636092d519ca903f186d608eed3c8 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Thu, 31 Dec 2020 17:35:08 +0100 +Subject: [PATCH backport 5.10 126/182] devlink: implement line card + provisioning + +In order to be able to configure all needed stuff on a port/netdevice +of a line card without the line card being present, introduce line card +provisioning. Basically by setting a type, provisioning process will +start and driver is supposed to create a placeholder for instances +(ports/netdevices) for a line card type. + +Allow the user to query the supported line card types over line card +get command. Then implement two netlink command SET to allow user to +set/unset the card type. + +On the driver API side, add provision/unprovision ops and supported +types array to be advertised. Upon provision op call, the driver should +take care of creating the instances for the particular line card type. +Introduce provision_set/clear() functions to be called by the driver +once the provisioning/unprovisioning is done on its side. These helpers +are not to be called directly due to the async nature of provisioning. + +Signed-off-by: Jiri Pirko +--- + include/net/devlink.h | 41 ++++- + include/uapi/linux/devlink.h | 15 ++ + net/core/devlink.c | 311 ++++++++++++++++++++++++++++++++--- + 3 files changed, 346 insertions(+), 21 deletions(-) + +diff --git a/include/net/devlink.h b/include/net/devlink.h +index e8f046590579..44b60085ec16 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -142,11 +142,43 @@ struct devlink_port { + struct mutex reporters_lock; /* Protects reporter_list */ + }; + ++struct devlink_linecard_ops; ++struct devlink_linecard_type; ++ + struct devlink_linecard { + struct list_head list; + struct devlink *devlink; + unsigned int index; + refcount_t refcount; ++ const struct devlink_linecard_ops *ops; ++ void *priv; ++ enum devlink_linecard_state state; ++ struct mutex state_lock; /* Protects state */ ++ const char *type; ++ struct devlink_linecard_type *types; ++ unsigned int types_count; ++}; ++ ++/** ++ * struct devlink_linecard_ops - Linecard operations ++ * @provision: callback to provision the linecard slot with certain ++ * type of linecard ++ * @unprovision: callback to unprovision the linecard slot ++ * @types_init: callback to initialize types list ++ * @types_fini: callback to finalize types list ++ * @types_get: callback to get next type in list ++ */ ++struct devlink_linecard_ops { ++ int (*provision)(struct devlink_linecard *linecard, void *priv, ++ const char *type, const void *type_priv, ++ struct netlink_ext_ack *extack); ++ int (*unprovision)(struct devlink_linecard *linecard, void *priv, ++ struct netlink_ext_ack *extack); ++ unsigned int (*types_count)(struct devlink_linecard *linecard, ++ void *priv); ++ void (*types_get)(struct devlink_linecard *linecard, ++ void *priv, unsigned int index, const char **type, ++ const void **type_priv); + }; + + struct devlink_sb_pool_info { +@@ -1413,9 +1445,14 @@ void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 contro + u16 pf, bool external); + void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller, + u16 pf, u16 vf, bool external); +-struct devlink_linecard *devlink_linecard_create(struct devlink *devlink, +- unsigned int linecard_index); ++struct devlink_linecard * ++devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index, ++ const struct devlink_linecard_ops *ops, void *priv); + void devlink_linecard_destroy(struct devlink_linecard *linecard); ++void devlink_linecard_provision_set(struct devlink_linecard *linecard, ++ const char *type); ++void devlink_linecard_provision_clear(struct devlink_linecard *linecard); ++void devlink_linecard_provision_fail(struct devlink_linecard *linecard); + int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, +diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h +index ff07ad596035..d8833664522f 100644 +--- a/include/uapi/linux/devlink.h ++++ b/include/uapi/linux/devlink.h +@@ -334,6 +334,18 @@ enum devlink_reload_limit { + + #define DEVLINK_RELOAD_LIMITS_VALID_MASK (_BITUL(__DEVLINK_RELOAD_LIMIT_MAX) - 1) + ++enum devlink_linecard_state { ++ DEVLINK_LINECARD_STATE_UNSPEC, ++ DEVLINK_LINECARD_STATE_UNPROVISIONED, ++ DEVLINK_LINECARD_STATE_UNPROVISIONING, ++ DEVLINK_LINECARD_STATE_PROVISIONING, ++ DEVLINK_LINECARD_STATE_PROVISIONING_FAILED, ++ DEVLINK_LINECARD_STATE_PROVISIONED, ++ ++ __DEVLINK_LINECARD_STATE_MAX, ++ DEVLINK_LINECARD_STATE_MAX = __DEVLINK_LINECARD_STATE_MAX - 1 ++}; ++ + enum devlink_attr { + /* don't change the order or add anything between, this is ABI! */ + DEVLINK_ATTR_UNSPEC, +@@ -550,6 +562,9 @@ enum devlink_attr { + DEVLINK_ATTR_REGION_MAX_SNAPSHOTS, /* u32 */ + + DEVLINK_ATTR_LINECARD_INDEX, /* u32 */ ++ DEVLINK_ATTR_LINECARD_STATE, /* u8 */ ++ DEVLINK_ATTR_LINECARD_TYPE, /* string */ ++ DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES, /* nested */ + + /* add new attributes above here, update the policy in devlink.c */ + +diff --git a/net/core/devlink.c b/net/core/devlink.c +index 645fe0612b53..943973ffc450 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -265,8 +265,10 @@ devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info) + + static void devlink_linecard_put(struct devlink_linecard *linecard) + { +- if (refcount_dec_and_test(&linecard->refcount)) ++ if (refcount_dec_and_test(&linecard->refcount)) { ++ mutex_destroy(&linecard->state_lock); + kfree(linecard); ++ } + } + + struct devlink_sb { +@@ -1233,6 +1235,12 @@ static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb, + return devlink_port_unsplit(devlink, port_index, info->extack); + } + ++struct devlink_linecard_type { ++ struct list_head list; ++ const char *type; ++ const void *priv; ++}; ++ + static int devlink_nl_linecard_fill(struct sk_buff *msg, + struct devlink *devlink, + struct devlink_linecard *linecard, +@@ -1240,7 +1248,10 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg, + u32 seq, int flags, + struct netlink_ext_ack *extack) + { ++ struct devlink_linecard_type *linecard_type; ++ struct nlattr *attr; + void *hdr; ++ int i; + + hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); + if (!hdr) +@@ -1250,6 +1261,25 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg, + goto nla_put_failure; + if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index)) + goto nla_put_failure; ++ if (nla_put_u8(msg, DEVLINK_ATTR_LINECARD_STATE, linecard->state)) ++ goto nla_put_failure; ++ if (linecard->state >= DEVLINK_LINECARD_STATE_PROVISIONED && ++ nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE, linecard->type)) ++ goto nla_put_failure; ++ ++ if (linecard->types_count) { ++ attr = nla_nest_start(msg, ++ DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES); ++ if (!attr) ++ goto nla_put_failure; ++ for (i = 0; i < linecard->types_count; i++) { ++ linecard_type = &linecard->types[i]; ++ if (nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE, ++ linecard_type->type)) ++ goto nla_put_failure; ++ } ++ nla_nest_end(msg, attr); ++ } + + genlmsg_end(msg, hdr); + return 0; +@@ -1335,12 +1365,14 @@ static int devlink_nl_cmd_linecard_get_dumpit(struct sk_buff *msg, + idx++; + continue; + } ++ mutex_lock(&linecard->state_lock); + err = devlink_nl_linecard_fill(msg, devlink, linecard, + DEVLINK_CMD_LINECARD_NEW, + NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, + NLM_F_MULTI, + cb->extack); ++ mutex_unlock(&linecard->state_lock); + if (err) { + mutex_unlock(&devlink->linecards_lock); + devlink_put(devlink); +@@ -1359,6 +1391,153 @@ static int devlink_nl_cmd_linecard_get_dumpit(struct sk_buff *msg, + return msg->len; + } + ++static struct devlink_linecard_type * ++devlink_linecard_type_lookup(struct devlink_linecard *linecard, ++ const char *type) ++{ ++ struct devlink_linecard_type *linecard_type; ++ int i; ++ ++ for (i = 0; i < linecard->types_count; i++) { ++ linecard_type = &linecard->types[i]; ++ if (!strcmp(type, linecard_type->type)) ++ return linecard_type; ++ } ++ return NULL; ++} ++ ++static int devlink_linecard_type_set(struct devlink_linecard *linecard, ++ const char *type, ++ struct netlink_ext_ack *extack) ++{ ++ struct devlink_linecard_type *linecard_type; ++ int err; ++ ++ mutex_lock(&linecard->state_lock); ++ if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) { ++ NL_SET_ERR_MSG_MOD(extack, "Linecard is currently being provisioned"); ++ err = -EBUSY; ++ goto out; ++ } ++ if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) { ++ NL_SET_ERR_MSG_MOD(extack, "Linecard is currently being unprovisioned"); ++ err = -EBUSY; ++ goto out; ++ } ++ if (linecard->state != DEVLINK_LINECARD_STATE_UNPROVISIONED && ++ linecard->state != DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) { ++ NL_SET_ERR_MSG_MOD(extack, "Linecard already provisioned"); ++ err = -EBUSY; ++ goto out; ++ } ++ ++ linecard_type = devlink_linecard_type_lookup(linecard, type); ++ if (!linecard_type) { ++ NL_SET_ERR_MSG_MOD(extack, "Unsupported provision type provided"); ++ err = -EINVAL; ++ goto out; ++ } ++ ++ linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING; ++ linecard->type = linecard_type->type; ++ devlink_linecard_notify(linecard, ++ DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++ err = linecard->ops->provision(linecard, linecard->priv, ++ linecard_type->type, linecard_type->priv, ++ extack); ++ if (err) { ++ /* Provisioning failed. Assume the linecard is unprovisioned ++ * for future operations. ++ */ ++ mutex_lock(&linecard->state_lock); ++ linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++ } ++ return err; ++ ++out: ++ mutex_unlock(&linecard->state_lock); ++ return err; ++} ++ ++static int devlink_linecard_type_unset(struct devlink_linecard *linecard, ++ struct netlink_ext_ack *extack) ++{ ++ int err; ++ ++ mutex_lock(&linecard->state_lock); ++ if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) { ++ NL_SET_ERR_MSG_MOD(extack, "Linecard is currently being provisioned"); ++ err = -EBUSY; ++ goto out; ++ } ++ if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) { ++ NL_SET_ERR_MSG_MOD(extack, "Linecard is currently being unprovisioned"); ++ err = -EBUSY; ++ goto out; ++ } ++ if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) { ++ linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; ++ linecard->type = NULL; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ err = 0; ++ goto out; ++ } ++ ++ if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONED || ++ linecard->state == DEVLINK_LINECARD_STATE_UNSPEC) { ++ NL_SET_ERR_MSG_MOD(extack, "Linecard is not provisioned"); ++ err = -EOPNOTSUPP; ++ goto out; ++ } ++ linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONING; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++ err = linecard->ops->unprovision(linecard, linecard->priv, ++ extack); ++ if (err) { ++ /* Unprovisioning failed. Assume the linecard is unprovisioned ++ * for future operations. ++ */ ++ mutex_lock(&linecard->state_lock); ++ linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++ } ++ return err; ++ ++out: ++ mutex_unlock(&linecard->state_lock); ++ return err; ++} ++ ++static int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb, ++ struct genl_info *info) ++{ ++ struct devlink_linecard *linecard = info->user_ptr[1]; ++ struct netlink_ext_ack *extack = info->extack; ++ int err; ++ ++ if (info->attrs[DEVLINK_ATTR_LINECARD_TYPE]) { ++ const char *type; ++ ++ type = nla_data(info->attrs[DEVLINK_ATTR_LINECARD_TYPE]); ++ if (strcmp(type, "")) { ++ err = devlink_linecard_type_set(linecard, type, extack); ++ if (err) ++ return err; ++ } else { ++ err = devlink_linecard_type_unset(linecard, extack); ++ if (err) ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ + static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink, + struct devlink_sb *devlink_sb, + enum devlink_command cmd, u32 portid, +@@ -7818,19 +7997,8 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT, + DEVLINK_RELOAD_ACTION_MAX), + [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK), +-//<<<<<<< HEAD +-//======= +- [DEVLINK_ATTR_PORT_FLAVOUR] = { .type = NLA_U16 }, +- [DEVLINK_ATTR_PORT_PCI_PF_NUMBER] = { .type = NLA_U16 }, +- [DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .type = NLA_U32 }, +- [DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .type = NLA_U32 }, +- [DEVLINK_ATTR_RATE_TYPE] = { .type = NLA_U16 }, +- [DEVLINK_ATTR_RATE_TX_SHARE] = { .type = NLA_U64 }, +- [DEVLINK_ATTR_RATE_TX_MAX] = { .type = NLA_U64 }, +- [DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING }, +- [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING }, + [DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 }, +-//>>>>>>> 1180815a3831... devlink: add support to create line card and expose to user ++ [DEVLINK_ATTR_LINECARD_TYPE] = { .type = NLA_NUL_STRING }, + }; + + static const struct genl_small_ops devlink_nl_ops[] = { +@@ -7878,6 +8046,13 @@ static const struct genl_small_ops devlink_nl_ops[] = { + DEVLINK_NL_FLAG_NO_LOCK, + /* can be retrieved by unprivileged users */ + }, ++ { ++ .cmd = DEVLINK_CMD_LINECARD_SET, ++ .doit = devlink_nl_cmd_linecard_set_doit, ++ .flags = GENL_ADMIN_PERM, ++ .internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD | ++ DEVLINK_NL_FLAG_NO_LOCK, ++ }, + { + .cmd = DEVLINK_CMD_SB_GET, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, +@@ -8677,35 +8852,85 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, + return 0; + } + ++static int devlink_linecard_types_init(struct devlink_linecard *linecard) ++{ ++ struct devlink_linecard_type *linecard_type; ++ unsigned int count; ++ int i; ++ ++ count = linecard->ops->types_count(linecard, linecard->priv); ++ linecard->types = kmalloc_array(count, sizeof(*linecard_type), ++ GFP_KERNEL); ++ if (!linecard->types) ++ return -ENOMEM; ++ linecard->types_count = count; ++ ++ for (i = 0; i < count; i++) { ++ linecard_type = &linecard->types[i]; ++ linecard->ops->types_get(linecard, linecard->priv, i, ++ &linecard_type->type, ++ &linecard_type->priv); ++ } ++ return 0; ++} ++ ++static void devlink_linecard_types_fini(struct devlink_linecard *linecard) ++{ ++ kfree(linecard->types); ++} ++ + /** + * devlink_linecard_create - Create devlink linecard + * + * @devlink: devlink + * @linecard_index: driver-specific numerical identifier of the linecard ++ * @ops: linecards ops ++ * @priv: user priv pointer + * + * Create devlink linecard instance with provided linecard index. + * Caller can use any indexing, even hw-related one. + */ +-struct devlink_linecard *devlink_linecard_create(struct devlink *devlink, +- unsigned int linecard_index) ++struct devlink_linecard * ++devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index, ++ const struct devlink_linecard_ops *ops, void *priv) + { + struct devlink_linecard *linecard; ++ int err; ++ ++ if (WARN_ON(!ops || !ops->provision || !ops->unprovision || ++ !ops->types_count || !ops->types_get)) ++ return ERR_PTR(-EINVAL); + + mutex_lock(&devlink->linecards_lock); + if (devlink_linecard_index_exists(devlink, linecard_index)) { +- mutex_unlock(&devlink->linecards_lock); +- return ERR_PTR(-EEXIST); ++ linecard = ERR_PTR(-EEXIST); ++ goto unlock; + } + + linecard = kzalloc(sizeof(*linecard), GFP_KERNEL); +- if (!linecard) +- return ERR_PTR(-ENOMEM); ++ if (!linecard) { ++ linecard = ERR_PTR(-ENOMEM); ++ goto unlock; ++ } + + linecard->devlink = devlink; + linecard->index = linecard_index; ++ linecard->ops = ops; ++ linecard->priv = priv; ++ linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; ++ mutex_init(&linecard->state_lock); ++ ++ err = devlink_linecard_types_init(linecard); ++ if (err) { ++ kfree(linecard); ++ linecard = ERR_PTR(err); ++ goto unlock; ++ } ++ + list_add_tail(&linecard->list, &devlink->linecard_list); + refcount_set(&linecard->refcount, 1); + devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++unlock: + mutex_unlock(&devlink->linecards_lock); + return linecard; + } +@@ -8721,6 +8946,7 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard) + struct devlink *devlink = linecard->devlink; + + devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL); ++ devlink_linecard_types_fini(linecard); + mutex_lock(&devlink->linecards_lock); + list_del(&linecard->list); + mutex_unlock(&devlink->linecards_lock); +@@ -8728,6 +8954,53 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard) + } + EXPORT_SYMBOL_GPL(devlink_linecard_destroy); + ++/** ++ * devlink_linecard_provision_set - Set provisioning on linecard ++ * ++ * @linecard: devlink linecard ++ * @type: linecard type ++ */ ++void devlink_linecard_provision_set(struct devlink_linecard *linecard, ++ const char *type) ++{ ++ mutex_lock(&linecard->state_lock); ++ WARN_ON(linecard->type && linecard->type != type); ++ linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED; ++ linecard->type = type; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_provision_set); ++ ++/** ++ * devlink_linecard_provision_clear - Clear provisioning on linecard ++ * ++ * @linecard: devlink linecard ++ */ ++void devlink_linecard_provision_clear(struct devlink_linecard *linecard) ++{ ++ mutex_lock(&linecard->state_lock); ++ linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; ++ linecard->type = NULL; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear); ++ ++/** ++ * devlink_linecard_provision_fail - Fail provisioning on linecard ++ * ++ * @linecard: devlink linecard ++ */ ++void devlink_linecard_provision_fail(struct devlink_linecard *linecard) ++{ ++ mutex_lock(&linecard->state_lock); ++ linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail); ++ + int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, +-- +2.20.1 + diff --git a/patch/0127-devlink-implement-line-card-active-state.patch b/patch/0127-devlink-implement-line-card-active-state.patch new file mode 100644 index 000000000..548b8f4a6 --- /dev/null +++ b/patch/0127-devlink-implement-line-card-active-state.patch @@ -0,0 +1,99 @@ +From 9edffb671d73df181e382930bda0a3870e6ac120 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Wed, 6 Jan 2021 16:03:43 +0100 +Subject: [PATCH backport 5.10 127/182] devlink: implement line card active + state + +Allow driver to mark a linecard as active. Expose this state to the +userspace over devlink netlink interface with proper notifications. + +Signed-off-by: Jiri Pirko +--- + include/net/devlink.h | 3 +++ + include/uapi/linux/devlink.h | 1 + + net/core/devlink.c | 36 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 40 insertions(+) + +diff --git a/include/net/devlink.h b/include/net/devlink.h +index 44b60085ec16..d9b2b559c9a2 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -157,6 +157,7 @@ struct devlink_linecard { + const char *type; + struct devlink_linecard_type *types; + unsigned int types_count; ++ bool active; + }; + + /** +@@ -1453,6 +1454,8 @@ void devlink_linecard_provision_set(struct devlink_linecard *linecard, + const char *type); + void devlink_linecard_provision_clear(struct devlink_linecard *linecard); + void devlink_linecard_provision_fail(struct devlink_linecard *linecard); ++void devlink_linecard_activate(struct devlink_linecard *linecard); ++void devlink_linecard_deactivate(struct devlink_linecard *linecard); + int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, +diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h +index d8833664522f..5ace55666d27 100644 +--- a/include/uapi/linux/devlink.h ++++ b/include/uapi/linux/devlink.h +@@ -341,6 +341,7 @@ enum devlink_linecard_state { + DEVLINK_LINECARD_STATE_PROVISIONING, + DEVLINK_LINECARD_STATE_PROVISIONING_FAILED, + DEVLINK_LINECARD_STATE_PROVISIONED, ++ DEVLINK_LINECARD_STATE_ACTIVE, + + __DEVLINK_LINECARD_STATE_MAX, + DEVLINK_LINECARD_STATE_MAX = __DEVLINK_LINECARD_STATE_MAX - 1 +diff --git a/net/core/devlink.c b/net/core/devlink.c +index 943973ffc450..724633810758 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -9001,6 +9001,42 @@ void devlink_linecard_provision_fail(struct devlink_linecard *linecard) + } + EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail); + ++/** ++ * devlink_linecard_activate - Set linecard active ++ * ++ * @devlink_linecard: devlink linecard ++ */ ++void devlink_linecard_activate(struct devlink_linecard *linecard) ++{ ++ mutex_lock(&linecard->state_lock); ++ WARN_ON(linecard->state != DEVLINK_LINECARD_STATE_PROVISIONED); ++ linecard->state = DEVLINK_LINECARD_STATE_ACTIVE; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_activate); ++ ++/** ++ * devlink_linecard_deactivate - Set linecard inactive ++ * ++ * @devlink_linecard: devlink linecard ++ */ ++void devlink_linecard_deactivate(struct devlink_linecard *linecard) ++{ ++ bool should_notify = false; ++ ++ mutex_lock(&linecard->state_lock); ++ if (linecard->state != DEVLINK_LINECARD_STATE_UNPROVISIONING) { ++ WARN_ON(linecard->state != DEVLINK_LINECARD_STATE_ACTIVE); ++ linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED; ++ should_notify = true; ++ } ++ if (should_notify) ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_deactivate); ++ + int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, +-- +2.20.1 + diff --git a/patch/0128-devlink-add-port-to-line-card-relationship-set.patch b/patch/0128-devlink-add-port-to-line-card-relationship-set.patch new file mode 100644 index 000000000..41628c616 --- /dev/null +++ b/patch/0128-devlink-add-port-to-line-card-relationship-set.patch @@ -0,0 +1,102 @@ +From fb810d890bd142a7cfc14fb7e5f1519eee366208 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 22 Dec 2021 14:10:14 +0000 +Subject: [PATCH backport 5.10 128/182] devlink: add port to line card + relationship set + +In order to properly inform user about relationship between port and +line card, introduce a driver API to set line card for a port. Use this +information to extend port devlink netlink message by line card index +and also include the line card index into phys_port_name and by that +into a netdevice name. + +Signed-off-by: Jiri Pirko +--- + include/net/devlink.h | 4 ++++ + net/core/devlink.c | 34 ++++++++++++++++++++++++++++------ + 2 files changed, 32 insertions(+), 6 deletions(-) + +diff --git a/include/net/devlink.h b/include/net/devlink.h +index d9b2b559c9a2..3d4ceb2902b8 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -140,6 +140,8 @@ struct devlink_port { + struct delayed_work type_warn_dw; + struct list_head reporter_list; + struct mutex reporters_lock; /* Protects reporter_list */ ++ ++ struct devlink_linecard *linecard; + }; + + struct devlink_linecard_ops; +@@ -1446,6 +1448,8 @@ void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 contro + u16 pf, bool external); + void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller, + u16 pf, u16 vf, bool external); ++void devlink_port_linecard_set(struct devlink_port *devlink_port, ++ struct devlink_linecard *linecard); + struct devlink_linecard * + devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index, + const struct devlink_linecard_ops *ops, void *priv); +diff --git a/net/core/devlink.c b/net/core/devlink.c +index 724633810758..b43e93ccc672 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -905,6 +905,10 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink, + goto nla_put_failure; + if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack)) + goto nla_put_failure; ++ if (devlink_port->linecard && ++ nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, ++ devlink_port->linecard->index)) ++ goto nla_put_failure; + + genlmsg_end(msg, hdr); + return 0; +@@ -8795,6 +8799,21 @@ void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 contro + } + EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set); + ++/** ++ * devlink_port_linecard_set - Link port with a linecard ++ * ++ * @devlink_port: devlink port ++ * @devlink_linecard: devlink linecard ++ */ ++void devlink_port_linecard_set(struct devlink_port *devlink_port, ++ struct devlink_linecard *linecard) ++{ ++ if (WARN_ON(devlink_port->devlink)) ++ return; ++ devlink_port->linecard = linecard; ++} ++EXPORT_SYMBOL_GPL(devlink_port_linecard_set); ++ + static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, + char *name, size_t len) + { +@@ -8806,12 +8825,15 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, + + switch (attrs->flavour) { + case DEVLINK_PORT_FLAVOUR_PHYSICAL: +- if (!attrs->split) +- n = snprintf(name, len, "p%u", attrs->phys.port_number); +- else +- n = snprintf(name, len, "p%us%u", +- attrs->phys.port_number, +- attrs->phys.split_subport_number); ++ if (devlink_port->linecard) ++ n = snprintf(name, len, "l%u", ++ devlink_port->linecard->index); ++ if (n < len) ++ n += snprintf(name + n, len - n, "p%u", ++ attrs->phys.port_number); ++ if (n < len && attrs->split) ++ n += snprintf(name + n, len - n, "s%u", ++ attrs->phys.split_subport_number); + break; + case DEVLINK_PORT_FLAVOUR_CPU: + case DEVLINK_PORT_FLAVOUR_DSA: +-- +2.20.1 + diff --git a/patch/0129-devlink-introduce-linecard-info-get-message.patch b/patch/0129-devlink-introduce-linecard-info-get-message.patch new file mode 100644 index 000000000..3ea32fc35 --- /dev/null +++ b/patch/0129-devlink-introduce-linecard-info-get-message.patch @@ -0,0 +1,246 @@ +From 13e29cf4f38755ae717615071b07cd438e8819e6 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 19 Feb 2021 09:36:15 +0100 +Subject: [PATCH backport 5.10 129/182] devlink: introduce linecard info get + message + +Allow the driver to provide per line card info get op to fill-up info, +similar to the "devlink dev info". + +Signed-off-by: Jiri Pirko +--- + include/net/devlink.h | 7 +- + include/uapi/linux/devlink.h | 3 + + net/core/devlink.c | 135 +++++++++++++++++++++++++++++++++-- + 3 files changed, 140 insertions(+), 5 deletions(-) + +diff --git a/include/net/devlink.h b/include/net/devlink.h +index 3d4ceb2902b8..059bed6aef3c 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -162,6 +162,8 @@ struct devlink_linecard { + bool active; + }; + ++struct devlink_info_req; ++ + /** + * struct devlink_linecard_ops - Linecard operations + * @provision: callback to provision the linecard slot with certain +@@ -170,6 +172,7 @@ struct devlink_linecard { + * @types_init: callback to initialize types list + * @types_fini: callback to finalize types list + * @types_get: callback to get next type in list ++ * @info_get: callback to get linecard info + */ + struct devlink_linecard_ops { + int (*provision)(struct devlink_linecard *linecard, void *priv, +@@ -182,6 +185,9 @@ struct devlink_linecard_ops { + void (*types_get)(struct devlink_linecard *linecard, + void *priv, unsigned int index, const char **type, + const void **type_priv); ++ int (*info_get)(struct devlink_linecard *linecard, void *priv, ++ struct devlink_info_req *req, ++ struct netlink_ext_ack *extack); + }; + + struct devlink_sb_pool_info { +@@ -630,7 +636,6 @@ struct devlink_flash_update_params { + #define DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK BIT(1) + + struct devlink_region; +-struct devlink_info_req; + + /** + * struct devlink_region_ops - Region operations +diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h +index 5ace55666d27..2c9f7d584b48 100644 +--- a/include/uapi/linux/devlink.h ++++ b/include/uapi/linux/devlink.h +@@ -136,6 +136,8 @@ enum devlink_command { + DEVLINK_CMD_LINECARD_NEW, + DEVLINK_CMD_LINECARD_DEL, + ++ DEVLINK_CMD_LINECARD_INFO_GET, /* can dump */ ++ + /* add new commands above here */ + __DEVLINK_CMD_MAX, + DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1 +@@ -566,6 +568,7 @@ enum devlink_attr { + DEVLINK_ATTR_LINECARD_STATE, /* u8 */ + DEVLINK_ATTR_LINECARD_TYPE, /* string */ + DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES, /* nested */ ++ DEVLINK_ATTR_LINECARD_INFO, /* nested */ + + /* add new attributes above here, update the policy in devlink.c */ + +diff --git a/net/core/devlink.c b/net/core/devlink.c +index b43e93ccc672..04f8038f8e23 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -1245,6 +1245,10 @@ struct devlink_linecard_type { + const void *priv; + }; + ++struct devlink_info_req { ++ struct sk_buff *msg; ++}; ++ + static int devlink_nl_linecard_fill(struct sk_buff *msg, + struct devlink *devlink, + struct devlink_linecard *linecard, +@@ -1542,6 +1546,125 @@ static int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb, + return 0; + } + ++static int ++devlink_nl_linecard_info_fill(struct sk_buff *msg, struct devlink *devlink, ++ struct devlink_linecard *linecard, ++ enum devlink_command cmd, u32 portid, ++ u32 seq, int flags, struct netlink_ext_ack *extack) ++{ ++ struct devlink_info_req req; ++ struct nlattr *attr; ++ void *hdr; ++ int err; ++ ++ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); ++ if (!hdr) ++ return -EMSGSIZE; ++ ++ err = -EMSGSIZE; ++ if (devlink_nl_put_handle(msg, devlink)) ++ goto nla_put_failure; ++ if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index)) ++ goto nla_put_failure; ++ ++ attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_INFO); ++ if (!attr) ++ goto nla_put_failure; ++ req.msg = msg; ++ err = linecard->ops->info_get(linecard, linecard->priv, &req, extack); ++ if (err) ++ goto nla_put_failure; ++ nla_nest_end(msg, attr); ++ ++ genlmsg_end(msg, hdr); ++ return 0; ++ ++nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ return err; ++} ++ ++static int devlink_nl_cmd_linecard_info_get_doit(struct sk_buff *skb, ++ struct genl_info *info) ++{ ++ struct devlink_linecard *linecard = info->user_ptr[1]; ++ struct devlink *devlink = linecard->devlink; ++ struct sk_buff *msg; ++ int err; ++ ++ if (!linecard->ops->info_get) ++ return -EOPNOTSUPP; ++ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!msg) ++ return -ENOMEM; ++ ++ err = devlink_nl_linecard_info_fill(msg, devlink, linecard, ++ DEVLINK_CMD_LINECARD_INFO_GET, ++ info->snd_portid, info->snd_seq, 0, ++ info->extack); ++ if (err) { ++ nlmsg_free(msg); ++ return err; ++ } ++ ++ return genlmsg_reply(msg, info); ++} ++ ++static int devlink_nl_cmd_linecard_info_get_dumpit(struct sk_buff *msg, ++ struct netlink_callback *cb) ++{ ++ struct devlink_linecard *linecard; ++ struct devlink *devlink; ++ int start = cb->args[0]; ++ unsigned long index; ++ int idx = 0; ++ int err = 0; ++ ++ mutex_lock(&devlink_mutex); ++ xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { ++ if (!devlink_try_get(devlink)) ++ continue; ++ ++ if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) ++ goto retry; ++ ++ mutex_lock(&devlink->linecards_lock); ++ list_for_each_entry(linecard, &devlink->linecard_list, list) { ++ if (idx < start || !linecard->ops->info_get) { ++ idx++; ++ continue; ++ } ++ mutex_lock(&linecard->state_lock); ++ err = devlink_nl_linecard_info_fill(msg, devlink, linecard, ++ DEVLINK_CMD_LINECARD_INFO_GET, ++ NETLINK_CB(cb->skb).portid, ++ cb->nlh->nlmsg_seq, ++ NLM_F_MULTI, ++ cb->extack); ++ mutex_unlock(&linecard->state_lock); ++ if (err) { ++ mutex_unlock(&devlink->linecards_lock); ++ devlink_put(devlink); ++ goto out; ++ } ++ idx++; ++ } ++ mutex_unlock(&devlink->linecards_lock); ++retry: ++ devlink_put(devlink); ++ } ++out: ++ mutex_unlock(&devlink_mutex); ++ ++ if (err != -EMSGSIZE) ++ return err; ++ ++ cb->args[0] = idx; ++ return msg->len; ++} ++ ++ + static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink, + struct devlink_sb *devlink_sb, + enum devlink_command cmd, u32 portid, +@@ -5455,10 +5578,6 @@ static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb, + return err; + } + +-struct devlink_info_req { +- struct sk_buff *msg; +-}; +- + int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name) + { + return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name); +@@ -8057,6 +8176,14 @@ static const struct genl_small_ops devlink_nl_ops[] = { + .internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD | + DEVLINK_NL_FLAG_NO_LOCK, + }, ++ { ++ .cmd = DEVLINK_CMD_LINECARD_INFO_GET, ++ .doit = devlink_nl_cmd_linecard_info_get_doit, ++ .dumpit = devlink_nl_cmd_linecard_info_get_dumpit, ++ .internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD | ++ DEVLINK_NL_FLAG_NO_LOCK, ++ /* can be retrieved by unprivileged users */ ++ }, + { + .cmd = DEVLINK_CMD_SB_GET, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, +-- +2.20.1 + diff --git a/patch/0130-devlink-introduce-linecard-info-get-message.patch b/patch/0130-devlink-introduce-linecard-info-get-message.patch new file mode 100644 index 000000000..d2f92f77e --- /dev/null +++ b/patch/0130-devlink-introduce-linecard-info-get-message.patch @@ -0,0 +1,316 @@ +From b8243b5c2fdb9871cd55a864b95e197ced9ad532 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 22 Dec 2021 15:11:36 +0000 +Subject: [PATCH backport 5.10 130/182] devlink: introduce linecard info get + message + +Allow the driver to provide per line card info get op to fill-up info, +similar to the "devlink dev info". + +devlink: introduce line card devices support + +Line card can contain a device. For example, this can be a gearbox with +flash. This flash could be updated. Provide the driver possibility to +attach such devices to a line card and expose those to user. Leverage +the existing devlink flash update mechanism and allow driver to pass a +custom "component name" string identifying the line card device to +flash. + +Signed-off-by: Jiri Pirko +--- + include/net/devlink.h | 12 +++ + include/uapi/linux/devlink.h | 4 + + net/core/devlink.c | 166 +++++++++++++++++++++++++++++++++++ + 3 files changed, 182 insertions(+) + +diff --git a/include/net/devlink.h b/include/net/devlink.h +index 059bed6aef3c..06b61c1d7938 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -160,9 +160,11 @@ struct devlink_linecard { + struct devlink_linecard_type *types; + unsigned int types_count; + bool active; ++ struct list_head device_list; + }; + + struct devlink_info_req; ++struct devlink_linecard_device; + + /** + * struct devlink_linecard_ops - Linecard operations +@@ -188,6 +190,9 @@ struct devlink_linecard_ops { + int (*info_get)(struct devlink_linecard *linecard, void *priv, + struct devlink_info_req *req, + struct netlink_ext_ack *extack); ++ int (*device_info_get)(struct devlink_linecard_device *device, ++ void *priv, struct devlink_info_req *req, ++ struct netlink_ext_ack *extack); + }; + + struct devlink_sb_pool_info { +@@ -1459,6 +1464,13 @@ struct devlink_linecard * + devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index, + const struct devlink_linecard_ops *ops, void *priv); + void devlink_linecard_destroy(struct devlink_linecard *linecard); ++struct devlink_linecard_device * ++devlink_linecard_device_create(struct devlink_linecard *linecard, ++ unsigned int device_index, ++ const char *flash_component, void *priv); ++void ++devlink_linecard_device_destroy(struct devlink_linecard *linecard, ++ struct devlink_linecard_device *linecard_device); + void devlink_linecard_provision_set(struct devlink_linecard *linecard, + const char *type); + void devlink_linecard_provision_clear(struct devlink_linecard *linecard); +diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h +index 2c9f7d584b48..bac94c3c1bb0 100644 +--- a/include/uapi/linux/devlink.h ++++ b/include/uapi/linux/devlink.h +@@ -569,6 +569,10 @@ enum devlink_attr { + DEVLINK_ATTR_LINECARD_TYPE, /* string */ + DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES, /* nested */ + DEVLINK_ATTR_LINECARD_INFO, /* nested */ ++ DEVLINK_ATTR_LINECARD_DEVICE_LIST, /* nested */ ++ DEVLINK_ATTR_LINECARD_DEVICE, /* nested */ ++ DEVLINK_ATTR_LINECARD_DEVICE_INDEX, /* u32 */ ++ DEVLINK_ATTR_LINECARD_DEVICE_INFO, /* nested */ + + /* add new attributes above here, update the policy in devlink.c */ + +diff --git a/net/core/devlink.c b/net/core/devlink.c +index 04f8038f8e23..ca014f40ac02 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -1249,6 +1249,59 @@ struct devlink_info_req { + struct sk_buff *msg; + }; + ++struct devlink_linecard_device { ++ struct list_head list; ++ unsigned int index; ++ const char *flash_component; ++ void *priv; ++}; ++ ++static int ++devlink_nl_linecard_device_fill(struct sk_buff *msg, ++ struct devlink_linecard *linecard, ++ struct devlink_linecard_device *linecard_device) ++{ ++ struct nlattr *attr; ++ ++ attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE); ++ if (!attr) ++ return -EMSGSIZE; ++ if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_DEVICE_INDEX, ++ linecard_device->index)) ++ return -EMSGSIZE; ++ if (linecard_device->flash_component && ++ nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT, ++ linecard_device->flash_component)) ++ return -EMSGSIZE; ++ nla_nest_end(msg, attr); ++ ++ return 0; ++} ++ ++static int devlink_nl_linecard_devices_fill(struct sk_buff *msg, ++ struct devlink_linecard *linecard) ++{ ++ struct devlink_linecard_device *linecard_device; ++ struct nlattr *attr; ++ int err; ++ ++ if (list_empty(&linecard->device_list)) ++ return 0; ++ ++ attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE_LIST); ++ if (!attr) ++ return -EMSGSIZE; ++ list_for_each_entry(linecard_device, &linecard->device_list, list) { ++ err = devlink_nl_linecard_device_fill(msg, linecard, ++ linecard_device); ++ if (err) ++ return err; ++ } ++ nla_nest_end(msg, attr); ++ ++ return 0; ++} ++ + static int devlink_nl_linecard_fill(struct sk_buff *msg, + struct devlink *devlink, + struct devlink_linecard *linecard, +@@ -1259,6 +1312,7 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg, + struct devlink_linecard_type *linecard_type; + struct nlattr *attr; + void *hdr; ++ int err; + int i; + + hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); +@@ -1289,6 +1343,10 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg, + nla_nest_end(msg, attr); + } + ++ err = devlink_nl_linecard_devices_fill(msg, linecard); ++ if (err) ++ goto nla_put_failure; ++ + genlmsg_end(msg, hdr); + return 0; + +@@ -1546,6 +1604,66 @@ static int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb, + return 0; + } + ++static int ++devlink_nl_linecard_device_info_fill(struct sk_buff *msg, ++ struct devlink_linecard *linecard, ++ struct devlink_linecard_device *linecard_device, ++ struct netlink_ext_ack *extack) ++{ ++ struct nlattr *attr, *attr2; ++ ++ attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE); ++ if (!attr) ++ return -EMSGSIZE; ++ if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_DEVICE_INDEX, ++ linecard_device->index)) ++ return -EMSGSIZE; ++ if (linecard->ops->device_info_get) { ++ struct devlink_info_req req; ++ int err; ++ ++ attr2 = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE_INFO); ++ if (!attr2) ++ return -EMSGSIZE; ++ req.msg = msg; ++ err = linecard->ops->device_info_get(linecard_device, ++ linecard_device->priv, ++ &req, extack); ++ if (err) ++ return -EMSGSIZE; ++ nla_nest_end(msg, attr2); ++ } ++ nla_nest_end(msg, attr); ++ ++ return 0; ++} ++ ++static int devlink_nl_linecard_devices_info_fill(struct sk_buff *msg, ++ struct devlink_linecard *linecard, ++ struct netlink_ext_ack *extack) ++{ ++ struct devlink_linecard_device *linecard_device; ++ struct nlattr *attr; ++ int err; ++ ++ if (list_empty(&linecard->device_list)) ++ return 0; ++ ++ attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE_LIST); ++ if (!attr) ++ return -EMSGSIZE; ++ list_for_each_entry(linecard_device, &linecard->device_list, list) { ++ err = devlink_nl_linecard_device_info_fill(msg, linecard, ++ linecard_device, ++ extack); ++ if (err) ++ return err; ++ } ++ nla_nest_end(msg, attr); ++ ++ return 0; ++} ++ + static int + devlink_nl_linecard_info_fill(struct sk_buff *msg, struct devlink *devlink, + struct devlink_linecard *linecard, +@@ -1576,6 +1694,10 @@ devlink_nl_linecard_info_fill(struct sk_buff *msg, struct devlink *devlink, + goto nla_put_failure; + nla_nest_end(msg, attr); + ++ err = devlink_nl_linecard_devices_info_fill(msg, linecard, extack); ++ if (err) ++ goto nla_put_failure; ++ + genlmsg_end(msg, hdr); + return 0; + +@@ -9068,6 +9190,7 @@ devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index, + linecard->priv = priv; + linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; + mutex_init(&linecard->state_lock); ++ INIT_LIST_HEAD(&linecard->device_list); + + err = devlink_linecard_types_init(linecard); + if (err) { +@@ -9096,6 +9219,7 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard) + + devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL); + devlink_linecard_types_fini(linecard); ++ WARN_ON(!list_empty(&linecard->device_list)); + mutex_lock(&devlink->linecards_lock); + list_del(&linecard->list); + mutex_unlock(&devlink->linecards_lock); +@@ -9103,6 +9227,47 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard) + } + EXPORT_SYMBOL_GPL(devlink_linecard_destroy); + ++/** ++ * devlink_linecard_device_create - Create a device on linecard ++ * ++ * @devlink_linecard: devlink linecard ++ * @device_index: index of the linecard device ++ * @flash_component: name of flash update component, ++ * NULL if unable to flash ++ */ ++struct devlink_linecard_device * ++devlink_linecard_device_create(struct devlink_linecard *linecard, ++ unsigned int device_index, ++ const char *flash_component, void *priv) ++{ ++ struct devlink_linecard_device *linecard_device; ++ ++ linecard_device = kzalloc(sizeof(*linecard_device), GFP_KERNEL); ++ if (!linecard_device) ++ return ERR_PTR(-ENOMEM); ++ linecard_device->index = device_index; ++ linecard_device->flash_component = flash_component; ++ linecard_device->priv = priv; ++ mutex_lock(&linecard->devlink->lock); ++ list_add_tail(&linecard_device->list, &linecard->device_list); ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->devlink->lock); ++ return linecard_device; ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_device_create); ++ ++void ++devlink_linecard_device_destroy(struct devlink_linecard *linecard, ++ struct devlink_linecard_device *linecard_device) ++{ ++ mutex_lock(&linecard->devlink->lock); ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ list_del(&linecard_device->list); ++ mutex_unlock(&linecard->devlink->lock); ++ kfree(linecard_device); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_device_destroy); ++ + /** + * devlink_linecard_provision_set - Set provisioning on linecard + * +@@ -9129,6 +9294,7 @@ EXPORT_SYMBOL_GPL(devlink_linecard_provision_set); + void devlink_linecard_provision_clear(struct devlink_linecard *linecard) + { + mutex_lock(&linecard->state_lock); ++ WARN_ON(!list_empty(&linecard->device_list)); + linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; + linecard->type = NULL; + devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); +-- +2.20.1 + diff --git a/patch/0131-mlxsw-reg-Add-Ports-Mapping-event-Configuration-Regi.patch b/patch/0131-mlxsw-reg-Add-Ports-Mapping-event-Configuration-Regi.patch new file mode 100644 index 000000000..179d95f44 --- /dev/null +++ b/patch/0131-mlxsw-reg-Add-Ports-Mapping-event-Configuration-Regi.patch @@ -0,0 +1,99 @@ +From 4a49468e7fc7e94a83703215445d9b3919642eb9 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 29 Jan 2021 08:45:09 +0100 +Subject: [PATCH backport 5.10 131/182] mlxsw: reg: Add Ports Mapping event + Configuration Register + +The PMECR register use to enable/disable event trigger in case of +local port mapping change. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 64 +++++++++++++++++++++++ + 1 file changed, 64 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 98c627ffe039..93e3366cfcb9 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -5524,6 +5524,69 @@ static inline void mlxsw_reg_pplr_pack(char *payload, u8 local_port, + MLXSW_REG_PPLR_LB_TYPE_BIT_PHY_LOCAL : 0); + } + ++/* PMECR - Ports Mapping event Configuration Register ++ * -------------------------------------------------- ++ * The PMECR register use to enable/disable event trigger in case of ++ * local port mapping change. ++ */ ++#define MLXSW_REG_PMECR_ID 0x501B ++#define MLXSW_REG_PMECR_LEN 0x20 ++ ++MLXSW_REG_DEFINE(pmecr, MLXSW_REG_PMECR_ID, MLXSW_REG_PMECR_LEN); ++ ++/* reg_pmecr_local_port ++ * Local port number. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, pmecr, local_port, 0x00, 16, 8); ++ ++/* reg_pmecr_ee ++ * Event update enable. If this bit is set, event generation will be updated ++ * based on the e field. Only relevant on Set operations. ++ * Access: WO ++ */ ++MLXSW_ITEM32(reg, pmecr, ee, 0x04, 30, 1); ++ ++/* reg_pmecr_eswi ++ * Software ignore enable bit. If this bit is set, the value if swi is used. ++ * If this bit is clear, the value of swi is ignored. ++ * Only relevant on Set operations. ++ * Access: WO ++ */ ++MLXSW_ITEM32(reg, pmecr, eswi, 0x04, 24, 1); ++ ++/* reg_pmecr_swi ++ * Software ignore. If this bit is set, the device shouldn't generate events ++ * in case of PMLP SET operation but only upon self local port mapping change ++ * (if applicable according to e configuration). This is supplementary ++ * configuration on top of e value. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, pmecr, swi, 0x04, 8, 1); ++ ++enum mlxsw_reg_pmecr_e { ++ MLXSW_REG_PMECR_E_DO_NOT_GENERATE_EVENT, ++ MLXSW_REG_PMECR_E_GENERATE_EVENT, ++ MLXSW_REG_PMECR_E_GENERATE_SINGLE_EVENT, ++}; ++ ++/* reg_pmecr_e ++ * Event generation on local port mapping change. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, pmecr, e, 0x04, 0, 2); ++ ++static inline void mlxsw_reg_pmecr_pack(char *payload, u8 local_port, ++ enum mlxsw_reg_pmecr_e e) ++{ ++ MLXSW_REG_ZERO(pmecr, payload); ++ mlxsw_reg_pmecr_local_port_set(payload, local_port); ++ mlxsw_reg_pmecr_e_set(payload, e); ++ mlxsw_reg_pmecr_ee_set(payload, true); ++ mlxsw_reg_pmecr_swi_set(payload, true); ++ mlxsw_reg_pmecr_eswi_set(payload, true); ++} ++ + /* PMPE - Port Module Plug/Unplug Event Register + * --------------------------------------------- + * This register reports any operational status change of a module. +@@ -11375,6 +11438,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { + MLXSW_REG(pspa), + MLXSW_REG(pmaos), + MLXSW_REG(pplr), ++ MLXSW_REG(pmecr), + MLXSW_REG(pmpe), + MLXSW_REG(pddr), + MLXSW_REG(pmtm), +-- +2.20.1 + diff --git a/patch/0132-mlxsw-reg-Add-Management-DownStream-Device-Query-Reg.patch b/patch/0132-mlxsw-reg-Add-Management-DownStream-Device-Query-Reg.patch new file mode 100644 index 000000000..730e1f898 --- /dev/null +++ b/patch/0132-mlxsw-reg-Add-Management-DownStream-Device-Query-Reg.patch @@ -0,0 +1,268 @@ +From 5d8d4899f493e3b18712fc96a45eb020985740b1 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 3 Jan 2022 10:20:49 +0000 +Subject: [PATCH backport 5.10 132/182] mlxsw: reg: Add Management DownStream + Device Query Register + +The MDDQ register allows to query the DownStream device properties. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 234 ++++++++++++++++++++++ + 1 file changed, 234 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 93e3366cfcb9..ad7faeb95646 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10296,6 +10296,239 @@ mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, + *num_of_slots = mlxsw_reg_mgpir_num_of_slots_get(payload); + } + ++/* MDDQ - Management DownStream Device Query Register ++ * -------------------------------------------------- ++ * This register allows to query the DownStream device properties. The desired ++ * information is chosen upon the query_type field and is delivered by 32B ++ * of data blocks. ++ */ ++#define MLXSW_REG_MDDQ_ID 0x9161 ++#define MLXSW_REG_MDDQ_LEN 0x30 ++ ++MLXSW_REG_DEFINE(mddq, MLXSW_REG_MDDQ_ID, MLXSW_REG_MDDQ_LEN); ++ ++/* reg_mddq_sie ++ * Slot info event enable. ++ * When set to '1', each change in the slot_info.provisioned / sr_valid / ++ * active / ready will generate an event. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, mddq, sie, 0x00, 31, 1); ++ ++enum mlxsw_reg_mddq_query_type { ++ MLXSW_REG_MDDQ_QUERY_TYPE_SLOT_INFO = 1, ++ MLXSW_REG_MDDQ_QUERY_TYPE_DEVICE_INFO, /* If there are no devices ++ * on the slot, data_valid ++ * will be '0'. ++ */ ++ MLXSW_REG_MDDQ_QUERY_TYPE_SLOT_NAME, ++}; ++ ++/* reg_mddq_query_type ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mddq, query_type, 0x00, 16, 8); ++ ++/* reg_mddq_slot_index ++ * Slot index. 0 is reserved. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mddq, slot_index, 0x00, 0, 4); ++ ++/* reg_mddq_response_msg_seq ++ * Response message sequential number. For a specific request, the response ++ * message sequential number is the following one. In addition, the last ++ * message should be 0. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, response_msg_seq, 0x04, 16, 8); ++ ++/* reg_mddq_request_msg_seq ++ * Request message sequential number. ++ * The first message number should be 0. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mddq, request_msg_seq, 0x04, 0, 8); ++ ++/* reg_mddq_data_valid ++ * If set, the data in the data field is valid and contain the information ++ * for the queried index. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, data_valid, 0x08, 31, 1); ++ ++/* reg_mddq_provisioned ++ * If set, the INI file is applied and the card is provisioned. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, provisioned, 0x10, 31, 1); ++ ++/* reg_mddq_sr_valid ++ * If set, Shift Register is valid (after being provisioned). ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, sr_valid, 0x10, 30, 1); ++ ++enum mlxsw_reg_mddq_ready { ++ MLXSW_REG_MDDQ_READY_NOT_READY, ++ MLXSW_REG_MDDQ_READY_READY, ++ MLXSW_REG_MDDQ_READY_ERROR, ++}; ++ ++/* reg_mddq_lc_ready ++ * If set, the LC is powered on, matching the INI version and a new FW ++ * version can be burnt (if necessary). ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, lc_ready, 0x10, 28, 2); ++ ++/* reg_mddq_active ++ * If set, the FW has completed the MDDC.device_enable command. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, active, 0x10, 27, 1); ++ ++/* reg_mddq_hw_revision ++ * Major user-configured version number of the current INI file. ++ * Valid only when active or ready are '1'. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, hw_revision, 0x14, 16, 16); ++ ++/* reg_mddq_ini_file_version ++ * User-configured version number of the current INI file. ++ * Valid only when active or lc_ready are '1'. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, ini_file_version, 0x14, 0, 16); ++ ++enum mlxsw_reg_mddq_card_type { ++ MLXSW_REG_MDDQ_CARD_TYPE_BUFFALO_4X400G, ++ MLXSW_REG_MDDQ_CARD_TYPE_BUFFALO_8X200G, ++ MLXSW_REG_MDDQ_CARD_TYPE_BUFFALO_16X100G, ++}; ++ ++/* reg_mddq_card_type ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, card_type, 0x18, 0, 8); ++ ++static inline void ++__mlxsw_reg_mddq_pack(char *payload, u8 slot_index, ++ enum mlxsw_reg_mddq_query_type query_type) ++{ ++ MLXSW_REG_ZERO(mddq, payload); ++ mlxsw_reg_mddq_slot_index_set(payload, slot_index); ++ mlxsw_reg_mddq_query_type_set(payload, query_type); ++} ++ ++static inline void ++mlxsw_reg_mddq_slot_info_pack(char *payload, u8 slot_index, bool sie) ++{ ++ __mlxsw_reg_mddq_pack(payload, slot_index, ++ MLXSW_REG_MDDQ_QUERY_TYPE_SLOT_INFO); ++ mlxsw_reg_mddq_sie_set(payload, sie); ++} ++ ++static inline void ++mlxsw_reg_mddq_slot_info_unpack(const char *payload, u8 *p_slot_index, ++ bool *p_provisioned, bool *p_sr_valid, ++ enum mlxsw_reg_mddq_ready *p_lc_ready, ++ bool *p_active, u16 *p_hw_revision, ++ u16 *p_ini_file_version, ++ enum mlxsw_reg_mddq_card_type *p_card_type) ++{ ++ *p_slot_index = mlxsw_reg_mddq_slot_index_get(payload); ++ *p_provisioned = mlxsw_reg_mddq_provisioned_get(payload); ++ *p_sr_valid = mlxsw_reg_mddq_sr_valid_get(payload); ++ *p_lc_ready = mlxsw_reg_mddq_lc_ready_get(payload); ++ *p_active = mlxsw_reg_mddq_active_get(payload); ++ *p_hw_revision = mlxsw_reg_mddq_hw_revision_get(payload); ++ *p_ini_file_version = mlxsw_reg_mddq_ini_file_version_get(payload); ++ *p_card_type = mlxsw_reg_mddq_card_type_get(payload); ++} ++ ++/* reg_mddq_flash_owner ++ * If set, the device is the flash owner. Otherwise, a shared flash ++ * is used by this device (another device is the flash owner). ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, flash_owner, 0x10, 30, 1); ++ ++/* reg_mddq_device_index ++ * Device index. The first device should number 0. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, device_index, 0x10, 0, 8); ++ ++/* reg_mddq_fw_major ++ * Major FW version number. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, fw_major, 0x14, 16, 16); ++ ++/* reg_mddq_fw_minor ++ * Minor FW version number. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, fw_minor, 0x18, 16, 16); ++ ++/* reg_mddq_fw_sub_minor ++ * Sub-minor FW version number. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, fw_sub_minor, 0x18, 0, 16); ++ ++static inline void ++mlxsw_reg_mddq_device_info_pack(char *payload, u8 slot_index, ++ u8 request_msg_seq) ++{ ++ __mlxsw_reg_mddq_pack(payload, slot_index, ++ MLXSW_REG_MDDQ_QUERY_TYPE_DEVICE_INFO); ++ mlxsw_reg_mddq_request_msg_seq_set(payload, request_msg_seq); ++} ++ ++static inline void ++mlxsw_reg_mddq_device_info_unpack(const char *payload, u8 *p_response_msg_seq, ++ bool *p_data_valid, bool *p_flash_owner, ++ u8 *p_device_index, u16 *p_fw_major, ++ u16 *p_fw_minor, u16 *p_fw_sub_minor) ++{ ++ *p_response_msg_seq = mlxsw_reg_mddq_response_msg_seq_get(payload); ++ *p_data_valid = mlxsw_reg_mddq_data_valid_get(payload); ++ if (p_flash_owner) ++ *p_flash_owner = mlxsw_reg_mddq_flash_owner_get(payload); ++ *p_device_index = mlxsw_reg_mddq_device_index_get(payload); ++ if (p_fw_major) ++ *p_fw_major = mlxsw_reg_mddq_fw_major_get(payload); ++ if (p_fw_minor) ++ *p_fw_minor = mlxsw_reg_mddq_fw_minor_get(payload); ++ if (p_fw_sub_minor) ++ *p_fw_sub_minor = mlxsw_reg_mddq_fw_sub_minor_get(payload); ++} ++ ++#define MLXSW_REG_MDDQ_SLOT_ACII_NAME_LEN 20 ++ ++/* reg_mddq_slot_ascii_name ++ * Slot's ASCII name. ++ * Access: RO ++ */ ++MLXSW_ITEM_BUF(reg, mddq, slot_ascii_name, 0x10, ++ MLXSW_REG_MDDQ_SLOT_ACII_NAME_LEN); ++ ++static inline void ++mlxsw_reg_mddq_slot_name_pack(char *payload, u8 slot_index) ++{ ++ __mlxsw_reg_mddq_pack(payload, slot_index, ++ MLXSW_REG_MDDQ_QUERY_TYPE_SLOT_NAME); ++} ++ ++static inline void ++mlxsw_reg_mddq_slot_name_unpack(const char *payload, char *slot_ascii_name) ++{ ++ mlxsw_reg_mddq_slot_ascii_name_memcpy_from(payload, slot_ascii_name); ++} ++ + /* MFDE - Monitoring FW Debug Register + * ----------------------------------- + */ +@@ -11495,6 +11728,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { + MLXSW_REG(mtptpt), + MLXSW_REG(mfgd), + MLXSW_REG(mgpir), ++ MLXSW_REG(mddq), + MLXSW_REG(mfde), + MLXSW_REG(tngcr), + MLXSW_REG(tnumt), +-- +2.20.1 + diff --git a/patch/0133-mlxsw-reg-Add-Management-DownStream-Device-Control-R.patch b/patch/0133-mlxsw-reg-Add-Management-DownStream-Device-Control-R.patch new file mode 100644 index 000000000..22f63a055 --- /dev/null +++ b/patch/0133-mlxsw-reg-Add-Management-DownStream-Device-Control-R.patch @@ -0,0 +1,71 @@ +From 14d65a09a9b77a5ed632a73ff006042d26be3226 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Tue, 19 Jan 2021 12:16:58 +0100 +Subject: [PATCH backport 5.10 133/182] mlxsw: reg: Add Management DownStream + Device Control Register + +The MDDC register allows control downstream devices and line cards. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 37 +++++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index ad7faeb95646..cddfe5702140 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10529,6 +10529,42 @@ mlxsw_reg_mddq_slot_name_unpack(const char *payload, char *slot_ascii_name) + mlxsw_reg_mddq_slot_ascii_name_memcpy_from(payload, slot_ascii_name); + } + ++/* MDDC - Management DownStream Device Control Register ++ * ---------------------------------------------------- ++ * This register allows control downstream devices and line cards. ++ */ ++#define MLXSW_REG_MDDC_ID 0x9163 ++#define MLXSW_REG_MDDC_LEN 0x30 ++ ++MLXSW_REG_DEFINE(mddc, MLXSW_REG_MDDC_ID, MLXSW_REG_MDDC_LEN); ++ ++/* reg_mddc_slot_index ++ * Slot index. 0 is reserved. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mddc, slot_index, 0x00, 0, 4); ++ ++/* reg_mddc_rst ++ * Reset request. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, mddc, rst, 0x04, 29, 1); ++ ++/* reg_mddc_device_enable ++ * When set, FW is the manager and allowed to program the Downstream Device. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, mddc, device_enable, 0x04, 28, 1); ++ ++static inline void mlxsw_reg_mddc_pack(char *payload, u8 slot_index, bool rst, ++ bool device_enable) ++{ ++ MLXSW_REG_ZERO(mddc, payload); ++ mlxsw_reg_mddc_slot_index_set(payload, slot_index); ++ mlxsw_reg_mddc_rst_set(payload, rst); ++ mlxsw_reg_mddc_device_enable_set(payload, device_enable); ++} ++ + /* MFDE - Monitoring FW Debug Register + * ----------------------------------- + */ +@@ -11729,6 +11765,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { + MLXSW_REG(mfgd), + MLXSW_REG(mgpir), + MLXSW_REG(mddq), ++ MLXSW_REG(mddc), + MLXSW_REG(mfde), + MLXSW_REG(tngcr), + MLXSW_REG(tnumt), +-- +2.20.1 + diff --git a/patch/0134-mlxsw-reg-Add-Management-Binary-Code-Transfer-Regist.patch b/patch/0134-mlxsw-reg-Add-Management-Binary-Code-Transfer-Regist.patch new file mode 100644 index 000000000..9aefc453b --- /dev/null +++ b/patch/0134-mlxsw-reg-Add-Management-Binary-Code-Transfer-Regist.patch @@ -0,0 +1,155 @@ +From e9afbd683a14e3369ba25dcb9c8147a8b478b5c0 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Thu, 10 Dec 2020 18:27:38 +0100 +Subject: [PATCH backport 5.10 134/182] mlxsw: reg: Add Management Binary Code + Transfer Register + +The MBCT register allows to transfer binary codes from the Host to +the management FW by transferring it by chunks of maximum 1KB. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 120 ++++++++++++++++++++++ + 1 file changed, 120 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index cddfe5702140..e060f054e0a9 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10296,6 +10296,125 @@ mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, + *num_of_slots = mlxsw_reg_mgpir_num_of_slots_get(payload); + } + ++/* MBCT - Management Binary Code Transfer Register ++ * ----------------------------------------------- ++ * This register allows to transfer binary codes from the Host to ++ * the management FW by transferring it by chunks of maximum 1KB. ++ */ ++#define MLXSW_REG_MBCT_ID 0x9120 ++#define MLXSW_REG_MBCT_LEN 0x420 ++ ++MLXSW_REG_DEFINE(mbct, MLXSW_REG_MBCT_ID, MLXSW_REG_MBCT_LEN); ++ ++/* reg_mbct_slot_index ++ * Slot index. 0 is reserved. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mbct, slot_index, 0x00, 0, 4); ++ ++/* reg_mbct_data_size ++ * Actual data field size in bytes for the current data transfer. ++ * Access: WO ++ */ ++MLXSW_ITEM32(reg, mbct, data_size, 0x04, 0, 11); ++ ++enum mlxsw_reg_mbct_op { ++ MLXSW_REG_MBCT_OP_ERASE_INI_IMAGE = 1, ++ MLXSW_REG_MBCT_OP_DATA_TRANSFER, /* Download */ ++ MLXSW_REG_MBCT_OP_ACTIVATE, ++ MLXSW_REG_MBCT_OP_CLEAR_ERRORS = 6, ++ MLXSW_REG_MBCT_OP_QUERY_STATUS, ++}; ++ ++/* reg_mbct_op ++ * Access: OP ++ */ ++MLXSW_ITEM32(reg, mbct, op, 0x08, 28, 4); ++ ++/* reg_mbct_last ++ * Indicates that the current data field is the last chunk of the INI. ++ * Access: WO ++ */ ++MLXSW_ITEM32(reg, mbct, last, 0x08, 26, 1); ++ ++/* reg_mbct_oee ++ * Opcode Event Enable. When set an event will be sent once the opcode ++ * was executed and the fsm_state has changed. ++ * Access: WO ++ */ ++MLXSW_ITEM32(reg, mbct, oee, 0x08, 25, 1); ++ ++enum mlxsw_reg_mbct_status { ++ /* Partial data transfer completed successfully and ready for next ++ * data transfer. ++ */ ++ MLXSW_REG_MBCT_STATUS_PART_DATA = 2, ++ MLXSW_REG_MBCT_STATUS_LAST_DATA, ++ MLXSW_REG_MBCT_STATUS_ERASE_COMPLETE, ++ /* Error - trying to erase INI while it being used. */ ++ MLXSW_REG_MBCT_STATUS_ERROR_INI_IN_USE, ++ /* Last data transfer completed, applying magic pattern. */ ++ MLXSW_REG_MBCT_STATUS_ERASE_FAILED = 7, ++ MLXSW_REG_MBCT_STATUS_INI_ERROR, ++ MLXSW_REG_MBCT_STATUS_ACTIVATION_FAILED, ++ MLXSW_REG_MBCT_STATUS_ILLEGAL_OPERATION = 11, ++}; ++ ++/* reg_mbct_status ++ * Status. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mbct, status, 0x0C, 24, 5); ++ ++enum mlxsw_reg_mbct_fsm_state { ++ MLXSW_REG_MBCT_FSM_STATE_INI_IN_USE = 5, ++ MLXSW_REG_MBCT_FSM_STATE_ERROR = 6, ++}; ++ ++/* reg_mbct_fsm_state ++ * FSM state. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mbct, fsm_state, 0x0C, 16, 4); ++ ++#define MLXSW_REG_MBCT_DATA_LEN 1024 ++ ++/* reg_mbct_data ++ * Up to 1KB of data. ++ * Access: WO ++ */ ++MLXSW_ITEM_BUF(reg, mbct, data, 0x20, MLXSW_REG_MBCT_DATA_LEN); ++ ++static inline void mlxsw_reg_mbct_pack(char *payload, u8 slot_index, ++ enum mlxsw_reg_mbct_op op, ++ u16 data_size, bool last, bool oee, ++ const char *data) ++{ ++ MLXSW_REG_ZERO(mbct, payload); ++ mlxsw_reg_mbct_slot_index_set(payload, slot_index); ++ mlxsw_reg_mbct_op_set(payload, op); ++ mlxsw_reg_mbct_oee_set(payload, oee); ++ if (op == MLXSW_REG_MBCT_OP_DATA_TRANSFER) { ++ if (WARN_ON(data_size > MLXSW_REG_MBCT_DATA_LEN)) ++ return; ++ mlxsw_reg_mbct_data_size_set(payload, data_size); ++ mlxsw_reg_mbct_last_set(payload, last); ++ mlxsw_reg_mbct_data_memcpy_to(payload, data); ++ } ++} ++ ++static inline void ++mlxsw_reg_mbct_unpack(const char *payload, u8 *p_slot_index, ++ enum mlxsw_reg_mbct_status *p_status, ++ enum mlxsw_reg_mbct_fsm_state *p_fsm_state) ++{ ++ if (p_slot_index) ++ *p_slot_index = mlxsw_reg_mbct_slot_index_get(payload); ++ *p_status = mlxsw_reg_mbct_status_get(payload); ++ if (p_fsm_state) ++ *p_fsm_state = mlxsw_reg_mbct_fsm_state_get(payload); ++} ++ + /* MDDQ - Management DownStream Device Query Register + * -------------------------------------------------- + * This register allows to query the DownStream device properties. The desired +@@ -11764,6 +11883,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { + MLXSW_REG(mtptpt), + MLXSW_REG(mfgd), + MLXSW_REG(mgpir), ++ MLXSW_REG(mbct), + MLXSW_REG(mddq), + MLXSW_REG(mddc), + MLXSW_REG(mfde), +-- +2.20.1 + diff --git a/patch/0135-mlxsw-core_linecards-Add-line-card-objects-and-imple.patch b/patch/0135-mlxsw-core_linecards-Add-line-card-objects-and-imple.patch new file mode 100644 index 000000000..f35efc3b2 --- /dev/null +++ b/patch/0135-mlxsw-core_linecards-Add-line-card-objects-and-imple.patch @@ -0,0 +1,1062 @@ +From 59c953deed31161dc358e6d397af2b5b0f5ee61c Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 22 Dec 2021 16:06:54 +0000 +Subject: [PATCH backport 5.10 135/182] mlxsw: core_linecards: Add line card + objects and implement provisioning + +Introduce objects for line cards and an infrastructure around that. +Use devlink_linecard_create/destroy() to register the line card with +devlink core. Implement provisioning ops with a list of supported +line cards. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/Makefile | 3 +- + drivers/net/ethernet/mellanox/mlxsw/core.c | 22 + + drivers/net/ethernet/mellanox/mlxsw/core.h | 46 ++ + .../ethernet/mellanox/mlxsw/core_linecards.c | 775 ++++++++++++++++++ + .../net/ethernet/mellanox/mlxsw/spectrum.c | 68 ++ + drivers/net/ethernet/mellanox/mlxsw/trap.h | 6 + + 6 files changed, 919 insertions(+), 1 deletion(-) + create mode 100644 drivers/net/ethernet/mellanox/mlxsw/core_linecards.c + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile +index 892724380ea2..ca7260a145f5 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/Makefile ++++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile +@@ -1,7 +1,8 @@ + # SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_MLXSW_CORE) += mlxsw_core.o + mlxsw_core-objs := core.o core_acl_flex_keys.o \ +- core_acl_flex_actions.o core_env.o ++ core_acl_flex_actions.o core_env.o \ ++ core_linecards.o + mlxsw_core-$(CONFIG_MLXSW_CORE_HWMON) += core_hwmon.o + mlxsw_core-$(CONFIG_MLXSW_CORE_THERMAL) += core_thermal.o + obj-$(CONFIG_MLXSW_PCI) += mlxsw_pci.o +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 0b1888318ef1..246db548f011 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -82,6 +82,7 @@ struct mlxsw_core { + struct mlxsw_res res; + struct mlxsw_hwmon *hwmon; + struct mlxsw_thermal *thermal; ++ struct mlxsw_linecards *linecards; + struct mlxsw_core_port *ports; + unsigned int max_ports; + bool fw_flash_in_progress; +@@ -93,6 +94,11 @@ struct mlxsw_core { + /* driver_priv has to be always the last item */ + }; + ++struct mlxsw_linecards *mlxsw_core_linecards(struct mlxsw_core *mlxsw_core) ++{ ++ return mlxsw_core->linecards; ++} ++ + #define MLXSW_PORT_MAX_PORTS_DEFAULT 0x40 + + static int mlxsw_ports_init(struct mlxsw_core *mlxsw_core) +@@ -1918,6 +1924,11 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + if (err) + goto err_emad_init; + ++ err = mlxsw_linecards_init(mlxsw_core, mlxsw_bus_info, ++ &mlxsw_core->linecards); ++ if (err) ++ goto err_linecards_init; ++ + if (!reload) { + err = devlink_register(devlink, mlxsw_bus_info->dev); + if (err) +@@ -1963,8 +1974,15 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + if (!reload) + devlink_reload_enable(devlink); + ++ err = mlxsw_linecards_post_init(mlxsw_core, mlxsw_core->linecards); ++ if (err) ++ goto err_linecards_post_init; ++ + return 0; + ++err_linecards_post_init: ++ if (mlxsw_core->driver->fini) ++ mlxsw_core->driver->fini(mlxsw_core); + err_driver_init: + mlxsw_env_fini(mlxsw_core->env); + err_env_init: +@@ -1981,6 +1999,8 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + if (!reload) + devlink_unregister(devlink); + err_devlink_register: ++ mlxsw_linecards_fini(mlxsw_core, mlxsw_core->linecards); ++err_linecards_init: + mlxsw_emad_fini(mlxsw_core); + err_emad_init: + kfree(mlxsw_core->lag.mapping); +@@ -2042,6 +2062,7 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, + } + + devlink_params_unpublish(devlink); ++ mlxsw_linecards_pre_fini(mlxsw_core, mlxsw_core->linecards); + if (mlxsw_core->driver->fini) + mlxsw_core->driver->fini(mlxsw_core); + mlxsw_env_fini(mlxsw_core->env); +@@ -2052,6 +2073,7 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, + mlxsw_core_params_unregister(mlxsw_core); + if (!reload) + devlink_unregister(devlink); ++ mlxsw_linecards_fini(mlxsw_core, mlxsw_core->linecards); + mlxsw_emad_fini(mlxsw_core); + kfree(mlxsw_core->lag.mapping); + mlxsw_ports_fini(mlxsw_core); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 0ceb7dae95f6..d3c5d8289a85 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -30,6 +30,8 @@ unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core); + + void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core); + ++struct mlxsw_linecards *mlxsw_core_linecards(struct mlxsw_core *mlxsw_core); ++ + bool mlxsw_core_temp_warn_enabled(const struct mlxsw_core *mlxsw_core); + + bool +@@ -509,4 +511,48 @@ static inline struct mlxsw_skb_cb *mlxsw_skb_cb(struct sk_buff *skb) + return (struct mlxsw_skb_cb *) skb->cb; + } + ++struct mlxsw_linecards; ++ ++struct mlxsw_linecard { ++ u8 slot_index; ++ struct mlxsw_linecards *linecards; ++ struct devlink_linecard *devlink_linecard; ++ struct mutex lock; /* Locks accesses to the linecard structure */ ++ char read_name[MLXSW_REG_MDDQ_SLOT_ACII_NAME_LEN]; ++ char mbct_pl[MLXSW_REG_MBCT_LEN]; /* too big for stack */ ++ bool provisioned; ++}; ++ ++struct mlxsw_linecard_types_info; ++ ++struct mlxsw_linecards { ++ struct list_head event_ops_list; ++ struct workqueue_struct *wq; ++ struct mlxsw_core *mlxsw_core; ++ const struct mlxsw_bus_info *bus_info; ++ u8 count; ++ struct mlxsw_linecard_types_info *types_info; ++ struct mlxsw_linecard linecards[0]; ++}; ++ ++static inline struct mlxsw_linecard * ++mlxsw_linecard_get(struct mlxsw_linecards *linecards, u8 slot_index) ++{ ++ return &linecards->linecards[slot_index - 1]; ++} ++ ++int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core, ++ const struct mlxsw_bus_info *bus_info, ++ struct mlxsw_linecards **p_linecards); ++int mlxsw_linecards_post_init(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards); ++void mlxsw_linecards_pre_fini(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards); ++void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards); ++int mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, ++ const char *mddq_pl); ++int mlxsw_linecard_bct_process(struct mlxsw_core *mlxsw_core, ++ const char *mbct_pl); ++ + #endif +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +new file mode 100644 +index 000000000000..a324ce2436e8 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +@@ -0,0 +1,775 @@ ++// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 ++/* Copyright (c) 2021 NVIDIA Corporation and Mellanox Technologies. All rights reserved */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "core.h" ++#include "../mlxfw/mlxfw.h" ++ ++struct mlxsw_linecard_ini_file { ++ __le16 size; ++ union { ++ u8 data[0]; ++ struct { ++ u8 __dontcare[7]; ++ u8 type; ++ u8 name[20]; ++ } format; ++ }; ++}; ++ ++struct mlxsw_linecard_types_info { ++ struct mlxsw_linecard_ini_file **ini_files; ++ unsigned int count; ++ size_t data_size; ++ char *data; ++}; ++ ++static const char * ++mlxsw_linecard_types_lookup(struct mlxsw_linecards *linecards, ++ enum mlxsw_reg_mddq_card_type card_type) ++{ ++ struct mlxsw_linecard_types_info *types_info; ++ struct mlxsw_linecard_ini_file *ini_file; ++ int i; ++ ++ types_info = linecards->types_info; ++ for (i = 0; i < types_info->count; i++) { ++ ini_file = linecards->types_info->ini_files[i]; ++ if (ini_file->format.type == card_type) ++ return ini_file->format.name; ++ } ++ return NULL; ++} ++ ++static const char *mlxsw_linecard_type_name(struct mlxsw_linecard *linecard) ++{ ++ struct mlxsw_core *mlxsw_core = linecard->linecards->mlxsw_core; ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ int err; ++ ++ mlxsw_reg_mddq_slot_name_pack(mddq_pl, linecard->slot_index); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddq), mddq_pl); ++ if (err) ++ return NULL; ++ mlxsw_reg_mddq_slot_name_unpack(mddq_pl, linecard->read_name); ++ return linecard->read_name; ++} ++ ++static void mlxsw_linecard_provision_fail(struct mlxsw_linecard *linecard) ++{ ++ linecard->provisioned = false; ++ devlink_linecard_provision_fail(linecard->devlink_linecard); ++} ++ ++static int ++mlxsw_linecard_provision_set(struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard, ++ enum mlxsw_reg_mddq_card_type card_type) ++{ ++ const char *type = mlxsw_linecard_types_lookup(linecards, card_type); ++ ++ if (!type) ++ type = mlxsw_linecard_type_name(linecard); ++ if (!type) { ++ mlxsw_linecard_provision_fail(linecard); ++ return -EINVAL; ++ } ++ linecard->provisioned = true; ++ devlink_linecard_provision_set(linecard->devlink_linecard, type); ++ return 0; ++} ++ ++static void mlxsw_linecard_provision_clear(struct mlxsw_linecard *linecard) ++{ ++ linecard->provisioned = false; ++ devlink_linecard_provision_clear(linecard->devlink_linecard); ++} ++ ++static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard, ++ const char *mddq_pl) ++{ ++ enum mlxsw_reg_mddq_card_type card_type; ++ enum mlxsw_reg_mddq_ready ready; ++ bool provisioned; ++ u16 ini_version; ++ u16 hw_revision; ++ bool sr_valid; ++ u8 slot_index; ++ int err = 0; ++ bool active; ++ ++ mlxsw_reg_mddq_slot_info_unpack(mddq_pl, &slot_index, &provisioned, ++ &sr_valid, &ready, &active, ++ &hw_revision, &ini_version, ++ &card_type); ++ ++ if (linecard) { ++ if (slot_index != linecard->slot_index) ++ return -EINVAL; ++ } else { ++ if (slot_index > linecards->count) ++ return -EINVAL; ++ linecard = mlxsw_linecard_get(linecards, slot_index); ++ } ++ ++ mutex_lock(&linecard->lock); ++ ++ if (provisioned && linecard->provisioned != provisioned) { ++ err = mlxsw_linecard_provision_set(linecards, linecard, ++ card_type); ++ if (err) ++ goto out; ++ } ++ ++ if (!provisioned && linecard->provisioned != provisioned) ++ mlxsw_linecard_provision_clear(linecard); ++ ++out: ++ mutex_unlock(&linecard->lock); ++ return err; ++} ++ ++int mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, ++ const char *mddq_pl) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); ++ ++ return __mlxsw_linecard_status_process(mlxsw_core, linecards, NULL, ++ mddq_pl); ++} ++EXPORT_SYMBOL(mlxsw_linecard_status_process); ++ ++static int mlxsw_linecard_status_get_and_process(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard) ++{ ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ int err; ++ ++ mlxsw_reg_mddq_slot_info_pack(mddq_pl, linecard->slot_index, false); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddq), mddq_pl); ++ if (err) ++ return err; ++ ++ return __mlxsw_linecard_status_process(mlxsw_core, linecards, linecard, ++ mddq_pl); ++} ++ ++static int __mlxsw_linecard_fix_fsm_state(struct mlxsw_linecard *linecard) ++{ ++ dev_info(linecard->linecards->bus_info->dev, "linecard %u: Clearing FSM state error", ++ linecard->slot_index); ++ mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, ++ MLXSW_REG_MBCT_OP_CLEAR_ERRORS, 0, ++ false, false, NULL); ++ return mlxsw_reg_write(linecard->linecards->mlxsw_core, ++ MLXSW_REG(mbct), linecard->mbct_pl); ++} ++ ++static int mlxsw_linecard_fix_fsm_state(struct mlxsw_linecard *linecard, ++ enum mlxsw_reg_mbct_fsm_state fsm_state) ++{ ++ if (fsm_state != MLXSW_REG_MBCT_FSM_STATE_ERROR) ++ return 0; ++ return __mlxsw_linecard_fix_fsm_state(linecard); ++} ++ ++static int mlxsw_linecard_query_status(struct mlxsw_linecard *linecard, ++ enum mlxsw_reg_mbct_status *status, ++ enum mlxsw_reg_mbct_fsm_state *fsm_state, ++ struct netlink_ext_ack *extack) ++{ ++ bool second_try = false; ++ int err; ++ ++another_try: ++ mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, ++ MLXSW_REG_MBCT_OP_QUERY_STATUS, 0, ++ false, false, NULL); ++ err = mlxsw_reg_query(linecard->linecards->mlxsw_core, MLXSW_REG(mbct), ++ linecard->mbct_pl); ++ if (err) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to query linecard INI status"); ++ return err; ++ } ++ mlxsw_reg_mbct_unpack(linecard->mbct_pl, NULL, status, fsm_state); ++ if (!second_try && ++ (*status == MLXSW_REG_MBCT_STATUS_ILLEGAL_OPERATION || ++ *fsm_state == MLXSW_REG_MBCT_FSM_STATE_ERROR)) { ++ err = __mlxsw_linecard_fix_fsm_state(linecard); ++ if (!err) { ++ second_try = true; ++ goto another_try; ++ } ++ } ++ return err; ++} ++ ++static int ++mlxsw_linecard_provision_data(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard, ++ const struct mlxsw_linecard_ini_file *ini_file, ++ struct netlink_ext_ack *extack) ++{ ++ enum mlxsw_reg_mbct_fsm_state fsm_state; ++ enum mlxsw_reg_mbct_status status; ++ size_t size_left; ++ const u8 *data; ++ int err; ++ ++ size_left = le16_to_cpu(ini_file->size); ++ data = ini_file->data; ++ while (size_left) { ++ size_t data_size = MLXSW_REG_MBCT_DATA_LEN; ++ bool is_last = false; ++ ++ if (size_left <= MLXSW_REG_MBCT_DATA_LEN) { ++ data_size = size_left; ++ is_last = true; ++ } ++ ++ mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, ++ MLXSW_REG_MBCT_OP_DATA_TRANSFER, data_size, ++ is_last, false, data); ++ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mbct), ++ linecard->mbct_pl); ++ if (err) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to transfer linecard INI data"); ++ return err; ++ } ++ mlxsw_reg_mbct_unpack(linecard->mbct_pl, NULL, ++ &status, &fsm_state); ++ if ((!is_last && status != MLXSW_REG_MBCT_STATUS_PART_DATA) || ++ (is_last && status != MLXSW_REG_MBCT_STATUS_LAST_DATA)) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to transfer linecard INI data"); ++ mlxsw_linecard_fix_fsm_state(linecard, fsm_state); ++ return -EINVAL; ++ } ++ size_left -= data_size; ++ data += data_size; ++ } ++ ++ return 0; ++} ++ ++int mlxsw_linecard_bct_process(struct mlxsw_core *mlxsw_core, ++ const char *mbct_pl) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); ++ enum mlxsw_reg_mbct_fsm_state fsm_state; ++ enum mlxsw_reg_mbct_status status; ++ struct mlxsw_linecard *linecard; ++ u8 slot_index; ++ int err; ++ ++ mlxsw_reg_mbct_unpack(mbct_pl, &slot_index, &status, &fsm_state); ++ if (slot_index > linecards->count) ++ return -EINVAL; ++ linecard = mlxsw_linecard_get(linecards, slot_index); ++ if (status == MLXSW_REG_MBCT_STATUS_ACTIVATION_FAILED) { ++ dev_err(linecards->bus_info->dev, "linecard %u: Failed to activate INI", ++ linecard->slot_index); ++ err = -EINVAL; ++ goto fix_fsm_err_out; ++ } ++ return 0; ++ ++fix_fsm_err_out: ++ mlxsw_linecard_fix_fsm_state(linecard, fsm_state); ++ mlxsw_linecard_provision_fail(linecard); ++ return err; ++} ++EXPORT_SYMBOL(mlxsw_linecard_bct_process); ++ ++static int mlxsw_linecard_provision(struct devlink_linecard *devlink_linecard, ++ void *priv, const char *type, ++ const void *type_priv, ++ struct netlink_ext_ack *extack) ++{ ++ const struct mlxsw_linecard_ini_file *ini_file = type_priv; ++ enum mlxsw_reg_mbct_fsm_state fsm_state; ++ struct mlxsw_linecard *linecard = priv; ++ struct mlxsw_linecards *linecards; ++ enum mlxsw_reg_mbct_status status; ++ struct mlxsw_core *mlxsw_core; ++ int err; ++ ++ mutex_lock(&linecard->lock); ++ ++ linecards = linecard->linecards; ++ mlxsw_core = linecards->mlxsw_core; ++ mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, ++ MLXSW_REG_MBCT_OP_ERASE_INI_IMAGE, 0, ++ false, false, NULL); ++ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mbct), linecard->mbct_pl); ++ if (err) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to erase linecard INI"); ++ goto err_out; ++ } ++ mlxsw_reg_mbct_unpack(linecard->mbct_pl, NULL, &status, &fsm_state); ++ if (status == MLXSW_REG_MBCT_STATUS_ERASE_FAILED) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to erase linecard INI"); ++ err = -EINVAL; ++ goto fix_fsm_err_out; ++ } ++ ++ err = mlxsw_linecard_provision_data(mlxsw_core, linecards, ++ linecard, ini_file, extack); ++ if (err) ++ goto err_out; ++ ++ mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, ++ MLXSW_REG_MBCT_OP_ACTIVATE, 0, ++ false, true, NULL); ++ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mbct), linecard->mbct_pl); ++ if (err) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to activate linecard INI"); ++ goto err_out; ++ } ++ mlxsw_reg_mbct_unpack(linecard->mbct_pl, NULL, &status, &fsm_state); ++ if (status == MLXSW_REG_MBCT_STATUS_ACTIVATION_FAILED) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to activate linecard INI"); ++ goto fix_fsm_err_out; ++ } ++ ++ goto out; ++ ++fix_fsm_err_out: ++ mlxsw_linecard_fix_fsm_state(linecard, fsm_state); ++err_out: ++ mlxsw_linecard_provision_fail(linecard); ++out: ++ mutex_unlock(&linecard->lock); ++ return err; ++} ++ ++#define MLXSW_LINECARD_INI_WAIT_RETRIES 10 ++#define MLXSW_LINECARD_INI_WAIT_MS 500 ++ ++static int mlxsw_linecard_unprovision(struct devlink_linecard *devlink_linecard, ++ void *priv, ++ struct netlink_ext_ack *extack) ++{ ++ enum mlxsw_reg_mbct_fsm_state fsm_state; ++ struct mlxsw_linecard *linecard = priv; ++ struct mlxsw_linecards *linecards; ++ enum mlxsw_reg_mbct_status status; ++ unsigned int ini_wait_retries = 0; ++ struct mlxsw_core *mlxsw_core; ++ int err; ++ ++ mutex_lock(&linecard->lock); ++ ++ linecards = linecard->linecards; ++ mlxsw_core = linecard->linecards->mlxsw_core; ++ ++query_ini_status: ++ err = mlxsw_linecard_query_status(linecard, &status, ++ &fsm_state, extack); ++ if (err) ++ goto err_out; ++ ++ switch (fsm_state) { ++ case MLXSW_REG_MBCT_FSM_STATE_INI_IN_USE: ++ if (ini_wait_retries++ > MLXSW_LINECARD_INI_WAIT_RETRIES) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to wait for linecard INI to be not used"); ++ goto err_out; ++ } ++ mdelay(MLXSW_LINECARD_INI_WAIT_MS); ++ goto query_ini_status; ++ default: ++ break; ++ } ++ ++ mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, ++ MLXSW_REG_MBCT_OP_ERASE_INI_IMAGE, 0, ++ false, false, NULL); ++ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mbct), ++ linecard->mbct_pl); ++ if (err) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to erase linecard INI"); ++ goto err_out; ++ } ++ mlxsw_reg_mbct_unpack(linecard->mbct_pl, NULL, &status, &fsm_state); ++ switch (status) { ++ case MLXSW_REG_MBCT_STATUS_ERASE_COMPLETE: ++ break; ++ default: ++ /* Should not happen */ ++ fallthrough; ++ case MLXSW_REG_MBCT_STATUS_ERASE_FAILED: ++ NL_SET_ERR_MSG_MOD(extack, "Failed to erase linecard INI"); ++ goto fix_fsm_err_out; ++ case MLXSW_REG_MBCT_STATUS_ERROR_INI_IN_USE: ++ NL_SET_ERR_MSG_MOD(extack, "Failed to erase linecard INI while being used"); ++ goto fix_fsm_err_out; ++ } ++ goto out; ++ ++fix_fsm_err_out: ++ mlxsw_linecard_fix_fsm_state(linecard, fsm_state); ++err_out: ++ mlxsw_linecard_provision_fail(linecard); ++out: ++ mutex_unlock(&linecard->lock); ++ return err; ++} ++ ++static unsigned int ++mlxsw_linecard_types_count(struct devlink_linecard *devlink_linecard, ++ void *priv) ++{ ++ struct mlxsw_linecard *linecard = priv; ++ ++ return linecard->linecards->types_info->count; ++} ++ ++static void mlxsw_linecard_types_get(struct devlink_linecard *devlink_linecard, ++ void *priv, unsigned int index, ++ const char **type, const void **type_priv) ++{ ++ struct mlxsw_linecard_types_info *types_info; ++ struct mlxsw_linecard_ini_file *ini_file; ++ struct mlxsw_linecard *linecard = priv; ++ ++ types_info = linecard->linecards->types_info; ++ ini_file = types_info->ini_files[index]; ++ *type = ini_file->format.name; ++ *type_priv = ini_file; ++} ++ ++static const struct devlink_linecard_ops mlxsw_linecard_ops = { ++ .provision = mlxsw_linecard_provision, ++ .unprovision = mlxsw_linecard_unprovision, ++ .types_count = mlxsw_linecard_types_count, ++ .types_get = mlxsw_linecard_types_get, ++}; ++ ++static int mlxsw_linecard_init(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ u8 slot_index) ++{ ++ struct devlink_linecard *devlink_linecard; ++ struct mlxsw_linecard *linecard; ++ int err; ++ ++ linecard = mlxsw_linecard_get(linecards, slot_index); ++ linecard->slot_index = slot_index; ++ linecard->linecards = linecards; ++ mutex_init(&linecard->lock); ++ ++ devlink_linecard = devlink_linecard_create(priv_to_devlink(mlxsw_core), ++ slot_index, &mlxsw_linecard_ops, ++ linecard); ++ if (IS_ERR(devlink_linecard)) ++ return PTR_ERR(devlink_linecard); ++ linecard->devlink_linecard = devlink_linecard; ++ ++ err = mlxsw_linecard_status_get_and_process(mlxsw_core, linecards, ++ linecard); ++ if (err) ++ goto err_status_get_and_process; ++ ++ return 0; ++ ++err_status_get_and_process: ++ devlink_linecard_destroy(linecard->devlink_linecard); ++ return err; ++} ++ ++static int mlxsw_linecard_event_delivery_set(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard, ++ bool enable) ++{ ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ ++ mlxsw_reg_mddq_slot_info_pack(mddq_pl, linecard->slot_index, enable); ++ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddq), mddq_pl); ++} ++ ++static int mlxsw_linecard_post_init(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ u8 slot_index) ++{ ++ struct mlxsw_linecard *linecard; ++ int err; ++ ++ linecard = mlxsw_linecard_get(linecards, slot_index); ++ linecard->slot_index = slot_index; ++ ++ err = mlxsw_linecard_event_delivery_set(mlxsw_core, linecard, true); ++ if (err) ++ return err; ++ ++ err = mlxsw_linecard_status_get_and_process(mlxsw_core, linecards, ++ linecard); ++ if (err) ++ goto err_status_get_and_process; ++ ++ return 0; ++ ++err_status_get_and_process: ++ mlxsw_linecard_event_delivery_set(mlxsw_core, linecard, false); ++ return err; ++} ++ ++static void mlxsw_linecard_pre_fini(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ u8 slot_index) ++{ ++ struct mlxsw_linecard *linecard; ++ ++ linecard = mlxsw_linecard_get(linecards, slot_index); ++ mlxsw_linecard_event_delivery_set(mlxsw_core, linecard, false); ++} ++ ++static void mlxsw_linecard_fini(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ u8 slot_index) ++{ ++ struct mlxsw_linecard *linecard; ++ ++ linecard = mlxsw_linecard_get(linecards, slot_index); ++ devlink_linecard_destroy(linecard->devlink_linecard); ++ mutex_destroy(&linecard->lock); ++} ++ ++#define MLXSW_LINECARDS_INI_BUNDLE_MINOR 2008 ++#define MLXSW_LINECARDS_INI_BUNDLE_MINOR_SUBMINOR 9999 ++#define MLXSW_LINECARDS_INI_BUNDLE_FILE \ ++ "mellanox/lc_ini_bundle_" \ ++ __stringify(MLXSW_LINECARDS_INI_BUNDLE_MINOR) "_" \ ++ __stringify(MLXSW_LINECARDS_INI_BUNDLE_MINOR_SUBMINOR) ".bin" ++#define MLXSW_LINECARDS_INI_BUNDLE_MAGIC "NVLCINI+" ++ ++static int mlxsw_linecard_types_init(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards) ++{ ++ struct mlxsw_linecard_types_info *types_info; ++ struct mlxsw_linecard_ini_file *ini_file; ++ const struct firmware *firmware; ++ unsigned int count; ++ u16 ini_file_size; ++ size_t magic_size; ++ const u8 *data; ++ size_t size; ++ int err; ++ ++ types_info = kzalloc(sizeof(*types_info), GFP_KERNEL); ++ if (!types_info) ++ return -ENOMEM; ++ linecards->types_info = types_info; ++ return 0; /* Skip for non-upstream flow. */ ++ err = request_firmware_direct(&firmware, ++ MLXSW_LINECARDS_INI_BUNDLE_FILE, ++ linecards->bus_info->dev); ++ if (err) { ++ dev_warn(linecards->bus_info->dev, "Could not request linecards INI file \"" MLXSW_LINECARDS_INI_BUNDLE_FILE "\", provisioning will not be possible\n"); ++ return 0; ++ } ++ ++ types_info->data_size = firmware->size; ++ types_info->data = kmemdup(firmware->data, firmware->size, GFP_KERNEL); ++ release_firmware(firmware); ++ if (!types_info->data) { ++ err = -ENOMEM; ++ goto free_types_info; ++ } ++ ++ data = types_info->data; ++ size = types_info->data_size; ++ magic_size = strlen(MLXSW_LINECARDS_INI_BUNDLE_MAGIC); ++ ++ if (size < magic_size || ++ memcmp(data, MLXSW_LINECARDS_INI_BUNDLE_MAGIC, magic_size)) ++ goto incorrect_inis_file_format; ++ data += magic_size; ++ size -= magic_size; ++ count = 0; ++ ++ while (size > 0) { ++ if (size < sizeof(*ini_file)) ++ goto incorrect_inis_file_format; ++ ini_file = (struct mlxsw_linecard_ini_file *) data; ++ ini_file_size = le16_to_cpu(ini_file->size); ++ if (ini_file_size > size || ini_file_size % 4) ++ goto incorrect_inis_file_format; ++ data += ini_file_size + sizeof(__le16); ++ size -= ini_file_size + sizeof(__le16); ++ count++; ++ } ++ if (size) ++ goto incorrect_inis_file_format; ++ ++ types_info->ini_files = kmalloc_array(count, sizeof(ini_file), ++ GFP_KERNEL); ++ if (!types_info->ini_files) { ++ err = -ENOMEM; ++ goto free_types_info; ++ } ++ ++ data = types_info->data + magic_size; ++ size = types_info->data_size - magic_size; ++ count = 0; ++ ++ while (size) { ++ int i; ++ ++ ini_file = (struct mlxsw_linecard_ini_file *) data; ++ ini_file_size = le16_to_cpu(ini_file->size); ++ for (i = 0; i < ini_file_size / 4; i++) { ++ u32 *val = &((u32 *) ini_file->data)[i]; ++ ++ *val = swab32(*val); ++ } ++ types_info->ini_files[count] = ini_file; ++ data += ini_file_size + sizeof(__le16); ++ size -= ini_file_size + sizeof(__le16); ++ count++; ++ } ++ ++ types_info->count = count; ++ return 0; ++ ++incorrect_inis_file_format: ++ dev_warn(linecards->bus_info->dev, "Incorrect linecards INIs file format, provisioning will not be possible\n"); ++ return 0; ++ ++free_types_info: ++ kfree(types_info); ++ return err; ++} ++ ++static void mlxsw_linecard_types_fini(struct mlxsw_linecards *linecards) ++{ ++ struct mlxsw_linecard_types_info *types_info = linecards->types_info; ++ ++ kfree(types_info->ini_files); ++ kfree(types_info->data); ++ kfree(types_info); ++} ++ ++int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core, ++ const struct mlxsw_bus_info *bus_info, ++ struct mlxsw_linecards **p_linecards) ++{ ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; ++ struct mlxsw_linecards *linecards; ++ u8 slot_count; ++ int err; ++ int i; ++ ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, ++ NULL, &slot_count); ++ if (!slot_count) { ++ *p_linecards = NULL; ++ return 0; ++ } ++ ++ linecards = kzalloc(struct_size(linecards, linecards, slot_count), ++ GFP_KERNEL); ++ if (!linecards) ++ return -ENOMEM; ++ linecards->count = slot_count; ++ linecards->mlxsw_core = mlxsw_core; ++ linecards->bus_info = bus_info; ++ ++ linecards->wq = alloc_workqueue("mlxsw_linecards", 0, 0); ++ if (!linecards->wq) { ++ err = ENOMEM; ++ goto err_wq_alloc; ++ } ++ ++ err = mlxsw_linecard_types_init(mlxsw_core, linecards); ++ if (err) ++ goto err_types_init; ++ ++ for (i = 0; i < linecards->count; i++) { ++ err = mlxsw_linecard_init(mlxsw_core, linecards, i + 1); ++ if (err) ++ goto err_linecard_init; ++ } ++ ++ *p_linecards = linecards; ++ ++ return 0; ++ ++err_linecard_init: ++ for (i--; i >= 0; i--) ++ mlxsw_linecard_fini(mlxsw_core, linecards, i + 1); ++err_types_init: ++ destroy_workqueue(linecards->wq); ++err_wq_alloc: ++ kfree(linecards); ++ ++ return err; ++} ++ ++int mlxsw_linecards_post_init(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards) ++{ ++ int err; ++ int i; ++ ++ if (!linecards) ++ return 0; ++ ++ for (i = 0; i < linecards->count; i++) { ++ err = mlxsw_linecard_post_init(mlxsw_core, linecards, i + 1); ++ if (err) ++ goto err_linecard_post_init; ++ } ++ return 0; ++ ++err_linecard_post_init: ++ for (i--; i >= 0; i--) ++ mlxsw_linecard_pre_fini(mlxsw_core, linecards, i + 1); ++ ++ return err; ++} ++ ++void mlxsw_linecards_pre_fini(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards) ++{ ++ int i; ++ ++ if (!linecards) ++ return; ++ for (i = 0; i < linecards->count; i++) ++ mlxsw_linecard_pre_fini(mlxsw_core, linecards, i + 1); ++ /* Make sure all scheduled events are processed */ ++ mlxsw_core_flush_owq(); ++} ++ ++void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards) ++{ ++ int i; ++ ++ if (!linecards) ++ return; ++ for (i = 0; i < linecards->count; i++) ++ mlxsw_linecard_fini(mlxsw_core, linecards, i + 1); ++ mlxsw_linecard_types_fini(linecards); ++ destroy_workqueue(linecards->wq); ++ kfree(linecards); ++} ++ ++MODULE_FIRMWARE(MLXSW_LINECARDS_INI_BUNDLE_FILE); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +index e0424f490c6f..bc233a5c8a79 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -2076,6 +2076,72 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg, + } + } + ++struct mlxsw_sp_linecard_status_event { ++ struct mlxsw_core *mlxsw_core; ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ struct work_struct work; ++}; ++ ++static void mlxsw_sp_linecard_status_event_work(struct work_struct *work) ++{ ++ struct mlxsw_sp_linecard_status_event *event; ++ struct mlxsw_core *mlxsw_core; ++ ++ event = container_of(work, struct mlxsw_sp_linecard_status_event, work); ++ mlxsw_core = event->mlxsw_core; ++ mlxsw_linecard_status_process(mlxsw_core, event->mddq_pl); ++ kfree(event); ++} ++ ++static void ++mlxsw_sp_linecard_status_listener_func(const struct mlxsw_reg_info *reg, ++ char *mddq_pl, void *priv) ++{ ++ struct mlxsw_sp_linecard_status_event *event; ++ struct mlxsw_sp *mlxsw_sp = priv; ++ ++ event = kmalloc(sizeof(*event), GFP_ATOMIC); ++ if (!event) ++ return; ++ event->mlxsw_core = mlxsw_sp->core; ++ memcpy(event->mddq_pl, mddq_pl, sizeof(event->mddq_pl)); ++ INIT_WORK(&event->work, mlxsw_sp_linecard_status_event_work); ++ mlxsw_core_schedule_work(&event->work); ++} ++ ++struct mlxsw_sp_linecard_bct_event { ++ struct mlxsw_core *mlxsw_core; ++ char mbct_pl[MLXSW_REG_MBCT_LEN]; ++ struct work_struct work; ++}; ++ ++static void mlxsw_sp_linecard_bct_event_work(struct work_struct *work) ++{ ++ struct mlxsw_sp_linecard_bct_event *event; ++ struct mlxsw_core *mlxsw_core; ++ ++ event = container_of(work, struct mlxsw_sp_linecard_bct_event, work); ++ mlxsw_core = event->mlxsw_core; ++ mlxsw_linecard_bct_process(mlxsw_core, event->mbct_pl); ++ kfree(event); ++} ++ ++static void ++mlxsw_sp_linecard_bct_listener_func(const struct mlxsw_reg_info *reg, ++ char *mbct_pl, void *priv) ++{ ++ struct mlxsw_sp_linecard_bct_event *event; ++ struct mlxsw_sp *mlxsw_sp = priv; ++ ++ event = kmalloc(sizeof(*event), GFP_ATOMIC); ++ if (!event) ++ return; ++ event->mlxsw_core = mlxsw_sp->core; ++ memcpy(event->mbct_pl, mbct_pl, sizeof(event->mbct_pl)); ++ INIT_WORK(&event->work, mlxsw_sp_linecard_bct_event_work); ++ mlxsw_core_schedule_work(&event->work); ++} ++ + static void mlxsw_sp1_ptp_fifo_event_func(struct mlxsw_sp *mlxsw_sp, + char *mtpptr_pl, bool ingress) + { +@@ -2206,6 +2272,8 @@ void mlxsw_sp_sample_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, + static const struct mlxsw_listener mlxsw_sp_listener[] = { + /* Events */ + MLXSW_SP_EVENTL(mlxsw_sp_pude_event_func, PUDE), ++ MLXSW_SP_EVENTL(mlxsw_sp_linecard_status_listener_func, DSDSC), ++ MLXSW_SP_EVENTL(mlxsw_sp_linecard_bct_listener_func, BCTOE), + /* L2 traps */ + MLXSW_SP_RXL_NO_MARK(FID_MISS, TRAP_TO_CPU, FID_MISS, false), + /* L3 traps */ +diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h +index 57f9e24602d0..f3e522de2f68 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/trap.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h +@@ -132,6 +132,12 @@ enum mlxsw_event_trap_id { + MLXSW_TRAP_ID_PTP_ING_FIFO = 0x2D, + /* PTP Egress FIFO has a new entry */ + MLXSW_TRAP_ID_PTP_EGR_FIFO = 0x2E, ++ /* Downstream Device Status Change */ ++ MLXSW_TRAP_ID_DSDSC = 0x321, ++ /* Binary Code Transfer Operation Executed Event */ ++ MLXSW_TRAP_ID_BCTOE = 0x322, ++ /* Port mapping change */ ++ MLXSW_TRAP_ID_PMLPE = 0x32E, + }; + + #endif /* _MLXSW_TRAP_H */ +-- +2.20.1 + diff --git a/patch/0136-mlxsw-core_linecards-Implement-line-card-activation-.patch b/patch/0136-mlxsw-core_linecards-Implement-line-card-activation-.patch new file mode 100644 index 000000000..50e93d73a --- /dev/null +++ b/patch/0136-mlxsw-core_linecards-Implement-line-card-activation-.patch @@ -0,0 +1,206 @@ +From e7379493c9f7e30f7d20459ed07a435095e9a889 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 22 Jan 2021 14:45:06 +0100 +Subject: [PATCH backport 5.10 136/182] mlxsw: core_linecards: Implement line + card activation process + +Allow to process events generated upon line card getting "ready" and +"active". + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/core.h | 3 + + .../ethernet/mellanox/mlxsw/core_linecards.c | 85 +++++++++++++++++-- + 2 files changed, 80 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index d3c5d8289a85..ecd91bb8ca77 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -521,6 +521,9 @@ struct mlxsw_linecard { + char read_name[MLXSW_REG_MDDQ_SLOT_ACII_NAME_LEN]; + char mbct_pl[MLXSW_REG_MBCT_LEN]; /* too big for stack */ + bool provisioned; ++ bool ready; ++ bool active; ++ bool unprovision_done; + }; + + struct mlxsw_linecard_types_info; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +index a324ce2436e8..134437f49219 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +@@ -67,6 +67,8 @@ static const char *mlxsw_linecard_type_name(struct mlxsw_linecard *linecard) + static void mlxsw_linecard_provision_fail(struct mlxsw_linecard *linecard) + { + linecard->provisioned = false; ++ linecard->ready = false; ++ linecard->active = false; + devlink_linecard_provision_fail(linecard->devlink_linecard); + } + +@@ -94,10 +96,51 @@ static void mlxsw_linecard_provision_clear(struct mlxsw_linecard *linecard) + devlink_linecard_provision_clear(linecard->devlink_linecard); + } + ++static int mlxsw_linecard_ready_set(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard) ++{ ++ char mddc_pl[MLXSW_REG_MDDC_LEN]; ++ int err; ++ ++ mlxsw_reg_mddc_pack(mddc_pl, linecard->slot_index, false, true); ++ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddc), mddc_pl); ++ if (err) ++ return err; ++ linecard->ready = true; ++ return 0; ++} ++ ++static int mlxsw_linecard_ready_clear(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard) ++{ ++ char mddc_pl[MLXSW_REG_MDDC_LEN]; ++ int err; ++ ++ mlxsw_reg_mddc_pack(mddc_pl, linecard->slot_index, false, false); ++ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddc), mddc_pl); ++ if (err) ++ return err; ++ linecard->ready = false; ++ return 0; ++} ++ ++static void mlxsw_linecard_active_set(struct mlxsw_linecard *linecard) ++{ ++ linecard->active = true; ++ devlink_linecard_activate(linecard->devlink_linecard); ++} ++ ++static void mlxsw_linecard_active_clear(struct mlxsw_linecard *linecard) ++{ ++ linecard->active = false; ++ devlink_linecard_deactivate(linecard->devlink_linecard); ++} ++ + static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecards *linecards, + struct mlxsw_linecard *linecard, +- const char *mddq_pl) ++ const char *mddq_pl, ++ bool process_provision_only) + { + enum mlxsw_reg_mddq_card_type card_type; + enum mlxsw_reg_mddq_ready ready; +@@ -132,6 +175,27 @@ static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + goto out; + } + ++ if (!process_provision_only && !linecard->unprovision_done && ++ ready == MLXSW_REG_MDDQ_READY_READY && !linecard->ready) { ++ err = mlxsw_linecard_ready_set(mlxsw_core, linecard); ++ if (err) ++ goto out; ++ } ++ ++ if (!process_provision_only && !linecard->unprovision_done && active && ++ linecard->active != active && linecard->ready) ++ mlxsw_linecard_active_set(linecard); ++ ++ if (!process_provision_only && !active && linecard->active != active) ++ mlxsw_linecard_active_clear(linecard); ++ ++ if (!process_provision_only && ready != MLXSW_REG_MDDQ_READY_READY && ++ linecard->ready) { ++ err = mlxsw_linecard_ready_clear(mlxsw_core, linecard); ++ if (err) ++ goto out; ++ } ++ + if (!provisioned && linecard->provisioned != provisioned) + mlxsw_linecard_provision_clear(linecard); + +@@ -146,13 +210,14 @@ int mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); + + return __mlxsw_linecard_status_process(mlxsw_core, linecards, NULL, +- mddq_pl); ++ mddq_pl, false); + } + EXPORT_SYMBOL(mlxsw_linecard_status_process); + + static int mlxsw_linecard_status_get_and_process(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecards *linecards, +- struct mlxsw_linecard *linecard) ++ struct mlxsw_linecard *linecard, ++ bool process_provision_only) + { + char mddq_pl[MLXSW_REG_MDDQ_LEN]; + int err; +@@ -163,7 +228,7 @@ static int mlxsw_linecard_status_get_and_process(struct mlxsw_core *mlxsw_core, + return err; + + return __mlxsw_linecard_status_process(mlxsw_core, linecards, linecard, +- mddq_pl); ++ mddq_pl, process_provision_only); + } + + static int __mlxsw_linecard_fix_fsm_state(struct mlxsw_linecard *linecard) +@@ -308,6 +373,7 @@ static int mlxsw_linecard_provision(struct devlink_linecard *devlink_linecard, + + mutex_lock(&linecard->lock); + ++ linecard->unprovision_done = false; + linecards = linecard->linecards; + mlxsw_core = linecards->mlxsw_core; + mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, +@@ -416,6 +482,7 @@ static int mlxsw_linecard_unprovision(struct devlink_linecard *devlink_linecard, + NL_SET_ERR_MSG_MOD(extack, "Failed to erase linecard INI while being used"); + goto fix_fsm_err_out; + } ++ linecard->unprovision_done = true; + goto out; + + fix_fsm_err_out: +@@ -478,7 +545,7 @@ static int mlxsw_linecard_init(struct mlxsw_core *mlxsw_core, + linecard->devlink_linecard = devlink_linecard; + + err = mlxsw_linecard_status_get_and_process(mlxsw_core, linecards, +- linecard); ++ linecard, true); + if (err) + goto err_status_get_and_process; + +@@ -514,7 +581,7 @@ static int mlxsw_linecard_post_init(struct mlxsw_core *mlxsw_core, + return err; + + err = mlxsw_linecard_status_get_and_process(mlxsw_core, linecards, +- linecard); ++ linecard, false); + if (err) + goto err_status_get_and_process; + +@@ -533,6 +600,10 @@ static void mlxsw_linecard_pre_fini(struct mlxsw_core *mlxsw_core, + + linecard = mlxsw_linecard_get(linecards, slot_index); + mlxsw_linecard_event_delivery_set(mlxsw_core, linecard, false); ++ /* Make sure all scheduled events are processed */ ++ mlxsw_core_flush_owq(); ++ if (linecard->active) ++ mlxsw_linecard_active_clear(linecard); + } + + static void mlxsw_linecard_fini(struct mlxsw_core *mlxsw_core, +@@ -754,8 +825,6 @@ void mlxsw_linecards_pre_fini(struct mlxsw_core *mlxsw_core, + return; + for (i = 0; i < linecards->count; i++) + mlxsw_linecard_pre_fini(mlxsw_core, linecards, i + 1); +- /* Make sure all scheduled events are processed */ +- mlxsw_core_flush_owq(); + } + + void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core, +-- +2.20.1 + diff --git a/patch/0137-mlxsw-core-Extend-driver-ops-by-remove-selected-port.patch b/patch/0137-mlxsw-core-Extend-driver-ops-by-remove-selected-port.patch new file mode 100644 index 000000000..77348d45f --- /dev/null +++ b/patch/0137-mlxsw-core-Extend-driver-ops-by-remove-selected-port.patch @@ -0,0 +1,99 @@ +From a0e62e8df42c4ae6eabba2ea0c2d076d8c8d06fb Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 22 Dec 2021 16:26:43 +0000 +Subject: [PATCH backport 5.10 137/182] mlxsw: core: Extend driver ops by + remove selected ports op + +In case of line card implementation, the core has to have a way to +remove relevant ports manually. Extend the Spectrum driver ops by an op +that implements port removal of selected ports upon request. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 9 +++++++++ + drivers/net/ethernet/mellanox/mlxsw/core.h | 8 ++++++++ + drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 15 +++++++++++++++ + 3 files changed, 32 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 246db548f011..2b4f9844b1d6 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -2870,6 +2870,15 @@ mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core, + } + EXPORT_SYMBOL(mlxsw_core_port_devlink_port_get); + ++void mlxsw_core_ports_remove_selected(struct mlxsw_core *mlxsw_core, ++ bool (*selector)(void *priv, u16 local_port), ++ void *priv) ++{ ++ if (WARN_ON(!mlxsw_core->driver->ports_remove_selected)) ++ return; ++ mlxsw_core->driver->ports_remove_selected(mlxsw_core, selector, priv); ++} ++ + struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core) + { + return mlxsw_core->env; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index ecd91bb8ca77..70f97ef74a2c 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -223,6 +223,10 @@ enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core, + struct devlink_port * + mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core, + u8 local_port); ++void mlxsw_core_ports_remove_selected(struct mlxsw_core *mlxsw_core, ++ bool (*selector)(void *priv, ++ u16 local_port), ++ void *priv); + struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core); + int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module); + +@@ -296,6 +300,10 @@ struct mlxsw_driver { + unsigned int count, struct netlink_ext_ack *extack); + int (*port_unsplit)(struct mlxsw_core *mlxsw_core, u8 local_port, + struct netlink_ext_ack *extack); ++ void (*ports_remove_selected)(struct mlxsw_core *mlxsw_core, ++ bool (*selector)(void *priv, ++ u16 local_port), ++ void *priv); + int (*sb_pool_get)(struct mlxsw_core *mlxsw_core, + unsigned int sb_index, u16 pool_index, + struct devlink_sb_pool_info *pool_info); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +index bc233a5c8a79..82acff318dcd 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -1736,6 +1736,20 @@ static void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp) + mlxsw_sp->ports = NULL; + } + ++static void ++mlxsw_sp_ports_remove_selected(struct mlxsw_core *mlxsw_core, ++ bool (*selector)(void *priv, u16 local_port), ++ void *priv) ++{ ++ struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); ++ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_core); ++ int i; ++ ++ for (i = 1; i < max_ports; i++) ++ if (mlxsw_sp_port_created(mlxsw_sp, i) && selector(priv, i)) ++ mlxsw_sp_port_remove(mlxsw_sp, i); ++} ++ + static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp) + { + unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); +@@ -3370,6 +3384,7 @@ static struct mlxsw_driver mlxsw_sp3_driver = { + .basic_trap_groups_set = mlxsw_sp_basic_trap_groups_set, + .port_split = mlxsw_sp_port_split, + .port_unsplit = mlxsw_sp_port_unsplit, ++ .ports_remove_selected = mlxsw_sp_ports_remove_selected, + .sb_pool_get = mlxsw_sp_sb_pool_get, + .sb_pool_set = mlxsw_sp_sb_pool_set, + .sb_port_pool_get = mlxsw_sp_sb_port_pool_get, +-- +2.20.1 + diff --git a/patch/0138-mlxsw-spectrum-Add-port-to-linecard-mapping.patch b/patch/0138-mlxsw-spectrum-Add-port-to-linecard-mapping.patch new file mode 100644 index 000000000..5a56db150 --- /dev/null +++ b/patch/0138-mlxsw-spectrum-Add-port-to-linecard-mapping.patch @@ -0,0 +1,153 @@ +From 718b7aec4ec4c7e3c327b2ffbf43b27126688836 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 3 Jan 2022 11:22:42 +0000 +Subject: [PATCH backport 5.10 138/182] mlxsw: spectrum: Add port to linecard + mapping + +For each port get slot_index using PMLP register. For ports residing +on a linecard, identify it with the linecard by setting mapping +using devlink_port_linecard_set() helper. Use linecard slot index for +PMTDB register queries. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 18 ++++++++++++++---- + drivers/net/ethernet/mellanox/mlxsw/core.h | 3 ++- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/switchib.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 2 +- + 6 files changed, 20 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 2b4f9844b1d6..68ef007ac48c 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -48,6 +48,7 @@ struct mlxsw_core_port { + struct devlink_port devlink_port; + void *port_driver_priv; + u8 local_port; ++ struct mlxsw_linecard *linecard; + }; + + void *mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port) +@@ -2723,7 +2724,7 @@ EXPORT_SYMBOL(mlxsw_core_res_get); + + static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port, + enum devlink_port_flavour flavour, +- u32 port_number, bool split, ++ u8 slot_index, u32 port_number, bool split, + u32 split_port_subnumber, + bool splittable, u32 lanes, + const unsigned char *switch_id, +@@ -2746,6 +2747,15 @@ static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port, + attrs.switch_id.id_len = switch_id_len; + mlxsw_core_port->local_port = local_port; + devlink_port_attrs_set(devlink_port, &attrs); ++ if (slot_index) { ++ struct mlxsw_linecard *linecard; ++ ++ linecard = mlxsw_linecard_get(mlxsw_core->linecards, ++ slot_index); ++ mlxsw_core_port->linecard = linecard; ++ devlink_port_linecard_set(devlink_port, ++ linecard->devlink_linecard); ++ } + err = devlink_port_register(devlink, devlink_port, local_port); + if (err) + memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port)); +@@ -2763,14 +2773,14 @@ static void __mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port) + } + + int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port, +- u32 port_number, bool split, ++ u8 slot_index, u32 port_number, bool split, + u32 split_port_subnumber, + bool splittable, u32 lanes, + const unsigned char *switch_id, + unsigned char switch_id_len) + { + return __mlxsw_core_port_init(mlxsw_core, local_port, +- DEVLINK_PORT_FLAVOUR_PHYSICAL, ++ DEVLINK_PORT_FLAVOUR_PHYSICAL, slot_index, + port_number, split, split_port_subnumber, + splittable, lanes, + switch_id, switch_id_len); +@@ -2794,7 +2804,7 @@ int mlxsw_core_cpu_port_init(struct mlxsw_core *mlxsw_core, + + err = __mlxsw_core_port_init(mlxsw_core, MLXSW_PORT_CPU_PORT, + DEVLINK_PORT_FLAVOUR_CPU, +- 0, false, 0, false, 0, ++ 0, 0, false, 0, false, 0, + switch_id, switch_id_len); + if (err) + return err; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 70f97ef74a2c..8e738ddb39c8 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -202,7 +202,8 @@ void mlxsw_core_lag_mapping_clear(struct mlxsw_core *mlxsw_core, + + void *mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port); + int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port, +- u32 port_number, bool split, u32 split_port_subnumber, ++ u8 slot_index, u32 port_number, bool split, ++ u32 split_port_subnumber, + bool splittable, u32 lanes, + const unsigned char *switch_id, + unsigned char switch_id_len); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 104f1ba0242f..30925f57362e 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -210,7 +210,7 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) + struct net_device *dev; + int err; + +- err = mlxsw_core_port_init(mlxsw_m->core, local_port, ++ err = mlxsw_core_port_init(mlxsw_m->core, local_port, 0, + module + 1, false, 0, false, + 0, mlxsw_m->base_mac, + sizeof(mlxsw_m->base_mac)); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +index 82acff318dcd..c87267d002c6 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -1399,7 +1399,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, + int err; + + splittable = lanes > 1 && !split; +- err = mlxsw_core_port_init(mlxsw_sp->core, local_port, ++ err = mlxsw_core_port_init(mlxsw_sp->core, local_port, 0, + port_mapping->module + 1, split, + port_mapping->lane / lanes, + splittable, lanes, +diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchib.c b/drivers/net/ethernet/mellanox/mlxsw/switchib.c +index 1e561132eb1e..090b9a103c04 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/switchib.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/switchib.c +@@ -280,7 +280,7 @@ static int mlxsw_sib_port_create(struct mlxsw_sib *mlxsw_sib, u8 local_port, + { + int err; + +- err = mlxsw_core_port_init(mlxsw_sib->core, local_port, ++ err = mlxsw_core_port_init(mlxsw_sib->core, local_port, 0, + module + 1, false, 0, false, 0, + mlxsw_sib->hw_id, sizeof(mlxsw_sib->hw_id)); + if (err) { +diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +index 131b2a53d261..bf8a54776861 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +@@ -1085,7 +1085,7 @@ static int mlxsw_sx_port_eth_create(struct mlxsw_sx *mlxsw_sx, u8 local_port, + { + int err; + +- err = mlxsw_core_port_init(mlxsw_sx->core, local_port, ++ err = mlxsw_core_port_init(mlxsw_sx->core, local_port, 0, + module + 1, false, 0, false, 0, + mlxsw_sx->hw_id, sizeof(mlxsw_sx->hw_id)); + if (err) { +-- +2.20.1 + diff --git a/patch/0139-mlxsw-reg-Introduce-Management-Temperature-Extended-.patch b/patch/0139-mlxsw-reg-Introduce-Management-Temperature-Extended-.patch new file mode 100644 index 000000000..8f7fc94e0 --- /dev/null +++ b/patch/0139-mlxsw-reg-Introduce-Management-Temperature-Extended-.patch @@ -0,0 +1,105 @@ +From 44b270551552a48c2a0799f1660b7bfdd0c10519 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 12 May 2021 22:57:37 +0300 +Subject: [PATCH backport 5.10 139/182] mlxsw: reg: Introduce Management + Temperature Extended Capabilities Register + +Introduce new register MTECR (Management Temperature Extended +Capabilities Register). This register exposes the capabilities of the +device and system temperature sensing. It provides information for +all possible temperature sensors that are on the system. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 67 +++++++++++++++++++++++ + 1 file changed, 67 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index e060f054e0a9..5757c4f40277 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10296,6 +10296,72 @@ mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, + *num_of_slots = mlxsw_reg_mgpir_num_of_slots_get(payload); + } + ++/* MTECR - Management Temperature Extended Capabilities Register ++ * ------------------------------------------------------------- ++ * MTECR register exposes the capabilities of the device and system ++ * temperature sensing. ++ */ ++#define MLXSW_REG_MTECR_ID 0x9109 ++#define MLXSW_REG_MTECR_LEN 0x60 ++#define MLXSW_REG_MTECR_SENSOR_MAP_LEN 0x58 ++ ++MLXSW_REG_DEFINE(mtecr, MLXSW_REG_MTECR_ID, MLXSW_REG_MTECR_LEN); ++ ++/* reg_mtecr_last_sensor. ++ * Last sensor index that is available in the system to read from. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mtecr, last_sensor, 0x00, 16, 12); ++ ++/* reg_mtecr_sensor_count. ++ * Number of sensors supported by the device. ++ * This includes the ASIC, ambient sensors, Gearboxes etc. ++ * QSFP module sensors are not included. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mtecr, sensor_count, 0x00, 0, 12); ++ ++/* reg_mtecr_slot_index. ++ * Slot index (0: Main board). ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mtecr, slot_index, 0x04, 28, 4); ++ ++/* reg_mtecr_internal_sensor_count. ++ * Number of sensors supported by the device that are in the ASIC. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mtecr, internal_sensor_count, 0x04, 0, 7); ++ ++/* reg_mtecr_sensor_map. ++ * Mapping of system sensors supported by the device. Each bit represents a ++ * sensor. This field is size variable based on the last_sensor field and in ++ * granularity of 32 bits. ++ * 0: Not connected or not supported ++ * 1: Supports temperature measurements ++ * ++ */ ++MLXSW_ITEM_BIT_ARRAY(reg, mtecr, sensor_map, 0x08, MLXSW_REG_MTECR_SENSOR_MAP_LEN, 1); ++ ++static inline void mlxsw_reg_mtecr_pack(char *payload, u8 slot_index) ++{ ++ MLXSW_REG_ZERO(mtecr, payload); ++ mlxsw_reg_mtecr_slot_index_set(payload, slot_index); ++} ++ ++static inline void mlxsw_reg_mtecr_unpack(char *payload, u16 *sensor_count, ++ u16 *last_sensor, ++ u8 *internal_sensor_count) ++{ ++ if (sensor_count) ++ *sensor_count = mlxsw_reg_mtecr_sensor_count_get(payload); ++ if (last_sensor) ++ *last_sensor = mlxsw_reg_mtecr_last_sensor_get(payload); ++ if (internal_sensor_count) ++ *internal_sensor_count = ++ mlxsw_reg_mtecr_internal_sensor_count_get(payload); ++} ++ + /* MBCT - Management Binary Code Transfer Register + * ----------------------------------------------- + * This register allows to transfer binary codes from the Host to +@@ -11883,6 +11949,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { + MLXSW_REG(mtptpt), + MLXSW_REG(mfgd), + MLXSW_REG(mgpir), ++ MLXSW_REG(mtecr), + MLXSW_REG(mbct), + MLXSW_REG(mddq), + MLXSW_REG(mddc), +-- +2.20.1 + diff --git a/patch/0140-mlxsw-core-Add-APIs-for-thermal-sensor-mapping.patch b/patch/0140-mlxsw-core-Add-APIs-for-thermal-sensor-mapping.patch new file mode 100644 index 000000000..35b85c12d --- /dev/null +++ b/patch/0140-mlxsw-core-Add-APIs-for-thermal-sensor-mapping.patch @@ -0,0 +1,114 @@ +From 3614c1e72e48e03c64ce88d269d97ee4743f9cc4 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 13 Dec 2021 12:29:10 +0000 +Subject: [PATCH backport 5.10 140/182] mlxsw: core: Add APIs for thermal + sensor mapping + +Add APIs mlxsw_env_sensor_map_init() and mlxsw_env_sensor_map_fini((). +The purpose of the first one is to allocate and create thermal sensors +mapping for temperature sensors, presented within the main board or +line card. It obtains mapping information from the Management +Temperature Extended Capabilities Register, by specifying the relevant +device by the number of a slot at which this device is located. Slot +zero is used for the main board. The second API just free allocated +memory. +The motivation is to create dynamic mapping for gearbox thermal sensors +access. + +Signed-off-by: Vadim Pasternak +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 47 +++++++++++++++++++ + .../net/ethernet/mellanox/mlxsw/core_env.h | 12 +++++ + 2 files changed, 59 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 4553dfa68f96..4f3fc25af013 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -624,6 +624,53 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, + } + EXPORT_SYMBOL(mlxsw_env_set_module_power_mode); + ++int mlxsw_env_sensor_map_create(struct mlxsw_core *core, ++ const struct mlxsw_bus_info *bus_info, ++ u8 slot_index, ++ struct mlxsw_env_gearbox_sensors_map *map) ++{ ++ char mtecr_pl[MLXSW_REG_MTECR_LEN]; ++ u16 last_sensor, offset; ++ int i, bit, err; ++ ++ mlxsw_reg_mtecr_pack(mtecr_pl, slot_index); ++ err = mlxsw_reg_query(core, MLXSW_REG(mtecr), mtecr_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mtecr_unpack(mtecr_pl, &map->sensor_count, &last_sensor, NULL); ++ if (!map->sensor_count) { ++ map->sensor_bit_map = NULL; ++ return 0; ++ } ++ ++ /* Fill out sensor mapping array. */ ++ map->sensor_bit_map = kcalloc(map->sensor_count, sizeof(u16), GFP_KERNEL); ++ if (!map->sensor_bit_map) ++ return -ENOMEM; ++ ++ /* Sensors bitmap is size variable based on the last_sensor field and ++ * in granularity of 32 bits. Calculate an offset in payload buffer to ++ * start from. ++ */ ++ offset = MLXSW_REG_MTECR_SENSOR_MAP_LEN * 8 - last_sensor - 1; ++ offset -= offset % 32; ++ for (bit = 0, i = 0; bit <= last_sensor && i < map->sensor_count; bit++) { ++ if (mlxsw_reg_mtecr_sensor_map_get(mtecr_pl, bit + offset)) ++ map->sensor_bit_map[i++] = bit; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(mlxsw_env_sensor_map_create); ++ ++void mlxsw_env_sensor_map_destroy(const struct mlxsw_bus_info *bus_info, ++ u16 *sensor_bit_map) ++{ ++ kfree(sensor_bit_map); ++} ++EXPORT_SYMBOL(mlxsw_env_sensor_map_destroy); ++ + static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core, + u8 slot_index, u8 module, + bool *p_has_temp_sensor) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.h b/drivers/net/ethernet/mellanox/mlxsw/core_env.h +index 03d027870d65..336c9ee579cb 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.h +@@ -9,6 +9,11 @@ + struct ethtool_modinfo; + struct ethtool_eeprom; + ++struct mlxsw_env_gearbox_sensors_map { ++ u16 sensor_count; ++ u16 *sensor_bit_map; ++}; ++ + int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, + u8 slot_index, int module, int off, + int *temp); +@@ -21,6 +26,13 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev, + int module, struct ethtool_eeprom *ee, + u8 *data); + ++int mlxsw_env_sensor_map_create(struct mlxsw_core *core, ++ const struct mlxsw_bus_info *bus_info, ++ u8 slot_index, ++ struct mlxsw_env_gearbox_sensors_map *map); ++void mlxsw_env_sensor_map_destroy(const struct mlxsw_bus_info *bus_info, ++ u16 *sensor_bit_map); ++ + int + mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, + u8 slot_index, u8 module, +-- +2.20.1 + diff --git a/patch/0141-mlxsw-reg-Add-Management-DownStream-Device-Tunneling.patch b/patch/0141-mlxsw-reg-Add-Management-DownStream-Device-Tunneling.patch new file mode 100644 index 000000000..1d0966082 --- /dev/null +++ b/patch/0141-mlxsw-reg-Add-Management-DownStream-Device-Tunneling.patch @@ -0,0 +1,126 @@ +From d7353e41900e4d6fa44fa5e51a483b9f01432846 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Thu, 25 Feb 2021 10:17:53 +0100 +Subject: [PATCH backport 5.10 141/182] mlxsw: reg: Add Management DownStream + Device Tunneling Register + +The MDDT register allows deliver query and request messages +(PRM registers, commands) to a DownStream device. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 91 +++++++++++++++++++++++ + 1 file changed, 91 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 5757c4f40277..7b71e9ae3d51 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10481,6 +10481,96 @@ mlxsw_reg_mbct_unpack(const char *payload, u8 *p_slot_index, + *p_fsm_state = mlxsw_reg_mbct_fsm_state_get(payload); + } + ++/* MDDT - Management DownStream Device Tunneling Register ++ * ------------------------------------------------------ ++ * This register allows deliver query and request messages (PRM registers, ++ * commands) to a DownStream device. ++ */ ++#define MLXSW_REG_MDDT_ID 0x9160 ++#define MLXSW_REG_MDDT_LEN 0x110 ++ ++MLXSW_REG_DEFINE(mddt, MLXSW_REG_MDDT_ID, MLXSW_REG_MDDT_LEN); ++ ++/* reg_mddt_slot_index ++ * Slot index. ++ * Access: Index ++ */ ++ ++MLXSW_ITEM32(reg, mddt, slot_index, 0x00, 8, 4); ++ ++/* reg_mddt_device_index ++ * Device index. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mddt, device_index, 0x00, 0, 8); ++ ++/* reg_mddt_read_size ++ * Read size in D-Words. ++ * Access: OP ++ */ ++MLXSW_ITEM32(reg, mddt, read_size, 0x04, 24, 8); ++ ++/* reg_mddt_write_size ++ * Write size in D-Words. ++ * Access: OP ++ */ ++MLXSW_ITEM32(reg, mddt, write_size, 0x04, 16, 8); ++ ++enum mlxsw_reg_mddt_status { ++ MLXSW_REG_MDDT_STATUS_OK, ++}; ++ ++/* reg_mddt_status ++ * Return code of the Downstream Device to the register that was sent. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddt, status, 0x0C, 24, 8); ++ ++enum mlxsw_reg_mddt_method { ++ MLXSW_REG_MDDT_METHOD_QUERY, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++}; ++ ++/* reg_mddt_method ++ * Access: OP ++ */ ++MLXSW_ITEM32(reg, mddt, method, 0x0C, 22, 2); ++ ++/* reg_mddt_register_id ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mddt, register_id, 0x0C, 0, 16); ++ ++#define MLXSW_REG_MDDT_PAYLOAD_OFFSET 0x0C ++#define MLXSW_REG_MDDT_PRM_REGISTER_HEADER_LEN 4 ++ ++static inline char *mlxsw_reg_mddt_inner_payload(char *payload) ++{ ++ return payload + MLXSW_REG_MDDT_PAYLOAD_OFFSET + ++ MLXSW_REG_MDDT_PRM_REGISTER_HEADER_LEN; ++} ++ ++static inline void mlxsw_reg_mddt_pack(char *payload, u8 slot_index, ++ u8 device_index, ++ enum mlxsw_reg_mddt_method method, ++ const struct mlxsw_reg_info *reg, ++ char **inner_payload) ++{ ++ int len = reg->len + MLXSW_REG_MDDT_PRM_REGISTER_HEADER_LEN; ++ ++ if (WARN_ON(len + MLXSW_REG_MDDT_PAYLOAD_OFFSET > MLXSW_REG_MDDT_LEN)) ++ len = MLXSW_REG_MDDT_LEN - MLXSW_REG_MDDT_PAYLOAD_OFFSET; ++ ++ MLXSW_REG_ZERO(mddt, payload); ++ mlxsw_reg_mddt_slot_index_set(payload, slot_index); ++ mlxsw_reg_mddt_device_index_set(payload, device_index); ++ mlxsw_reg_mddt_method_set(payload, method); ++ mlxsw_reg_mddt_register_id_set(payload, reg->id); ++ mlxsw_reg_mddt_read_size_set(payload, len / 4); ++ mlxsw_reg_mddt_write_size_set(payload, len / 4); ++ *inner_payload = mlxsw_reg_mddt_inner_payload(payload); ++} ++ + /* MDDQ - Management DownStream Device Query Register + * -------------------------------------------------- + * This register allows to query the DownStream device properties. The desired +@@ -11951,6 +12041,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { + MLXSW_REG(mgpir), + MLXSW_REG(mtecr), + MLXSW_REG(mbct), ++ MLXSW_REG(mddt), + MLXSW_REG(mddq), + MLXSW_REG(mddc), + MLXSW_REG(mfde), +-- +2.20.1 + diff --git a/patch/0142-mlxsw-core_linecards-Probe-devices-for-provisioned-l.patch b/patch/0142-mlxsw-core_linecards-Probe-devices-for-provisioned-l.patch new file mode 100644 index 000000000..c08636be7 --- /dev/null +++ b/patch/0142-mlxsw-core_linecards-Probe-devices-for-provisioned-l.patch @@ -0,0 +1,224 @@ +From 51f5cf36b8b2c94d8a71bfa17d5f71257048c314 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 26 Feb 2021 13:15:09 +0100 +Subject: [PATCH backport 5.10 142/182] mlxsw: core_linecards: Probe devices + for provisioned line card and attach them + +In case the line card is provisioned, go over all possible existing +devices (gearboxes) on it and attach them, so devlink core is aware of +them. In case the device can be flashed, register mlxsw flash component. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/core.h | 3 + + .../ethernet/mellanox/mlxsw/core_linecards.c | 113 ++++++++++++++++-- + 2 files changed, 108 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 8e738ddb39c8..593470d14815 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -533,6 +533,9 @@ struct mlxsw_linecard { + bool ready; + bool active; + bool unprovision_done; ++ u16 hw_revision; ++ u16 ini_version; ++ struct list_head device_list; + }; + + struct mlxsw_linecard_types_info; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +index 134437f49219..720ad6d82798 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +@@ -64,27 +64,120 @@ static const char *mlxsw_linecard_type_name(struct mlxsw_linecard *linecard) + return linecard->read_name; + } + +-static void mlxsw_linecard_provision_fail(struct mlxsw_linecard *linecard) ++struct mlxsw_linecard_device { ++ struct list_head list; ++ u8 index; ++ struct mlxsw_linecard *linecard; ++ struct devlink_linecard_device *devlink_device; ++}; ++ ++static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard, ++ u8 device_index, bool flash_owner) ++{ ++ struct mlxsw_linecard_device *device; ++ int err; ++ ++ device = kzalloc(sizeof(*device), GFP_KERNEL); ++ if (!device) ++ return -ENOMEM; ++ device->index = device_index; ++ device->linecard = linecard; ++ ++ device->devlink_device = devlink_linecard_device_create(linecard->devlink_linecard, ++ device_index, ++ NULL, NULL); ++ if (IS_ERR(device->devlink_device)) { ++ err = PTR_ERR(device->devlink_device); ++ goto err_devlink_linecard_device_attach; ++ } ++ ++ list_add_tail(&device->list, &linecard->device_list); ++ return 0; ++ ++err_devlink_linecard_device_attach: ++ kfree(device); ++ return err; ++} ++ ++static void mlxsw_linecard_device_detach(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard, ++ struct mlxsw_linecard_device *device) ++{ ++ list_del(&device->list); ++ devlink_linecard_device_destroy(linecard->devlink_linecard, ++ device->devlink_device); ++ kfree(device); ++} ++ ++static int mlxsw_linecard_devices_attach(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard) ++{ ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ bool flash_owner; ++ bool data_valid; ++ u8 device_index; ++ u8 msg_seq = 0; ++ int err; ++ ++ do { ++ mlxsw_reg_mddq_device_info_pack(mddq_pl, linecard->slot_index, ++ msg_seq); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddq), mddq_pl); ++ if (err) ++ return err; ++ mlxsw_reg_mddq_device_info_unpack(mddq_pl, &msg_seq, ++ &data_valid, &flash_owner, ++ &device_index, NULL, ++ NULL, NULL); ++ if (!data_valid) ++ break; ++ err = mlxsw_linecard_device_attach(mlxsw_core, linecard, ++ device_index, flash_owner); ++ if (err) ++ return err; ++ } while (msg_seq); ++ ++ return 0; ++} ++ ++static void mlxsw_linecard_devices_detach(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard) ++{ ++ struct mlxsw_linecard_device *device, *tmp; ++ ++ list_for_each_entry_safe(device, tmp, &linecard->device_list, list) ++ mlxsw_linecard_device_detach(mlxsw_core, linecard, device); ++} ++ ++static void mlxsw_linecard_provision_fail(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard) + { + linecard->provisioned = false; + linecard->ready = false; + linecard->active = false; ++ mlxsw_linecard_devices_detach(mlxsw_core, linecard); + devlink_linecard_provision_fail(linecard->devlink_linecard); + } + + static int +-mlxsw_linecard_provision_set(struct mlxsw_linecards *linecards, ++mlxsw_linecard_provision_set(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, + struct mlxsw_linecard *linecard, + enum mlxsw_reg_mddq_card_type card_type) + { + const char *type = mlxsw_linecard_types_lookup(linecards, card_type); ++ int err; + + if (!type) + type = mlxsw_linecard_type_name(linecard); + if (!type) { +- mlxsw_linecard_provision_fail(linecard); ++ mlxsw_linecard_provision_fail(mlxsw_core, linecard); + return -EINVAL; + } ++ err = mlxsw_linecard_devices_attach(mlxsw_core, linecard); ++ if (err) ++ return err; + linecard->provisioned = true; + devlink_linecard_provision_set(linecard->devlink_linecard, type); + return 0; +@@ -93,6 +186,8 @@ mlxsw_linecard_provision_set(struct mlxsw_linecards *linecards, + static void mlxsw_linecard_provision_clear(struct mlxsw_linecard *linecard) + { + linecard->provisioned = false; ++ mlxsw_linecard_devices_detach(linecard->linecards->mlxsw_core, ++ linecard); + devlink_linecard_provision_clear(linecard->devlink_linecard); + } + +@@ -169,8 +264,8 @@ static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + mutex_lock(&linecard->lock); + + if (provisioned && linecard->provisioned != provisioned) { +- err = mlxsw_linecard_provision_set(linecards, linecard, +- card_type); ++ err = mlxsw_linecard_provision_set(mlxsw_core, linecards, ++ linecard, card_type); + if (err) + goto out; + } +@@ -353,7 +448,7 @@ int mlxsw_linecard_bct_process(struct mlxsw_core *mlxsw_core, + + fix_fsm_err_out: + mlxsw_linecard_fix_fsm_state(linecard, fsm_state); +- mlxsw_linecard_provision_fail(linecard); ++ mlxsw_linecard_provision_fail(mlxsw_core, linecard); + return err; + } + EXPORT_SYMBOL(mlxsw_linecard_bct_process); +@@ -415,7 +510,7 @@ static int mlxsw_linecard_provision(struct devlink_linecard *devlink_linecard, + fix_fsm_err_out: + mlxsw_linecard_fix_fsm_state(linecard, fsm_state); + err_out: +- mlxsw_linecard_provision_fail(linecard); ++ mlxsw_linecard_provision_fail(mlxsw_core, linecard); + out: + mutex_unlock(&linecard->lock); + return err; +@@ -488,7 +583,7 @@ static int mlxsw_linecard_unprovision(struct devlink_linecard *devlink_linecard, + fix_fsm_err_out: + mlxsw_linecard_fix_fsm_state(linecard, fsm_state); + err_out: +- mlxsw_linecard_provision_fail(linecard); ++ mlxsw_linecard_provision_fail(mlxsw_core, linecard); + out: + mutex_unlock(&linecard->lock); + return err; +@@ -536,6 +631,7 @@ static int mlxsw_linecard_init(struct mlxsw_core *mlxsw_core, + linecard->slot_index = slot_index; + linecard->linecards = linecards; + mutex_init(&linecard->lock); ++ INIT_LIST_HEAD(&linecard->device_list); + + devlink_linecard = devlink_linecard_create(priv_to_devlink(mlxsw_core), + slot_index, &mlxsw_linecard_ops, +@@ -613,6 +709,7 @@ static void mlxsw_linecard_fini(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecard *linecard; + + linecard = mlxsw_linecard_get(linecards, slot_index); ++ mlxsw_linecard_devices_detach(mlxsw_core, linecard); + devlink_linecard_destroy(linecard->devlink_linecard); + mutex_destroy(&linecard->lock); + } +-- +2.20.1 + diff --git a/patch/0143-mlxsw-core_linecards-Expose-device-FW-version-over-d.patch b/patch/0143-mlxsw-core_linecards-Expose-device-FW-version-over-d.patch new file mode 100644 index 000000000..78fe94419 --- /dev/null +++ b/patch/0143-mlxsw-core_linecards-Expose-device-FW-version-over-d.patch @@ -0,0 +1,177 @@ +From e4830f23af9d14fac42764dd077f49de8de7bff2 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Thu, 10 Jun 2021 15:32:00 +0200 +Subject: [PATCH backport 5.10 143/182] mlxsw: core_linecards: Expose device FW + version over device info + +Extend MDDQ to obtain FW version of line card device and implement +device_info_get() op to fill up the info with that. + +Signed-off-by: Jiri Pirko +--- + .../ethernet/mellanox/mlxsw/core_linecards.c | 104 +++++++++++++++++- + 1 file changed, 100 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +index 720ad6d82798..cb872f918f01 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +@@ -64,13 +64,31 @@ static const char *mlxsw_linecard_type_name(struct mlxsw_linecard *linecard) + return linecard->read_name; + } + ++struct mlxsw_linecard_device_info { ++ u16 fw_major; ++ u16 fw_minor; ++ u16 fw_sub_minor; ++}; ++ + struct mlxsw_linecard_device { + struct list_head list; + u8 index; + struct mlxsw_linecard *linecard; + struct devlink_linecard_device *devlink_device; ++ struct mlxsw_linecard_device_info info; + }; + ++static struct mlxsw_linecard_device * ++mlxsw_linecard_device_lookup(struct mlxsw_linecard *linecard, u8 index) ++{ ++ struct mlxsw_linecard_device *device; ++ ++ list_for_each_entry(device, &linecard->device_list, list) ++ if (device->index == index) ++ return device; ++ return NULL; ++} ++ + static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecard *linecard, + u8 device_index, bool flash_owner) +@@ -86,7 +104,7 @@ static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, + + device->devlink_device = devlink_linecard_device_create(linecard->devlink_linecard, + device_index, +- NULL, NULL); ++ NULL, device); + if (IS_ERR(device->devlink_device)) { + err = PTR_ERR(device->devlink_device); + goto err_devlink_linecard_device_attach; +@@ -150,6 +168,71 @@ static void mlxsw_linecard_devices_detach(struct mlxsw_core *mlxsw_core, + mlxsw_linecard_device_detach(mlxsw_core, linecard, device); + } + ++static void mlxsw_linecard_device_update(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard, ++ u8 device_index, ++ struct mlxsw_linecard_device_info *info) ++{ ++ struct mlxsw_linecard_device *device; ++ ++ device = mlxsw_linecard_device_lookup(linecard, device_index); ++ if (!device) ++ return; ++ device->info = *info; ++} ++ ++static int mlxsw_linecard_devices_update(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard) ++{ ++ struct mlxsw_linecard_device_info info; ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ bool data_valid; ++ u8 device_index; ++ u8 msg_seq = 0; ++ int err; ++ ++ do { ++ mlxsw_reg_mddq_device_info_pack(mddq_pl, linecard->slot_index, ++ msg_seq); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddq), mddq_pl); ++ if (err) ++ return err; ++ mlxsw_reg_mddq_device_info_unpack(mddq_pl, &msg_seq, ++ &data_valid, NULL, ++ &device_index, ++ &info.fw_major, ++ &info.fw_minor, ++ &info.fw_sub_minor); ++ if (!data_valid) ++ break; ++ mlxsw_linecard_device_update(mlxsw_core, linecard, ++ device_index, &info); ++ } while (msg_seq); ++ ++ return 0; ++} ++ ++static int ++mlxsw_linecard_device_info_get(struct devlink_linecard_device *devlink_linecard_device, ++ void *priv, struct devlink_info_req *req, ++ struct netlink_ext_ack *extack) ++{ ++ struct mlxsw_linecard_device *device = priv; ++ struct mlxsw_linecard_device_info *info; ++ char buf[32]; ++ ++ if (!device->linecard->active) ++ return 0; ++ ++ info = &device->info; ++ ++ sprintf(buf, "%u.%u.%u", info->fw_major, info->fw_minor, ++ info->fw_sub_minor); ++ return devlink_info_version_running_put(req, ++ DEVLINK_INFO_VERSION_GENERIC_FW, ++ buf); ++} ++ + static void mlxsw_linecard_provision_fail(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecard *linecard) + { +@@ -219,10 +302,18 @@ static int mlxsw_linecard_ready_clear(struct mlxsw_core *mlxsw_core, + return 0; + } + +-static void mlxsw_linecard_active_set(struct mlxsw_linecard *linecard) ++static int mlxsw_linecard_active_set(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard, ++ u16 hw_revision, u16 ini_version) + { ++ int err; ++ ++ err = mlxsw_linecard_devices_update(mlxsw_core, linecard); ++ if (err) ++ return err; + linecard->active = true; + devlink_linecard_activate(linecard->devlink_linecard); ++ return 0; + } + + static void mlxsw_linecard_active_clear(struct mlxsw_linecard *linecard) +@@ -278,8 +369,12 @@ static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + } + + if (!process_provision_only && !linecard->unprovision_done && active && +- linecard->active != active && linecard->ready) +- mlxsw_linecard_active_set(linecard); ++ linecard->active != active && linecard->ready) { ++ err = mlxsw_linecard_active_set(mlxsw_core, linecard, ++ hw_revision, ini_version); ++ if (err) ++ goto out; ++ } + + if (!process_provision_only && !active && linecard->active != active) + mlxsw_linecard_active_clear(linecard); +@@ -617,6 +712,7 @@ static const struct devlink_linecard_ops mlxsw_linecard_ops = { + .unprovision = mlxsw_linecard_unprovision, + .types_count = mlxsw_linecard_types_count, + .types_get = mlxsw_linecard_types_get, ++ .device_info_get = mlxsw_linecard_device_info_get, + }; + + static int mlxsw_linecard_init(struct mlxsw_core *mlxsw_core, +-- +2.20.1 + diff --git a/patch/0144-mlxsw-core-Introduce-flash-update-components.patch b/patch/0144-mlxsw-core-Introduce-flash-update-components.patch new file mode 100644 index 000000000..87018bd86 --- /dev/null +++ b/patch/0144-mlxsw-core-Introduce-flash-update-components.patch @@ -0,0 +1,244 @@ +From 1eb0843255d6e92aa96d0ea11a15ab1f86b20e4f Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 26 Feb 2021 18:40:28 +0100 +Subject: [PATCH backport 5.10 144/182] mlxsw: core: Introduce flash update + components + +Introduce an infrastructure allowing to have multiple components for +flashing purposes that can be registered from inside the driver. Convert +the existing "no component" flash update to use the new infra. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 117 +++++++++++++++++++-- + drivers/net/ethernet/mellanox/mlxsw/core.h | 12 +++ + include/net/devlink.h | 3 + + 3 files changed, 125 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 68ef007ac48c..f55071982271 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -91,6 +91,10 @@ struct mlxsw_core { + struct devlink_health_reporter *fw_fatal; + } health; + struct mlxsw_env *env; ++ struct list_head flash_component_list; ++ struct mutex flash_update_lock; /* Protects component list and component ++ * callbacks. ++ */ + unsigned long driver_priv[]; + /* driver_priv has to be always the last item */ + }; +@@ -1113,21 +1117,101 @@ static int mlxsw_core_fw_rev_validate(struct mlxsw_core *mlxsw_core, + return 0; + } + ++static int mlxsw_core_fw_flash_cb(struct mlxsw_core *mlxsw_core, ++ const struct firmware *firmware, ++ struct netlink_ext_ack *extack, void *priv) ++{ ++ return mlxsw_core_fw_flash(mlxsw_core, firmware, extack); ++} ++ ++struct mlxsw_core_flash_component { ++ struct list_head list; ++ const char *name; ++ mlxsw_core_flash_update_cb cb; ++ void *priv; ++}; ++ ++static struct mlxsw_core_flash_component * ++mlxsw_core_flash_component_lookup(struct mlxsw_core *mlxsw_core, ++ const char *name) ++{ ++ struct mlxsw_core_flash_component *component; ++ ++ list_for_each_entry(component, &mlxsw_core->flash_component_list, ++ list) { ++ if ((name && component->name && ++ !strcmp(name, component->name)) || ++ (!name && !component->name)) ++ return component; ++ } ++ return NULL; ++} ++ + static int mlxsw_core_fw_flash_update(struct mlxsw_core *mlxsw_core, + struct devlink_flash_update_params *params, + struct netlink_ext_ack *extack) + { +- const struct firmware *firmware; ++ struct mlxsw_core_flash_component *component; + int err; + +- err = request_firmware_direct(&firmware, params->file_name, mlxsw_core->bus_info->dev); +- if (err) +- return err; +- err = mlxsw_core_fw_flash(mlxsw_core, firmware, extack); +- release_firmware(firmware); ++ mutex_lock(&mlxsw_core->flash_update_lock); ++ component = mlxsw_core_flash_component_lookup(mlxsw_core, ++ params->component); ++ if (!component) { ++ NL_SET_ERR_MSG_MOD(extack, "Component does not exist"); ++ err = -ENOENT; ++ goto unlock; ++ } ++ err = component->cb(mlxsw_core, params->fw, extack, component->priv); ++unlock: ++ mutex_unlock(&mlxsw_core->flash_update_lock); ++ return err; ++} + ++int mlxsw_core_flash_component_register(struct mlxsw_core *mlxsw_core, ++ const char *name, ++ mlxsw_core_flash_update_cb cb, ++ void *priv) ++{ ++ struct mlxsw_core_flash_component *component; ++ int err = 0; ++ ++ mutex_lock(&mlxsw_core->flash_update_lock); ++ component = mlxsw_core_flash_component_lookup(mlxsw_core, name); ++ if (WARN_ON(component)) { ++ err = -EEXIST; ++ goto unlock; ++ } ++ component = kzalloc(sizeof(*component), GFP_KERNEL); ++ if (!component) { ++ err = -ENOMEM; ++ goto unlock; ++ } ++ component->name = name; ++ component->cb = cb; ++ component->priv = priv; ++ list_add_tail(&component->list, &mlxsw_core->flash_component_list); ++unlock: ++ mutex_unlock(&mlxsw_core->flash_update_lock); + return err; + } ++EXPORT_SYMBOL(mlxsw_core_flash_component_register); ++ ++void mlxsw_core_flash_component_unregister(struct mlxsw_core *mlxsw_core, ++ const char *name) ++{ ++ struct mlxsw_core_flash_component *component; ++ ++ mutex_lock(&mlxsw_core->flash_update_lock); ++ component = mlxsw_core_flash_component_lookup(mlxsw_core, name); ++ if (WARN_ON(!component)) ++ goto unlock; ++ list_del(&component->list); ++unlock: ++ mutex_unlock(&mlxsw_core->flash_update_lock); ++ kfree(component); ++} ++EXPORT_SYMBOL(mlxsw_core_flash_component_unregister); + + static int mlxsw_core_devlink_param_fw_load_policy_validate(struct devlink *devlink, u32 id, + union devlink_param_value val, +@@ -1572,6 +1656,7 @@ mlxsw_devlink_trap_policer_counter_get(struct devlink *devlink, + } + + static const struct devlink_ops mlxsw_devlink_ops = { ++ .supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT, + .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) | + BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE), + .reload_down = mlxsw_devlink_core_bus_device_reload_down, +@@ -1894,6 +1979,16 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + mlxsw_core->bus_priv = bus_priv; + mlxsw_core->bus_info = mlxsw_bus_info; + ++ if (!reload) { ++ INIT_LIST_HEAD(&mlxsw_core->flash_component_list); ++ mutex_init(&mlxsw_core->flash_update_lock); ++ err = mlxsw_core_flash_component_register(mlxsw_core, NULL, ++ mlxsw_core_fw_flash_cb, ++ NULL); ++ if (err) ++ goto err_flash_component_register; ++ } ++ + res = mlxsw_driver->res_query_enabled ? &mlxsw_core->res : NULL; + err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile, res); + if (err) +@@ -2013,6 +2108,11 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + err_register_resources: + mlxsw_bus->fini(bus_priv); + err_bus_init: ++ if (!reload) { ++ mlxsw_core_flash_component_unregister(mlxsw_core, NULL); ++ mutex_destroy(&mlxsw_core->flash_update_lock); ++ } ++err_flash_component_register: + if (!reload) + devlink_free(devlink); + err_devlink_alloc: +@@ -2081,8 +2181,11 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, + if (!reload) + devlink_resources_unregister(devlink, NULL); + mlxsw_core->bus->fini(mlxsw_core->bus_priv); +- if (!reload) ++ if (!reload) { ++ mlxsw_core_flash_component_unregister(mlxsw_core, NULL); ++ mutex_destroy(&mlxsw_core->flash_update_lock); + devlink_free(devlink); ++ } + + return; + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 593470d14815..30f00da0a48d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -41,6 +41,18 @@ mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev, + int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver); + void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver); + ++typedef int (*mlxsw_core_flash_update_cb)(struct mlxsw_core *mlxsw_core, ++ const struct firmware *firmware, ++ struct netlink_ext_ack *extack, ++ void *priv); ++ ++int mlxsw_core_flash_component_register(struct mlxsw_core *mlxsw_core, ++ const char *name, ++ mlxsw_core_flash_update_cb cb, ++ void *priv); ++void mlxsw_core_flash_component_unregister(struct mlxsw_core *mlxsw_core, ++ const char *name); ++ + int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + const struct mlxsw_bus *mlxsw_bus, + void *bus_priv, bool reload, +diff --git a/include/net/devlink.h b/include/net/devlink.h +index 06b61c1d7938..fafbec26d2c4 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #define DEVLINK_RELOAD_STATS_ARRAY_SIZE \ + (__DEVLINK_RELOAD_LIMIT_MAX * __DEVLINK_RELOAD_ACTION_MAX) +@@ -624,6 +625,7 @@ enum devlink_param_generic_id { + + /** + * struct devlink_flash_update_params - Flash Update parameters ++ * @fw: pointer to the firmware data to update from + * @file_name: the name of the flash firmware file to update from + * @component: the flash component to update + * +@@ -632,6 +634,7 @@ enum devlink_param_generic_id { + * their devlink_ops structure. + */ + struct devlink_flash_update_params { ++ const struct firmware *fw; + const char *file_name; + const char *component; + u32 overwrite_mask; +-- +2.20.1 + diff --git a/patch/0145-mlxfw-Get-the-PSID-value-using-op-instead-of-passing.patch b/patch/0145-mlxfw-Get-the-PSID-value-using-op-instead-of-passing.patch new file mode 100644 index 000000000..de282a124 --- /dev/null +++ b/patch/0145-mlxfw-Get-the-PSID-value-using-op-instead-of-passing.patch @@ -0,0 +1,200 @@ +From 81cb237570a4d0251455d17e073337f73c1b4aa9 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 4 Jun 2021 10:25:35 +0200 +Subject: [PATCH backport 5.10 145/182] mlxfw: Get the PSID value using op + instead of passing it in struct + +In preparation for line card device flashing, where the PSID is going to +be obtained dynamically using MGIR register for each individual line +card device. So convert the PSID value get to an extra op. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlx5/core/fw.c | 18 +++++++++++++-- + drivers/net/ethernet/mellanox/mlxfw/mlxfw.h | 4 ++-- + .../net/ethernet/mellanox/mlxfw/mlxfw_fsm.c | 23 ++++++++++++++----- + drivers/net/ethernet/mellanox/mlxsw/core.c | 19 +++++++++++++-- + 4 files changed, 52 insertions(+), 12 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c +index 02558ac2ace6..06edfd5b12e0 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c +@@ -494,6 +494,20 @@ struct mlx5_mlxfw_dev { + struct mlx5_core_dev *mlx5_core_dev; + }; + ++static const char *mlx5_psid_get(struct mlxfw_dev *mlxfw_dev, u16 *psid_size) ++{ ++ struct mlx5_mlxfw_dev *mlx5_mlxfw_dev = ++ container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev); ++ struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev; ++ ++ *psid_size = MLX5_BOARD_ID_LEN; ++ return dev->board_id; ++} ++ ++static void mlx5_psid_put(const char *psid) ++{ ++} ++ + static int mlx5_component_query(struct mlxfw_dev *mlxfw_dev, + u16 component_index, u32 *p_max_size, + u8 *p_align_bits, u16 *p_max_write_size) +@@ -651,6 +665,8 @@ static int mlx5_fsm_reactivate(struct mlxfw_dev *mlxfw_dev, u8 *status) + } + + static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = { ++ .psid_get = mlx5_psid_get, ++ .psid_put = mlx5_psid_put, + .component_query = mlx5_component_query, + .fsm_lock = mlx5_fsm_lock, + .fsm_component_update = mlx5_fsm_component_update, +@@ -670,8 +686,6 @@ int mlx5_firmware_flash(struct mlx5_core_dev *dev, + struct mlx5_mlxfw_dev mlx5_mlxfw_dev = { + .mlxfw_dev = { + .ops = &mlx5_mlxfw_dev_ops, +- .psid = dev->board_id, +- .psid_size = strlen(dev->board_id), + .devlink = priv_to_devlink(dev), + }, + .mlx5_core_dev = dev +diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h +index 7654841a05c2..b83651246c1f 100644 +--- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h ++++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h +@@ -11,8 +11,6 @@ + + struct mlxfw_dev { + const struct mlxfw_dev_ops *ops; +- const char *psid; +- u16 psid_size; + struct devlink *devlink; + }; + +@@ -70,6 +68,8 @@ enum mlxfw_fsm_reactivate_status { + }; + + struct mlxfw_dev_ops { ++ const char * (*psid_get)(struct mlxfw_dev *mlxfw_dev, u16 *psid_size); ++ void (*psid_put)(const char *psid); + int (*component_query)(struct mlxfw_dev *mlxfw_dev, u16 component_index, + u32 *p_max_size, u8 *p_align_bits, + u16 *p_max_write_size); +diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c +index bcd166911d44..329ddf1b3b89 100644 +--- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c ++++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c +@@ -303,7 +303,8 @@ static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev, + return err; + } + +-static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, ++static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, const char *psid, ++ u16 psid_size, u32 fwhandle, + struct mlxfw_mfa2_file *mfa2_file, + bool reactivate_supp, + struct netlink_ext_ack *extack) +@@ -312,8 +313,7 @@ static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + int err; + int i; + +- err = mlxfw_mfa2_file_component_count(mfa2_file, mlxfw_dev->psid, +- mlxfw_dev->psid_size, ++ err = mlxfw_mfa2_file_component_count(mfa2_file, psid, psid_size, + &component_count); + if (err) { + MLXFW_ERR_MSG(mlxfw_dev, extack, +@@ -324,8 +324,8 @@ static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + for (i = 0; i < component_count; i++) { + struct mlxfw_mfa2_component *comp; + +- comp = mlxfw_mfa2_file_component_get(mfa2_file, mlxfw_dev->psid, +- mlxfw_dev->psid_size, i); ++ comp = mlxfw_mfa2_file_component_get(mfa2_file, psid, ++ psid_size, i); + if (IS_ERR(comp)) { + err = PTR_ERR(comp); + MLXFW_ERR_MSG(mlxfw_dev, extack, +@@ -350,6 +350,8 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, + { + struct mlxfw_mfa2_file *mfa2_file; + bool reactivate_supp = true; ++ const char *psid; ++ u16 psid_size; + u32 fwhandle; + int err; + +@@ -392,8 +394,16 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, + if (err) + goto err_state_wait_reactivate_to_locked; + +- err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file, ++ psid = mlxfw_dev->ops->psid_get(mlxfw_dev, &psid_size); ++ if (IS_ERR(psid)) { ++ err = PTR_ERR(psid); ++ goto err_psid_get; ++ } ++ ++ err = mlxfw_flash_components(mlxfw_dev, psid, psid_size, ++ fwhandle, mfa2_file, + reactivate_supp, extack); ++ mlxfw_dev->ops->psid_put(psid); + if (err) + goto err_flash_components; + +@@ -423,6 +433,7 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, + err_state_wait_activate_to_locked: + err_fsm_activate: + err_flash_components: ++err_psid_get: + err_state_wait_reactivate_to_locked: + err_fsm_reactivate: + err_state_wait_idle_to_locked: +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index f55071982271..8c128078105a 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -890,6 +890,21 @@ struct mlxsw_core_fw_info { + struct mlxsw_core *mlxsw_core; + }; + ++static const char *mlxsw_core_fw_psid_get(struct mlxfw_dev *mlxfw_dev, ++ u16 *psid_size) ++{ ++ struct mlxsw_core_fw_info *mlxsw_core_fw_info = ++ container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev); ++ struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core; ++ ++ *psid_size = strlen(mlxsw_core->bus_info->psid); ++ return mlxsw_core->bus_info->psid; ++} ++ ++static void mlxsw_core_fw_psid_put(const char *psid) ++{ ++} ++ + static int mlxsw_core_fw_component_query(struct mlxfw_dev *mlxfw_dev, + u16 component_index, u32 *p_max_size, + u8 *p_align_bits, u16 *p_max_write_size) +@@ -1028,6 +1043,8 @@ static void mlxsw_core_fw_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) + } + + static const struct mlxfw_dev_ops mlxsw_core_fw_mlxsw_dev_ops = { ++ .psid_get = mlxsw_core_fw_psid_get, ++ .psid_put = mlxsw_core_fw_psid_put, + .component_query = mlxsw_core_fw_component_query, + .fsm_lock = mlxsw_core_fw_fsm_lock, + .fsm_component_update = mlxsw_core_fw_fsm_component_update, +@@ -1045,8 +1062,6 @@ static int mlxsw_core_fw_flash(struct mlxsw_core *mlxsw_core, const struct firmw + struct mlxsw_core_fw_info mlxsw_core_fw_info = { + .mlxfw_dev = { + .ops = &mlxsw_core_fw_mlxsw_dev_ops, +- .psid = mlxsw_core->bus_info->psid, +- .psid_size = strlen(mlxsw_core->bus_info->psid), + .devlink = priv_to_devlink(mlxsw_core), + }, + .mlxsw_core = mlxsw_core +-- +2.20.1 + diff --git a/patch/0146-mlxsw-core_linecards-Implement-line-card-device-flas.patch b/patch/0146-mlxsw-core_linecards-Implement-line-card-device-flas.patch new file mode 100644 index 000000000..8855ba192 --- /dev/null +++ b/patch/0146-mlxsw-core_linecards-Implement-line-card-device-flas.patch @@ -0,0 +1,401 @@ +From 0e642e558b98e1a686b39acb53f53c1fb9735b02 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 5 Mar 2021 09:33:21 +0100 +Subject: [PATCH backport 5.10 146/182] mlxsw: core_linecards: Implement line + card device flashing + +Generate flash component name and register it internally within mlxsw +for flashing. Also, propagate the component name to devlink core which +exposes the information about device being flashable and the component +name to use to the user. Implement flashing using MDDT register and +mlxfw. + +Signed-off-by: Jiri Pirko +--- + .../ethernet/mellanox/mlxsw/core_linecards.c | 335 +++++++++++++++++- + 1 file changed, 334 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +index cb872f918f01..9f9ee582fce2 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +@@ -73,6 +73,7 @@ struct mlxsw_linecard_device_info { + struct mlxsw_linecard_device { + struct list_head list; + u8 index; ++ char component_name[16]; + struct mlxsw_linecard *linecard; + struct devlink_linecard_device *devlink_device; + struct mlxsw_linecard_device_info info; +@@ -89,11 +90,322 @@ mlxsw_linecard_device_lookup(struct mlxsw_linecard *linecard, u8 index) + return NULL; + } + ++struct mlxsw_linecard_device_fw_info { ++ struct mlxfw_dev mlxfw_dev; ++ struct mlxsw_core *mlxsw_core; ++ struct mlxsw_linecard_device *device; ++}; ++ ++static const char * ++mlxsw_linecard_device_fw_psid_get(struct mlxfw_dev *mlxfw_dev, u16 *psid_size) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mgir_pl; ++ char *psid; ++ int err; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_QUERY, ++ MLXSW_REG(mgir), &mgir_pl); ++ ++ mlxsw_reg_mgir_pack(mgir_pl); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++ if (err) ++ return ERR_PTR(err); ++ psid = kzalloc(MLXSW_REG_MGIR_FW_INFO_PSID_SIZE, GFP_KERNEL); ++ if (!psid) ++ return ERR_PTR(-ENOMEM); ++ ++ mlxsw_reg_mgir_fw_info_psid_memcpy_from(mgir_pl, psid); ++ *psid_size = strlen(psid); ++ return psid; ++} ++ ++static void mlxsw_linecard_device_fw_psid_put(const char *psid) ++{ ++ kfree(psid); ++} ++ ++static int mlxsw_linecard_device_fw_component_query(struct mlxfw_dev *mlxfw_dev, ++ u16 component_index, ++ u32 *p_max_size, ++ u8 *p_align_bits, ++ u16 *p_max_write_size) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcqi_pl; ++ int err; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_QUERY, ++ MLXSW_REG(mcqi), &mcqi_pl); ++ ++ mlxsw_reg_mcqi_pack(mcqi_pl, component_index); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++ if (err) ++ return err; ++ mlxsw_reg_mcqi_unpack(mcqi_pl, p_max_size, p_align_bits, ++ p_max_write_size); ++ ++ *p_align_bits = max_t(u8, *p_align_bits, 2); ++ *p_max_write_size = min_t(u16, *p_max_write_size, ++ MLXSW_REG_MCDA_MAX_DATA_LEN); ++ return 0; ++} ++ ++static int mlxsw_linecard_device_fw_fsm_lock(struct mlxfw_dev *mlxfw_dev, ++ u32 *fwhandle) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ u8 control_state; ++ char *mcc_pl; ++ int err; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_QUERY, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, 0, 0, 0, 0); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mcc_unpack(mcc_pl, fwhandle, NULL, &control_state); ++ if (control_state != MLXFW_FSM_STATE_IDLE) ++ return -EBUSY; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_QUERY, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE, ++ 0, *fwhandle, 0); ++ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static int ++mlxsw_linecard_device_fw_fsm_component_update(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle, ++ u16 component_index, ++ u32 component_size) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcc_pl; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_UPDATE_COMPONENT, ++ component_index, fwhandle, component_size); ++ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static int ++mlxsw_linecard_device_fw_fsm_block_download(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle, u8 *data, ++ u16 size, u32 offset) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcda_pl; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++ MLXSW_REG(mcda), &mcda_pl); ++ mlxsw_reg_mcda_pack(mcda_pl, fwhandle, offset, size, data); ++ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static int ++mlxsw_linecard_device_fw_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle, u16 component_index) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcc_pl; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_VERIFY_COMPONENT, ++ component_index, fwhandle, 0); ++ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static int mlxsw_linecard_device_fw_fsm_activate(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcc_pl; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_ACTIVATE, ++ 0, fwhandle, 0); ++ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static int ++mlxsw_linecard_device_fw_fsm_query_state(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle, ++ enum mlxfw_fsm_state *fsm_state, ++ enum mlxfw_fsm_state_err *fsm_state_err) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ u8 control_state; ++ u8 error_code; ++ char *mcc_pl; ++ int err; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_QUERY, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, 0, 0, fwhandle, 0); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mcc_unpack(mcc_pl, NULL, &error_code, &control_state); ++ *fsm_state = control_state; ++ *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code, ++ MLXFW_FSM_STATE_ERR_MAX); ++ return 0; ++} ++ ++static void mlxsw_linecard_device_fw_fsm_cancel(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcc_pl; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_CANCEL, ++ 0, fwhandle, 0); ++ mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static void mlxsw_linecard_device_fw_fsm_release(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcc_pl; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, ++ MLXSW_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, ++ 0, fwhandle, 0); ++ mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static const struct mlxfw_dev_ops mlxsw_linecard_device_dev_ops = { ++ .psid_get = mlxsw_linecard_device_fw_psid_get, ++ .psid_put = mlxsw_linecard_device_fw_psid_put, ++ .component_query = mlxsw_linecard_device_fw_component_query, ++ .fsm_lock = mlxsw_linecard_device_fw_fsm_lock, ++ .fsm_component_update = mlxsw_linecard_device_fw_fsm_component_update, ++ .fsm_block_download = mlxsw_linecard_device_fw_fsm_block_download, ++ .fsm_component_verify = mlxsw_linecard_device_fw_fsm_component_verify, ++ .fsm_activate = mlxsw_linecard_device_fw_fsm_activate, ++ .fsm_query_state = mlxsw_linecard_device_fw_fsm_query_state, ++ .fsm_cancel = mlxsw_linecard_device_fw_fsm_cancel, ++ .fsm_release = mlxsw_linecard_device_fw_fsm_release, ++}; ++ ++static int mlxsw_linecard_device_fw_flash(struct mlxsw_core *mlxsw_core, ++ const struct firmware *firmware, ++ struct mlxsw_linecard_device *device, ++ struct netlink_ext_ack *extack) ++{ ++ struct mlxsw_linecard_device_fw_info info = { ++ .mlxfw_dev = { ++ .ops = &mlxsw_linecard_device_dev_ops, ++ .devlink = priv_to_devlink(mlxsw_core), ++ }, ++ .mlxsw_core = mlxsw_core, ++ .device = device, ++ }; ++ ++ return mlxfw_firmware_flash(&info.mlxfw_dev, firmware, extack); ++} ++ ++static int mlxsw_linecard_device_flash_cb(struct mlxsw_core *mlxsw_core, ++ const struct firmware *firmware, ++ struct netlink_ext_ack *extack, void *priv) ++{ ++ struct mlxsw_linecard_device *device = priv; ++ ++ return mlxsw_linecard_device_fw_flash(mlxsw_core, firmware, ++ device, extack); ++} ++ + static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecard *linecard, + u8 device_index, bool flash_owner) + { + struct mlxsw_linecard_device *device; ++ char *component_name = NULL; + int err; + + device = kzalloc(sizeof(*device), GFP_KERNEL); +@@ -102,9 +414,23 @@ static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, + device->index = device_index; + device->linecard = linecard; + ++ if (flash_owner) { ++ snprintf(device->component_name, ++ sizeof(device->component_name), "lc%u_dev%u", ++ linecard->slot_index, device->index); ++ component_name = device->component_name; ++ err = mlxsw_core_flash_component_register(mlxsw_core, ++ component_name, ++ mlxsw_linecard_device_flash_cb, ++ device); ++ if (err) ++ goto err_flash_component_register; ++ } ++ + device->devlink_device = devlink_linecard_device_create(linecard->devlink_linecard, + device_index, +- NULL, device); ++ component_name, ++ device); + if (IS_ERR(device->devlink_device)) { + err = PTR_ERR(device->devlink_device); + goto err_devlink_linecard_device_attach; +@@ -114,6 +440,10 @@ static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, + return 0; + + err_devlink_linecard_device_attach: ++ if (flash_owner) ++ mlxsw_core_flash_component_unregister(mlxsw_core, ++ device->component_name); ++err_flash_component_register: + kfree(device); + return err; + } +@@ -125,6 +455,9 @@ static void mlxsw_linecard_device_detach(struct mlxsw_core *mlxsw_core, + list_del(&device->list); + devlink_linecard_device_destroy(linecard->devlink_linecard, + device->devlink_device); ++ if (strlen(device->component_name)) ++ mlxsw_core_flash_component_unregister(mlxsw_core, ++ device->component_name); + kfree(device); + } + +-- +2.20.1 + diff --git a/patch/0147-mlxsw-core_linecards-Introduce-ops-for-linecards-sta.patch b/patch/0147-mlxsw-core_linecards-Introduce-ops-for-linecards-sta.patch new file mode 100644 index 000000000..22c42d0ce --- /dev/null +++ b/patch/0147-mlxsw-core_linecards-Introduce-ops-for-linecards-sta.patch @@ -0,0 +1,277 @@ +From 5e3bebf1e096e4770cad3aaf3d03fa22429fe5f9 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 22 Jan 2021 15:01:06 +0100 +Subject: [PATCH backport 5.10 147/182] mlxsw: core_linecards: Introduce ops + for linecards status change tracking + +Introduce an infrastructure allowing the core to register set of ops +which are called whenever line card gets provisione/unprovisioned +and active/inactive. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/core.h | 22 +++ + .../ethernet/mellanox/mlxsw/core_linecards.c | 134 +++++++++++++++++- + 2 files changed, 150 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 30f00da0a48d..10ea541bb19d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -582,4 +582,26 @@ int mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + int mlxsw_linecard_bct_process(struct mlxsw_core *mlxsw_core, + const char *mbct_pl); + ++struct mlxsw_linecards_event_ops { ++ int (*got_provisioned)(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, ++ void *priv); ++ void (*got_unprovisioned)(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, ++ void *priv); ++ void (*got_active)(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, ++ void *priv); ++ void (*got_inactive)(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, ++ void *priv); ++}; ++ ++int mlxsw_linecards_event_ops_register(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards_event_ops *ops, ++ void *priv); ++void mlxsw_linecards_event_ops_unregister(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards_event_ops *ops, ++ void *priv); ++ + #endif +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +index 9f9ee582fce2..3a2fdd22dc21 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +@@ -576,6 +576,59 @@ static void mlxsw_linecard_provision_fail(struct mlxsw_core *mlxsw_core, + devlink_linecard_provision_fail(linecard->devlink_linecard); + } + ++struct mlxsw_linecards_event_ops_item { ++ struct list_head list; ++ struct mlxsw_linecards_event_ops *event_ops; ++ void *priv; ++}; ++ ++static int ++mlxsw_linecard_provision_cbs_call(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard) ++{ ++ struct mlxsw_linecards_event_ops_item *item; ++ int err; ++ ++ list_for_each_entry(item, &linecards->event_ops_list, list) { ++ if (!item->event_ops->got_provisioned) ++ continue; ++ err = item->event_ops->got_provisioned(mlxsw_core, ++ linecard->slot_index, ++ linecard, item->priv); ++ if (err) ++ goto rollback; ++ } ++ return 0; ++ ++rollback: ++ list_for_each_entry_continue_reverse(item, &linecards->event_ops_list, ++ list) { ++ if (!item->event_ops->got_unprovisioned) ++ continue; ++ item->event_ops->got_unprovisioned(mlxsw_core, ++ linecard->slot_index, ++ linecard, item->priv); ++ } ++ return err; ++} ++ ++static void ++mlxsw_linecard_unprovision_cbs_call(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard) ++{ ++ struct mlxsw_linecards_event_ops_item *item; ++ ++ list_for_each_entry(item, &linecards->event_ops_list, list) { ++ if (!item->event_ops->got_unprovisioned) ++ continue; ++ item->event_ops->got_unprovisioned(mlxsw_core, ++ linecard->slot_index, ++ linecard, item->priv); ++ } ++} ++ + static int + mlxsw_linecard_provision_set(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecards *linecards, +@@ -594,14 +647,27 @@ mlxsw_linecard_provision_set(struct mlxsw_core *mlxsw_core, + err = mlxsw_linecard_devices_attach(mlxsw_core, linecard); + if (err) + return err; ++ err = mlxsw_linecard_provision_cbs_call(mlxsw_core, linecards, ++ linecard); ++ if (err) ++ goto err_cbs_call; + linecard->provisioned = true; + devlink_linecard_provision_set(linecard->devlink_linecard, type); + return 0; ++ ++err_cbs_call: ++ mlxsw_linecard_devices_detach(linecard->linecards->mlxsw_core, ++ linecard); ++ return err; + } + +-static void mlxsw_linecard_provision_clear(struct mlxsw_linecard *linecard) ++static void mlxsw_linecard_provision_clear(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard) + { + linecard->provisioned = false; ++ mlxsw_linecard_unprovision_cbs_call(mlxsw_core, linecards, ++ linecard); + mlxsw_linecard_devices_detach(linecard->linecards->mlxsw_core, + linecard); + devlink_linecard_provision_clear(linecard->devlink_linecard); +@@ -636,22 +702,43 @@ static int mlxsw_linecard_ready_clear(struct mlxsw_core *mlxsw_core, + } + + static int mlxsw_linecard_active_set(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, + struct mlxsw_linecard *linecard, + u16 hw_revision, u16 ini_version) + { ++ struct mlxsw_linecards_event_ops_item *item; + int err; + + err = mlxsw_linecard_devices_update(mlxsw_core, linecard); + if (err) + return err; ++ + linecard->active = true; ++ linecard->hw_revision = hw_revision; ++ linecard->ini_version = ini_version; ++ list_for_each_entry(item, &linecards->event_ops_list, list) { ++ if (!item->event_ops->got_active) ++ continue; ++ item->event_ops->got_active(mlxsw_core, linecard->slot_index, ++ linecard, item->priv); ++ } + devlink_linecard_activate(linecard->devlink_linecard); + return 0; + } + +-static void mlxsw_linecard_active_clear(struct mlxsw_linecard *linecard) ++static void mlxsw_linecard_active_clear(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard) + { ++ struct mlxsw_linecards_event_ops_item *item; ++ + linecard->active = false; ++ list_for_each_entry(item, &linecards->event_ops_list, list) { ++ if (!item->event_ops->got_inactive) ++ continue; ++ item->event_ops->got_inactive(mlxsw_core, linecard->slot_index, ++ linecard, item->priv); ++ } + devlink_linecard_deactivate(linecard->devlink_linecard); + } + +@@ -703,14 +790,14 @@ static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + + if (!process_provision_only && !linecard->unprovision_done && active && + linecard->active != active && linecard->ready) { +- err = mlxsw_linecard_active_set(mlxsw_core, linecard, ++ err = mlxsw_linecard_active_set(mlxsw_core, linecards, linecard, + hw_revision, ini_version); + if (err) + goto out; + } + + if (!process_provision_only && !active && linecard->active != active) +- mlxsw_linecard_active_clear(linecard); ++ mlxsw_linecard_active_clear(mlxsw_core, linecards, linecard); + + if (!process_provision_only && ready != MLXSW_REG_MDDQ_READY_READY && + linecard->ready) { +@@ -720,7 +807,7 @@ static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + } + + if (!provisioned && linecard->provisioned != provisioned) +- mlxsw_linecard_provision_clear(linecard); ++ mlxsw_linecard_provision_clear(mlxsw_core, linecards, linecard); + + out: + mutex_unlock(&linecard->lock); +@@ -1128,7 +1215,7 @@ static void mlxsw_linecard_pre_fini(struct mlxsw_core *mlxsw_core, + /* Make sure all scheduled events are processed */ + mlxsw_core_flush_owq(); + if (linecard->active) +- mlxsw_linecard_active_clear(linecard); ++ mlxsw_linecard_active_clear(mlxsw_core, linecards, linecard); + } + + static void mlxsw_linecard_fini(struct mlxsw_core *mlxsw_core, +@@ -1287,6 +1374,7 @@ int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core, + linecards->count = slot_count; + linecards->mlxsw_core = mlxsw_core; + linecards->bus_info = bus_info; ++ INIT_LIST_HEAD(&linecards->event_ops_list); + + linecards->wq = alloc_workqueue("mlxsw_linecards", 0, 0); + if (!linecards->wq) { +@@ -1360,6 +1448,7 @@ void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core, + + if (!linecards) + return; ++ WARN_ON(!list_empty(&linecards->event_ops_list)); + for (i = 0; i < linecards->count; i++) + mlxsw_linecard_fini(mlxsw_core, linecards, i + 1); + mlxsw_linecard_types_fini(linecards); +@@ -1367,4 +1456,37 @@ void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core, + kfree(linecards); + } + ++int mlxsw_linecards_event_ops_register(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards_event_ops *ops, ++ void *priv) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); ++ struct mlxsw_linecards_event_ops_item *item; ++ ++ item = kzalloc(sizeof(*item), GFP_KERNEL); ++ if (!item) ++ return -ENOMEM; ++ item->event_ops = ops; ++ item->priv = priv; ++ list_add_tail(&item->list, &linecards->event_ops_list); ++ return 0; ++} ++EXPORT_SYMBOL(mlxsw_linecards_event_ops_register); ++ ++void mlxsw_linecards_event_ops_unregister(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards_event_ops *ops, ++ void *priv) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); ++ struct mlxsw_linecards_event_ops_item *item, *tmp; ++ ++ list_for_each_entry_safe(item, tmp, &linecards->event_ops_list, list) { ++ if (item->event_ops == ops && item->priv == priv) { ++ list_del(&item->list); ++ kfree(item); ++ } ++ } ++} ++EXPORT_SYMBOL(mlxsw_linecards_event_ops_unregister); ++ + MODULE_FIRMWARE(MLXSW_LINECARDS_INI_BUNDLE_FILE); +-- +2.20.1 + diff --git a/patch/0148-mlxsw-core-Add-interfaces-for-line-card-initializati.patch b/patch/0148-mlxsw-core-Add-interfaces-for-line-card-initializati.patch new file mode 100644 index 000000000..e5e39186a --- /dev/null +++ b/patch/0148-mlxsw-core-Add-interfaces-for-line-card-initializati.patch @@ -0,0 +1,133 @@ +From d037308b118ee4a1ccf557dc3f1c47b81bb62c4c Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 13 Dec 2021 12:54:36 +0000 +Subject: [PATCH backport 5.10 148/182] mlxsw: core: Add interfaces for line + card initialization and de-initialization + +Add callback functions for line card cables info initialization and +de-initialization. + +The line card initialization / de-initialization APIs are to be called +when line card is set to active / inactive state by got_active() / +got_inactive() callbacks from line card state machine. +Access to cable info and real number of modules is available only after +line card is activated. + +Signed-off-by: Vadim Pasternak +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 78 +++++++++++++++++++ + 1 file changed, 78 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 4f3fc25af013..98f7cf672d9e 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -1160,6 +1160,77 @@ mlxsw_env_module_event_disable(struct mlxsw_env *mlxsw_env, u8 slot_index) + { + } + ++static void ++mlxsw_env_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_env *mlxsw_env = priv; ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; ++ int err; ++ ++ mlxsw_reg_mgpir_pack(mgpir_pl, slot_index); ++ err = mlxsw_reg_query(mlxsw_env->core, MLXSW_REG(mgpir), mgpir_pl); ++ if (err) ++ return; ++ ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, ++ &mlxsw_env->line_cards[slot_index]->module_count, ++ NULL); ++ mlxsw_env_module_event_enable(mlxsw_env, slot_index); ++} ++ ++static void ++mlxsw_env_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_env *mlxsw_env = priv; ++ ++ mlxsw_env_module_event_disable(mlxsw_env, slot_index); ++} ++ ++static struct mlxsw_linecards_event_ops mlxsw_env_event_ops = { ++ .got_active = mlxsw_env_got_active, ++ .got_inactive = mlxsw_env_got_inactive, ++}; ++ ++static int mlxsw_env_linecards_register(struct mlxsw_env *mlxsw_env) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_env->core); ++ int err; ++ ++ if (!linecards || !linecards->count) ++ return 0; ++ ++ err = mlxsw_linecards_event_ops_register(mlxsw_env->core, ++ &mlxsw_env_event_ops, ++ mlxsw_env); ++ if (err) ++ goto err_linecards_event_ops_register; ++ ++ return 0; ++ ++err_linecards_event_ops_register: ++ return err; ++} ++ ++static void mlxsw_env_linecards_unregister(struct mlxsw_env *mlxsw_env) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_env->core); ++ int i; ++ ++ if (!linecards || !linecards->count) ++ return; ++ ++ for (i = 1; i <= linecards->count; i++) { ++ if (mlxsw_env->line_cards[i]->module_count) ++ mlxsw_env_got_inactive(mlxsw_env->core, i, NULL, ++ mlxsw_env); ++ } ++ ++ mlxsw_linecards_event_ops_unregister(mlxsw_env->core, ++ &mlxsw_env_event_ops, mlxsw_env); ++} ++ + int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + { + u8 module_count, num_of_slots, max_module_count; +@@ -1196,6 +1267,10 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + mutex_init(&env->line_cards_lock); + *p_env = env; + ++ err = mlxsw_env_linecards_register(env); ++ if (err) ++ goto err_linecards_register; ++ + err = mlxsw_env_temp_warn_event_register(mlxsw_core); + if (err) + goto err_temp_warn_event_register; +@@ -1223,6 +1298,8 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + err_module_plug_event_register: + mlxsw_env_temp_warn_event_unregister(env); + err_temp_warn_event_register: ++ mlxsw_env_linecards_unregister(env); ++err_linecards_register: + mutex_destroy(&env->line_cards_lock); + mlxsw_env_line_cards_free(env); + err_mlxsw_env_line_cards_alloc: +@@ -1237,6 +1314,7 @@ void mlxsw_env_fini(struct mlxsw_env *env) + /* Make sure there is no more event work scheduled. */ + mlxsw_core_flush_owq(); + mlxsw_env_temp_warn_event_unregister(env); ++ mlxsw_env_linecards_unregister(env); + mutex_destroy(&env->line_cards_lock); + mlxsw_env_line_cards_free(env); + kfree(env); +-- +2.20.1 + diff --git a/patch/0149-mlxsw-core_thermal-Add-interfaces-for-line-card-init.patch b/patch/0149-mlxsw-core_thermal-Add-interfaces-for-line-card-init.patch new file mode 100644 index 000000000..e68844037 --- /dev/null +++ b/patch/0149-mlxsw-core_thermal-Add-interfaces-for-line-card-init.patch @@ -0,0 +1,213 @@ +From 71416a2dd1900ac8eb9b7d5cd08911d331b074ff Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 12 May 2021 22:57:39 +0300 +Subject: [PATCH backport 5.10 149/182] mlxsw: core_thermal: Add interfaces for + line card initialization and de-initialization + +Add callback functions for line card thermal area initialization and +de-initialization. Each line card is associated with the relevant +thermal area, which may contain thermal zones for cages and gearboxes +found on this line card. + +The line card thermal initialization / de-initialization APIs are to be +called when line card is set to active / inactive state by +got_active() / got_inactive() callbacks from line card state machine. + +For example thermal zone for module #9 located at line card #7 will +have type: +mlxsw-lc7-module9. +And thermal zone for gearbox #2 located at line card #5 will have type: +mlxsw-lc5-gearbox2. + +For now the slot index is always 0 and field 'name' of the structure +'mlxsw_hwmon_dev' is empty. For line card this field is supposed to +be initialized to 'lc#n', when line card in slot #n is enabled. + +Add validation of modules number found on main board in function +mlxsw_thermal_modules_init(). On modular system this counter might be +zero. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Jiri Pirko +--- + .../ethernet/mellanox/mlxsw/core_thermal.c | 129 ++++++++++++++++++ + 1 file changed, 129 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index b9253c9f70d9..529108aea3c6 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -88,6 +88,7 @@ struct mlxsw_thermal_module { + }; + + struct mlxsw_thermal_area { ++ struct mlxsw_thermal *parent; + struct mlxsw_thermal_module *tz_module_arr; + u8 tz_module_num; + struct mlxsw_thermal_module *tz_gearbox_arr; +@@ -105,6 +106,7 @@ struct mlxsw_thermal { + u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1]; + struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; + struct mlxsw_thermal_area *main; ++ struct mlxsw_thermal_area **linecards; + unsigned int tz_highest_score; + struct thermal_zone_device *tz_highest_dev; + }; +@@ -948,6 +950,126 @@ mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal, + mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]); + } + ++static void ++mlxsw_thermal_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_env_gearbox_sensors_map map; ++ struct mlxsw_thermal *thermal = priv; ++ struct mlxsw_thermal_area *lc; ++ int err; ++ ++ lc = kzalloc(sizeof(*lc), GFP_KERNEL); ++ if (!lc) ++ return; ++ ++ lc->slot_index = slot_index; ++ lc->parent = thermal; ++ thermal->linecards[slot_index - 1] = lc; ++ err = mlxsw_thermal_modules_init(thermal->bus_info->dev, thermal->core, ++ thermal, lc); ++ if (err) ++ goto err_thermal_linecard_modules_init; ++ ++ err = mlxsw_env_sensor_map_create(thermal->core, thermal->bus_info, ++ linecard->slot_index, &map); ++ if (err) ++ goto err_thermal_linecard_env_sensor_map_create; ++ ++ lc->gearbox_sensor_map = map.sensor_bit_map; ++ lc->tz_gearbox_num = map.sensor_count; ++ lc->tz_gearbox_arr = kcalloc(lc->tz_gearbox_num, sizeof(*lc->tz_gearbox_arr), ++ GFP_KERNEL); ++ if (!lc->tz_gearbox_arr) { ++ err = -ENOMEM; ++ goto err_tz_gearbox_arr_alloc; ++ } ++ ++ err = mlxsw_thermal_gearboxes_init(thermal->bus_info->dev, thermal->core, ++ thermal, lc); ++ if (err) ++ goto err_thermal_linecard_gearboxes_init; ++ ++ return; ++ ++err_thermal_linecard_gearboxes_init: ++ kfree(lc->tz_gearbox_arr); ++err_tz_gearbox_arr_alloc: ++ mlxsw_env_sensor_map_destroy(thermal->bus_info, ++ lc->gearbox_sensor_map); ++err_thermal_linecard_env_sensor_map_create: ++ mlxsw_thermal_modules_fini(thermal, lc); ++err_thermal_linecard_modules_init: ++ kfree(lc); ++ thermal->linecards[slot_index - 1] = NULL; ++} ++ ++static void mlxsw_thermal_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_thermal *thermal = priv; ++ struct mlxsw_thermal_area *lc = thermal->linecards[slot_index - 1]; ++ ++ mlxsw_thermal_gearboxes_fini(thermal, lc); ++ kfree(lc->tz_gearbox_arr); ++ mlxsw_env_sensor_map_destroy(thermal->bus_info, ++ lc->gearbox_sensor_map); ++ mlxsw_thermal_modules_fini(thermal, lc); ++ kfree(lc); ++ thermal->linecards[slot_index - 1] = NULL; ++} ++ ++static struct mlxsw_linecards_event_ops mlxsw_thermal_event_ops = { ++ .got_active = mlxsw_thermal_got_active, ++ .got_inactive = mlxsw_thermal_got_inactive, ++}; ++ ++static int mlxsw_thermal_linecards_register(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_thermal *thermal) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); ++ int err; ++ ++ if (!linecards || !linecards->count) ++ return 0; ++ ++ thermal->linecards = kcalloc(linecards->count, sizeof(*thermal->linecards), ++ GFP_KERNEL); ++ if (!thermal->linecards) ++ return -ENOMEM; ++ ++ err = mlxsw_linecards_event_ops_register(mlxsw_core, ++ &mlxsw_thermal_event_ops, ++ thermal); ++ if (err) ++ goto err_linecards_event_ops_register; ++ ++ return 0; ++ ++err_linecards_event_ops_register: ++ kfree(thermal->linecards); ++ return err; ++} ++ ++static void mlxsw_thermal_linecards_unregister(struct mlxsw_thermal *thermal) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(thermal->core); ++ int i; ++ ++ if (!linecards || !linecards->count) ++ return; ++ ++ for (i = 1; i <= linecards->count; i++) { ++ if (thermal->linecards[i - 1]) ++ mlxsw_thermal_got_inactive(thermal->core, i, NULL, ++ thermal); ++ } ++ ++ mlxsw_linecards_event_ops_unregister(thermal->core, ++ &mlxsw_thermal_event_ops, thermal); ++ kfree(thermal->linecards); ++} ++ + int mlxsw_thermal_init(struct mlxsw_core *core, + const struct mlxsw_bus_info *bus_info, + struct mlxsw_thermal **p_thermal) +@@ -1052,6 +1174,10 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + if (err) + goto err_thermal_gearboxes_init; + ++ err = mlxsw_thermal_linecards_register(core, thermal); ++ if (err) ++ goto err_linecards_register; ++ + err = thermal_zone_device_enable(thermal->tzdev); + if (err) + goto err_thermal_zone_device_enable; +@@ -1060,6 +1186,8 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + return 0; + + err_thermal_zone_device_enable: ++ mlxsw_thermal_linecards_unregister(thermal); ++err_linecards_register: + mlxsw_thermal_gearboxes_fini(thermal, thermal->main); + err_thermal_gearboxes_init: + mlxsw_thermal_gearboxes_main_fini(thermal->main); +@@ -1087,6 +1215,7 @@ void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) + { + int i; + ++ mlxsw_thermal_linecards_unregister(thermal); + mlxsw_thermal_gearboxes_fini(thermal, thermal->main); + mlxsw_thermal_gearboxes_main_fini(thermal->main); + mlxsw_thermal_modules_fini(thermal, thermal->main); +-- +2.20.1 + diff --git a/patch/0150-mlxsw-core_hwmon-Add-interfaces-for-line-card-initia.patch b/patch/0150-mlxsw-core_hwmon-Add-interfaces-for-line-card-initia.patch new file mode 100644 index 000000000..3c229622d --- /dev/null +++ b/patch/0150-mlxsw-core_hwmon-Add-interfaces-for-line-card-initia.patch @@ -0,0 +1,235 @@ +From 7405ad4281c96aedcf879357d03487556abed05d Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 12 May 2021 22:57:42 +0300 +Subject: [PATCH backport 5.10 150/182] mlxsw: core_hwmon: Add interfaces for + line card initialization and de-initialization + +Add callback functions for line card 'hwmon' initialization and +de-initialization. Each line card is associated with the relevant +'hwmon' device, which may contain thermal attributes for the cages +and gearboxes found on this line card. + +The line card 'hwmon' initialization / de-initialization APIs are to be +called when line card is set to active / inactive state by +got_active() / got_inactive() callbacks from line card state machine. + +For example cage temperature for module #9 located at line card #7 will +be exposed by utility 'sensors' like: +linecard#07 +front panel 009: +32.0C (crit = +70.0C, emerg = +80.0C) +And temperature for gearbox #3 located at line card #5 will be exposed +like: +linecard#05 +gearbox 003: +41.0C (highest = +41.0C) + +Signed-off-by: Vadim Pasternak +Signed-off-by: Jiri Pirko +--- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 137 +++++++++++++++++- + 1 file changed, 134 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 6af23f4724e4..a27146ccafc5 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -19,6 +19,7 @@ + #define MLXSW_HWMON_ATTR_PER_SENSOR 3 + #define MLXSW_HWMON_ATTR_PER_MODULE 7 + #define MLXSW_HWMON_ATTR_PER_GEARBOX 4 ++#define MLXSW_HWMON_DEV_NAME_LEN_MAX 16 + + #define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_SENSORS_MAX_COUNT * MLXSW_HWMON_ATTR_PER_SENSOR + \ + MLXSW_HWMON_MODULES_MAX_COUNT * MLXSW_HWMON_ATTR_PER_MODULE + \ +@@ -42,6 +43,7 @@ mlxsw_hwmon_get_attr_index(int index, int count, u16 *gearbox_sensor_map) + } + + struct mlxsw_hwmon_dev { ++ char name[MLXSW_HWMON_DEV_NAME_LEN_MAX]; + struct mlxsw_hwmon *hwmon; + struct device *hwmon_dev; + struct attribute_group group; +@@ -59,6 +61,7 @@ struct mlxsw_hwmon { + struct mlxsw_core *core; + const struct mlxsw_bus_info *bus_info; + struct mlxsw_hwmon_dev *main; ++ struct mlxsw_hwmon_dev **linecards; + }; + + static ssize_t mlxsw_hwmon_temp_show(struct device *dev, +@@ -405,9 +408,14 @@ mlxsw_hwmon_module_temp_label_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev; ++ int index = mlxsw_hwmon_attr->type_index; ++ ++ mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ if (strlen(mlxsw_hwmon_dev->name)) ++ index += 1; + +- return sprintf(buf, "front panel %03u\n", +- mlxsw_hwmon_attr->type_index); ++ return sprintf(buf, "front panel %03u\n", index); + } + + static ssize_t +@@ -691,7 +699,7 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + u8 module_sensor_max; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl, 0); ++ mlxsw_reg_mgpir_pack(mgpir_pl, mlxsw_hwmon_dev->slot_index); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; +@@ -819,6 +827,122 @@ mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, u8 gbox_num) + return 0; + } + ++static void ++mlxsw_hwmon_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_hwmon *hwmon = priv; ++ struct device *dev = hwmon->bus_info->dev; ++ struct mlxsw_env_gearbox_sensors_map map; ++ struct mlxsw_hwmon_dev *lc; ++ int err; ++ ++ lc = kzalloc(sizeof(*lc), GFP_KERNEL); ++ if (!lc) ++ return; ++ lc->slot_index = slot_index; ++ lc->hwmon = hwmon; ++ err = mlxsw_hwmon_module_init(lc); ++ if (err) ++ goto err_hwmon_linecard_module_init; ++ ++ err = mlxsw_env_sensor_map_create(hwmon->core, ++ hwmon->bus_info, slot_index, ++ &map); ++ if (err) ++ goto err_hwmon_linecard_env_sensor_map_create; ++ ++ lc->gearbox_sensor_map = map.sensor_bit_map; ++ err = mlxsw_hwmon_gearbox_init(lc, map.sensor_count); ++ if (err) ++ goto err_hwmon_linecard_gearbox_init; ++ ++ lc->groups[0] = &lc->group; ++ lc->group.attrs = lc->attrs; ++ sprintf(lc->name, "%s#%02u", "linecard", slot_index); ++ lc->hwmon_dev = hwmon_device_register_with_groups(dev, (const char *) lc->name, ++ lc, lc->groups); ++ if (IS_ERR(lc->hwmon_dev)) { ++ err = PTR_ERR(lc->hwmon_dev); ++ goto err_hwmon_linecard_register; ++ } ++ hwmon->linecards[slot_index - 1] = lc; ++ ++ return; ++ ++err_hwmon_linecard_register: ++err_hwmon_linecard_gearbox_init: ++ mlxsw_env_sensor_map_destroy(hwmon->bus_info, ++ lc->gearbox_sensor_map); ++err_hwmon_linecard_env_sensor_map_create: ++err_hwmon_linecard_module_init: ++ kfree(lc); ++} ++ ++static void ++mlxsw_hwmon_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_hwmon *hwmon = priv; ++ struct mlxsw_hwmon_dev *lc = hwmon->linecards[slot_index - 1]; ++ ++ if (lc->hwmon_dev) ++ hwmon_device_unregister(lc->hwmon_dev); ++ mlxsw_env_sensor_map_destroy(hwmon->bus_info, ++ lc->gearbox_sensor_map); ++ kfree(lc); ++ hwmon->linecards[slot_index - 1] = NULL; ++} ++ ++static struct mlxsw_linecards_event_ops mlxsw_hwmon_event_ops = { ++ .got_active = mlxsw_hwmon_got_active, ++ .got_inactive = mlxsw_hwmon_got_inactive, ++}; ++ ++static int mlxsw_hwmon_linecards_register(struct mlxsw_hwmon *hwmon) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(hwmon->core); ++ int err; ++ ++ if (!linecards || !linecards->count) ++ return 0; ++ ++ hwmon->linecards = kcalloc(linecards->count, sizeof(*hwmon->linecards), ++ GFP_KERNEL); ++ if (!hwmon->linecards) ++ return -ENOMEM; ++ ++ err = mlxsw_linecards_event_ops_register(hwmon->core, ++ &mlxsw_hwmon_event_ops, ++ hwmon); ++ if (err) ++ goto err_linecards_event_ops_register; ++ ++ return 0; ++ ++err_linecards_event_ops_register: ++ kfree(hwmon->linecards); ++ return err; ++} ++ ++static void mlxsw_hwmon_linecards_unregister(struct mlxsw_hwmon *hwmon) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(hwmon->core); ++ int i; ++ ++ if (!linecards || !linecards->count) ++ return; ++ ++ for (i = 1; i <= linecards->count; i++) { ++ if (hwmon->linecards[i - 1]) ++ mlxsw_hwmon_got_inactive(hwmon->core, i, NULL, hwmon); ++ } ++ ++ mlxsw_linecards_event_ops_unregister(hwmon->core, ++ &mlxsw_hwmon_event_ops, hwmon); ++ kfree(hwmon->linecards); ++} ++ + int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + const struct mlxsw_bus_info *mlxsw_bus_info, + struct mlxsw_hwmon **p_hwmon) +@@ -872,10 +996,16 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + goto err_hwmon_register; + } + ++ err = mlxsw_hwmon_linecards_register(mlxsw_hwmon); ++ if (err) ++ goto err_linecards_register; ++ + mlxsw_hwmon->main->hwmon_dev = hwmon_dev; + *p_hwmon = mlxsw_hwmon; + return 0; + ++err_linecards_register: ++ hwmon_device_unregister(mlxsw_hwmon->main->hwmon_dev); + err_hwmon_register: + err_gearbox_init: + mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon->main); +@@ -891,6 +1021,7 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + + void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon) + { ++ mlxsw_hwmon_linecards_unregister(mlxsw_hwmon); + hwmon_device_unregister(mlxsw_hwmon->main->hwmon_dev); + mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon->main); + kfree(mlxsw_hwmon->main); +-- +2.20.1 + diff --git a/patch/0151-mlxsw-minimal-Prepare-driver-for-modular-system-supp.patch b/patch/0151-mlxsw-minimal-Prepare-driver-for-modular-system-supp.patch new file mode 100644 index 000000000..8aeb3848a --- /dev/null +++ b/patch/0151-mlxsw-minimal-Prepare-driver-for-modular-system-supp.patch @@ -0,0 +1,496 @@ +From e3a3f15e69b566577c2ebe0b6f3bc019476c6879 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 30 Dec 2021 16:02:59 +0000 +Subject: [PATCH backport 5.10 151/182] mlxsw: minimal: Prepare driver for + modular system support + +As a preparation for line cards support: +- Allocate per line card array according to the queried number of slots + in the system. For each line card, allocate a port mapping array + according to the queried maximum number of ports available in system. + Port mapping array includes port object handle, local port number and + module number. +- Extend port creation APIs with 'slot_index' argument. +- Extend port structure with slot index and module offset for this slot + index. + +For main board, slot will always be set to zero and these APIs will work +as before. For the ports located on line cards, slot should be set to the +physical slot number, where line card is located in modular systems. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 293 +++++++++++++++--- + 1 file changed, 242 insertions(+), 51 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 30925f57362e..59c5053dc5fd 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -24,22 +24,40 @@ static const struct mlxsw_fw_rev mlxsw_m_fw_rev = { + .subminor = MLXSW_M_FWREV_SUBMINOR, + }; + ++struct mlxsw_m_line_card; + struct mlxsw_m_port; + + struct mlxsw_m { +- struct mlxsw_m_port **ports; +- int *module_to_port; + struct mlxsw_core *core; + const struct mlxsw_bus_info *bus_info; + u8 base_mac[ETH_ALEN]; + u8 max_ports; ++ u8 max_module_count; /* Maximum number of modules per-slot. */ ++ u8 num_of_slots; /* Including the main board. */ ++ struct mlxsw_m_line_card **line_cards; ++}; ++ ++struct mlxsw_m_port_mapping { ++ struct mlxsw_m_port *port; ++ int module_to_port; ++ u8 module; ++}; ++ ++struct mlxsw_m_line_card { ++ struct mlxsw_m *mlxsw_m; ++ u8 max_ports; ++ u8 module_offset; ++ bool active; ++ struct mlxsw_m_port_mapping port_mapping[]; + }; + + struct mlxsw_m_port { + struct net_device *dev; + struct mlxsw_m *mlxsw_m; +- u8 local_port; ++ u16 local_port; + u8 module; ++ u8 slot_index; ++ u8 module_offset; + }; + + static int mlxsw_m_base_mac_get(struct mlxsw_m *mlxsw_m) +@@ -111,8 +129,8 @@ static int mlxsw_m_get_module_info(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_info(core, 0, mlxsw_m_port->module, +- modinfo); ++ return mlxsw_env_get_module_info(core, mlxsw_m_port->slot_index, ++ mlxsw_m_port->module, modinfo); + } + + static int +@@ -122,7 +140,8 @@ mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_eeprom(netdev, core, 0, ++ return mlxsw_env_get_module_eeprom(netdev, core, ++ mlxsw_m_port->slot_index, + mlxsw_m_port->module, ee, data); + } + +@@ -134,7 +153,8 @@ mlxsw_m_get_module_eeprom_by_page(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_eeprom_by_page(core, 0, ++ return mlxsw_env_get_module_eeprom_by_page(core, ++ mlxsw_m_port->slot_index, + mlxsw_m_port->module, + page, extack); + } +@@ -144,7 +164,8 @@ static int mlxsw_m_reset(struct net_device *netdev, u32 *flags) + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_reset_module(netdev, core, 0, mlxsw_m_port->module, ++ return mlxsw_env_reset_module(netdev, core, mlxsw_m_port->slot_index, ++ mlxsw_m_port->module, + flags); + } + +@@ -156,7 +177,8 @@ mlxsw_m_get_module_power_mode(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_power_mode(core, 0, mlxsw_m_port->module, ++ return mlxsw_env_get_module_power_mode(core, mlxsw_m_port->slot_index, ++ mlxsw_m_port->module, + params, extack); + } + +@@ -168,7 +190,8 @@ mlxsw_m_set_module_power_mode(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_set_module_power_mode(core, 0, mlxsw_m_port->module, ++ return mlxsw_env_set_module_power_mode(core, mlxsw_m_port->slot_index, ++ mlxsw_m_port->module, + params->policy, extack); + } + +@@ -199,19 +222,31 @@ mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port) + * to be such it does not overflow when adding local_port + * value. + */ +- dev->dev_addr[ETH_ALEN - 1] = mlxsw_m_port->module + 1; ++ dev->dev_addr[ETH_ALEN - 1] = mlxsw_m_port->module + 1 + ++ mlxsw_m_port->module_offset; + return 0; + } + ++static struct ++mlxsw_m_port_mapping *mlxsw_m_port_mapping_get(struct mlxsw_m *mlxsw_m, ++ u8 slot_index, u8 local_port) ++{ ++ return &mlxsw_m->line_cards[slot_index]->port_mapping[local_port]; ++} ++ + static int +-mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) ++mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 slot_index, u16 local_port, ++ u8 module) + { ++ struct mlxsw_m_port_mapping *port_mapping; + struct mlxsw_m_port *mlxsw_m_port; + struct net_device *dev; ++ u8 module_offset; + int err; + +- err = mlxsw_core_port_init(mlxsw_m->core, local_port, 0, +- module + 1, false, 0, false, ++ module_offset = mlxsw_m->line_cards[slot_index]->module_offset; ++ err = mlxsw_core_port_init(mlxsw_m->core, local_port, slot_index, ++ module + 1 + module_offset, false, 0, false, + 0, mlxsw_m->base_mac, + sizeof(mlxsw_m->base_mac)); + if (err) { +@@ -233,6 +268,13 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) + mlxsw_m_port->mlxsw_m = mlxsw_m; + mlxsw_m_port->local_port = local_port; + mlxsw_m_port->module = module; ++ mlxsw_m_port->slot_index = slot_index; ++ /* Add module offset for line card. Offset for main board iz zero. ++ * For line card in slot #n offset is calculated as (#n - 1) ++ * multiplied by maximum modules number, which could be found on a line ++ * card. ++ */ ++ mlxsw_m_port->module_offset = module_offset; + + dev->netdev_ops = &mlxsw_m_port_netdev_ops; + dev->ethtool_ops = &mlxsw_m_port_ethtool_ops; +@@ -245,7 +287,9 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) + } + + netif_carrier_off(dev); +- mlxsw_m->ports[local_port] = mlxsw_m_port; ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ local_port); ++ port_mapping->port = mlxsw_m_port; + err = register_netdev(dev); + if (err) { + dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to register netdev\n", +@@ -259,7 +303,7 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) + return 0; + + err_register_netdev: +- mlxsw_m->ports[local_port] = NULL; ++ port_mapping->port = NULL; + err_dev_addr_get: + free_netdev(dev); + err_alloc_etherdev: +@@ -267,72 +311,130 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) + return err; + } + +-static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 local_port) ++static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 slot_index, ++ u16 local_port) + { +- struct mlxsw_m_port *mlxsw_m_port = mlxsw_m->ports[local_port]; ++ struct mlxsw_m_port_mapping *port_mapping; ++ struct mlxsw_m_port *mlxsw_m_port; + ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ local_port); ++ mlxsw_m_port = port_mapping->port; + mlxsw_core_port_clear(mlxsw_m->core, local_port, mlxsw_m); + unregister_netdev(mlxsw_m_port->dev); /* This calls ndo_stop */ +- mlxsw_m->ports[local_port] = NULL; ++ port_mapping->port = NULL; + free_netdev(mlxsw_m_port->dev); + mlxsw_core_port_fini(mlxsw_m->core, local_port); + } + +-static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) ++static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 slot_index, ++ u16 local_port, u8 module) ++{ ++ struct mlxsw_m_port_mapping *port_mapping; ++ ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ local_port); ++ ++ if (WARN_ON_ONCE(port_mapping->module_to_port >= mlxsw_m->max_ports)) ++ return -EINVAL; ++ mlxsw_env_module_port_map(mlxsw_m->core, slot_index, module); ++ port_mapping->module_to_port = local_port; ++ port_mapping->module = module; ++ ++ return 0; ++} ++ ++static void ++mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 slot_index, ++ struct mlxsw_m_port_mapping *port_mapping) + { ++ port_mapping->module_to_port = -1; ++ mlxsw_env_module_port_unmap(mlxsw_m->core, slot_index, ++ port_mapping->module); ++} ++ ++static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m, u8 slot_index) ++{ ++ struct mlxsw_m_port_mapping *port_mapping; ++ struct mlxsw_m_line_card *line_card; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl, 0); ++ mlxsw_reg_mgpir_pack(mgpir_pl, slot_index); + err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + ++ line_card = mlxsw_m->line_cards[slot_index]; + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, +- &mlxsw_m->max_ports, NULL); +- if (!mlxsw_m->max_ports) ++ &line_card->max_ports, NULL); ++ if (!line_card->max_ports) + return 0; + +- mlxsw_m->ports = kcalloc(mlxsw_m->max_ports, sizeof(*mlxsw_m->ports), +- GFP_KERNEL); +- if (!mlxsw_m->ports) +- return -ENOMEM; ++ line_card->max_ports += 1; ++ line_card->module_offset = slot_index ? (slot_index - 1) * ++ mlxsw_m->max_module_count : 0; + +- mlxsw_m->module_to_port = kmalloc_array(mlxsw_m->max_ports, sizeof(int), +- GFP_KERNEL); +- if (!mlxsw_m->module_to_port) { +- err = -ENOMEM; +- goto err_module_to_port_alloc; ++ /* Fill out module to local port mapping array */ ++ for (i = 1; i < mlxsw_m->line_cards[slot_index]->max_ports; i++) { ++ err = mlxsw_m_port_module_map(mlxsw_m, slot_index, i + ++ line_card->module_offset, i - 1); ++ if (err) ++ goto err_module_to_port_map; + } + +- /* Create port objects for each entry. */ ++ /* Create port objects for each valid entry */ + for (i = 0; i < mlxsw_m->max_ports; i++) { +- mlxsw_m->module_to_port[i] = i; +- err = mlxsw_m_port_create(mlxsw_m, mlxsw_m->module_to_port[i], i); +- if (err) +- goto err_module_to_port_create; ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ i); ++ if (port_mapping->module_to_port > 0) { ++ err = mlxsw_m_port_create(mlxsw_m, slot_index, ++ port_mapping->module_to_port, ++ port_mapping->module); ++ if (err) ++ goto err_module_to_port_create; ++ } + } + + return 0; + + err_module_to_port_create: +- for (i--; i >= 0; i--) +- mlxsw_m_port_remove(mlxsw_m, mlxsw_m->module_to_port[i]); +- kfree(mlxsw_m->module_to_port); +-err_module_to_port_alloc: +- kfree(mlxsw_m->ports); ++ for (i--; i >= 0; i--) { ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ i); ++ if (port_mapping->module_to_port > 0) ++ mlxsw_m_port_remove(mlxsw_m, slot_index, ++ port_mapping->module_to_port); ++ } ++ i = mlxsw_m->max_ports; ++err_module_to_port_map: ++ for (i--; i > 0; i--) { ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ i); ++ if (port_mapping->module_to_port > 0) ++ mlxsw_m_port_module_unmap(mlxsw_m, slot_index, ++ port_mapping); ++ } + return err; + } + +-static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) ++static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m, u8 slot_index) + { ++ struct mlxsw_m_port_mapping *port_mapping; ++ u8 module; + int i; + +- for (i = 0; i < mlxsw_m->max_ports; i++) +- mlxsw_m_port_remove(mlxsw_m, mlxsw_m->module_to_port[i]); +- +- kfree(mlxsw_m->module_to_port); +- kfree(mlxsw_m->ports); ++ for (i = 0; i < mlxsw_m->max_ports; i++) { ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ i); ++ if (port_mapping->module_to_port > 0) { ++ module = port_mapping->port->module; ++ mlxsw_m_port_remove(mlxsw_m, slot_index, ++ port_mapping->module_to_port); ++ mlxsw_m_port_module_unmap(mlxsw_m, slot_index, ++ port_mapping); ++ } ++ } + } + + static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m) +@@ -353,6 +455,78 @@ static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m) + return -EINVAL; + } + ++static int mlxsw_m_get_peripheral_info(struct mlxsw_m *mlxsw_m) ++{ ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; ++ u8 module_count; ++ int err; ++ ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); ++ err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mgpir), mgpir_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count, ++ &mlxsw_m->num_of_slots); ++ /* If the system is modular, get the maximum number of modules per-slot. ++ * Otherwise, get the maximum number of modules on the main board. ++ */ ++ mlxsw_m->max_module_count = mlxsw_m->num_of_slots ? ++ mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl) : ++ module_count; ++ /* Add slot for main board. */ ++ mlxsw_m->num_of_slots += 1; ++ ++ return 0; ++} ++ ++static int mlxsw_env_line_cards_alloc(struct mlxsw_m *mlxsw_m) ++{ ++ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core); ++ struct mlxsw_m_port_mapping *port_mapping; ++ int i, j; ++ ++ mlxsw_m->line_cards = kcalloc(mlxsw_m->num_of_slots, ++ sizeof(*mlxsw_m->line_cards), ++ GFP_KERNEL); ++ if (!mlxsw_m->line_cards) ++ goto err_kcalloc; ++ ++ for (i = 0; i < mlxsw_m->num_of_slots; i++) { ++ mlxsw_m->line_cards[i] = kzalloc(struct_size(mlxsw_m->line_cards[i], ++ port_mapping, max_ports), ++ GFP_KERNEL); ++ if (!mlxsw_m->line_cards[i]) ++ goto kzalloc_err; ++ ++ /* Invalidate the entries of module to local port mapping array */ ++ for (j = 0; j < mlxsw_m->max_ports; j++) { ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, i, j); ++ port_mapping->module_to_port = -1; ++ } ++ } ++ ++ mlxsw_m->max_ports = max_ports; ++ ++ return 0; ++ ++kzalloc_err: ++ for (i--; i >= 0; i--) ++ kfree(mlxsw_m->line_cards[i]); ++err_kcalloc: ++ kfree(mlxsw_m->line_cards); ++ return -ENOMEM; ++} ++ ++static void mlxsw_m_line_cards_free(struct mlxsw_m *mlxsw_m) ++{ ++ int i = mlxsw_m->num_of_slots; ++ ++ for (i--; i >= 0; i--) ++ kfree(mlxsw_m->line_cards[i]); ++ kfree(mlxsw_m->line_cards); ++} ++ + static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) +@@ -367,26 +541,43 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, + if (err) + return err; + ++ err = mlxsw_m_get_peripheral_info(mlxsw_m); ++ if (err) { ++ dev_err(mlxsw_m->bus_info->dev, "Failed to get peripheral info\n"); ++ return err; ++ } ++ + err = mlxsw_m_base_mac_get(mlxsw_m); + if (err) { + dev_err(mlxsw_m->bus_info->dev, "Failed to get base mac\n"); + return err; + } + +- err = mlxsw_m_ports_create(mlxsw_m); ++ err = mlxsw_env_line_cards_alloc(mlxsw_m); + if (err) { +- dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n"); ++ dev_err(mlxsw_m->bus_info->dev, "Failed to allocate memory\n"); + return err; + } + ++ err = mlxsw_m_ports_create(mlxsw_m, 0); ++ if (err) { ++ dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n"); ++ goto err_mlxsw_m_ports_create; ++ } ++ + return 0; ++ ++err_mlxsw_m_ports_create: ++ mlxsw_m_line_cards_free(mlxsw_m); ++ return err; + } + + static void mlxsw_m_fini(struct mlxsw_core *mlxsw_core) + { + struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); + +- mlxsw_m_ports_remove(mlxsw_m); ++ mlxsw_m_ports_remove(mlxsw_m, 0); ++ mlxsw_m_line_cards_free(mlxsw_m); + } + + static const struct mlxsw_config_profile mlxsw_m_config_profile; +-- +2.20.1 + diff --git a/patch/0152-mlxsw-core-Extend-bus-init-function-with-event-handl.patch b/patch/0152-mlxsw-core-Extend-bus-init-function-with-event-handl.patch new file mode 100644 index 000000000..d81e11aa1 --- /dev/null +++ b/patch/0152-mlxsw-core-Extend-bus-init-function-with-event-handl.patch @@ -0,0 +1,90 @@ +From da7c615b231402e3084dae855468be117538535c Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 15 Dec 2021 08:59:14 +0000 +Subject: [PATCH backport 5.10 152/182] mlxsw: core: Extend bus init function + with event handler argument + +The purpose of new argument - is to introduce system event handler for +treating line card activation / deactivation signals on modular system. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 3 ++- + drivers/net/ethernet/mellanox/mlxsw/core.h | 4 +++- + drivers/net/ethernet/mellanox/mlxsw/i2c.c | 3 ++- + drivers/net/ethernet/mellanox/mlxsw/pci.c | 9 ++++++--- + 4 files changed, 13 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 8c128078105a..a9bb43837b33 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -2005,7 +2005,8 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + } + + res = mlxsw_driver->res_query_enabled ? &mlxsw_core->res : NULL; +- err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile, res); ++ err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile, res, ++ mlxsw_driver->sys_event_handler); + if (err) + goto err_bus_init; + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 10ea541bb19d..b09f9013db77 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -390,6 +390,7 @@ struct mlxsw_driver { + */ + void (*ptp_transmitted)(struct mlxsw_core *mlxsw_core, + struct sk_buff *skb, u8 local_port); ++ void (*sys_event_handler)(struct mlxsw_core *mlxsw_core); + + u8 txhdr_len; + const struct mlxsw_config_profile *profile; +@@ -432,7 +433,8 @@ struct mlxsw_bus { + const char *kind; + int (*init)(void *bus_priv, struct mlxsw_core *mlxsw_core, + const struct mlxsw_config_profile *profile, +- struct mlxsw_res *res); ++ struct mlxsw_res *res, ++ void (*sys_event_handler)(struct mlxsw_core *mlxsw_core)); + void (*fini)(void *bus_priv); + bool (*skb_transmit_busy)(void *bus_priv, + const struct mlxsw_tx_info *tx_info); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +index ce843ea91464..0cdb9b9d8353 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +@@ -509,7 +509,8 @@ static int mlxsw_i2c_skb_transmit(void *bus_priv, struct sk_buff *skb, + static int + mlxsw_i2c_init(void *bus_priv, struct mlxsw_core *mlxsw_core, + const struct mlxsw_config_profile *profile, +- struct mlxsw_res *res) ++ struct mlxsw_res *res, ++ void (*sys_event_handler)(struct mlxsw_core *mlxsw_core)) + { + struct mlxsw_i2c *mlxsw_i2c = bus_priv; + char *mbox; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c +index dbb16ce25bdf..e8e91130cdf5 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c +@@ -1411,9 +1411,12 @@ static void mlxsw_pci_free_irq_vectors(struct mlxsw_pci *mlxsw_pci) + pci_free_irq_vectors(mlxsw_pci->pdev); + } + +-static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, +- const struct mlxsw_config_profile *profile, +- struct mlxsw_res *res) ++static int ++mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, ++ const struct mlxsw_config_profile *profile, ++ struct mlxsw_res *res, ++ void (*sys_event_handler)(struct mlxsw_core *mlxsw_core)) ++ + { + struct mlxsw_pci *mlxsw_pci = bus_priv; + struct pci_dev *pdev = mlxsw_pci->pdev; +-- +2.20.1 + diff --git a/patch/0153-mlxsw-i2c-Add-support-for-system-events-handling.patch b/patch/0153-mlxsw-i2c-Add-support-for-system-events-handling.patch new file mode 100644 index 000000000..8c877cce2 --- /dev/null +++ b/patch/0153-mlxsw-i2c-Add-support-for-system-events-handling.patch @@ -0,0 +1,199 @@ +From 4cc4f0a420eddc9157f8749a5ec133f998d17974 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 19 Dec 2021 09:12:58 +0000 +Subject: [PATCH backport 5.10 153/182] mlxsw: i2c: Add support for system + events handling + +Extend i2c bus driver with interrupt handler to support system specific +hotplug events, related to line card state change. +Provide system IRQ line for interrupt handler. Line Id could be +provided through the platform data if available, or could be set to the +default value. +Handler is supposed to be set by "mlxsw" driver through bus driver init() +call. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/i2c.c | 110 ++++++++++++++++++++++ + 1 file changed, 110 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +index 0cdb9b9d8353..015f6dbe0f8a 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + + #include "cmd.h" +@@ -51,6 +52,12 @@ + #define MLXSW_I2C_TIMEOUT_MSECS 5000 + #define MLXSW_I2C_MAX_DATA_SIZE 256 + ++#define MLXSW_I2C_WORK_ARMED 1 ++#define MLXSW_I2C_WORK_CLOSED GENMASK(31, 0) ++#define MLXSW_I2C_WORK_DELAY (usecs_to_jiffies(100)) ++#define MLXSW_I2C_DEFAULT_IRQ 17 ++#define MLXSW_I2C_VIRT_SLAVE 0x37 ++ + /** + * struct mlxsw_i2c - device private data: + * @cmd: command attributes; +@@ -63,6 +70,12 @@ + * @core: switch core pointer; + * @bus_info: bus info block; + * @block_size: maximum block size allowed to pass to under layer; ++ * @pdata: device platform data; ++ * @dwork_irq: interrupts delayed work queue; ++ * @lock - lock for interrupts sync; ++ * @sys_event_handler: system events handler callback; ++ * @irq: IRQ line number; ++ * @irq_unhandled_count: number of unhandled interrupts; + */ + struct mlxsw_i2c { + struct { +@@ -76,6 +89,12 @@ struct mlxsw_i2c { + struct mlxsw_core *core; + struct mlxsw_bus_info bus_info; + u16 block_size; ++ struct mlxreg_core_hotplug_platform_data *pdata; ++ struct delayed_work dwork_irq; ++ spinlock_t lock; /* sync with interrupt */ ++ void (*sys_event_handler)(struct mlxsw_core *mlxsw_core); ++ int irq; ++ atomic_t irq_unhandled_count; + }; + + #define MLXSW_I2C_READ_MSG(_client, _addr_buf, _buf, _len) { \ +@@ -517,6 +536,7 @@ mlxsw_i2c_init(void *bus_priv, struct mlxsw_core *mlxsw_core, + int err; + + mlxsw_i2c->core = mlxsw_core; ++ mlxsw_i2c->sys_event_handler = sys_event_handler; + + mbox = mlxsw_cmd_mbox_alloc(); + if (!mbox) +@@ -547,6 +567,87 @@ static void mlxsw_i2c_fini(void *bus_priv) + mlxsw_i2c->core = NULL; + } + ++static void mlxsw_i2c_work_handler(struct work_struct *work) ++{ ++ struct mlxsw_i2c *mlxsw_i2c; ++ unsigned long flags; ++ ++ mlxsw_i2c = container_of(work, struct mlxsw_i2c, dwork_irq.work); ++ ++ if (atomic_read(&mlxsw_i2c->irq_unhandled_count)) { ++ if (atomic_dec_and_test(&mlxsw_i2c->irq_unhandled_count)) ++ return; ++ } ++ ++ mlxsw_i2c->sys_event_handler(mlxsw_i2c->core); ++ ++ spin_lock_irqsave(&mlxsw_i2c->lock, flags); ++ ++ /* It is possible, that some signals have been inserted, while ++ * interrupts has been masked. In this case such signals could be missed. ++ * In order to handle these signals delayed work is canceled and work task ++ * re-scheduled for immediate execution. It allows to handle missed ++ * signals, if any. In other case work handler just validates that no new ++ * signals have been received during masking. ++ */ ++ cancel_delayed_work(&mlxsw_i2c->dwork_irq); ++ schedule_delayed_work(&mlxsw_i2c->dwork_irq, MLXSW_I2C_WORK_DELAY); ++ ++ spin_unlock_irqrestore(&mlxsw_i2c->lock, flags); ++ ++ if (!atomic_read(&mlxsw_i2c->irq_unhandled_count)) ++ atomic_set(&mlxsw_i2c->irq_unhandled_count, MLXSW_I2C_WORK_ARMED); ++} ++ ++static irqreturn_t mlxsw_i2c_irq_handler(int irq, void *dev) ++{ ++ struct mlxsw_i2c *mlxsw_i2c = (struct mlxsw_i2c *)dev; ++ ++ /* Schedule work task for immediate execution.*/ ++ schedule_delayed_work(&mlxsw_i2c->dwork_irq, 0); ++ ++ return IRQ_NONE; ++} ++ ++static int mlxsw_i2c_event_handler_register(struct mlxsw_i2c *mlxsw_i2c) ++{ ++ int err; ++ ++ /* Initialize interrupt handler if system hotplug driver is reachable ++ * and platform data is available. ++ */ ++ if (!IS_REACHABLE(CONFIG_MLXREG_HOTPLUG)) ++ return 0; ++ ++ if (mlxsw_i2c->pdata && mlxsw_i2c->pdata->irq) ++ mlxsw_i2c->irq = mlxsw_i2c->pdata->irq; ++ ++ if (!mlxsw_i2c->irq) ++ return 0; ++ ++ err = request_irq(mlxsw_i2c->irq, mlxsw_i2c_irq_handler, ++ IRQF_TRIGGER_FALLING | IRQF_SHARED, "mlxsw-i2c", ++ mlxsw_i2c); ++ if (err) { ++ dev_err(mlxsw_i2c->bus_info.dev, "Failed to request irq: %d\n", ++ err); ++ return err; ++ } ++ ++ spin_lock_init(&mlxsw_i2c->lock); ++ INIT_DELAYED_WORK(&mlxsw_i2c->dwork_irq, mlxsw_i2c_work_handler); ++ ++ return 0; ++} ++ ++static void mlxsw_i2c_event_handler_unregister(struct mlxsw_i2c *mlxsw_i2c) ++{ ++ if (!IS_REACHABLE(CONFIG_MLXREG_HOTPLUG) || !mlxsw_i2c->irq) ++ return; ++ cancel_delayed_work_sync(&mlxsw_i2c->dwork_irq); ++ free_irq(mlxsw_i2c->irq, mlxsw_i2c); ++} ++ + static const struct mlxsw_bus mlxsw_i2c_bus = { + .kind = "i2c", + .init = mlxsw_i2c_init, +@@ -639,6 +740,7 @@ static int mlxsw_i2c_probe(struct i2c_client *client, + mlxsw_i2c->bus_info.dev = &client->dev; + mlxsw_i2c->bus_info.low_frequency = true; + mlxsw_i2c->dev = &client->dev; ++ mlxsw_i2c->pdata = client->dev.platform_data; + + err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info, + &mlxsw_i2c_bus, mlxsw_i2c, false, +@@ -648,6 +750,12 @@ static int mlxsw_i2c_probe(struct i2c_client *client, + return err; + } + ++ if (client->addr == MLXSW_I2C_VIRT_SLAVE) ++ mlxsw_i2c->irq = MLXSW_I2C_DEFAULT_IRQ; ++ err = mlxsw_i2c_event_handler_register(mlxsw_i2c); ++ if (err) ++ return err; ++ + return 0; + + errout: +@@ -661,6 +769,8 @@ static int mlxsw_i2c_remove(struct i2c_client *client) + { + struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); + ++ atomic_set(&mlxsw_i2c->irq_unhandled_count, MLXSW_I2C_WORK_CLOSED); ++ mlxsw_i2c_event_handler_unregister(mlxsw_i2c); + mlxsw_core_bus_device_unregister(mlxsw_i2c->core, false); + mutex_destroy(&mlxsw_i2c->cmd.lock); + +-- +2.20.1 + diff --git a/patch/0154-mlxsw-core-Export-line-card-API.patch b/patch/0154-mlxsw-core-Export-line-card-API.patch new file mode 100644 index 000000000..fca84d737 --- /dev/null +++ b/patch/0154-mlxsw-core-Export-line-card-API.patch @@ -0,0 +1,27 @@ +From a89d212954b74f3169e3061a3623eadfb86441e6 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 19 Dec 2021 09:31:32 +0000 +Subject: [PATCH backport 5.10 154/182] mlxsw: core: Export line card API + +Export API mlxsw_core_linecards() for being used by 'minimal' driver. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index a9bb43837b33..a26c6d880928 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -103,6 +103,7 @@ struct mlxsw_linecards *mlxsw_core_linecards(struct mlxsw_core *mlxsw_core) + { + return mlxsw_core->linecards; + } ++EXPORT_SYMBOL(mlxsw_core_linecards); + + #define MLXSW_PORT_MAX_PORTS_DEFAULT 0x40 + +-- +2.20.1 + diff --git a/patch/0155-mlxsw-minimal-Add-system-event-handler.patch b/patch/0155-mlxsw-minimal-Add-system-event-handler.patch new file mode 100644 index 000000000..da23b7086 --- /dev/null +++ b/patch/0155-mlxsw-minimal-Add-system-event-handler.patch @@ -0,0 +1,62 @@ +From deb4f328672850d9ac4d8d51be7e0d8e727387af Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 19 Dec 2021 09:25:35 +0000 +Subject: [PATCH backport 5.10 155/182] mlxsw: minimal: Add system event + handler + +Add system event handler for treating line card specific signals on +modular system. These signals indicate line card state changes, like +line card activation or de-activation. +When such signals are received, driver should create or destroy "hwmon" +"thermal" and module info objects, associated with line card in a slot, +for which signal has been received. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 23 +++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 59c5053dc5fd..27afb28e439f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -527,6 +527,28 @@ static void mlxsw_m_line_cards_free(struct mlxsw_m *mlxsw_m) + kfree(mlxsw_m->line_cards); + } + ++static void mlxsw_m_sys_event_handler(struct mlxsw_core *mlxsw_core) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); ++ struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ int i, err; ++ ++ if (!linecards) ++ return; ++ ++ /* Handle line cards, for which active status has been changed. */ ++ for (i = 1; i <= linecards->count; i++) { ++ mlxsw_reg_mddq_slot_info_pack(mddq_pl, i, false); ++ err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mddq), mddq_pl); ++ if (err) ++ dev_err(mlxsw_m->bus_info->dev, "Fail to query MDDQ register for slot %d\n", ++ i); ++ ++ mlxsw_linecard_status_process(mlxsw_m->core, mddq_pl); ++ } ++} ++ + static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) +@@ -587,6 +609,7 @@ static struct mlxsw_driver mlxsw_m_driver = { + .priv_size = sizeof(struct mlxsw_m), + .init = mlxsw_m_init, + .fini = mlxsw_m_fini, ++ .sys_event_handler = mlxsw_m_sys_event_handler, + .profile = &mlxsw_m_config_profile, + .res_query_enabled = true, + }; +-- +2.20.1 + diff --git a/patch/0156-mlxsw-minimal-Add-interfaces-for-line-card-initializ.patch b/patch/0156-mlxsw-minimal-Add-interfaces-for-line-card-initializ.patch new file mode 100644 index 000000000..421536ead --- /dev/null +++ b/patch/0156-mlxsw-minimal-Add-interfaces-for-line-card-initializ.patch @@ -0,0 +1,119 @@ +From 933a623916a00d83616d653a82329750d94de0f1 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 19 Dec 2021 09:40:34 +0000 +Subject: [PATCH backport 5.10 156/182] mlxsw: minimal: Add interfaces for line + card initialization and de-initialization + +Add callback functions for line card 'netdevice' objects initialization +and de-initialization. Each line card is associated with the set of +'netdevices', which are created/destroyed dynamically, when line card +is getting to active / inactive states. + +Add APIs for line card registration and de-registration during init and +de-init. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 70 +++++++++++++++++++ + 1 file changed, 70 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 27afb28e439f..0b605c6aa637 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -549,6 +549,69 @@ static void mlxsw_m_sys_event_handler(struct mlxsw_core *mlxsw_core) + } + } + ++static void ++mlxsw_m_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_m *mlxsw_m = priv; ++ int err; ++ ++ err = mlxsw_m_ports_create(mlxsw_m, slot_index); ++ if (err) { ++ dev_err(mlxsw_m->bus_info->dev, "Failed to set line card at slot %d\n", ++ slot_index); ++ goto mlxsw_m_ports_create_fail; ++ } ++ mlxsw_m->line_cards[slot_index]->active = true; ++ ++mlxsw_m_ports_create_fail: ++ return; ++} ++ ++static void ++mlxsw_m_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_m *mlxsw_m = priv; ++ ++ mlxsw_m_ports_remove(mlxsw_m, slot_index); ++ mlxsw_m->line_cards[slot_index]->active = false; ++} ++ ++static struct mlxsw_linecards_event_ops mlxsw_m_event_ops = { ++ .got_active = mlxsw_m_got_active, ++ .got_inactive = mlxsw_m_got_inactive, ++}; ++ ++static int mlxsw_m_linecards_register(struct mlxsw_m *mlxsw_m) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_m->core); ++ ++ if (!linecards || !linecards->count) ++ return 0; ++ ++ return mlxsw_linecards_event_ops_register(mlxsw_m->core, ++ &mlxsw_m_event_ops, ++ mlxsw_m); ++} ++ ++static void mlxsw_m_linecards_unregister(struct mlxsw_m *mlxsw_m) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_m->core); ++ int i; ++ ++ if (!linecards || !linecards->count) ++ return; ++ ++ for (i = 1; i <= linecards->count; i++) { ++ if (mlxsw_m->line_cards[i]->active) ++ mlxsw_m_got_inactive(mlxsw_m->core, i, NULL, mlxsw_m); ++ } ++ ++ mlxsw_linecards_event_ops_unregister(mlxsw_m->core, ++ &mlxsw_m_event_ops, mlxsw_m); ++} ++ + static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) +@@ -587,8 +650,14 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, + goto err_mlxsw_m_ports_create; + } + ++ err = mlxsw_m_linecards_register(mlxsw_m); ++ if (err) ++ goto err_linecards_register; ++ + return 0; + ++err_linecards_register: ++ mlxsw_m_ports_remove(mlxsw_m, 0); + err_mlxsw_m_ports_create: + mlxsw_m_line_cards_free(mlxsw_m); + return err; +@@ -598,6 +667,7 @@ static void mlxsw_m_fini(struct mlxsw_core *mlxsw_core) + { + struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); + ++ mlxsw_m_linecards_unregister(mlxsw_m); + mlxsw_m_ports_remove(mlxsw_m, 0); + mlxsw_m_line_cards_free(mlxsw_m); + } +-- +2.20.1 + diff --git a/patch/0157-platform-x86-mlx-platform-Make-activation-of-some-dr.patch b/patch/0157-platform-x86-mlx-platform-Make-activation-of-some-dr.patch index 0bea5c955..287146719 100644 --- a/patch/0157-platform-x86-mlx-platform-Make-activation-of-some-dr.patch +++ b/patch/0157-platform-x86-mlx-platform-Make-activation-of-some-dr.patch @@ -1,8 +1,8 @@ -From b384a287a5732f7ea3b6e0b13b1aa6ba0d70c440 Mon Sep 17 00:00:00 2001 +From 3124aea618244c17aee9b523f55c500ca3badf15 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 14 Feb 2022 09:46:16 +0200 -Subject: [PATCH platform-next 1/8] platform/x86: mlx-platform: Make activation - of some drivers conditional +Subject: [PATCH backport 5.10 157/182] platform/x86: mlx-platform: Make + activation of some drivers conditional Current assumption in driver that any system is capable of LED, hotplug or watchdog support. It could be not true for some new coming @@ -16,7 +16,7 @@ Signed-off-by: Vadim Pasternak 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index fac4b6dcf..e0a35412f 100644 +index fac4b6dcfdc7..e0a35412fa77 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -5206,16 +5206,18 @@ static int __init mlxplat_init(void) diff --git a/patch/0158-platform-x86-mlx-platform-Add-cosmetic-changes-for-a.patch b/patch/0158-platform-x86-mlx-platform-Add-cosmetic-changes-for-a.patch index 3696e76d8..589a91228 100644 --- a/patch/0158-platform-x86-mlx-platform-Add-cosmetic-changes-for-a.patch +++ b/patch/0158-platform-x86-mlx-platform-Add-cosmetic-changes-for-a.patch @@ -1,8 +1,8 @@ -From cd26dadb7e9c5eedb4e24cd60d4de1cda0e8f889 Mon Sep 17 00:00:00 2001 +From 90e92c0d97686b0592415dba845a57362d78d122 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 14 Feb 2022 10:07:11 +0200 -Subject: [PATCH platform-next 2/8] platform/x86: mlx-platform: Add cosmetic - changes for alignment +Subject: [PATCH backport 5.10 158/182] platform/x86: mlx-platform: Add + cosmetic changes for alignment Align the first argument with open parenthesis for platform_device_register_resndata() calls. @@ -13,7 +13,7 @@ Signed-off-by: Vadim Pasternak 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index e0a35412f..a74fcd9d1 100644 +index e0a35412fa77..a74fcd9d184d 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -5183,22 +5183,20 @@ static int __init mlxplat_init(void) diff --git a/patch/0159-mlx-platform-Add-support-for-systems-equipped-with-t.patch b/patch/0159-mlx-platform-Add-support-for-systems-equipped-with-t.patch index 9f8c00636..96046a821 100644 --- a/patch/0159-mlx-platform-Add-support-for-systems-equipped-with-t.patch +++ b/patch/0159-mlx-platform-Add-support-for-systems-equipped-with-t.patch @@ -1,8 +1,8 @@ -From a16c819d0896932ca52006fc0ba1c977bd2ad7f6 Mon Sep 17 00:00:00 2001 +From b04a280dbab5d36d0e3ee87f99ef21906a9238c5 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 26 Jan 2022 17:16:26 +0200 -Subject: [PATCH platform backport v5.10 03/10] mlx-platform: Add support for - systems equipped with two ASICs +Subject: [PATCH backport 5.10 159/182] mlx-platform: Add support for systems + equipped with two ASICs Motivation is to support new systems equipped with two ASICs. @@ -18,7 +18,7 @@ Reviewed-by: Oleksandr Shamray 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index a74fcd9d1..cbe9eab34 100644 +index a74fcd9d184d..cbe9eab3467f 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -34,6 +34,7 @@ diff --git a/patch/0160-platform-mellanox-Introduce-support-for-COMe-NVSwitc.patch b/patch/0160-platform-mellanox-Introduce-support-for-COMe-managem.patch similarity index 97% rename from patch/0160-platform-mellanox-Introduce-support-for-COMe-NVSwitc.patch rename to patch/0160-platform-mellanox-Introduce-support-for-COMe-managem.patch index d6de42d39..9e7905d53 100644 --- a/patch/0160-platform-mellanox-Introduce-support-for-COMe-NVSwitc.patch +++ b/patch/0160-platform-mellanox-Introduce-support-for-COMe-managem.patch @@ -1,8 +1,8 @@ -From 333d4bcd32e3501d9bf3991dd5f2ff82061dab6b Mon Sep 17 00:00:00 2001 +From fd01b3306efc0e7a73e3b339ac4ae80678743b2a Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 26 Jan 2022 20:34:32 +0200 -Subject: [PATCH backport 5.10 01/17] platform: mellanox: Introduce support for - COMe management module for chassis +Subject: [PATCH backport 5.10 160/182] platform: mellanox: Introduce support + for COMe management module for chassis The system is built for artificial intelligence and accelerated analytics applications. Chassis is offered to cloud service @@ -17,7 +17,7 @@ Reviewed-by: Oleksandr Shamray 1 file changed, 269 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index cbe9eab34..e06fd1725 100644 +index cbe9eab3467f..e06fd1725beb 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -67,6 +67,9 @@ @@ -336,7 +336,7 @@ index cbe9eab34..e06fd1725 100644 + return 1; +} + - static int __init mlxplat_dmi_modular_matched(const struct dmi_system_id *dmi) + static int __init mlxplat_dmi_qmb8700_matched(const struct dmi_system_id *dmi) { int i; @@ -5044,6 +5307,12 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { diff --git a/patch/0161-platform-x86-mlx-platform-Add-support-for-new-system.patch b/patch/0161-platform-x86-mlx-platform-Add-support-for-new-system.patch index 602f752b7..ddb5b0377 100644 --- a/patch/0161-platform-x86-mlx-platform-Add-support-for-new-system.patch +++ b/patch/0161-platform-x86-mlx-platform-Add-support-for-new-system.patch @@ -1,7 +1,7 @@ -From 993337e78b0f9b88dba2a37eba37ae69828632e1 Mon Sep 17 00:00:00 2001 +From a38f9cb27bde5616bc71899841db733e305bf6c3 Mon Sep 17 00:00:00 2001 From: Felix Radensky Date: Sun, 24 Oct 2021 16:26:40 +0000 -Subject: [PATCH backport 5.10 02/17] platform/x86: mlx-platform: Add support +Subject: [PATCH backport 5.10 161/182] platform/x86: mlx-platform: Add support for new system XH3000 Add support for new system type XH3000, which is a water cooling @@ -17,7 +17,7 @@ Reviewed-by: Vadim Pasternak 1 file changed, 51 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index e06fd1725..2b1441a87 100644 +index e06fd1725beb..2b1441a8786f 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -2262,6 +2262,25 @@ static struct mlxreg_core_platform_data mlxplat_default_led_wc_data = { @@ -79,7 +79,7 @@ index e06fd1725..2b1441a87 100644 { int i; @@ -5277,6 +5321,13 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { - DMI_MATCH(DMI_PRODUCT_NAME, "MQM87"), + DMI_MATCH(DMI_PRODUCT_NAME, "MQM8700"), }, }, + { diff --git a/patch/0162-platform-mellanox-Add-COME-board-revision-register.patch b/patch/0162-platform-mellanox-Add-COME-board-revision-register.patch index 1efadbe99..bdc01da8a 100644 --- a/patch/0162-platform-mellanox-Add-COME-board-revision-register.patch +++ b/patch/0162-platform-mellanox-Add-COME-board-revision-register.patch @@ -1,7 +1,7 @@ -From 01cec35c2103e425d9f66f35f9cb91db7e9d9267 Mon Sep 17 00:00:00 2001 +From 267f4ad4ee5f52ecb3a7d3631d9f5a08a3adecef Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 6 Jul 2022 17:26:41 +0300 -Subject: [PATCH backport 5.10 03/17] platform: mellanox: Add COME board +Subject: [PATCH backport 5.10 162/182] platform: mellanox: Add COME board revision register Add to CPLD COME board configuration register for getting a board @@ -15,7 +15,7 @@ Signed-off-by: Vadim Pasternak 1 file changed, 21 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index 2b1441a87..1d0c13c65 100644 +index 2b1441a8786f..1d0c13c653b3 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -150,6 +150,7 @@ diff --git a/patch/0163-platform-mellanox-Introduce-support-for-rack-manager.patch b/patch/0163-platform-mellanox-Introduce-support-for-rack-manager.patch new file mode 100644 index 000000000..5865c7ddd --- /dev/null +++ b/patch/0163-platform-mellanox-Introduce-support-for-rack-manager.patch @@ -0,0 +1,421 @@ +From 3ddb1633cbd4c914ac58b64247d5724ab7f2d6c3 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 14 Feb 2022 13:24:44 +0200 +Subject: [PATCH backport 5.10 163/182] platform: mellanox: Introduce support + for rack manager switch + +The rack switch is designed to provide high bandwidth, low latency +connectivity using optical fiber as the primary interconnect. + +System supports 32 OSFP ports, non-blocking switching capacity of +25.6Tbps. +System equipped with: +- 2 replaceable power supplies (AC) with 1+1 redundancy model. +- 7 replaceable fan drawers with 6+1 redundancy model. +- 2 External Root of Trust or EROT (Glacier) devices for securing + ASICs firmware. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 259 ++++++++++++++++++++++++++++ + 1 file changed, 259 insertions(+) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 1d0c13c653b3..3ad85934d6e3 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -90,6 +90,12 @@ + #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_EROT_OFFSET 0x91 ++#define MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET 0x92 ++#define MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET 0x93 ++#define MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET 0x94 ++#define MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET 0x95 ++#define MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET 0x96 + #define MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET 0x9a + #define MLXPLAT_CPLD_LPC_REG_LC_VR_EVENT_OFFSET 0x9b + #define MLXPLAT_CPLD_LPC_REG_LC_VR_MASK_OFFSET 0x9c +@@ -109,6 +115,8 @@ + #define MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET 0xaa + #define MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET 0xab + #define MLXPLAT_CPLD_LPC_REG_LC_PWR_ON 0xb2 ++#define MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET 0xc2 ++#define MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT 0xc3 + #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 +@@ -215,6 +223,7 @@ + #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) + #define MLXPLAT_CPLD_VOLTREG_UPD_MASK GENMASK(5, 4) + #define MLXPLAT_CPLD_GWP_MASK GENMASK(0, 0) ++#define MLXPLAT_CPLD_EROT_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_I2C_CAP_BIT 0x04 + #define MLXPLAT_CPLD_I2C_CAP_MASK GENMASK(5, MLXPLAT_CPLD_I2C_CAP_BIT) + +@@ -244,6 +253,7 @@ + #define MLXPLAT_CPLD_CH2_ETH_MODULAR 3 + #define MLXPLAT_CPLD_CH3_ETH_MODULAR 43 + #define MLXPLAT_CPLD_CH4_ETH_MODULAR 51 ++#define MLXPLAT_CPLD_CH2_RACK_SWITCH 18 + + /* Number of LPC attached MUX platform devices */ + #define MLXPLAT_CPLD_LPC_MUX_DEVS 4 +@@ -281,6 +291,9 @@ + /* Minimum power required for turning on Ethernet modular system (WATT) */ + #define MLXPLAT_CPLD_ETH_MODULAR_PWR_MIN 50 + ++/* Default value for PWM control register for rack switch system */ ++#define MLXPLAT_REGMAP_NVSWITCH_PWM_DEFAULT 0xf4 ++ + /* mlxplat_priv - platform private data + * @pdev_i2c - i2c controller platform device + * @pdev_mux - array of mux platform devices +@@ -461,6 +474,36 @@ static struct i2c_mux_reg_platform_data mlxplat_modular_mux_data[] = { + }, + }; + ++/* Platform channels for rack swicth system family */ ++static const int mlxplat_rack_switch_channels[] = { ++ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ++}; ++ ++/* Platform rack switch mux data */ ++static struct i2c_mux_reg_platform_data mlxplat_rack_switch_mux_data[] = { ++ { ++ .parent = 1, ++ .base_nr = MLXPLAT_CPLD_CH1, ++ .write_only = 1, ++ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1, ++ .reg_size = 1, ++ .idle_in_use = 1, ++ .values = mlxplat_rack_switch_channels, ++ .n_values = ARRAY_SIZE(mlxplat_rack_switch_channels), ++ }, ++ { ++ .parent = 1, ++ .base_nr = MLXPLAT_CPLD_CH2_RACK_SWITCH, ++ .write_only = 1, ++ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, ++ .reg_size = 1, ++ .idle_in_use = 1, ++ .values = mlxplat_msn21xx_channels, ++ .n_values = ARRAY_SIZE(mlxplat_msn21xx_channels), ++ }, ++ ++}; ++ + /* Platform hotplug devices */ + static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { + { +@@ -2165,6 +2208,97 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_chassis_blade_data = { + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, + }; + ++/* Platform hotplug for switch systems family data */ ++static struct mlxreg_core_data mlxplat_mlxcpld_erot_ap_items_data[] = { ++ { ++ .label = "erot1_ap", ++ .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET, ++ .mask = BIT(0), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "erot2_ap", ++ .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET, ++ .mask = BIT(1), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++}; ++ ++static struct mlxreg_core_data mlxplat_mlxcpld_erot_error_items_data[] = { ++ { ++ .label = "erot1_error", ++ .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET, ++ .mask = BIT(0), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "erot2_error", ++ .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET, ++ .mask = BIT(1), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++}; ++ ++static struct mlxreg_core_item mlxplat_mlxcpld_rack_switch_items[] = { ++ { ++ .data = mlxplat_mlxcpld_ext_psu_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = MLXPLAT_CPLD_PSU_EXT_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_ext_psu_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_ext_pwr_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = MLXPLAT_CPLD_PWR_EXT_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_ext_pwr_items_data), ++ .inversed = 0, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_ng_fan_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = MLXPLAT_CPLD_FAN_NG_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_erot_ap_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET, ++ .mask = MLXPLAT_CPLD_EROT_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_ap_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_erot_error_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET, ++ .mask = MLXPLAT_CPLD_EROT_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_error_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++}; ++ ++static ++struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_rack_switch_data = { ++ .items = mlxplat_mlxcpld_rack_switch_items, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_rack_switch_items), ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, ++ .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ++ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, ++}; ++ + /* Platform led default data */ + static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { + { +@@ -3166,6 +3300,42 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0444, + }, ++ { ++ .label = "erot1_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0644, ++ }, ++ { ++ .label = "erot2_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(7), ++ .mode = 0644, ++ }, ++ { ++ .label = "erot1_recovery", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0644, ++ }, ++ { ++ .label = "erot2_recovery", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(7), ++ .mode = 0644, ++ }, ++ { ++ .label = "erot1_wp", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(4), ++ .mode = 0644, ++ }, ++ { ++ .label = "erot2_wp", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0644, ++ }, + { + .label = "reset_long_pb", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, +@@ -3361,6 +3531,25 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0644, + }, ++ { ++ .label = "erot1_ap_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(0), ++ .mode = 0444, ++ }, ++ { ++ .label = "erot2_ap_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(1), ++ .mode = 0444, ++ }, ++ { ++ .label = "spi_chnl_select", ++ .reg = MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT, ++ .mask = GENMASK(7, 0), ++ .bit = 1, ++ .mode = 0644, ++ }, + { + .label = "config1", + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET, +@@ -4577,6 +4766,10 @@ 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_EROT_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_MASK_OFFSET: +@@ -4594,6 +4787,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON: ++ case MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT: + 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: +@@ -4678,6 +4872,12 @@ 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_EROT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET: +@@ -4702,6 +4902,8 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON: ++ case MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT: + 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: +@@ -4812,6 +5014,12 @@ 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_EROT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET: +@@ -4836,6 +5044,8 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON: ++ case MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT: + case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: +@@ -4903,6 +5113,13 @@ static const struct reg_default mlxplat_mlxcpld_regmap_ng400[] = { + { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 }, + }; + ++static const struct reg_default mlxplat_mlxcpld_regmap_rack_switch[] = { ++ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, MLXPLAT_REGMAP_NVSWITCH_PWM_DEFAULT }, ++ { MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 }, ++}; ++ + static const struct reg_default mlxplat_mlxcpld_regmap_eth_modular[] = { + { MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, 0x61 }, + { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, +@@ -4996,6 +5213,20 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config_ng400 = { + .reg_write = mlxplat_mlxcpld_reg_write, + }; + ++static const struct regmap_config mlxplat_mlxcpld_regmap_config_rack_switch = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = 255, ++ .cache_type = REGCACHE_FLAT, ++ .writeable_reg = mlxplat_mlxcpld_writeable_reg, ++ .readable_reg = mlxplat_mlxcpld_readable_reg, ++ .volatile_reg = mlxplat_mlxcpld_volatile_reg, ++ .reg_defaults = mlxplat_mlxcpld_regmap_rack_switch, ++ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_rack_switch), ++ .reg_read = mlxplat_mlxcpld_reg_read, ++ .reg_write = mlxplat_mlxcpld_reg_write, ++}; ++ + static const struct regmap_config mlxplat_mlxcpld_regmap_config_eth_modular = { + .reg_bits = 8, + .val_bits = 8, +@@ -5303,6 +5534,27 @@ static int __init mlxplat_dmi_qmb8700_matched(const struct dmi_system_id *dmi) + return 1; + } + ++static int __init mlxplat_dmi_rack_switch_matched(const struct dmi_system_id *dmi) ++{ ++ int i; ++ ++ mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; ++ mlxplat_mux_num = ARRAY_SIZE(mlxplat_rack_switch_mux_data); ++ mlxplat_mux_data = mlxplat_rack_switch_mux_data; ++ mlxplat_hotplug = &mlxplat_mlxcpld_rack_switch_data; ++ mlxplat_hotplug->deferred_nr = ++ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; ++ 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]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; ++ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_rack_switch; ++ ++ return 1; ++} ++ + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + { + .callback = mlxplat_dmi_default_wc_matched, +@@ -5367,6 +5619,13 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0009"), + }, + }, ++ { ++ .callback = mlxplat_dmi_rack_switch_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0010"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "HI142"), ++ }, ++ }, + { + .callback = mlxplat_dmi_ng400_matched, + .matches = { +-- +2.20.1 + diff --git a/patch/0164-hwmon-jc42-Add-support-for-Seiko-Instruments-S-34TS0.patch b/patch/0164-hwmon-jc42-Add-support-for-Seiko-Instruments-S-34TS0.patch index 946a19675..1d5e6dd09 100644 --- a/patch/0164-hwmon-jc42-Add-support-for-Seiko-Instruments-S-34TS0.patch +++ b/patch/0164-hwmon-jc42-Add-support-for-Seiko-Instruments-S-34TS0.patch @@ -1,7 +1,8 @@ -From d8f82a399f46cfc1b91c2dd64dd18741ce9d7e5a Mon Sep 17 00:00:00 2001 +From c1af33181092b2b2fc53ee5bd10f9ebcdcea1faf Mon Sep 17 00:00:00 2001 From: Oleksandr Shamray Date: Tue, 22 Feb 2022 18:55:15 +0200 -Subject: [PATCH] hwmon: (jc42) Add support for Seiko Instruments S-34TS04A +Subject: [PATCH backport 5.10 164/182] hwmon: (jc42) Add support for Seiko + Instruments S-34TS04A S-34TS04A is a JC42.4 compatible temperature sensor from Seiko Instruments. @@ -12,7 +13,7 @@ Reviewed-by: Vadim Pasternak 1 file changed, 6 insertions(+) diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c -index 4a03d010e..bda2c9fb1 100644 +index 4a03d010ec5a..bda2c9fb1f68 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -63,6 +63,7 @@ static const unsigned short normal_i2c[] = { @@ -43,5 +44,5 @@ index 4a03d010e..bda2c9fb1 100644 { STM_MANID, STTS424E_DEVID, STTS424E_DEVID_MASK }, { STM_MANID, STTS2002_DEVID, STTS2002_DEVID_MASK }, -- -2.14.1 +2.20.1 diff --git a/patch/0165-platform-mellanox-mlxreg-io-Add-locking-for-io-opera.patch b/patch/0165-platform-mellanox-mlxreg-io-Add-locking-for-io-opera.patch index 76ec54b57..494b1810f 100644 --- a/patch/0165-platform-mellanox-mlxreg-io-Add-locking-for-io-opera.patch +++ b/patch/0165-platform-mellanox-mlxreg-io-Add-locking-for-io-opera.patch @@ -1,8 +1,8 @@ -From 77e8886b6019a37335c66dceb39429c33eb87f28 Mon Sep 17 00:00:00 2001 +From 736f644255c56d2adf32b694d0fd83e2ab6d2d77 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 7 Feb 2022 21:22:04 +0200 -Subject: [PATCH platform-next 02/10] platform/mellanox: mlxreg-io: Add locking - for io operations +Subject: [PATCH backport 5.10 165/182] platform/mellanox: mlxreg-io: Add + locking for io operations Add lock to protect user read/write access to the registers. @@ -12,7 +12,7 @@ Signed-off-by: Vadim Pasternak 1 file changed, 23 insertions(+) diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c -index 2c2686d5c..ddc08abf3 100644 +index 2c2686d5c2fc..ddc08abf398c 100644 --- a/drivers/platform/mellanox/mlxreg-io.c +++ b/drivers/platform/mellanox/mlxreg-io.c @@ -31,6 +31,7 @@ diff --git a/patch/0167-leds-mlxreg-Send-udev-change-event.patch b/patch/0166-DS-leds-leds-mlxreg-Send-udev-event-from-leds-mlxreg.patch similarity index 63% rename from patch/0167-leds-mlxreg-Send-udev-change-event.patch rename to patch/0166-DS-leds-leds-mlxreg-Send-udev-event-from-leds-mlxreg.patch index 2ec9dd86f..9bc90efc9 100644 --- a/patch/0167-leds-mlxreg-Send-udev-change-event.patch +++ b/patch/0166-DS-leds-leds-mlxreg-Send-udev-event-from-leds-mlxreg.patch @@ -1,14 +1,22 @@ -From fffab288f4508647dd67ffc854f8f1af1fae44a7 Mon Sep 17 00:00:00 2001 -From: Kebo Liu -Date: Mon, 11 Jul 2022 15:26:20 +0800 -Subject: [PATCH] leds mlxreg send udev change event +From 58797f651264dd362655e7c45bce48a2929cf55c Mon Sep 17 00:00:00 2001 +From: Michael Shych +Date: Mon, 11 Jul 2022 12:51:27 +0300 +Subject: [PATCH backport 5.10 166/182] DS: leds: leds-mlxreg: Send udev event + from leds-mlxreg driver. +Add sending udev event from leds-mlxreg driver in case of color change. +This patch will not be accepted in upstream as it provides no regular flow. +It's done as a workaround of SN2201 limitation, difference, and in order +to save compatibility of NOS work with sysfs attributes. +The patch should be taken to NOSs as exceptions to the upstream procedure. + +Signed-off-by: Michael Shych --- drivers/leds/leds-mlxreg.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c -index 82aea1c..c9c7c82 100644 +index 7df4653a80d7..137ba5afa921 100644 --- a/drivers/leds/leds-mlxreg.c +++ b/drivers/leds/leds-mlxreg.c @@ -11,6 +11,7 @@ @@ -49,18 +57,18 @@ index 82aea1c..c9c7c82 100644 if (value) - return mlxreg_led_store_hw(led_data, led_data->base_color); -+ err = mlxreg_led_store_hw(led_data, led_data->base_color); ++ err = mlxreg_led_store_hw(led_data, led_data->base_color); + else -+ err = mlxreg_led_store_hw(led_data, MLXREG_LED_IS_OFF); ++ err = mlxreg_led_store_hw(led_data, MLXREG_LED_IS_OFF); + + if (!err) -+ return mlxreg_led_udev_event_send(led_data, value); ++ return mlxreg_led_udev_event_send(led_data, value); else - return mlxreg_led_store_hw(led_data, MLXREG_LED_IS_OFF); -+ return err; ++ return err; } static enum led_brightness -- -1.9.1 +2.20.1 diff --git a/patch/0170-i2c-mlxcpld-Fix-register-setting-for-400KHz-frequenc.patch b/patch/0170-i2c-mlxcpld-Fix-register-setting-for-400KHz-frequenc.patch index 3df1c9485..64e3412f9 100644 --- a/patch/0170-i2c-mlxcpld-Fix-register-setting-for-400KHz-frequenc.patch +++ b/patch/0170-i2c-mlxcpld-Fix-register-setting-for-400KHz-frequenc.patch @@ -1,7 +1,7 @@ -From 553016c0c35314b0cd9fc3ed3c37d04ec0c6c14e Mon Sep 17 00:00:00 2001 +From d0aec4e04bda89b1183f7568cc64519cda380da8 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 13 Jun 2022 20:51:35 +0300 -Subject: [PATCH i2c backport v5.10 1/1] i2c: mlxcpld: Fix register setting for +Subject: [PATCH backport 5.10 170/182] i2c: mlxcpld: Fix register setting for 400KHz frequency Fix setting of 'Half Cycle' register for 400KHz frequency. @@ -13,7 +13,7 @@ Signed-off-by: Vadim Pasternak 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c -index fb451d42a..85b78985f 100644 +index 363ea9fd66c4..72fcfb17dd67 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -49,7 +49,7 @@ diff --git a/patch/0171-platform-mellanox-mlxreg-lc-Fix-cleanup-on-failure-a.patch b/patch/0171-platform-mellanox-mlxreg-lc-Fix-cleanup-on-failure-a.patch index fd84f2801..0632d1bc3 100644 --- a/patch/0171-platform-mellanox-mlxreg-lc-Fix-cleanup-on-failure-a.patch +++ b/patch/0171-platform-mellanox-mlxreg-lc-Fix-cleanup-on-failure-a.patch @@ -1,8 +1,8 @@ -From 68ff1efc9fdb309cd9093c4317634b601984ff6e Mon Sep 17 00:00:00 2001 +From 7a45b6a2a14c292e89a09afde8fcc7d1ceb20ebd Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 22 Jun 2022 13:01:15 +0300 -Subject: [PATCH platform 1/1] platform/mellanox: mlxreg-lc: Fix cleanup on - failure and add more verbosity in error flow +Subject: [PATCH backport 5.10 171/182] platform/mellanox: mlxreg-lc: Fix + cleanup on failure and add more verbosity in error flow Clean client object in case of probing failure. Prevent running remove routine in case probing failed. @@ -15,10 +15,10 @@ Signed-off-by: Vadim Pasternak 1 file changed, 63 insertions(+), 22 deletions(-) diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c -index ea8324020..79d35a281 100644 +index 75c28179dd07..e3caccb1a528 100644 --- a/drivers/platform/mellanox/mlxreg-lc.c +++ b/drivers/platform/mellanox/mlxreg-lc.c -@@ -559,9 +559,6 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind, +@@ -569,9 +569,6 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind, dev_info(mlxreg_lc->dev, "linecard#%d state %d event kind %d action %d\n", mlxreg_lc->data->slot, mlxreg_lc->state, kind, action); @@ -28,7 +28,7 @@ index ea8324020..79d35a281 100644 switch (kind) { case MLXREG_HOTPLUG_LC_SYNCED: /* -@@ -715,8 +712,12 @@ mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, +@@ -725,8 +722,12 @@ mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, switch (regval) { case MLXREG_LC_SN4800_C16: err = mlxreg_lc_sn4800_c16_config_init(mlxreg_lc, regmap, data); @@ -42,7 +42,7 @@ index ea8324020..79d35a281 100644 break; default: return -ENODEV; -@@ -729,8 +730,11 @@ mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, +@@ -739,8 +740,11 @@ mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, mlxreg_lc->mux = platform_device_register_resndata(dev, "i2c-mux-mlxcpld", data->hpdev.nr, NULL, 0, mlxreg_lc->mux_data, sizeof(*mlxreg_lc->mux_data)); @@ -55,7 +55,7 @@ index ea8324020..79d35a281 100644 /* Register IO access driver. */ if (mlxreg_lc->io_data) { -@@ -739,6 +743,9 @@ mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, +@@ -749,6 +753,9 @@ mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, platform_device_register_resndata(dev, "mlxreg-io", data->hpdev.nr, NULL, 0, mlxreg_lc->io_data, sizeof(*mlxreg_lc->io_data)); if (IS_ERR(mlxreg_lc->io_regs)) { @@ -65,7 +65,7 @@ index ea8324020..79d35a281 100644 err = PTR_ERR(mlxreg_lc->io_regs); goto fail_register_io; } -@@ -752,6 +759,9 @@ mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, +@@ -762,6 +769,9 @@ mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, mlxreg_lc->led_data, sizeof(*mlxreg_lc->led_data)); if (IS_ERR(mlxreg_lc->led)) { @@ -75,7 +75,7 @@ index ea8324020..79d35a281 100644 err = PTR_ERR(mlxreg_lc->led); goto fail_register_led; } -@@ -808,7 +818,8 @@ static int mlxreg_lc_probe(struct platform_device *pdev) +@@ -818,7 +828,8 @@ static int mlxreg_lc_probe(struct platform_device *pdev) if (!data->hpdev.adapter) { dev_err(&pdev->dev, "Failed to get adapter for bus %d\n", data->hpdev.nr); @@ -85,7 +85,7 @@ index ea8324020..79d35a281 100644 } /* Create device at the top of line card I2C tree.*/ -@@ -817,32 +828,40 @@ static int mlxreg_lc_probe(struct platform_device *pdev) +@@ -827,32 +838,40 @@ static int mlxreg_lc_probe(struct platform_device *pdev) 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); @@ -135,7 +135,7 @@ index ea8324020..79d35a281 100644 par_pdata = data->hpdev.brdinfo->platform_data; mlxreg_lc->par_regmap = par_pdata->regmap; -@@ -853,12 +872,27 @@ static int mlxreg_lc_probe(struct platform_device *pdev) +@@ -863,12 +882,27 @@ static int mlxreg_lc_probe(struct platform_device *pdev) /* Configure line card. */ err = mlxreg_lc_config_init(mlxreg_lc, regmap, data); if (err) @@ -165,7 +165,7 @@ index ea8324020..79d35a281 100644 return err; } -@@ -867,11 +901,18 @@ static int mlxreg_lc_remove(struct platform_device *pdev) +@@ -877,11 +911,18 @@ static int mlxreg_lc_remove(struct platform_device *pdev) struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev); struct mlxreg_lc *mlxreg_lc = platform_get_drvdata(pdev); diff --git a/patch/0172-DS-platform-mlx-platform-Add-SPI-path-for-rack-switc.patch b/patch/0172-DS-platform-mlx-platform-Add-SPI-path-for-rack-switc.patch new file mode 100644 index 000000000..b5ec0ea19 --- /dev/null +++ b/patch/0172-DS-platform-mlx-platform-Add-SPI-path-for-rack-switc.patch @@ -0,0 +1,84 @@ +From b1e9734f4dc29c65e05a8f35ec67efb7784d321f Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 15 May 2022 14:31:10 +0300 +Subject: [PATCH backport 5.10 172/182] DS: platform: mlx-platform: Add SPI + path for rack switch for EROT access + +Create spidev for OOB access to External Root of Trusts devices. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 16 ++++++++++++++++ + drivers/spi/spi.c | 1 + + 2 files changed, 17 insertions(+) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 3ad85934d6e3..135ccea3a34e 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + + #define MLX_PLAT_DEVICE_NAME "mlxplat" + +@@ -2299,6 +2300,16 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_rack_switch_data = { + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, + }; + ++static struct spi_board_info rack_switch_switch_spi_board_info[] = { ++ { ++ .modalias = "spidev", ++ .irq = -1, ++ .max_speed_hz = 20000000, ++ .bus_num = 0, ++ .chip_select = 0, ++ }, ++}; ++ + /* Platform led default data */ + static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { + { +@@ -5254,6 +5265,7 @@ static struct mlxreg_core_platform_data *mlxplat_fan; + static struct mlxreg_core_platform_data + *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS]; + static const struct regmap_config *mlxplat_regmap_config; ++static struct spi_board_info *mlxplat_spi; + + static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) + { +@@ -5551,6 +5563,7 @@ static int __init mlxplat_dmi_rack_switch_matched(const struct dmi_system_id *dm + mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_rack_switch; ++ mlxplat_spi = rack_switch_switch_spi_board_info; + + return 1; + } +@@ -5917,6 +5930,9 @@ static int __init mlxplat_init(void) + } + } + ++ if (mlxplat_spi) ++ spi_register_board_info(mlxplat_spi, 1); ++ + /* Add WD drivers. */ + err = mlxplat_mlxcpld_check_wd_capability(priv->regmap); + if (err) +diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c +index 857a1399850c..2efafa34ff22 100644 +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -790,6 +790,7 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) + + return 0; + } ++EXPORT_SYMBOL(spi_register_board_info); + + /*-------------------------------------------------------------------------*/ + +-- +2.20.1 + diff --git a/patch/0173-core-Add-support-for-OSFP-transceiver-modules.patch b/patch/0173-mlxsw-core-Add-support-for-OSFP-transceiver-modules.patch similarity index 92% rename from patch/0173-core-Add-support-for-OSFP-transceiver-modules.patch rename to patch/0173-mlxsw-core-Add-support-for-OSFP-transceiver-modules.patch index 75963661e..579bb8455 100644 --- a/patch/0173-core-Add-support-for-OSFP-transceiver-modules.patch +++ b/patch/0173-mlxsw-core-Add-support-for-OSFP-transceiver-modules.patch @@ -1,7 +1,7 @@ -From 2d0cae902b722594b17335e7aceb6500d9bb4525 Mon Sep 17 00:00:00 2001 +From f4a99113cce99f7c41e753ff1097120bc33b6951 Mon Sep 17 00:00:00 2001 From: Danielle Ratson Date: Tue, 22 Feb 2022 19:17:03 +0200 -Subject: [PATCH platform backport v5.10 1/1] mlxsw: core: Add support for OSFP +Subject: [PATCH backport 5.10 173/182] mlxsw: core: Add support for OSFP transceiver modules The driver can already dump the EEPROM contents of QSFP-DD transceiver @@ -43,7 +43,7 @@ index 98f7cf672d9e..f9c770eec8f8 100644 * type through the identifier value. */ diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h -index ce3842ed8460..bec9d94b718a 100644 +index 7b71e9ae3d51..f8c828e057c8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -8950,6 +8950,7 @@ enum mlxsw_reg_mcia_eeprom_module_info_id { diff --git a/patch/0175-hwmon-pmbus-Add-support-for-Infineon-Digital-Multi-p.patch b/patch/0175-hwmon-pmbus-Add-support-for-Infineon-Digital-Multi-p.patch index 4f7b6a85b..7718796db 100644 --- a/patch/0175-hwmon-pmbus-Add-support-for-Infineon-Digital-Multi-p.patch +++ b/patch/0175-hwmon-pmbus-Add-support-for-Infineon-Digital-Multi-p.patch @@ -1,8 +1,8 @@ -From 0daa4a8f50be59f0549bbda2d06ad5b74d5134bd Mon Sep 17 00:00:00 2001 +From de8198c01c722ac99814d7eaa81d4b63044684e6 Mon Sep 17 00:00:00 2001 From: "Greg.Schwendimann@infineon.com" Date: Wed, 27 Apr 2022 18:40:12 +0000 -Subject: [PATCH hwmon backport v5.10 1/1] hwmon: (pmbus) Add support for - Infineon Digital Multi-phase xdp152 family controllers +Subject: [PATCH backport 5.10 175/182] hwmon: (pmbus) Add support for Infineon + Digital Multi-phase xdp152 family controllers Add support for devices XDPE152C4, XDPE12584. diff --git a/patch/0176-platform-mellanox-fix-reset_pwr_converter_fail-attri.patch b/patch/0176-platform-mellanox-fix-reset_pwr_converter_fail-attri.patch new file mode 100644 index 000000000..0ed069f65 --- /dev/null +++ b/patch/0176-platform-mellanox-fix-reset_pwr_converter_fail-attri.patch @@ -0,0 +1,31 @@ +From eb20a45ca217d897a1cb623c3ae84d97e6000f88 Mon Sep 17 00:00:00 2001 +From: Michael Shych +Date: Sun, 4 Sep 2022 10:41:45 +0300 +Subject: [PATCH backport 5.10 176/182] platform: mellanox: fix + reset_pwr_converter_fail attribute. + +Change incorrect reset_voltmon_upgrade_fail atitribute name to +reset_pwr_converter_fail. + +Signed-off-by: Michael Shych +Reviewed-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 135ccea3a34e..3f29ab98480d 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -3414,7 +3414,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mode = 0444, + }, + { +- .label = "reset_voltmon_upgrade_fail", ++ .label = "reset_pwr_converter_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0444, +-- +2.20.1 + diff --git a/patch/0177-Documentation-ABI-fix-description-of-fix-reset_pwr_c.patch b/patch/0177-Documentation-ABI-fix-description-of-fix-reset_pwr_c.patch new file mode 100644 index 000000000..7c3bed1ce --- /dev/null +++ b/patch/0177-Documentation-ABI-fix-description-of-fix-reset_pwr_c.patch @@ -0,0 +1,38 @@ +From 0e8bb4ec5d0133a9d3d3e307095aca57d47bfb36 Mon Sep 17 00:00:00 2001 +From: Michael Shych +Date: Sun, 4 Sep 2022 10:46:01 +0300 +Subject: [PATCH backport 5.10 177/182] Documentation/ABI: fix description of + fix reset_pwr_converter_fail attribute. + +Change description of incorrect reset_voltmon_upgrade_fail atitribute +name to reset_pwr_converter_fail. + +Signed-off-by: Michael Shych +Reviewed-by: Vadim Pasternak +--- + Documentation/ABI/stable/sysfs-driver-mlxreg-io | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/Documentation/ABI/stable/sysfs-driver-mlxreg-io b/Documentation/ABI/stable/sysfs-driver-mlxreg-io +index 0913a8daf767..ac503e84e7b3 100644 +--- a/Documentation/ABI/stable/sysfs-driver-mlxreg-io ++++ b/Documentation/ABI/stable/sysfs-driver-mlxreg-io +@@ -103,13 +103,13 @@ Description: These files show the system reset cause, as following: power + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_comex_pwr_fail + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_from_comex + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_system +-What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_voltmon_upgrade_fail ++What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_pwr_converter_fail + Date: November 2018 + KernelVersion: 5.0 + Contact: Vadim Pasternak + Description: These files show the system reset cause, as following: ComEx + power fail, reset from ComEx, system platform reset, reset +- due to voltage monitor devices upgrade failure, ++ due to power converter devices failure, + Value 1 in file means this is reset cause, 0 - otherwise. + Only one bit could be 1 at the same time, representing only + the last reset cause. +-- +2.20.1 + diff --git a/patch/0178-platform-mellanox-Introduce-support-for-next-generat.patch b/patch/0178-platform-mellanox-Introduce-support-for-next-generat.patch new file mode 100644 index 000000000..ecf135f71 --- /dev/null +++ b/patch/0178-platform-mellanox-Introduce-support-for-next-generat.patch @@ -0,0 +1,295 @@ +From 30a9045deb3da304b03f8451fad1a8d79a849da9 Mon Sep 17 00:00:00 2001 +From: Michael Shych +Date: Sun, 4 Sep 2022 14:03:58 +0300 +Subject: [PATCH backport 5.10 178/182] platform: mellanox: Introduce support + for next-generation 800GB/s ethernet switch. + +Introduce support for Nvidia next-generation 800GB/s ethernet switch - SN5600. +SN5600 is 51.2 Tbps Ethernet switch based on Nvidia Spectrum-4 ASIC. +It can provide up to 64x800Gb/s (ETH) full bidirectional bandwidth per port +using PAM-4 modulations. The system supports 64 Belly to Belly 2x4 OSFP cages. +The switch was designed to fit standard 2U racks. + +Features: +- 64 OSFP ports support 800GbE - 10GbE speed. +- Additional 25GbE - 1GbE service port on the front panel. +- Air-cooled with 3 + 1 redundant fan units. +- 1 + 1 redundant 3000W or 3600W PSUs. +- System management board is based on Intel Coffee-lake CPU E-2276 + with secure-boot support. + +Signed-off-by: Michael Shych +Reviewed-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 178 ++++++++++++++++++++++++++++ + 1 file changed, 178 insertions(+) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 3f29ab98480d..4bbe1d8f016d 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -255,6 +255,7 @@ + #define MLXPLAT_CPLD_CH3_ETH_MODULAR 43 + #define MLXPLAT_CPLD_CH4_ETH_MODULAR 51 + #define MLXPLAT_CPLD_CH2_RACK_SWITCH 18 ++#define MLXPLAT_CPLD_CH2_NG800 34 + + /* Number of LPC attached MUX platform devices */ + #define MLXPLAT_CPLD_LPC_MUX_DEVS 4 +@@ -505,6 +506,37 @@ static struct i2c_mux_reg_platform_data mlxplat_rack_switch_mux_data[] = { + + }; + ++/* Platform channels for ng800 system family */ ++static const int mlxplat_ng800_channels[] = { ++ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, ++ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 ++}; ++ ++/* Platform ng800 mux data */ ++static struct i2c_mux_reg_platform_data mlxplat_ng800_mux_data[] = { ++ { ++ .parent = 1, ++ .base_nr = MLXPLAT_CPLD_CH1, ++ .write_only = 1, ++ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1, ++ .reg_size = 1, ++ .idle_in_use = 1, ++ .values = mlxplat_ng800_channels, ++ .n_values = ARRAY_SIZE(mlxplat_ng800_channels), ++ }, ++ { ++ .parent = 1, ++ .base_nr = MLXPLAT_CPLD_CH2_NG800, ++ .write_only = 1, ++ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, ++ .reg_size = 1, ++ .idle_in_use = 1, ++ .values = mlxplat_msn21xx_channels, ++ .n_values = ARRAY_SIZE(mlxplat_msn21xx_channels), ++ }, ++ ++}; ++ + /* Platform hotplug devices */ + static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { + { +@@ -524,6 +556,15 @@ static struct i2c_board_info mlxplat_mlxcpld_ext_pwr[] = { + }, + }; + ++static struct i2c_board_info mlxplat_mlxcpld_pwr_ng800[] = { ++ { ++ I2C_BOARD_INFO("dps460", 0x59), ++ }, ++ { ++ I2C_BOARD_INFO("dps460", 0x5a), ++ }, ++}; ++ + static struct i2c_board_info mlxplat_mlxcpld_fan[] = { + { + I2C_BOARD_INFO("24c32", 0x50), +@@ -603,6 +644,23 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_wc_items_data[] = { + }, + }; + ++static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_ng800_items_data[] = { ++ { ++ .label = "pwr1", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = BIT(0), ++ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr_ng800[0], ++ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, ++ }, ++ { ++ .label = "pwr2", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = BIT(1), ++ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr_ng800[1], ++ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, ++ }, ++}; ++ + static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { + { + .label = "fan1", +@@ -1326,6 +1384,47 @@ static struct mlxreg_core_item mlxplat_mlxcpld_ext_items[] = { + } + }; + ++static struct mlxreg_core_item mlxplat_mlxcpld_ng800_items[] = { ++ { ++ .data = mlxplat_mlxcpld_default_ng_psu_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = MLXPLAT_CPLD_PSU_EXT_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_pwr_ng800_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = MLXPLAT_CPLD_PWR_EXT_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_pwr_ng800_items_data), ++ .inversed = 0, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_ng_fan_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = MLXPLAT_CPLD_FAN_NG_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_asic_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, ++ .mask = MLXPLAT_CPLD_ASIC_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), ++ .inversed = 0, ++ .health = true, ++ }, ++}; ++ + static + struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ext_data = { + .items = mlxplat_mlxcpld_ext_items, +@@ -1336,6 +1435,16 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ext_data = { + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2, + }; + ++static ++struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ng800_data = { ++ .items = mlxplat_mlxcpld_ng800_items, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_ng800_items), ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, ++ .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ++ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2, ++}; ++ + static struct mlxreg_core_data mlxplat_mlxcpld_modular_pwr_items_data[] = { + { + .label = "pwr1", +@@ -3323,6 +3432,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0644, + }, ++ { ++ .label = "clk_brd_prog_en", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(1), ++ .mode = 0644, ++ }, + { + .label = "erot1_recovery", + .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, +@@ -3449,6 +3564,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, ++ { ++ .label = "reset_ac_ok_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(7), ++ .mode = 0444, ++ }, + { + .label = "psu1_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, +@@ -3530,6 +3651,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .bit = 5, + .mode = 0444, + }, ++ { ++ .label = "pwr_converter_prog_en", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(0), ++ .mode = 0644, ++ }, + { + .label = "vpd_wp", + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, +@@ -3554,6 +3681,30 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0444, + }, ++ { ++ .label = "clk_brd1_boot_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(4), ++ .mode = 0444, ++ }, ++ { ++ .label = "clk_brd2_boot_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0444, ++ }, ++ { ++ .label = "clk_brd_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0444, ++ }, ++ { ++ .label = "asic_pg_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(7), ++ .mode = 0444, ++ }, + { + .label = "spi_chnl_select", + .reg = MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT, +@@ -5568,6 +5719,27 @@ static int __init mlxplat_dmi_rack_switch_matched(const struct dmi_system_id *dm + return 1; + } + ++static int __init mlxplat_dmi_ng800_matched(const struct dmi_system_id *dmi) ++{ ++ int i; ++ ++ mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; ++ mlxplat_mux_num = ARRAY_SIZE(mlxplat_ng800_mux_data); ++ mlxplat_mux_data = mlxplat_ng800_mux_data; ++ mlxplat_hotplug = &mlxplat_mlxcpld_ng800_data; ++ mlxplat_hotplug->deferred_nr = ++ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; ++ 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]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; ++ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng400; ++ ++ return 1; ++} ++ + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + { + .callback = mlxplat_dmi_default_wc_matched, +@@ -5651,6 +5823,12 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0011"), + }, + }, ++ { ++ .callback = mlxplat_dmi_ng800_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0013"), ++ }, ++ }, + { + .callback = mlxplat_dmi_chassis_blade_matched, + .matches = { +-- +2.20.1 + diff --git a/patch/0180-hwmon-pmbus-Fix-sensors-readouts-for-MPS-Multi-phase.patch b/patch/0180-hwmon-pmbus-Fix-sensors-readouts-for-MPS-Multi-phase.patch index 255263557..1ff0f3af4 100644 --- a/patch/0180-hwmon-pmbus-Fix-sensors-readouts-for-MPS-Multi-phase.patch +++ b/patch/0180-hwmon-pmbus-Fix-sensors-readouts-for-MPS-Multi-phase.patch @@ -1,8 +1,8 @@ -From ae1a79f21b9a91e1a8bf42586bd7a5c2afbb432a Mon Sep 17 00:00:00 2001 +From c5fe53f12090a49223c057b793b3aa411dabdd7a Mon Sep 17 00:00:00 2001 From: Oleksandr Shamray Date: Mon, 19 Sep 2022 14:55:22 +0300 -Subject: [PATCH hwmon 1/1] hwmon: (pmbus) Fix sensors readouts for MPS - Multi-phase mp2888 controller +Subject: [PATCH backport 5.10 180/182] hwmon: (pmbus) Fix sensors readouts for + MPS Multi-phase mp2888 controller Fix scale factors for reading MPS Multi-phase mp2888 controller. Fixed sensors: @@ -17,7 +17,7 @@ Reviewed-by: Vadim Pasternak 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/pmbus/mp2888.c b/drivers/hwmon/pmbus/mp2888.c -index 8ecd4ad..529eb3c 100644 +index 8ecd4adfef40..529eb3c95bb6 100644 --- a/drivers/hwmon/pmbus/mp2888.c +++ b/drivers/hwmon/pmbus/mp2888.c @@ -109,7 +109,7 @@ mp2888_read_phase(struct i2c_client *client, struct mp2888_data *data, int page, @@ -61,5 +61,5 @@ index 8ecd4ad..529eb3c 100644 /* * The below registers are not implemented by device or implemented not according to the -- -2.8.4 +2.20.1 diff --git a/patch/0182-platform-mellanox-Introduce-support-of-new-Nvidia-L1.patch b/patch/0182-platform-mellanox-Introduce-support-of-new-Nvidia-L1.patch new file mode 100644 index 000000000..40e28f821 --- /dev/null +++ b/patch/0182-platform-mellanox-Introduce-support-of-new-Nvidia-L1.patch @@ -0,0 +1,647 @@ +From 74ab8a216510df924ca88d2f3d5944eb107264d0 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 11 Dec 2022 09:26:48 +0200 +Subject: [PATCH backport 5.10 1/5] platform: mellanox: Introduce support of + new Nvidia L1 switch + +Add support for new L1 switch nodes providing L1 connectivity for +multi-node networking chassis. + +The purpose is to provide compute server with full management and IO +subsystems with connections to L1 switches. + +System contains the following components: +- COMe module based on Intel Coffee Lake CPU +- Switch baseboard with two ASICs, while + 24 ports of each ASICs are connected to one backplane connector + 32 ports of each ASIC are connected to 8 OSFPs +- Integrated 60mm dual-rotor FANs inside L1 node (N+2 redundancy) +- Support 48V or 54V DC input from the external power server. + +Add the structures related to the new systems to allow proper activation +of the all required platform driver. + +Add poweroff callback to support deep power cycle flow, which should +include special actions against CPLD device for performing graceful +operation. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 395 +++++++++++++++++++++++++++- + 1 file changed, 393 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 4bbe1d8f0..a2addd1b3 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -62,12 +63,19 @@ + #define MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET 0x37 + #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a + #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b ++#define MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET 0x3c ++#define MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET 0x3d ++#define MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET 0x3e ++#define MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET 0x3f + #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 + #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 + #define MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET 0x42 + #define MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET 0x43 + #define MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET 0x44 + #define MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET 0x45 ++#define MLXPLAT_CPLD_LPC_REG_BRD_OFFSET 0x47 ++#define MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET 0x48 ++#define MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET 0x49 + #define MLXPLAT_CPLD_LPC_REG_GWP_OFFSET 0x4a + #define MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET 0x4b + #define MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET 0x4c +@@ -97,6 +105,9 @@ + #define MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET 0x94 + #define MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET 0x95 + #define MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET 0x96 ++#define MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET 0x97 ++#define MLXPLAT_CPLD_LPC_REG_PWRB_EVENT_OFFSET 0x98 ++#define MLXPLAT_CPLD_LPC_REG_PWRB_MASK_OFFSET 0x99 + #define MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET 0x9a + #define MLXPLAT_CPLD_LPC_REG_LC_VR_EVENT_OFFSET 0x9b + #define MLXPLAT_CPLD_LPC_REG_LC_VR_MASK_OFFSET 0x9c +@@ -128,6 +139,7 @@ + #define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET 0xd1 + #define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET 0xd2 + #define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd3 ++#define MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET 0xd9 + #define MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET 0xde + #define MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET 0xdf + #define MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET 0xe0 +@@ -211,6 +223,7 @@ + MLXPLAT_CPLD_AGGR_MASK_LC_SDWN) + #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 + #define MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2 BIT(2) ++#define MLXPLAT_CPLD_LOW_AGGR_MASK_PWR_BUT BIT(4) + #define MLXPLAT_CPLD_LOW_AGGR_MASK_I2C BIT(6) + #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) +@@ -225,6 +238,16 @@ + #define MLXPLAT_CPLD_VOLTREG_UPD_MASK GENMASK(5, 4) + #define MLXPLAT_CPLD_GWP_MASK GENMASK(0, 0) + #define MLXPLAT_CPLD_EROT_MASK GENMASK(1, 0) ++#define MLXPLAT_CPLD_PWR_BUTTON_MASK BIT(0) ++#define MLXPLAT_CPLD_LATCH_RST_MASK BIT(5) ++#define MLXPLAT_CPLD_THERMAL1_PDB_MASK BIT(3) ++#define MLXPLAT_CPLD_THERMAL2_PDB_MASK BIT(4) ++#define MLXPLAT_CPLD_INTRUSION_MASK BIT(6) ++#define MLXPLAT_CPLD_PWM_PG_MASK BIT(7) ++#define MLXPLAT_CPLD_L1_CHA_HEALTH_MASK (MLXPLAT_CPLD_THERMAL1_PDB_MASK | \ ++ MLXPLAT_CPLD_THERMAL2_PDB_MASK | \ ++ MLXPLAT_CPLD_INTRUSION_MASK |\ ++ MLXPLAT_CPLD_PWM_PG_MASK) + #define MLXPLAT_CPLD_I2C_CAP_BIT 0x04 + #define MLXPLAT_CPLD_I2C_CAP_MASK GENMASK(5, MLXPLAT_CPLD_I2C_CAP_BIT) + +@@ -237,6 +260,8 @@ + /* Masks for aggregation for modular systems */ + #define MLXPLAT_CPLD_LPC_LC_MASK GENMASK(7, 0) + ++#define MLXPLAT_CPLD_HALT_MASK BIT(3) ++ + /* Default I2C parent bus number */ + #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1 + +@@ -317,6 +342,8 @@ struct mlxplat_priv { + void *regmap; + }; + ++static struct platform_device *mlxplat_dev; ++ + /* Regions for LPC I2C controller and LPC base register space */ + static const struct resource mlxplat_lpc_resources[] = { + [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR, +@@ -476,7 +503,7 @@ static struct i2c_mux_reg_platform_data mlxplat_modular_mux_data[] = { + }, + }; + +-/* Platform channels for rack swicth system family */ ++/* Platform channels for rack switch system family */ + static const int mlxplat_rack_switch_channels[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + }; +@@ -2409,6 +2436,156 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_rack_switch_data = { + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, + }; + ++/* Callback performs graceful shutdown after notification about power button event */ ++static int ++mlxplat_mlxcpld_l1_switch_pwr_events_handler(void *handle, enum mlxreg_hotplug_kind kind, ++ u8 action) ++{ ++ dev_info(&mlxplat_dev->dev, "System shutdown due to short press of power button"); ++ kernel_halt(); ++ return 0; ++} ++ ++static struct mlxreg_core_hotplug_notifier mlxplat_mlxcpld_l1_switch_pwr_events_notifier = { ++ .user_handler = mlxplat_mlxcpld_l1_switch_pwr_events_handler, ++}; ++ ++/* Platform hotplug for l1 switch systems family data */ ++static struct mlxreg_core_data mlxplat_mlxcpld_l1_switch_pwr_events_items_data[] = { ++ { ++ .label = "power_button", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET, ++ .mask = MLXPLAT_CPLD_PWR_BUTTON_MASK, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ .hpdev.notifier = &mlxplat_mlxcpld_l1_switch_pwr_events_notifier, ++ }, ++}; ++ ++/* Callback activates latch reset flow after notification about intrusion event */ ++static int ++mlxplat_mlxcpld_l1_switch_intrusion_events_handler(void *handle, enum mlxreg_hotplug_kind kind, ++ u8 action) ++{ ++ struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); ++ u32 regval; ++ int err; ++ ++ err = regmap_read(priv->regmap, MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ®val); ++ if (err) ++ goto fail_regmap_read; ++ ++ if (action) { ++ dev_info(&mlxplat_dev->dev, "Detected intrusion - system latch is opened"); ++ err = regmap_write(priv->regmap, MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ regval | MLXPLAT_CPLD_LATCH_RST_MASK); ++ } else { ++ dev_info(&mlxplat_dev->dev, "System latch is properly closed"); ++ err = regmap_write(priv->regmap, MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ regval & ~MLXPLAT_CPLD_LATCH_RST_MASK); ++ } ++ ++ if (err) ++ goto fail_regmap_write; ++ ++ return 0; ++ ++fail_regmap_read: ++fail_regmap_write: ++ dev_err(&mlxplat_dev->dev, "Register access failed"); ++ return err; ++} ++ ++static struct mlxreg_core_hotplug_notifier mlxplat_mlxcpld_l1_switch_intrusion_events_notifier = { ++ .user_handler = mlxplat_mlxcpld_l1_switch_intrusion_events_handler, ++}; ++ ++static struct mlxreg_core_data mlxplat_mlxcpld_l1_switch_health_events_items_data[] = { ++ { ++ .label = "thermal1_pdb", ++ .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET, ++ .mask = MLXPLAT_CPLD_THERMAL1_PDB_MASK, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "thermal2_pdb", ++ .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET, ++ .mask = MLXPLAT_CPLD_THERMAL2_PDB_MASK, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "intrusion", ++ .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET, ++ .mask = MLXPLAT_CPLD_INTRUSION_MASK, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ .hpdev.notifier = &mlxplat_mlxcpld_l1_switch_intrusion_events_notifier, ++ }, ++ { ++ .label = "pwm_pg", ++ .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET, ++ .mask = MLXPLAT_CPLD_PWM_PG_MASK, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++}; ++ ++static struct mlxreg_core_item mlxplat_mlxcpld_l1_switch_events_items[] = { ++ { ++ .data = mlxplat_mlxcpld_default_ng_fan_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = MLXPLAT_CPLD_FAN_NG_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_erot_ap_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET, ++ .mask = MLXPLAT_CPLD_EROT_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_ap_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_erot_error_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET, ++ .mask = MLXPLAT_CPLD_EROT_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_error_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_l1_switch_pwr_events_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET, ++ .mask = MLXPLAT_CPLD_PWR_BUTTON_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_pwr_events_items_data), ++ .inversed = 0, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_l1_switch_health_events_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET, ++ .mask = MLXPLAT_CPLD_L1_CHA_HEALTH_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_health_events_items_data), ++ .inversed = 0, ++ .health = false, ++ .ind = 8, ++ }, ++}; ++ ++static ++struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_l1_switch_data = { ++ .items = mlxplat_mlxcpld_l1_switch_events_items, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_events_items), ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, ++ .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ++ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_PWR_BUT, ++}; ++ + static struct spi_board_info rack_switch_switch_spi_board_info[] = { + { + .modalias = "spidev", +@@ -3066,6 +3243,114 @@ static struct mlxreg_core_platform_data mlxplat_qmb8700_led_data = { + .counter = ARRAY_SIZE(mlxplat_mlxcpld_qmb8700_led_data), + }; + ++/* Platform led data for chassis system */ ++static struct mlxreg_core_data mlxplat_mlxcpld_l1_switch_led_data[] = { ++ { ++ .label = "status:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ }, ++ { ++ .label = "status:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK ++ }, ++ { ++ .label = "fan1:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(0), ++ }, ++ { ++ .label = "fan1:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(0), ++ }, ++ { ++ .label = "fan2:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(1), ++ }, ++ { ++ .label = "fan2:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(1), ++ }, ++ { ++ .label = "fan3:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(2), ++ }, ++ { ++ .label = "fan3:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(2), ++ }, ++ { ++ .label = "fan4:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(3), ++ }, ++ { ++ .label = "fan4:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(3), ++ }, ++ { ++ .label = "fan5:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(4), ++ }, ++ { ++ .label = "fan5:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(4), ++ }, ++ { ++ .label = "fan6:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(5), ++ }, ++ { ++ .label = "fan6:orange", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, ++ .bit = BIT(5), ++ }, ++ { ++ .label = "uid:blue", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ }, ++}; ++ ++static struct mlxreg_core_platform_data mlxplat_l1_switch_led_data = { ++ .data = mlxplat_mlxcpld_l1_switch_led_data, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_led_data), ++}; ++ + /* Platform register access default */ + static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { + { +@@ -3594,12 +3879,48 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0200, + }, ++ { ++ .label = "deep_pwr_cycle", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0200, ++ }, ++ { ++ .label = "latch_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0200, ++ }, + { + .label = "jtag_enable", + .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0644, + }, ++ { ++ .label = "dbg1", ++ .reg = MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0644, ++ }, ++ { ++ .label = "dbg2", ++ .reg = MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0644, ++ }, ++ { ++ .label = "dbg3", ++ .reg = MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0644, ++ }, ++ { ++ .label = "dbg4", ++ .reg = MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0644, ++ }, + { + .label = "asic_health", + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, +@@ -4913,11 +5234,18 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET: + case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_BRD_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC2_EVENT_OFFSET: +@@ -4932,6 +5260,8 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWRB_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWRB_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_MASK_OFFSET: +@@ -4960,6 +5290,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM3_OFFSET: +@@ -5010,6 +5341,10 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET: +@@ -5019,6 +5354,9 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_GWP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_BRD_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: +@@ -5040,6 +5378,9 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWRB_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWRB_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET: +@@ -5076,6 +5417,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET: +@@ -5152,6 +5494,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET: +@@ -5161,6 +5507,9 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_GWP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_BRD_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: +@@ -5182,6 +5531,9 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWRB_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWRB_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET: +@@ -5212,6 +5564,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET: +@@ -5407,7 +5760,6 @@ static struct resource mlxplat_mlxcpld_resources[] = { + [0] = DEFINE_RES_IRQ_NAMED(MLXPLAT_CPLD_LPC_SYSIRQ, "mlxreg-hotplug"), + }; + +-static struct platform_device *mlxplat_dev; + static struct mlxreg_core_hotplug_platform_data *mlxplat_i2c; + static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; + static struct mlxreg_core_platform_data *mlxplat_led; +@@ -5418,6 +5770,14 @@ static struct mlxreg_core_platform_data + static const struct regmap_config *mlxplat_regmap_config; + static struct spi_board_info *mlxplat_spi; + ++/* Platform default poweroff function */ ++static void mlxplat_poweroff(void) ++{ ++ struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); ++ ++ regmap_write(priv->regmap, MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, MLXPLAT_CPLD_HALT_MASK); ++} ++ + static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) + { + int i; +@@ -5740,6 +6100,29 @@ static int __init mlxplat_dmi_ng800_matched(const struct dmi_system_id *dmi) + return 1; + } + ++static int __init mlxplat_dmi_l1_switch_matched(const struct dmi_system_id *dmi) ++{ ++ int i; ++ ++ mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; ++ mlxplat_mux_num = ARRAY_SIZE(mlxplat_rack_switch_mux_data); ++ mlxplat_mux_data = mlxplat_rack_switch_mux_data; ++ mlxplat_hotplug = &mlxplat_mlxcpld_l1_switch_data; ++ mlxplat_hotplug->deferred_nr = ++ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; ++ mlxplat_led = &mlxplat_l1_switch_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]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; ++ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_rack_switch; ++ pm_power_off = mlxplat_poweroff; ++ mlxplat_spi = rack_switch_switch_spi_board_info; ++ ++ return 1; ++} ++ + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + { + .callback = mlxplat_dmi_default_wc_matched, +@@ -5835,6 +6218,12 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0015"), + }, + }, ++ { ++ .callback = mlxplat_dmi_l1_switch_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0017"), ++ }, ++ }, + { + .callback = mlxplat_dmi_msn274x_matched, + .matches = { +@@ -6167,6 +6556,8 @@ static void __exit mlxplat_exit(void) + struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); + int i; + ++ if (pm_power_off) ++ pm_power_off = NULL; + for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) + platform_device_unregister(priv->pdev_wd[i]); + if (priv->pdev_fan) +-- +2.20.1 + diff --git a/patch/0183-platform-mellanox-Split-initialization-procedure.patch b/patch/0183-platform-mellanox-Split-initialization-procedure.patch new file mode 100644 index 000000000..deb8591ae --- /dev/null +++ b/patch/0183-platform-mellanox-Split-initialization-procedure.patch @@ -0,0 +1,168 @@ +From 5a2cfa144640a047ab17de5ef12dfefbe7e2f8c3 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 11 Dec 2022 10:44:43 +0200 +Subject: [PATCH backport 5.10 2/5] platform: mellanox: Split initialization + procedure + +Split mlxplat_init() into two by adding mlxplat_pre_init(). + +Motivation is to prepare 'mlx-platform' driver to support systems +equipped PCIe based programming logic device. + +Such systems are supposed to use different system resources, thus this +commit separates resources allocation related code. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 78 ++++++++++++++++++++++------- + 1 file changed, 60 insertions(+), 18 deletions(-) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index a2addd1b3..199f22d72 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -330,6 +330,8 @@ + * @pdev_fan - FAN platform devices + * @pdev_wd - array of watchdog platform devices + * @regmap: device register map ++ * @hotplug_resources: system hotplug resources ++ * @hotplug_resources_size: size of system hotplug resources + */ + struct mlxplat_priv { + struct platform_device *pdev_i2c; +@@ -340,6 +342,8 @@ struct mlxplat_priv { + struct platform_device *pdev_fan; + struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS]; + void *regmap; ++ struct resource *hotplug_resources; ++ unsigned int hotplug_resources_size; + }; + + static struct platform_device *mlxplat_dev; +@@ -6365,20 +6369,63 @@ static int mlxplat_mlxcpld_check_wd_capability(void *regmap) + return 0; + } + ++static int mlxplat_lpc_cpld_device_init(struct resource **hotplug_resources, ++ unsigned int *hotplug_resources_size) ++{ ++ int err; ++ ++ mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, PLATFORM_DEVID_NONE, ++ mlxplat_lpc_resources, ++ ARRAY_SIZE(mlxplat_lpc_resources)); ++ if (IS_ERR(mlxplat_dev)) ++ return PTR_ERR(mlxplat_dev); ++ ++ mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev, ++ mlxplat_lpc_resources[1].start, 1); ++ if (!mlxplat_mlxcpld_regmap_ctx.base) { ++ err = -ENOMEM; ++ goto fail_devm_ioport_map; ++ } ++ ++ *hotplug_resources = mlxplat_mlxcpld_resources; ++ *hotplug_resources_size = ARRAY_SIZE(mlxplat_mlxcpld_resources); ++ ++ return 0; ++ ++fail_devm_ioport_map: ++ platform_device_unregister(mlxplat_dev); ++ return err; ++} ++ ++static void mlxplat_lpc_cpld_device_exit(void) ++{ ++ platform_device_unregister(mlxplat_dev); ++} ++ ++static int ++mlxplat_pre_init(struct resource **hotplug_resources, unsigned int *hotplug_resources_size) ++{ ++ return mlxplat_lpc_cpld_device_init(hotplug_resources, hotplug_resources_size); ++} ++ ++static void mlxplat_post_exit(void) ++{ ++ mlxplat_lpc_cpld_device_exit(); ++} ++ + static int __init mlxplat_init(void) + { ++ unsigned int hotplug_resources_size; ++ struct resource *hotplug_resources; + struct mlxplat_priv *priv; + int i, j, nr, err; + + if (!dmi_check_system(mlxplat_dmi_table)) + return -ENODEV; + +- mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1, +- mlxplat_lpc_resources, +- ARRAY_SIZE(mlxplat_lpc_resources)); +- +- if (IS_ERR(mlxplat_dev)) +- return PTR_ERR(mlxplat_dev); ++ err = mlxplat_pre_init(&hotplug_resources, &hotplug_resources_size); ++ if (err) ++ return err; + + priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv), + GFP_KERNEL); +@@ -6388,12 +6435,8 @@ static int __init mlxplat_init(void) + } + platform_set_drvdata(mlxplat_dev, priv); + +- mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev, +- mlxplat_lpc_resources[1].start, 1); +- if (!mlxplat_mlxcpld_regmap_ctx.base) { +- err = -ENOMEM; +- goto fail_alloc; +- } ++ priv->hotplug_resources = hotplug_resources; ++ priv->hotplug_resources_size = hotplug_resources_size; + + if (!mlxplat_regmap_config) + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config; +@@ -6414,8 +6457,8 @@ static int __init mlxplat_init(void) + if (mlxplat_i2c) + mlxplat_i2c->regmap = priv->regmap; + priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld", +- nr, mlxplat_mlxcpld_resources, +- ARRAY_SIZE(mlxplat_mlxcpld_resources), ++ nr, priv->hotplug_resources, ++ priv->hotplug_resources_size, + mlxplat_i2c, sizeof(*mlxplat_i2c)); + if (IS_ERR(priv->pdev_i2c)) { + err = PTR_ERR(priv->pdev_i2c); +@@ -6439,8 +6482,8 @@ static int __init mlxplat_init(void) + priv->pdev_hotplug = + platform_device_register_resndata(&mlxplat_dev->dev, + "mlxreg-hotplug", PLATFORM_DEVID_NONE, +- mlxplat_mlxcpld_resources, +- ARRAY_SIZE(mlxplat_mlxcpld_resources), ++ priv->hotplug_resources, ++ priv->hotplug_resources_size, + mlxplat_hotplug, sizeof(*mlxplat_hotplug)); + if (IS_ERR(priv->pdev_hotplug)) { + err = PTR_ERR(priv->pdev_hotplug); +@@ -6545,7 +6588,6 @@ static int __init mlxplat_init(void) + platform_device_unregister(priv->pdev_mux[i]); + platform_device_unregister(priv->pdev_i2c); + fail_alloc: +- platform_device_unregister(mlxplat_dev); + + return err; + } +@@ -6573,7 +6615,7 @@ static void __exit mlxplat_exit(void) + platform_device_unregister(priv->pdev_mux[i]); + + platform_device_unregister(priv->pdev_i2c); +- platform_device_unregister(mlxplat_dev); ++ mlxplat_post_exit(); + } + module_exit(mlxplat_exit); + +-- +2.20.1 + diff --git a/patch/0184-platform-mellanox-Split-logic-in-init-and-exit-flow.patch b/patch/0184-platform-mellanox-Split-logic-in-init-and-exit-flow.patch new file mode 100644 index 000000000..3810a2dc0 --- /dev/null +++ b/patch/0184-platform-mellanox-Split-logic-in-init-and-exit-flow.patch @@ -0,0 +1,455 @@ +From f00081a6e0b7af5a0b85db3121afe3cc6a62f9e7 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 11 Dec 2022 11:08:07 +0200 +Subject: [PATCH backport 5.10 072/150] platform: mellanox: Split logic in init + and exit flow + +Split logic in mlxplat_init()/mlxplat_exit() routines. +Separate initialization of I2C infrastructure and others platform +drivers. + +Motivation is to provide synchronization between I2C bus and mux +drivers and other drivers using this infrastructure. +I2C main bus and MUX busses are implemented in FPGA logic. On some new +systems the numbers allocated for these busses could be variable +depending on order of initialization of I2C native busses. Since bus +numbers are passed to some other platform drivers during initialization +flow, it is necessary to synchronize completion of I2C infrastructure +drivers and activation of rest of drivers. + +Thus initialization flow will be performed in synchronized order. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 313 ++++++++++++++++++---------- + 1 file changed, 204 insertions(+), 109 deletions(-) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 199f22d72..05a630135 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -321,6 +321,9 @@ + /* Default value for PWM control register for rack switch system */ + #define MLXPLAT_REGMAP_NVSWITCH_PWM_DEFAULT 0xf4 + ++#define MLXPLAT_I2C_MAIN_BUS_NOTIFIED 0x01 ++#define MLXPLAT_I2C_MAIN_BUS_HANDLE_CREATED 0x02 ++ + /* mlxplat_priv - platform private data + * @pdev_i2c - i2c controller platform device + * @pdev_mux - array of mux platform devices +@@ -332,6 +335,7 @@ + * @regmap: device register map + * @hotplug_resources: system hotplug resources + * @hotplug_resources_size: size of system hotplug resources ++ * @hi2c_main_init_status: init status of I2C main bus + */ + struct mlxplat_priv { + struct platform_device *pdev_i2c; +@@ -344,9 +348,11 @@ struct mlxplat_priv { + void *regmap; + struct resource *hotplug_resources; + unsigned int hotplug_resources_size; ++ u8 i2c_main_init_status; + }; + + static struct platform_device *mlxplat_dev; ++static int mlxplat_i2c_main_complition_notify(void *handle, int id); + + /* Regions for LPC I2C controller and LPC base register space */ + static const struct resource mlxplat_lpc_resources[] = { +@@ -381,6 +387,7 @@ static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = { + .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX, + .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_I2C, ++ .completion_notify = mlxplat_i2c_main_complition_notify, + }; + + /* Platform default channels */ +@@ -6413,68 +6420,9 @@ static void mlxplat_post_exit(void) + mlxplat_lpc_cpld_device_exit(); + } + +-static int __init mlxplat_init(void) ++static int mlxplat_post_init(struct mlxplat_priv *priv) + { +- unsigned int hotplug_resources_size; +- struct resource *hotplug_resources; +- struct mlxplat_priv *priv; +- int i, j, nr, err; +- +- if (!dmi_check_system(mlxplat_dmi_table)) +- return -ENODEV; +- +- err = mlxplat_pre_init(&hotplug_resources, &hotplug_resources_size); +- if (err) +- return err; +- +- priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv), +- GFP_KERNEL); +- if (!priv) { +- err = -ENOMEM; +- goto fail_alloc; +- } +- platform_set_drvdata(mlxplat_dev, priv); +- +- priv->hotplug_resources = hotplug_resources; +- priv->hotplug_resources_size = hotplug_resources_size; +- +- if (!mlxplat_regmap_config) +- mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config; +- +- priv->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, +- &mlxplat_mlxcpld_regmap_ctx, +- mlxplat_regmap_config); +- if (IS_ERR(priv->regmap)) { +- err = PTR_ERR(priv->regmap); +- goto fail_alloc; +- } +- +- err = mlxplat_mlxcpld_verify_bus_topology(&nr); +- if (nr < 0) +- goto fail_alloc; +- +- nr = (nr == mlxplat_max_adap_num) ? -1 : nr; +- if (mlxplat_i2c) +- mlxplat_i2c->regmap = priv->regmap; +- priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld", +- nr, priv->hotplug_resources, +- priv->hotplug_resources_size, +- mlxplat_i2c, sizeof(*mlxplat_i2c)); +- if (IS_ERR(priv->pdev_i2c)) { +- err = PTR_ERR(priv->pdev_i2c); +- goto fail_alloc; +- } +- +- for (i = 0; i < mlxplat_mux_num; i++) { +- priv->pdev_mux[i] = platform_device_register_resndata(&priv->pdev_i2c->dev, +- "i2c-mux-reg", i, NULL, 0, +- &mlxplat_mux_data[i], +- sizeof(mlxplat_mux_data[i])); +- if (IS_ERR(priv->pdev_mux[i])) { +- err = PTR_ERR(priv->pdev_mux[i]); +- goto fail_platform_mux_register; +- } +- } ++ int i = 0, err; + + /* Add hotplug driver */ + if (mlxplat_hotplug) { +@@ -6487,19 +6435,10 @@ static int __init mlxplat_init(void) + mlxplat_hotplug, sizeof(*mlxplat_hotplug)); + if (IS_ERR(priv->pdev_hotplug)) { + err = PTR_ERR(priv->pdev_hotplug); +- goto fail_platform_mux_register; ++ goto fail_platform_hotplug_register; + } + } + +- /* Set default registers. */ +- for (j = 0; j < mlxplat_regmap_config->num_reg_defaults; j++) { +- err = regmap_write(priv->regmap, +- mlxplat_regmap_config->reg_defaults[j].reg, +- mlxplat_regmap_config->reg_defaults[j].def); +- if (err) +- goto fail_platform_mux_register; +- } +- + /* Add LED driver. */ + if (mlxplat_led) { + mlxplat_led->regmap = priv->regmap; +@@ -6509,7 +6448,7 @@ static int __init mlxplat_init(void) + sizeof(*mlxplat_led)); + if (IS_ERR(priv->pdev_led)) { + err = PTR_ERR(priv->pdev_led); +- goto fail_platform_hotplug_register; ++ goto fail_platform_leds_register; + } + } + +@@ -6523,7 +6462,7 @@ static int __init mlxplat_init(void) + sizeof(*mlxplat_regs_io)); + if (IS_ERR(priv->pdev_io_regs)) { + err = PTR_ERR(priv->pdev_io_regs); +- goto fail_platform_led_register; ++ goto fail_platform_io_register; + } + } + +@@ -6536,7 +6475,7 @@ static int __init mlxplat_init(void) + sizeof(*mlxplat_fan)); + if (IS_ERR(priv->pdev_fan)) { + err = PTR_ERR(priv->pdev_fan); +- goto fail_platform_io_regs_register; ++ goto fail_platform_fan_register; + } + } + +@@ -6547,59 +6486,42 @@ static int __init mlxplat_init(void) + err = mlxplat_mlxcpld_check_wd_capability(priv->regmap); + if (err) + goto fail_platform_wd_register; +- for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) { +- if (mlxplat_wd_data[j]) { +- mlxplat_wd_data[j]->regmap = priv->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]); ++ for (i = 0; i < MLXPLAT_CPLD_WD_MAX_DEVS; i++) { ++ if (mlxplat_wd_data[i]) { ++ mlxplat_wd_data[i]->regmap = priv->regmap; ++ priv->pdev_wd[i] = ++ platform_device_register_resndata(&mlxplat_dev->dev, "mlx-wdt", i, ++ NULL, 0, mlxplat_wd_data[i], ++ sizeof(*mlxplat_wd_data[i])); ++ if (IS_ERR(priv->pdev_wd[i])) { ++ err = PTR_ERR(priv->pdev_wd[i]); + goto fail_platform_wd_register; + } + } + } + +- /* Sync registers with hardware. */ +- regcache_mark_dirty(priv->regmap); +- err = regcache_sync(priv->regmap); +- if (err) +- goto fail_platform_wd_register; +- + return 0; + + 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: ++ while (--i >= 0) ++ platform_device_unregister(priv->pdev_wd[i]); ++fail_platform_fan_register: + if (mlxplat_regs_io) + platform_device_unregister(priv->pdev_io_regs); +-fail_platform_led_register: ++fail_platform_io_register: + if (mlxplat_led) + platform_device_unregister(priv->pdev_led); +-fail_platform_hotplug_register: ++fail_platform_leds_register: + if (mlxplat_hotplug) + platform_device_unregister(priv->pdev_hotplug); +-fail_platform_mux_register: +- while (--i >= 0) +- platform_device_unregister(priv->pdev_mux[i]); +- platform_device_unregister(priv->pdev_i2c); +-fail_alloc: +- ++fail_platform_hotplug_register: + return err; + } +-module_init(mlxplat_init); + +-static void __exit mlxplat_exit(void) ++static void mlxplat_pre_exit(struct mlxplat_priv *priv) + { +- struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); + int i; + +- if (pm_power_off) +- pm_power_off = NULL; + for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) + platform_device_unregister(priv->pdev_wd[i]); + if (priv->pdev_fan) +@@ -6610,13 +6532,186 @@ static void __exit mlxplat_exit(void) + platform_device_unregister(priv->pdev_led); + if (priv->pdev_hotplug) + platform_device_unregister(priv->pdev_hotplug); ++} ++ ++static int ++mlxplat_i2c_mux_complition_notify(void *handle, struct i2c_adapter *parent, ++ struct i2c_adapter *adapters[]) ++{ ++ struct mlxplat_priv *priv = handle; ++ ++ return mlxplat_post_init(priv); ++} + +- for (i = mlxplat_mux_num - 1; i >= 0 ; i--) ++static int mlxplat_i2c_mux_topolgy_init(struct mlxplat_priv *priv) ++{ ++ int i, err; ++ ++ if (!priv->pdev_i2c) { ++ priv->i2c_main_init_status = MLXPLAT_I2C_MAIN_BUS_NOTIFIED; ++ return 0; ++ } ++ ++ priv->i2c_main_init_status = MLXPLAT_I2C_MAIN_BUS_HANDLE_CREATED; ++ for (i = 0; i < mlxplat_mux_num; i++) { ++ priv->pdev_mux[i] = platform_device_register_resndata(&priv->pdev_i2c->dev, ++ "i2c-mux-reg", i, NULL, 0, ++ &mlxplat_mux_data[i], ++ sizeof(mlxplat_mux_data[i])); ++ if (IS_ERR(priv->pdev_mux[i])) { ++ err = PTR_ERR(priv->pdev_mux[i]); ++ goto fail_platform_mux_register; ++ } ++ } ++ ++ return mlxplat_i2c_mux_complition_notify(priv, NULL, NULL); ++ ++fail_platform_mux_register: ++ while (--i >= 0) + platform_device_unregister(priv->pdev_mux[i]); ++ return err; ++} ++ ++static void mlxplat_i2c_mux_topolgy_exit(struct mlxplat_priv *priv) ++{ ++ int i; ++ ++ for (i = mlxplat_mux_num - 1; i >= 0 ; i--) { ++ if (priv->pdev_mux[i]) ++ platform_device_unregister(priv->pdev_mux[i]); ++ } + +- platform_device_unregister(priv->pdev_i2c); + mlxplat_post_exit(); + } ++ ++static int mlxplat_i2c_main_complition_notify(void *handle, int id) ++{ ++ struct mlxplat_priv *priv = handle; ++ ++ return mlxplat_i2c_mux_topolgy_init(priv); ++} ++ ++static int mlxplat_i2c_main_init(struct mlxplat_priv *priv) ++{ ++ int nr, err; ++ ++ if (!mlxplat_i2c) ++ return 0; ++ ++ err = mlxplat_mlxcpld_verify_bus_topology(&nr); ++ if (nr < 0) ++ goto fail_mlxplat_mlxcpld_verify_bus_topology; ++ ++ nr = (nr == mlxplat_max_adap_num) ? -1 : nr; ++ mlxplat_i2c->regmap = priv->regmap; ++ mlxplat_i2c->handle = priv; ++ ++ priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld", ++ nr, priv->hotplug_resources, ++ priv->hotplug_resources_size, ++ mlxplat_i2c, sizeof(*mlxplat_i2c)); ++ if (IS_ERR(priv->pdev_i2c)) { ++ err = PTR_ERR(priv->pdev_i2c); ++ goto fail_platform_i2c_register; ++ } ++ ++ if (priv->i2c_main_init_status == MLXPLAT_I2C_MAIN_BUS_NOTIFIED) { ++ err = mlxplat_i2c_mux_topolgy_init(priv); ++ if (err) ++ goto fail_mlxplat_i2c_mux_topolgy_init; ++ } ++ ++ return 0; ++ ++fail_mlxplat_i2c_mux_topolgy_init: ++fail_platform_i2c_register: ++fail_mlxplat_mlxcpld_verify_bus_topology: ++ return err; ++} ++ ++static void mlxplat_i2c_main_exit(struct mlxplat_priv *priv) ++{ ++ mlxplat_i2c_mux_topolgy_exit(priv); ++ if (priv->pdev_i2c) ++ platform_device_unregister(priv->pdev_i2c); ++} ++ ++static int __init mlxplat_init(void) ++{ ++ unsigned int hotplug_resources_size; ++ struct resource *hotplug_resources; ++ struct mlxplat_priv *priv; ++ int i, err; ++ ++ if (!dmi_check_system(mlxplat_dmi_table)) ++ return -ENODEV; ++ ++ err = mlxplat_pre_init(&hotplug_resources, &hotplug_resources_size); ++ if (err) ++ return err; ++ ++ priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv), ++ GFP_KERNEL); ++ if (!priv) { ++ err = -ENOMEM; ++ goto fail_alloc; ++ } ++ platform_set_drvdata(mlxplat_dev, priv); ++ priv->hotplug_resources = hotplug_resources; ++ priv->hotplug_resources_size = hotplug_resources_size; ++ ++ if (!mlxplat_regmap_config) ++ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config; ++ ++ priv->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, ++ &mlxplat_mlxcpld_regmap_ctx, ++ mlxplat_regmap_config); ++ if (IS_ERR(priv->regmap)) { ++ err = PTR_ERR(priv->regmap); ++ goto fail_alloc; ++ } ++ ++ /* Set default registers. */ ++ for (i = 0; i < mlxplat_regmap_config->num_reg_defaults; i++) { ++ err = regmap_write(priv->regmap, ++ mlxplat_regmap_config->reg_defaults[i].reg, ++ mlxplat_regmap_config->reg_defaults[i].def); ++ if (err) ++ goto fail_regmap_write; ++ } ++ ++ err = mlxplat_i2c_main_init(priv); ++ if (err) ++ goto fail_mlxplat_i2c_main_init; ++ ++ /* Sync registers with hardware. */ ++ regcache_mark_dirty(priv->regmap); ++ err = regcache_sync(priv->regmap); ++ if (err) ++ goto fail_regcache_sync; ++ ++ return 0; ++ ++fail_regcache_sync: ++ mlxplat_pre_exit(priv); ++fail_mlxplat_i2c_main_init: ++fail_regmap_write: ++fail_alloc: ++ mlxplat_post_exit(); ++ ++ return err; ++} ++module_init(mlxplat_init); ++ ++static void __exit mlxplat_exit(void) ++{ ++ struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); ++ ++ if (pm_power_off) ++ pm_power_off = NULL; ++ mlxplat_pre_exit(priv); ++ mlxplat_i2c_main_exit(priv); ++} + module_exit(mlxplat_exit); + + MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); +-- +2.20.1 + diff --git a/patch/0185-platform-mellanox-Extend-all-systems-with-I2C-notifi.patch b/patch/0185-platform-mellanox-Extend-all-systems-with-I2C-notifi.patch new file mode 100644 index 000000000..6209d6035 --- /dev/null +++ b/patch/0185-platform-mellanox-Extend-all-systems-with-I2C-notifi.patch @@ -0,0 +1,81 @@ +From 3a61ad447e2ec437079c86c277b80acde19e9173 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 26 Dec 2022 22:28:33 +0200 +Subject: [PATCH backport 5.10 073/150] platform: mellanox: Extend all systems + with I2C notification callback + +Motivation is to provide synchronization between I2C main bus and other +platform drivers using this notification callback. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 05a630135..1ef0bb975 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -365,6 +365,11 @@ static const struct resource mlxplat_lpc_resources[] = { + IORESOURCE_IO), + }; + ++/* Platform systems default i2c data */ ++static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_default_data = { ++ .completion_notify = mlxplat_i2c_main_complition_notify, ++}; ++ + /* Platform i2c next generation systems data */ + static struct mlxreg_core_data mlxplat_mlxcpld_i2c_ng_items_data[] = { + { +@@ -5807,6 +5812,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) + mlxplat_led = &mlxplat_default_led_data; + mlxplat_regs_io = &mlxplat_default_regs_io_data; + mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data; + + return 1; + } +@@ -5829,6 +5835,7 @@ static int __init mlxplat_dmi_default_wc_matched(const struct dmi_system_id *dmi + mlxplat_led = &mlxplat_default_led_wc_data; + mlxplat_regs_io = &mlxplat_default_regs_io_data; + mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data; + + return 1; + } +@@ -5876,6 +5883,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) + mlxplat_led = &mlxplat_msn21xx_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; + mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data; + + return 1; + } +@@ -5898,6 +5906,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) + mlxplat_led = &mlxplat_default_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; + mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data; + + return 1; + } +@@ -5920,6 +5929,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) + mlxplat_led = &mlxplat_msn21xx_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; + mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data; + + return 1; + } +@@ -5969,6 +5979,7 @@ static int __init mlxplat_dmi_comex_matched(const struct dmi_system_id *dmi) + 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]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data; + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_comex; + + return 1; +-- +2.20.1 + diff --git a/patch/0186-platform-mellanox-mlxreg-hotplug-Allow-more-flexible.patch b/patch/0186-platform-mellanox-mlxreg-hotplug-Allow-more-flexible.patch new file mode 100644 index 000000000..2e752b05d --- /dev/null +++ b/patch/0186-platform-mellanox-mlxreg-hotplug-Allow-more-flexible.patch @@ -0,0 +1,105 @@ +From 4244de9783c2348e15b40802c70816e4000e342d Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 9 Jan 2023 19:35:31 +0200 +Subject: [PATCH backport 5.10 5/5] platform/mellanox: mlxreg-hotplug: Allow + more flexible hotplug events configuration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently hotplug configuration in logic device assumes that all items +are provided with no holes. +Thus, any group of hotplug events, associated with the specific +status/event/mask registers is configured in those registers +successively from bit zero to bit #n (#n < 8). + +This logic is changed int order to allow non-successive definition to +support configuration with the skipped bits – for example bits 3, 5, 7 +in status/event/mask registers can be associated with hotplug events, +while others can be skipped. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/mellanox/mlxreg-hotplug.c | 28 ++++++++++++++++++---- + 1 file changed, 23 insertions(+), 5 deletions(-) + +diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c +index 117bc3f39..b7dcc64cd 100644 +--- a/drivers/platform/mellanox/mlxreg-hotplug.c ++++ b/drivers/platform/mellanox/mlxreg-hotplug.c +@@ -239,6 +239,17 @@ static ssize_t mlxreg_hotplug_attr_show(struct device *dev, + #define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i] + #define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i] + ++static int mlxreg_hotplug_item_label_index_get(u32 mask, u32 bit) ++{ ++ int i, j; ++ ++ for (i = 0, j = -1; i <= bit; i++) { ++ if (mask & BIT(i)) ++ j++; ++ } ++ return j; ++} ++ + static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) + { + struct mlxreg_core_hotplug_platform_data *pdata; +@@ -246,7 +257,7 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) + struct mlxreg_core_data *data; + unsigned long mask; + u32 regval; +- int num_attrs = 0, id = 0, i, j, k, ret; ++ int num_attrs = 0, id = 0, i, j, k, count, ret; + + pdata = dev_get_platdata(&priv->pdev->dev); + item = pdata->items; +@@ -272,7 +283,8 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) + /* Go over all unmasked units within item. */ + mask = item->mask; + k = 0; +- for_each_set_bit(j, &mask, item->count) { ++ count = item->ind ? item->ind : item->count; ++ for_each_set_bit(j, &mask, count) { + if (data->capability) { + /* + * Read capability register and skip non +@@ -282,16 +294,17 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) + data->capability, ®val); + if (ret) + return ret; ++ + if (!(regval & data->bit)) { + data++; + continue; + } + } ++ + PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr; + PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev, + GFP_KERNEL, + data->label); +- + if (!PRIV_ATTR(id)->name) { + dev_err(priv->dev, "Memory allocation failed for attr %d.\n", + id); +@@ -365,9 +378,14 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, + regval &= item->mask; + asserted = item->cache ^ regval; + item->cache = regval; +- + for_each_set_bit(bit, &asserted, 8) { +- data = item->data + bit; ++ int pos; ++ ++ pos = mlxreg_hotplug_item_label_index_get(item->mask, bit); ++ if (pos < 0) ++ goto out; ++ ++ data = item->data + pos; + if (regval & BIT(bit)) { + if (item->inversed) + mlxreg_hotplug_device_destroy(priv, data, item->kind); +-- +2.20.1 + diff --git a/patch/0187-platform_data-mlxreg-Add-field-with-mapped-resource-.patch b/patch/0187-platform_data-mlxreg-Add-field-with-mapped-resource-.patch new file mode 100644 index 000000000..2677a484f --- /dev/null +++ b/patch/0187-platform_data-mlxreg-Add-field-with-mapped-resource-.patch @@ -0,0 +1,37 @@ +From e1d1afba7f7285bebb2d30fce961901ee944d201 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 9 Nov 2022 09:43:28 +0200 +Subject: [PATCH backport 5.10 01/10] platform_data/mlxreg: Add field with + mapped resource address + +Add field with PCIe remapped based address for passing it across +relevant platform drivers sharing common system resources. + +Signed-off-by: Vadim Pasternak +--- + include/linux/platform_data/mlxreg.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h +index a6bd74e29..0b9f81a6f 100644 +--- a/include/linux/platform_data/mlxreg.h ++++ b/include/linux/platform_data/mlxreg.h +@@ -216,6 +216,7 @@ struct mlxreg_core_platform_data { + * @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; ++ * @addr: mapped resource address; + * @handle: handle to be passed by callback; + * @completion_notify: callback to notify when platform driver probing is done; + */ +@@ -230,6 +231,7 @@ struct mlxreg_core_hotplug_platform_data { + u32 mask_low; + int deferred_nr; + int shift_nr; ++ void __iomem *addr; + void *handle; + int (*completion_notify)(void *handle, int id); + }; +-- +2.20.1 + diff --git a/patch/0188-i2c-mux-Add-register-map-based-mux-driver.patch b/patch/0188-i2c-mux-Add-register-map-based-mux-driver.patch new file mode 100644 index 000000000..7912bf187 --- /dev/null +++ b/patch/0188-i2c-mux-Add-register-map-based-mux-driver.patch @@ -0,0 +1,253 @@ +From 03195e7418ec41d0a118973a392165f11ba881cf Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 9 Nov 2022 12:22:12 +0200 +Subject: [PATCH backport 5.10 026/100] i2c: mux: Add register map based mux + driver + +Add 'regmap' mux driver to allow virtual bus switching by setting a +single selector register. +The 'regmap' is supposed to be passed to driver within a platform data +by parent platform driver. + +Motivation is to support indirect access to register space where +selector register is located. +For example, Lattice FPGA LFD2NX-40 device, being connected through +PCIe bus provides SPI or LPC bus logic through PCIe-to-SPI or +PCIe-to-LPC bridging. Thus, FPGA operates a as host controller and +some slave devices can be connected to it. For example: +- CPU (PCIe) -> FPGA (PCIe-to-SPI bridge) -> CPLD or another FPGA. +- CPU (PCIe) -> FPGA (PCIe-to-LPC bridge) -> CPLD or another FPGA. +Where 1-st FPGA connected to PCIe is located on carrier board, while +2-nd programming logic device is located on some switch board and +cannot be connected to CPU PCIe root complex. + +In case mux selector register is located within the 2-nd device, SPI or +LPC transactions are sent indirectly through pre-defined protocol. + +To support such protocol reg_read()/reg_write() callbacks are provided +to 'regmap' object and these callback implements required indirect +access. + +For example, flow in reg_write() will be as following: +- Verify there is no pending transactions. +- Set address in PCIe register space. +- Set data to be written in PCIe register space. +- Activate write operation in PCIe register space. +- LPC or SPI write transaction is performed. + +Signed-off-by: Vadim Pasternak +--- + drivers/i2c/muxes/Kconfig | 12 ++ + drivers/i2c/muxes/Makefile | 1 + + drivers/i2c/muxes/i2c-mux-regmap.c | 123 +++++++++++++++++++ + include/linux/platform_data/i2c-mux-regmap.h | 34 +++++ + 4 files changed, 170 insertions(+) + create mode 100644 drivers/i2c/muxes/i2c-mux-regmap.c + create mode 100644 include/linux/platform_data/i2c-mux-regmap.h + +diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig +index 1708b1a82..48becd945 100644 +--- a/drivers/i2c/muxes/Kconfig ++++ b/drivers/i2c/muxes/Kconfig +@@ -99,6 +99,18 @@ config I2C_MUX_REG + This driver can also be built as a module. If so, the module + will be called i2c-mux-reg. + ++config I2C_MUX_REGMAP ++ tristate "Register map based I2C multiplexer" ++ depends on REGMAP ++ help ++ If you say yes to this option, support will be included for a ++ register map based I2C multiplexer. This driver provides access to ++ I2C busses connected through a MUX, which is controlled ++ by a single register through the regmap. ++ ++ This driver can also be built as a module. If so, the module ++ will be called i2c-mux-regmap. ++ + config I2C_DEMUX_PINCTRL + tristate "pinctrl-based I2C demultiplexer" + depends on PINCTRL && OF +diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile +index 6d9d865e8..092dca428 100644 +--- a/drivers/i2c/muxes/Makefile ++++ b/drivers/i2c/muxes/Makefile +@@ -14,5 +14,6 @@ obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o + obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o + obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o + obj-$(CONFIG_I2C_MUX_REG) += i2c-mux-reg.o ++obj-$(CONFIG_I2C_MUX_REGMAP) += i2c-mux-regmap.o + + ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG +diff --git a/drivers/i2c/muxes/i2c-mux-regmap.c b/drivers/i2c/muxes/i2c-mux-regmap.c +new file mode 100644 +index 000000000..e155c039a +--- /dev/null ++++ b/drivers/i2c/muxes/i2c-mux-regmap.c +@@ -0,0 +1,123 @@ ++// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 ++/* ++ * Regmap i2c mux driver ++ * ++ * Copyright (C) 2023 Nvidia Technologies Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* i2c_mux_regmap - mux control structure: ++ * @last_val - last selected register value or -1 if mux deselected; ++ * @pdata: platform data; ++ */ ++struct i2c_mux_regmap { ++ int last_val; ++ struct i2c_mux_regmap_platform_data pdata; ++}; ++ ++static int i2c_mux_regmap_select_chan(struct i2c_mux_core *muxc, u32 chan) ++{ ++ struct i2c_mux_regmap *mux = i2c_mux_priv(muxc); ++ int err = 0; ++ ++ /* Only select the channel if its different from the last channel */ ++ if (mux->last_val != chan) { ++ err = regmap_write(mux->pdata.regmap, mux->pdata.sel_reg_addr, chan); ++ mux->last_val = err < 0 ? -1 : chan; ++ } ++ ++ return err; ++} ++ ++static int i2c_mux_regmap_deselect(struct i2c_mux_core *muxc, u32 chan) ++{ ++ struct i2c_mux_regmap *mux = i2c_mux_priv(muxc); ++ ++ /* Deselect active channel */ ++ mux->last_val = -1; ++ ++ return regmap_write(mux->pdata.regmap, mux->pdata.sel_reg_addr, 0); ++} ++ ++/* Probe/reomove functions */ ++static int i2c_mux_regmap_probe(struct platform_device *pdev) ++{ ++ struct i2c_mux_regmap_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ struct i2c_mux_regmap *mux; ++ struct i2c_adapter *parent; ++ struct i2c_mux_core *muxc; ++ int num, err; ++ ++ if (!pdata) ++ return -EINVAL; ++ ++ mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); ++ if (!mux) ++ return -ENOMEM; ++ ++ memcpy(&mux->pdata, pdata, sizeof(*pdata)); ++ parent = i2c_get_adapter(mux->pdata.parent); ++ if (!parent) ++ return -EPROBE_DEFER; ++ ++ muxc = i2c_mux_alloc(parent, &pdev->dev, pdata->num_adaps, sizeof(*mux), 0, ++ i2c_mux_regmap_select_chan, i2c_mux_regmap_deselect); ++ if (!muxc) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, muxc); ++ muxc->priv = mux; ++ mux->last_val = -1; /* force the first selection */ ++ ++ /* Create an adapter for each channel. */ ++ for (num = 0; num < pdata->num_adaps; num++) { ++ err = i2c_mux_add_adapter(muxc, 0, pdata->chan_ids[num], 0); ++ if (err) ++ goto err_i2c_mux_add_adapter; ++ } ++ ++ /* Notify caller when all channels' adapters are created. */ ++ if (pdata->completion_notify) ++ pdata->completion_notify(pdata->handle, muxc->parent, muxc->adapter); ++ ++ return 0; ++ ++err_i2c_mux_add_adapter: ++ i2c_mux_del_adapters(muxc); ++ return err; ++} ++ ++static int i2c_mux_regmap_remove(struct platform_device *pdev) ++{ ++ struct i2c_mux_core *muxc = platform_get_drvdata(pdev); ++ ++ i2c_mux_del_adapters(muxc); ++ i2c_put_adapter(muxc->parent); ++ ++ return 0; ++} ++ ++static struct platform_driver i2c_mux_regmap_driver = { ++ .driver = { ++ .name = "i2c-mux-regmap", ++ }, ++ .probe = i2c_mux_regmap_probe, ++ .remove = i2c_mux_regmap_remove, ++}; ++ ++module_platform_driver(i2c_mux_regmap_driver); ++ ++MODULE_AUTHOR("Vadim Pasternak (vadimp@nvidia.com)"); ++MODULE_DESCRIPTION("Regmap I2C multiplexer driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_ALIAS("platform:i2c-mux-regmap"); +diff --git a/include/linux/platform_data/i2c-mux-regmap.h b/include/linux/platform_data/i2c-mux-regmap.h +new file mode 100644 +index 000000000..a06614e5e +--- /dev/null ++++ b/include/linux/platform_data/i2c-mux-regmap.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ ++/* ++ * Regmap i2c mux driver ++ * ++ * Copyright (C) 2023 Nvidia Technologies Ltd. ++ */ ++ ++#ifndef __LINUX_PLATFORM_DATA_I2C_MUX_REGMAP_H ++#define __LINUX_PLATFORM_DATA_I2C_MUX_REGMAP_H ++ ++/** ++ * struct i2c_mux_regmap_platform_data - Platform-dependent data for i2c-mux-regmap ++ * @regmap: register map of parent device; ++ * @parent: Parent I2C bus adapter number ++ * @chan_ids - channels array ++ * @num_adaps - number of adapters ++ * @sel_reg_addr - mux select register offset in CPLD space ++ * @reg_size: register size in bytes ++ * @handle: handle to be passed by callback ++ * @completion_notify: callback to notify when all the adapters are created ++ */ ++struct i2c_mux_regmap_platform_data { ++ void *regmap; ++ int parent; ++ const unsigned int *chan_ids; ++ int num_adaps; ++ int sel_reg_addr; ++ u8 reg_size; ++ void *handle; ++ int (*completion_notify)(void *handle, struct i2c_adapter *parent, ++ struct i2c_adapter *adapters[]); ++}; ++ ++#endif /* __LINUX_PLATFORM_DATA_I2C_MUX_REGMAP_H */ +-- +2.20.1 + diff --git a/patch/0189-i2c-mlxcpld-Allow-driver-to-run-on-ARM64-architectur.patch b/patch/0189-i2c-mlxcpld-Allow-driver-to-run-on-ARM64-architectur.patch new file mode 100644 index 000000000..b5c0e006e --- /dev/null +++ b/patch/0189-i2c-mlxcpld-Allow-driver-to-run-on-ARM64-architectur.patch @@ -0,0 +1,29 @@ +From c4d1a7d7f51a8315f727c9210961ed93b922d440 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 7 Nov 2022 12:00:37 +0200 +Subject: [PATCH backport 5.10 03/10] i2c: mlxcpld: Allow driver to run on + ARM64 architecture + +Extend driver dependency by ARM64 architecture. + +Signed-off-by: Vadim Pasternak +--- + drivers/i2c/busses/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index 7e693dcbd..c984305ee 100644 +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -1328,7 +1328,7 @@ config I2C_ICY + + config I2C_MLXCPLD + tristate "Mellanox I2C driver" +- depends on X86_64 || COMPILE_TEST ++ depends on X86_64 || ARM64 || COMPILE_TEST + help + This exposes the Mellanox platform I2C busses to the linux I2C layer + for X86 based systems. +-- +2.20.1 + diff --git a/patch/0190-i2c-mlxcpld-Modify-base-address-type.patch b/patch/0190-i2c-mlxcpld-Modify-base-address-type.patch new file mode 100644 index 000000000..36c3178e6 --- /dev/null +++ b/patch/0190-i2c-mlxcpld-Modify-base-address-type.patch @@ -0,0 +1,49 @@ +From d2130ff4d3aed72611f07213e9eceeb084f0fc65 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 9 Nov 2022 10:29:22 +0200 +Subject: [PATCH backport 5.10 04/10] i2c: mlxcpld: Modify base address type + +Change type of base address from 'u32' to 'u64'. + +Motivation is to support memory mapped virtual base address on ARM64 +architecture. + +Signed-off-by: Vadim Pasternak +--- + drivers/i2c/busses/i2c-mlxcpld.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c +index 72fcfb17d..57aea396c 100644 +--- a/drivers/i2c/busses/i2c-mlxcpld.c ++++ b/drivers/i2c/busses/i2c-mlxcpld.c +@@ -68,7 +68,7 @@ struct mlxcpld_i2c_curr_xfer { + + struct mlxcpld_i2c_priv { + struct i2c_adapter adap; +- u32 base_addr; ++ u64 base_addr; + struct mutex lock; + struct mlxcpld_i2c_curr_xfer xfer; + struct device *dev; +@@ -99,7 +99,7 @@ static void mlxcpld_i2c_lpc_read_buf(u8 *data, u8 len, u32 addr) + static void mlxcpld_i2c_read_comm(struct mlxcpld_i2c_priv *priv, u8 offs, + u8 *data, u8 datalen) + { +- u32 addr = priv->base_addr + offs; ++ u64 addr = priv->base_addr + offs; + + switch (datalen) { + case 1: +@@ -124,7 +124,7 @@ static void mlxcpld_i2c_read_comm(struct mlxcpld_i2c_priv *priv, u8 offs, + static void mlxcpld_i2c_write_comm(struct mlxcpld_i2c_priv *priv, u8 offs, + u8 *data, u8 datalen) + { +- u32 addr = priv->base_addr + offs; ++ u64 addr = priv->base_addr + offs; + + switch (datalen) { + case 1: +-- +2.20.1 + diff --git a/patch/0191-i2c-mlxcpld-Allow-to-configure-base-address-of-regis.patch b/patch/0191-i2c-mlxcpld-Allow-to-configure-base-address-of-regis.patch new file mode 100644 index 000000000..245bcaa4f --- /dev/null +++ b/patch/0191-i2c-mlxcpld-Allow-to-configure-base-address-of-regis.patch @@ -0,0 +1,34 @@ +From 0fcfc9b2eb7f071f3aa64845d262f1e8e4f741e7 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 9 Nov 2022 10:35:58 +0200 +Subject: [PATCH backport 5.10 05/10] i2c: mlxcpld: Allow to configure base + address of register space + +Allow to use configured base address. + +Currently driver uses constant base address of register space. +On new systems this base address could be different, thus it could be +passed to the driver through platform data. + +Signed-off-by: Vadim Pasternak +--- + drivers/i2c/busses/i2c-mlxcpld.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c +index 57aea396c..cd5401ce4 100644 +--- a/drivers/i2c/busses/i2c-mlxcpld.c ++++ b/drivers/i2c/busses/i2c-mlxcpld.c +@@ -538,6 +538,9 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) + err = mlxcpld_i2c_set_frequency(priv, pdata); + if (err) + goto mlxcpld_i2_probe_failed; ++ ++ if (pdata->addr) ++ priv->base_addr = (*(u64 __force *)pdata->addr); + } + + /* Register with i2c layer */ +-- +2.20.1 + diff --git a/patch/0192-i2c-mlxcpld-Add-support-for-extended-transaction-len.patch b/patch/0192-i2c-mlxcpld-Add-support-for-extended-transaction-len.patch new file mode 100644 index 000000000..282ef9312 --- /dev/null +++ b/patch/0192-i2c-mlxcpld-Add-support-for-extended-transaction-len.patch @@ -0,0 +1,57 @@ +From 22447625fff0e742b3dc9c2f78bbaac29b1f1031 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 27 Nov 2022 10:43:23 +0200 +Subject: [PATCH backport 5.10 06/10] i2c: mlxcpld: Add support for extended + transaction length for i2c-mlxcpld + +Add support for extended length of read and write transactions. +New FPGA logic allows to increase size of the read and write +transactions length. This feature is verified through capability +register 'CPBLTY_REG'. Two bits 5 and 6 of the register are used for +length capability detection. Value '10' indicates support of extended +transaction length - 128 bytes for read transactions and 132 for write +transactions. + +Signed-off-by: Vadim Pasternak +--- + drivers/i2c/busses/i2c-mlxcpld.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c +index cd5401ce4..0e1807be7 100644 +--- a/drivers/i2c/busses/i2c-mlxcpld.c ++++ b/drivers/i2c/busses/i2c-mlxcpld.c +@@ -22,6 +22,7 @@ + #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_EXT2_SZ_BIT BIT(6) + #define MLXCPLD_I2C_DATA_SZ_MASK GENMASK(6, 5) + #define MLXCPLD_I2C_SMBUS_BLK_BIT BIT(7) + #define MLXCPLD_I2C_MAX_ADDR_LEN 4 +@@ -466,6 +467,13 @@ static const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext = { + .max_comb_1st_msg_len = 4, + }; + ++static const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext2 = { ++ .flags = I2C_AQ_COMB_WRITE_THEN_READ, ++ .max_read_len = (MLXCPLD_I2C_DATA_REG_SZ - 4) * 4, ++ .max_write_len = (MLXCPLD_I2C_DATA_REG_SZ - 4) * 4 + MLXCPLD_I2C_MAX_ADDR_LEN, ++ .max_comb_1st_msg_len = 4, ++}; ++ + static struct i2c_adapter mlxcpld_i2c_adapter = { + .owner = THIS_MODULE, + .name = "i2c-mlxcpld", +@@ -550,6 +558,8 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) + /* 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; ++ else if ((val & MLXCPLD_I2C_DATA_SZ_MASK) == MLXCPLD_I2C_DATA_EXT2_SZ_BIT) ++ mlxcpld_i2c_adapter.quirks = &mlxcpld_i2c_quirks_ext2; + /* Check support for smbus block transaction */ + if (val & MLXCPLD_I2C_SMBUS_BLK_BIT) + priv->smbus_block = true; +-- +2.20.1 + diff --git a/patch/0193-platform-mellanox-mlx-platform-Add-mux-selection-reg.patch b/patch/0193-platform-mellanox-mlx-platform-Add-mux-selection-reg.patch new file mode 100644 index 000000000..79a4cafb6 --- /dev/null +++ b/patch/0193-platform-mellanox-mlx-platform-Add-mux-selection-reg.patch @@ -0,0 +1,99 @@ +From e1d377039ba9a364f4e7f9816f5f0b7a3b165b43 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 18 Jan 2023 15:08:46 +0200 +Subject: [PATCH backport 5.10 07/10] platform: mellanox: mlx-platform: Add mux + selection register to regmap +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Extend writeable, readable, volatile registers of the 'regmap' object +with for I2C mux selector registers. + +The motivation is to pass this object extended with selector registers +to I2C mux driver working over ‘regmap’. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index e8c656d6e..03c744f37 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -140,6 +140,10 @@ + #define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET 0xd2 + #define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd3 + #define MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET 0xd9 ++#define MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET 0xdb ++#define MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET 0xda ++#define MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET 0xdc ++#define MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET 0xdd + #define MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET 0xde + #define MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET 0xdf + #define MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET 0xe0 +@@ -173,23 +177,19 @@ + #define MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET 0xfc + #define MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET 0xfd + #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 +-#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb +-#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda +-#define MLXPLAT_CPLD_LPC_I2C_CH3_OFF 0xdc +-#define MLXPLAT_CPLD_LPC_I2C_CH4_OFF 0xdd + + #define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL + #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ +- MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \ ++ MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET) | \ + MLXPLAT_CPLD_LPC_PIO_OFFSET) + #define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ +- MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \ ++ MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET) | \ + MLXPLAT_CPLD_LPC_PIO_OFFSET) + #define MLXPLAT_CPLD_LPC_REG3 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ +- MLXPLAT_CPLD_LPC_I2C_CH3_OFF) | \ ++ MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET) | \ + MLXPLAT_CPLD_LPC_PIO_OFFSET) + #define MLXPLAT_CPLD_LPC_REG4 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ +- MLXPLAT_CPLD_LPC_I2C_CH4_OFF) | \ ++ MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET) | \ + MLXPLAT_CPLD_LPC_PIO_OFFSET) + + /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ +@@ -5307,6 +5307,10 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM3_OFFSET: +@@ -5434,6 +5438,10 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET: +@@ -5581,6 +5589,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET: +-- +2.20.1 + diff --git a/patch/0194-platform-mellanox-mlx-platform-Move-bus-shift-assign.patch b/patch/0194-platform-mellanox-mlx-platform-Move-bus-shift-assign.patch new file mode 100644 index 000000000..154f02d70 --- /dev/null +++ b/patch/0194-platform-mellanox-mlx-platform-Move-bus-shift-assign.patch @@ -0,0 +1,35 @@ +From deb8517499160d77e94b2969a98b3c01bed1a649 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 18 Jan 2023 15:25:37 +0200 +Subject: [PATCH backport 5.10 082/150] platform: mellanox: mlx-platform: Move + bus shift assignment out of the loop + +Move assignment of bus shift setting out of the loop to avoid redundant +operation. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index de8fd0886..9d4cab937 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -6371,10 +6371,11 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr) + 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; + } + ++ if (shift > 0) ++ mlxplat_hotplug->shift_nr = shift; ++ + return 0; + } + +-- +2.20.1 + diff --git a/patch/0195-platform-mellanox-Add-support-for-dynamic-I2C-channe.patch b/patch/0195-platform-mellanox-Add-support-for-dynamic-I2C-channe.patch new file mode 100644 index 000000000..fa2443032 --- /dev/null +++ b/patch/0195-platform-mellanox-Add-support-for-dynamic-I2C-channe.patch @@ -0,0 +1,158 @@ +From d1fbdc9c5bd0939362ebdb4d76a701cb938f3837 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 18 Jan 2023 19:12:12 +0200 +Subject: [PATCH backport 5.10 083/150] platform/mellanox: Add support for + dynamic I2C channels infrastructure + +Allow to support platform configuration for dynamically allocated I2C +channels. +Motivation is to support I2C channels allocated in a non-continuous +way. + +Currently hotplug platform driver data structure contains static mux +channels for I2C hotplug devices. These channels numbers can be updated +dynamically and returned by mux driver's callback through the adapters +array. +Thus, hotplug mux channels will be aligned according to the dynamic +adapters data. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 69 ++++++++++++++++++++++++----- + 1 file changed, 59 insertions(+), 10 deletions(-) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 9d4cab937..773d110c9 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -336,6 +337,7 @@ + * @hotplug_resources: system hotplug resources + * @hotplug_resources_size: size of system hotplug resources + * @hi2c_main_init_status: init status of I2C main bus ++ * @mux_added: number of added mux segments + */ + struct mlxplat_priv { + struct platform_device *pdev_i2c; +@@ -349,6 +351,7 @@ struct mlxplat_priv { + struct resource *hotplug_resources; + unsigned int hotplug_resources_size; + u8 i2c_main_init_status; ++ int mux_added; + }; + + static struct platform_device *mlxplat_dev; +@@ -436,7 +439,9 @@ static struct i2c_mux_reg_platform_data mlxplat_default_mux_data[] = { + /* Platform mux configuration variables */ + static int mlxplat_max_adap_num; + static int mlxplat_mux_num; ++static int mlxplat_mux_hotplug_num; + static struct i2c_mux_reg_platform_data *mlxplat_mux_data; ++static struct i2c_mux_regmap_platform_data *mlxplat_mux_regmap_data; + + /* Platform extended mux data */ + static struct i2c_mux_reg_platform_data mlxplat_extended_mux_data[] = { +@@ -6368,12 +6373,17 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr) + /* Shift adapter ids, since expected parent adapter is not free. */ + *nr = i; + for (i = 0; i < mlxplat_mux_num; i++) { +- shift = *nr - mlxplat_mux_data[i].parent; +- mlxplat_mux_data[i].parent = *nr; +- mlxplat_mux_data[i].base_nr += shift; ++ if (mlxplat_mux_data) { ++ shift = *nr - mlxplat_mux_data[i].parent; ++ mlxplat_mux_data[i].parent = *nr; ++ mlxplat_mux_data[i].base_nr += shift; ++ } else if (mlxplat_mux_regmap_data) { ++ mlxplat_mux_regmap_data[i].parent = *nr; ++ } + } + +- if (shift > 0) ++ /* Shift bus only if mux provided by 'mlxplat_mux_data'. */ ++ if (shift > 0 && mlxplat_mux_data) + mlxplat_hotplug->shift_nr = shift; + + return 0; +@@ -6563,8 +6573,31 @@ mlxplat_i2c_mux_complition_notify(void *handle, struct i2c_adapter *parent, + struct i2c_adapter *adapters[]) + { + struct mlxplat_priv *priv = handle; ++ struct mlxreg_core_item *item; ++ int i, j; ++ ++ /* ++ * Hotplug platform driver data structure contains static mux channels for I2C hotplug ++ * devices. These channels numbers can be updated dynamically and returned by mux callback ++ * through the adapters array. Update mux channels according to the dynamic adapters data. ++ */ ++ if (priv->mux_added == mlxplat_mux_hotplug_num) { ++ item = mlxplat_hotplug->items; ++ for (i = 0; i < mlxplat_hotplug->counter; i++, item++) { ++ struct mlxreg_core_data *data = item->data; ++ ++ for (j = 0; j < item->count; j++, data++) { ++ if (data->hpdev.nr != MLXPLAT_CPLD_NR_NONE) ++ data->hpdev.nr = adapters[data->hpdev.nr - 2]->nr; ++ } ++ } ++ } + +- return mlxplat_post_init(priv); ++ /* Start post initialization only after last nux segment is added */ ++ if (++priv->mux_added == mlxplat_mux_num) ++ return mlxplat_post_init(priv); ++ ++ return 0; + } + + static int mlxplat_i2c_mux_topolgy_init(struct mlxplat_priv *priv) +@@ -6578,17 +6611,33 @@ static int mlxplat_i2c_mux_topolgy_init(struct mlxplat_priv *priv) + + priv->i2c_main_init_status = MLXPLAT_I2C_MAIN_BUS_HANDLE_CREATED; + for (i = 0; i < mlxplat_mux_num; i++) { +- priv->pdev_mux[i] = platform_device_register_resndata(&priv->pdev_i2c->dev, +- "i2c-mux-reg", i, NULL, 0, +- &mlxplat_mux_data[i], +- sizeof(mlxplat_mux_data[i])); ++ if (mlxplat_mux_data) { ++ priv->pdev_mux[i] = ++ platform_device_register_resndata(&priv->pdev_i2c->dev, ++ "i2c-mux-reg", i, NULL, 0, ++ &mlxplat_mux_data[i], ++ sizeof(mlxplat_mux_data[i])); ++ } else { ++ mlxplat_mux_regmap_data[i].handle = priv; ++ mlxplat_mux_regmap_data[i].regmap = priv->regmap; ++ mlxplat_mux_regmap_data[i].completion_notify = ++ mlxplat_i2c_mux_complition_notify; ++ priv->pdev_mux[i] = ++ platform_device_register_resndata(&priv->pdev_i2c->dev, ++ "i2c-mux-regmap", i, NULL, 0, ++ &mlxplat_mux_regmap_data[i], ++ sizeof(mlxplat_mux_regmap_data[i])); ++ } + if (IS_ERR(priv->pdev_mux[i])) { + err = PTR_ERR(priv->pdev_mux[i]); + goto fail_platform_mux_register; + } + } + +- return mlxplat_i2c_mux_complition_notify(priv, NULL, NULL); ++ if (mlxplat_mux_regmap_data && mlxplat_mux_regmap_data->completion_notify) ++ return 0; ++ ++ return mlxplat_post_init(priv); + + fail_platform_mux_register: + while (--i >= 0) +-- +2.20.1 + diff --git a/patch/0196-platform-mellanox-Relocate-mlx-platform-driver.patch b/patch/0196-platform-mellanox-Relocate-mlx-platform-driver.patch new file mode 100644 index 000000000..c592b92b0 --- /dev/null +++ b/patch/0196-platform-mellanox-Relocate-mlx-platform-driver.patch @@ -0,0 +1,97 @@ +From 723dacff3d93f270a52195c895e2ddf233b146d7 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 7 Nov 2022 11:52:34 +0200 +Subject: [PATCH backport 5.10 084/150] platform: mellanox: Relocate + mlx-platform driver + +Move 'mlx-platform' driver 'x86' to 'mellanox' folder. + +Motivation to allow running it on systems with ARM architecture. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/mellanox/Kconfig | 12 ++++++++++++ + drivers/platform/mellanox/Makefile | 1 + + drivers/platform/{x86 => mellanox}/mlx-platform.c | 0 + drivers/platform/x86/Kconfig | 12 ------------ + drivers/platform/x86/Makefile | 1 - + 5 files changed, 13 insertions(+), 13 deletions(-) + rename drivers/platform/{x86 => mellanox}/mlx-platform.c (100%) + +diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig +index 75e2bee17..ff8267329 100644 +--- a/drivers/platform/mellanox/Kconfig ++++ b/drivers/platform/mellanox/Kconfig +@@ -14,6 +14,18 @@ menuconfig MELLANOX_PLATFORM + + if MELLANOX_PLATFORM + ++config MLX_PLATFORM ++ tristate "Mellanox Technologies platform support" ++ depends on I2C && REGMAP ++ help ++ This option enables system support for the Mellanox Technologies ++ platform. The Mellanox systems provide data center networking ++ solutions based on Virtual Protocol Interconnect (VPI) technology ++ enable seamless connectivity to 56/100Gb/s InfiniBand or 10/40/56GbE ++ connection. ++ ++ If you have a Mellanox system, say Y or M here. ++ + config MLXREG_HOTPLUG + tristate "Mellanox platform hotplug driver support" + depends on REGMAP +diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile +index 6af37ee88..23919e56a 100644 +--- a/drivers/platform/mellanox/Makefile ++++ b/drivers/platform/mellanox/Makefile +@@ -3,6 +3,7 @@ + # Makefile for linux/drivers/platform/mellanox + # Mellanox Platform-Specific Drivers + # ++obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o + obj-$(CONFIG_MLXBF_BOOTCTL) += mlxbf-bootctl.o + obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o + obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/mellanox/mlx-platform.c +similarity index 100% +rename from drivers/platform/x86/mlx-platform.c +rename to drivers/platform/mellanox/mlx-platform.c +diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig +index a1858689d..4270d4c17 100644 +--- a/drivers/platform/x86/Kconfig ++++ b/drivers/platform/x86/Kconfig +@@ -1193,18 +1193,6 @@ config I2C_MULTI_INSTANTIATE + To compile this driver as a module, choose M here: the module + will be called i2c-multi-instantiate. + +-config MLX_PLATFORM +- tristate "Mellanox Technologies platform support" +- depends on I2C && REGMAP +- help +- This option enables system support for the Mellanox Technologies +- platform. The Mellanox systems provide data center networking +- solutions based on Virtual Protocol Interconnect (VPI) technology +- enable seamless connectivity to 56/100Gb/s InfiniBand or 10/40/56GbE +- connection. +- +- If you have a Mellanox system, say Y or M here. +- + config TOUCHSCREEN_DMI + bool "DMI based touchscreen configuration info" + depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD +diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile +index 5f823f7ef..1db86675f 100644 +--- a/drivers/platform/x86/Makefile ++++ b/drivers/platform/x86/Makefile +@@ -122,7 +122,6 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o + + # Platform drivers + obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o +-obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o + obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o + + # Intel uncore drivers +-- +2.20.1 + diff --git a/patch/0197-platform-mellanox-Add-initial-support-for-PCIe-based.patch b/patch/0197-platform-mellanox-Add-initial-support-for-PCIe-based.patch new file mode 100644 index 000000000..ae18a952d --- /dev/null +++ b/patch/0197-platform-mellanox-Add-initial-support-for-PCIe-based.patch @@ -0,0 +1,186 @@ +From e831f971fd9895b74c0966b3cf3cd2e18c2f8fca Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 10 Nov 2022 08:53:49 +0200 +Subject: [PATCH backport 5.10 085/150] platform: mellanox: Add initial support + for PCIe based programming logic device + +Extend driver to support logic implemented by FPGA device connected +through PCIe bus. + +The motivation two support new generation of Nvidia COME module, based +on ARM64 architecture, and equipped with Lattice LFD2NX-40 FPGA device. + +In order to support new Nvidia COME module FPGA device driver +initialization flow is modified. In case FPGA device is detected, +system resources are to be mapped to this device, otherwise system +resources are to be mapped same as it has been done before for Lattice +LPC based CPLD. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/mellanox/mlx-platform.c | 106 ++++++++++++++++++++++- + 1 file changed, 105 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/mellanox/mlx-platform.c b/drivers/platform/mellanox/mlx-platform.c +index 773d110c9..f3df56c41 100644 +--- a/drivers/platform/mellanox/mlx-platform.c ++++ b/drivers/platform/mellanox/mlx-platform.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -315,6 +316,7 @@ + #define MLXPLAT_CPLD_WD_MAX_DEVS 2 + + #define MLXPLAT_CPLD_LPC_SYSIRQ 17 ++#define MLXPLAT_FPGA_PCIE_SYSIRQ 17 + + /* Minimum power required for turning on Ethernet modular system (WATT) */ + #define MLXPLAT_CPLD_ETH_MODULAR_PWR_MIN 50 +@@ -325,6 +327,11 @@ + #define MLXPLAT_I2C_MAIN_BUS_NOTIFIED 0x01 + #define MLXPLAT_I2C_MAIN_BUS_HANDLE_CREATED 0x02 + ++/* Lattice FPGA PCI configuration */ ++#define PCI_VENDOR_ID_LATTICE 0x1204 ++#define PCI_DEVICE_ID_LATTICE_LFD2NX40 0x9c1d ++#define MLXPLAT_FPGA_PCI_BAR0_SIZE 0x4000 ++ + /* mlxplat_priv - platform private data + * @pdev_i2c - i2c controller platform device + * @pdev_mux - array of mux platform devices +@@ -5793,6 +5800,11 @@ static struct resource mlxplat_mlxcpld_resources[] = { + [0] = DEFINE_RES_IRQ_NAMED(MLXPLAT_CPLD_LPC_SYSIRQ, "mlxreg-hotplug"), + }; + ++static struct resource mlxplat_mlxfpga_resources[] = { ++ [0] = DEFINE_RES_IRQ_NAMED(MLXPLAT_FPGA_PCIE_SYSIRQ, "mlxreg-hotplug"), ++}; ++ ++static struct platform_device *mlxplat_dev; + static struct mlxreg_core_hotplug_platform_data *mlxplat_i2c; + static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; + static struct mlxreg_core_platform_data *mlxplat_led; +@@ -5802,6 +5814,7 @@ static struct mlxreg_core_platform_data + *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS]; + static const struct regmap_config *mlxplat_regmap_config; + static struct spi_board_info *mlxplat_spi; ++static struct pci_dev *fpga_dev; + + /* Platform default poweroff function */ + static void mlxplat_poweroff(void) +@@ -6443,15 +6456,106 @@ static void mlxplat_lpc_cpld_device_exit(void) + platform_device_unregister(mlxplat_dev); + } + ++static int ++mlxplat_pci_fpga_device_init(struct resource **hotplug_resources, ++ unsigned int *hotplug_resources_size, struct pci_dev **fpga_dev) ++{ ++ struct pci_dev *pci_dev; ++ int err; ++ ++ pci_dev = pci_get_device(PCI_VENDOR_ID_LATTICE, PCI_DEVICE_ID_LATTICE_LFD2NX40, NULL); ++ if (!pci_dev) ++ return -ENODEV; ++ ++ err = pci_enable_device(pci_dev); ++ if (err) { ++ dev_err(&mlxplat_dev->dev, "pci_enable_device failed\n"); ++ goto fail_pci_enable_device; ++ } ++ ++ err = pci_request_regions(pci_dev, "mlx-patform"); ++ if (err) { ++ dev_err(&mlxplat_dev->dev, "pci_request_regions failed\n"); ++ goto fail_pci_request_regions; ++ } ++ ++ err = dma_set_mask_and_coherent(&mlxplat_dev->dev, DMA_BIT_MASK(64)); ++ if (err) { ++ err = dma_set_mask(&mlxplat_dev->dev, DMA_BIT_MASK(32)); ++ if (err) { ++ dev_err(&mlxplat_dev->dev, "dma_set_mask failed\n"); ++ goto fail_pci_set_dma_mask; ++ } ++ } ++ ++ if (pci_resource_len(pci_dev, 0) < MLXPLAT_FPGA_PCI_BAR0_SIZE) { ++ dev_err(&mlxplat_dev->dev, "invalid PCI region size\n"); ++ err = -EINVAL; ++ goto fail_pci_resource_len_check; ++ } ++ ++ mlxplat_mlxcpld_regmap_ctx.base = devm_ioremap(&mlxplat_dev->dev, ++ pci_resource_start(pci_dev, 0), ++ pci_resource_len(pci_dev, 0)); ++ if (!mlxplat_mlxcpld_regmap_ctx.base) { ++ dev_err(&mlxplat_dev->dev, "ioremap failed\n"); ++ err = -EIO; ++ goto fail_ioremap; ++ } ++ pci_set_master(pci_dev); ++ ++ mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, PLATFORM_DEVID_NONE, ++ NULL, 0); ++ if (IS_ERR(mlxplat_dev)) { ++ err = PTR_ERR(mlxplat_dev); ++ goto fail_platform_device_register_simple; ++ } ++ ++ *hotplug_resources = mlxplat_mlxfpga_resources; ++ *hotplug_resources_size = ARRAY_SIZE(mlxplat_mlxfpga_resources); ++ *fpga_dev = pci_dev; ++ ++ return 0; ++ ++fail_platform_device_register_simple: ++fail_ioremap: ++fail_pci_resource_len_check: ++fail_pci_set_dma_mask: ++ pci_release_regions(pci_dev); ++fail_pci_request_regions: ++ pci_disable_device(pci_dev); ++fail_pci_enable_device: ++ return err; ++} ++ ++static void mlxplat_pci_fpga_device_exit(void) ++{ ++ platform_device_unregister(mlxplat_dev); ++ iounmap(mlxplat_mlxcpld_regmap_ctx.base); ++ pci_release_regions(fpga_dev); ++ pci_disable_device(fpga_dev); ++} ++ + static int + mlxplat_pre_init(struct resource **hotplug_resources, unsigned int *hotplug_resources_size) + { ++ int err; ++ ++ err = mlxplat_pci_fpga_device_init(hotplug_resources, hotplug_resources_size, &fpga_dev); ++ if (!err) ++ return 0; ++ else if (err != -ENODEV) ++ return err; ++ + return mlxplat_lpc_cpld_device_init(hotplug_resources, hotplug_resources_size); + } + + static void mlxplat_post_exit(void) + { +- mlxplat_lpc_cpld_device_exit(); ++ if (fpga_dev) ++ mlxplat_pci_fpga_device_exit(); ++ else ++ mlxplat_lpc_cpld_device_exit(); + } + + static int mlxplat_post_init(struct mlxplat_priv *priv) +-- +2.20.1 + diff --git a/patch/0198-platform-mellanox-Introduce-support-for-switches-bas.patch b/patch/0198-platform-mellanox-Introduce-support-for-switches-bas.patch new file mode 100644 index 000000000..1c24c54d6 --- /dev/null +++ b/patch/0198-platform-mellanox-Introduce-support-for-switches-bas.patch @@ -0,0 +1,253 @@ +From bcdfc7d1d106889fa9af3404f252fb1260f5a0fd Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 15 Nov 2022 11:51:47 +0200 +Subject: [PATCH backport 5.10 086/150] platform: mellanox: Introduce support + for switches based on BlueField-3/ARM64 COMe +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add support for Nvidia MQM97xx family switches providing a +high-performance solution by delivering high bandwidth with low latency +to Enterprise Data Centers. + +These switches are based on previous generation of MQM97xx switches, +excepting CFL based COMe module is replaced by new BlueField®-3 COMe +module. + +Switches of this class are equipped with: +- Nvidia Quantumâ„¢-2 ASIC, providing up to 64x400GB/s (IB) full + bidirectional bandwidth per port using PAM-4 modulation. +- Com-Express type 7 module, based on Nvidia NVIDIA® BlueField®-3 + processing unit and equipped with LATTICE LFD2NX40 Certusâ„¢-NX FPGA + secured device with fail safe + mechanism, connected by PCIe bus. +- Switch board with two Lattice LCMXO3D-9400HC secured with fail safe + mechanism, connected by PCEi-to-LPC bridge. +- Fan board to supporting 7 fans. +- 2x power extender boards. +- 7x FRU fans. +- 2x 2000W AC/DC PSU (FRU). + +New switches platform configuration is based on the new VMOD0016 +class. Configuration is extended to support new register map with +callbacks supporting indirect addressing for PCIe-to-LPC bridge. +This bridge provides interface between FPAG at COMe board (directly +connected to CPU PCIe root complex) to CPLDs on switch board (which +cannot be connected directly to PCIe root complex). + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/mellanox/mlx-platform.c | 147 ++++++++++++++++++++++- + 1 file changed, 146 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/mellanox/mlx-platform.c b/drivers/platform/mellanox/mlx-platform.c +index f3df56c41..b1c8632d6 100644 +--- a/drivers/platform/mellanox/mlx-platform.c ++++ b/drivers/platform/mellanox/mlx-platform.c +@@ -270,6 +270,7 @@ + /* Maximum number of possible physical buses equipped on system */ + #define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16 + #define MLXPLAT_CPLD_MAX_PHYS_EXT_ADAPTER_NUM 24 ++#define MLXPLAT_CPLD_DEFAULT_MUX_HOTPLUG_VECTOR 0 + + /* Number of channels in group */ + #define MLXPLAT_CPLD_GRP_CHNL_NUM 8 +@@ -331,6 +332,17 @@ + #define PCI_VENDOR_ID_LATTICE 0x1204 + #define PCI_DEVICE_ID_LATTICE_LFD2NX40 0x9c1d + #define MLXPLAT_FPGA_PCI_BAR0_SIZE 0x4000 ++#define MLXPLAT_FPGA_PCI_BASE_OFFSET 0x00000000 ++#define MLXPLAT_FPGA_PCI_ADDR_OFFSET MLXPLAT_FPGA_PCI_BASE_OFFSET ++#define MLXPLAT_FPGA_PCI_DATA_OFFSET (MLXPLAT_FPGA_PCI_BASE_OFFSET + 0x02) ++#define MLXPLAT_FPGA_PCI_CTRL_OFFSET (MLXPLAT_FPGA_PCI_BASE_OFFSET + 0x04) ++#define MLXPLAT_FPGA_PCI_STAT_OFFSET (MLXPLAT_FPGA_PCI_BASE_OFFSET + 0x06) ++#define MLXPLAT_FPGA_PCI_I2C_LPC_OFFSET (MLXPLAT_FPGA_PCI_BASE_OFFSET + 0x400) ++ ++#define MLXPLAT_FPGA_PCI_CTRL_READ BIT(0) ++#define MLXPLAT_FPGA_PCI_CTRL_WRITE BIT(1) ++#define MLXPLAT_FPGA_PCI_COMPLETED BIT(0) ++#define MLXPLAT_FPGA_PCI_TO 50 /* usec */ + + /* mlxplat_priv - platform private data + * @pdev_i2c - i2c controller platform device +@@ -443,6 +455,28 @@ static struct i2c_mux_reg_platform_data mlxplat_default_mux_data[] = { + + }; + ++/* Default channels vector for regmap mux. */ ++static int mlxplat_default_regmap_mux_chan[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; ++ ++/* Platform regmap mux data */ ++static struct i2c_mux_regmap_platform_data mlxplat_default_regmap_mux_data[] = { ++ { ++ .parent = 1, ++ .chan_ids = mlxplat_default_regmap_mux_chan, ++ .num_adaps = ARRAY_SIZE(mlxplat_default_regmap_mux_chan), ++ .sel_reg_addr = MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET, ++ .reg_size = 1, ++ }, ++ { ++ .parent = 1, ++ .chan_ids = mlxplat_default_regmap_mux_chan, ++ .num_adaps = ARRAY_SIZE(mlxplat_default_regmap_mux_chan), ++ .sel_reg_addr = MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET, ++ .reg_size = 1, ++ }, ++ ++}; ++ + /* Platform mux configuration variables */ + static int mlxplat_max_adap_num; + static int mlxplat_mux_num; +@@ -5796,6 +5830,84 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config_eth_modular = { + .reg_write = mlxplat_mlxcpld_reg_write, + }; + ++/* Wait completion routine for indirect access for register map */ ++static int mlxplat_fpga_completion_wait(struct mlxplat_mlxcpld_regmap_context *ctx) ++{ ++ unsigned long end; ++ u16 status; ++ ++ end = jiffies + msecs_to_jiffies(MLXPLAT_FPGA_PCI_TO); ++ do { ++ status = ioread16(ctx->base + MLXPLAT_FPGA_PCI_STAT_OFFSET); ++ if (status & MLXPLAT_FPGA_PCI_COMPLETED) ++ return 0; ++ cond_resched(); ++ } while (time_before(jiffies, end)); ++ ++ return -EIO; ++} ++ ++/* Read callback for indirect register map access */ ++static int mlxplat_fpga_reg_read(void *context, unsigned int reg, unsigned int *val) ++{ ++ struct mlxplat_mlxcpld_regmap_context *ctx = context; ++ int err; ++ ++ /* Verify there is no pending transactions */ ++ err = mlxplat_fpga_completion_wait(ctx); ++ if (err) ++ return err; ++ ++ /* Set address in register space */ ++ iowrite16(reg, ctx->base + MLXPLAT_FPGA_PCI_ADDR_OFFSET); ++ /* Activate read operation */ ++ iowrite16(MLXPLAT_FPGA_PCI_CTRL_READ, ctx->base + MLXPLAT_FPGA_PCI_CTRL_OFFSET); ++ /* Verify transaction completion */ ++ err = mlxplat_fpga_completion_wait(ctx); ++ if (err) ++ return err; ++ ++ /* Read data */ ++ *val = ioread16(ctx->base + MLXPLAT_FPGA_PCI_DATA_OFFSET); ++ ++ return 0; ++} ++ ++/* Write callback for indirect register map access */ ++static int mlxplat_fpga_reg_write(void *context, unsigned int reg, unsigned int val) ++{ ++ struct mlxplat_mlxcpld_regmap_context *ctx = context; ++ int err; ++ ++ /* Verify there is no pending transactions */ ++ err = mlxplat_fpga_completion_wait(ctx); ++ if (err) ++ return err; ++ ++ /* Set address in register space */ ++ iowrite16(reg, ctx->base + MLXPLAT_FPGA_PCI_ADDR_OFFSET); ++ /* Set data to be written */ ++ iowrite16(val, ctx->base + MLXPLAT_FPGA_PCI_DATA_OFFSET); ++ /* Activate write operation */ ++ iowrite16(MLXPLAT_FPGA_PCI_CTRL_WRITE, ctx->base + MLXPLAT_FPGA_PCI_CTRL_OFFSET); ++ ++ return 0; ++} ++ ++static const struct regmap_config mlxplat_fpga_regmap_config_bf3_comex_default = { ++ .reg_bits = 16, ++ .val_bits = 8, ++ .max_register = 512, ++ .cache_type = REGCACHE_FLAT, ++ .writeable_reg = mlxplat_mlxcpld_writeable_reg, ++ .readable_reg = mlxplat_mlxcpld_readable_reg, ++ .volatile_reg = mlxplat_mlxcpld_volatile_reg, ++ .reg_defaults = mlxplat_mlxcpld_regmap_ng400, ++ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_ng400), ++ .reg_read = mlxplat_fpga_reg_read, ++ .reg_write = mlxplat_fpga_reg_write, ++}; ++ + static struct resource mlxplat_mlxcpld_resources[] = { + [0] = DEFINE_RES_IRQ_NAMED(MLXPLAT_CPLD_LPC_SYSIRQ, "mlxreg-hotplug"), + }; +@@ -6175,6 +6287,29 @@ static int __init mlxplat_dmi_l1_switch_matched(const struct dmi_system_id *dmi) + return 1; + } + ++static int __init mlxplat_dmi_bf3_comex_default_matched(const struct dmi_system_id *dmi) ++{ ++ int i; ++ ++ mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; ++ mlxplat_mux_hotplug_num = MLXPLAT_CPLD_DEFAULT_MUX_HOTPLUG_VECTOR; ++ mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_regmap_mux_data); ++ mlxplat_mux_regmap_data = mlxplat_default_regmap_mux_data; ++ mlxplat_hotplug = &mlxplat_mlxcpld_ext_data; ++ mlxplat_hotplug->deferred_nr = ++ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; ++ 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]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; ++ mlxplat_regmap_config = &mlxplat_fpga_regmap_config_bf3_comex_default; ++ pm_power_off = mlxplat_poweroff; ++ ++ return 1; ++} ++ + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + { + .callback = mlxplat_dmi_default_wc_matched, +@@ -6270,6 +6405,12 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0015"), + }, + }, ++ { ++ .callback = mlxplat_dmi_bf3_comex_default_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0016"), ++ }, ++ }, + { + .callback = mlxplat_dmi_l1_switch_matched, + .matches = { +@@ -6502,6 +6643,11 @@ mlxplat_pci_fpga_device_init(struct resource **hotplug_resources, + err = -EIO; + goto fail_ioremap; + } ++ ++ /* Set mapped base address of I2C-LPC bridge over PCIe */ ++ mlxplat_i2c->addr = mlxplat_mlxcpld_regmap_ctx.base + ++ MLXPLAT_FPGA_PCI_I2C_LPC_OFFSET; ++ + pci_set_master(pci_dev); + + mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, PLATFORM_DEVID_NONE, +@@ -6782,7 +6928,6 @@ static int mlxplat_i2c_main_init(struct mlxplat_priv *priv) + nr = (nr == mlxplat_max_adap_num) ? -1 : nr; + mlxplat_i2c->regmap = priv->regmap; + mlxplat_i2c->handle = priv; +- + priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld", + nr, priv->hotplug_resources, + priv->hotplug_resources_size, +-- +2.20.1 + diff --git a/patch/0199-platform-mellanox-mlx-platform-Add-reset-and-extend-.patch b/patch/0199-platform-mellanox-mlx-platform-Add-reset-and-extend-.patch new file mode 100644 index 000000000..f9079db49 --- /dev/null +++ b/patch/0199-platform-mellanox-mlx-platform-Add-reset-and-extend-.patch @@ -0,0 +1,138 @@ +From a556177a2359c784e063f0914049ffd7f8d8852d Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 22 Nov 2022 21:20:49 +0200 +Subject: [PATCH backport 5.10 087/150] platform: mellanox: mlx-platform: Add + reset and extend poweroff callbacks + +On ARM based systems reset and poweroff flow should include special +actions against CPLD device for performing graceful operations. +For reset it is necessary to toggle special PLATFORM_RESET# signal, for +poweroff special HALT# signal. + +In order to support such flows relevant actions are provided. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/mellanox/mlx-platform.c | 35 ++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/drivers/platform/mellanox/mlx-platform.c b/drivers/platform/mellanox/mlx-platform.c +index b1c8632d6..849fdf5de 100644 +--- a/drivers/platform/mellanox/mlx-platform.c ++++ b/drivers/platform/mellanox/mlx-platform.c +@@ -43,6 +43,7 @@ + #define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET 0x1d + #define MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET 0x1e + #define MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET 0x1f ++#define MLXPLAT_CPLD_LPC_REG_PG_RST_OFFSET 0x19 + #define MLXPLAT_CPLD_LPC_REG_LED1_OFFSET 0x20 + #define MLXPLAT_CPLD_LPC_REG_LED2_OFFSET 0x21 + #define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET 0x22 +@@ -263,6 +264,7 @@ + #define MLXPLAT_CPLD_LPC_LC_MASK GENMASK(7, 0) + + #define MLXPLAT_CPLD_HALT_MASK BIT(3) ++#define MLXPLAT_CPLD_RESET_MASK 0xfe + + /* Default I2C parent bus number */ + #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1 +@@ -483,6 +485,7 @@ static int mlxplat_mux_num; + static int mlxplat_mux_hotplug_num; + static struct i2c_mux_reg_platform_data *mlxplat_mux_data; + static struct i2c_mux_regmap_platform_data *mlxplat_mux_regmap_data; ++static struct notifier_block *mlxplat_reboot_nb; + + /* Platform extended mux data */ + static struct i2c_mux_reg_platform_data mlxplat_extended_mux_data[] = { +@@ -5280,6 +5283,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + switch (reg) { + case MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PG_RST_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: +@@ -5387,6 +5391,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PG_RST_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: +@@ -5546,6 +5551,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PG_RST_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: +@@ -5928,12 +5934,31 @@ static const struct regmap_config *mlxplat_regmap_config; + static struct spi_board_info *mlxplat_spi; + static struct pci_dev *fpga_dev; + ++/* Platform default reset function */ ++static int mlxplat_reboot_notifier(struct notifier_block *nb, unsigned long action, void *unused) ++{ ++ struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); ++ ++ if (action == SYS_RESTART) ++ regmap_write(priv->regmap, MLXPLAT_CPLD_LPC_REG_PG_RST_OFFSET, ++ MLXPLAT_CPLD_RESET_MASK); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block mlxplat_reboot_default_nb = { ++ .notifier_call = mlxplat_reboot_notifier, ++}; ++ + /* Platform default poweroff function */ + static void mlxplat_poweroff(void) + { + struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); + ++ if (mlxplat_reboot_nb) ++ unregister_reboot_notifier(mlxplat_reboot_nb); + regmap_write(priv->regmap, MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, MLXPLAT_CPLD_HALT_MASK); ++ kernel_halt(); + } + + static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) +@@ -6305,6 +6330,7 @@ static int __init mlxplat_dmi_bf3_comex_default_matched(const struct dmi_system_ + mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; + mlxplat_regmap_config = &mlxplat_fpga_regmap_config_bf3_comex_default; ++ mlxplat_reboot_nb = &mlxplat_reboot_default_nb; + pm_power_off = mlxplat_poweroff; + + return 1; +@@ -7012,8 +7038,15 @@ static int __init mlxplat_init(void) + if (err) + goto fail_regcache_sync; + ++ if (mlxplat_reboot_nb) { ++ err = register_reboot_notifier(mlxplat_reboot_nb); ++ if (err) ++ goto fail_register_reboot_notifier; ++ } ++ + return 0; + ++fail_register_reboot_notifier: + fail_regcache_sync: + mlxplat_pre_exit(priv); + fail_mlxplat_i2c_main_init: +@@ -7031,6 +7064,8 @@ static void __exit mlxplat_exit(void) + + if (pm_power_off) + pm_power_off = NULL; ++ if (mlxplat_reboot_nb) ++ unregister_reboot_notifier(mlxplat_reboot_nb); + mlxplat_pre_exit(priv); + mlxplat_i2c_main_exit(priv); + } +-- +2.20.1 + diff --git a/patch/0200-dt-bindings-i2c-mellanox-i2c-mlxbf-convert-txt-to-YA.patch b/patch/0200-dt-bindings-i2c-mellanox-i2c-mlxbf-convert-txt-to-YA.patch new file mode 100644 index 000000000..48fb3ea22 --- /dev/null +++ b/patch/0200-dt-bindings-i2c-mellanox-i2c-mlxbf-convert-txt-to-YA.patch @@ -0,0 +1,169 @@ +From d10a96f08067a214b2de469b406155d6604930f2 Mon Sep 17 00:00:00 2001 +From: Khalil Blaiech +Date: Fri, 20 Nov 2020 18:06:06 -0500 +Subject: [PATCH backport 5.10 01/63] dt-bindings: i2c: mellanox,i2c-mlxbf: + convert txt to YAML schema + +Write the devicetree binding text file associated with +the Mellanox BlueField I2C controller in schema file, +JSON compatible subset of YAML. Besides, add an entry +within MAINTAINERS file. + +Signed-off-by: Khalil Blaiech +Reviewed-by: Rob Herring +Signed-off-by: Wolfram Sang +--- + .../bindings/i2c/mellanox,i2c-mlxbf.txt | 42 ---------- + .../bindings/i2c/mellanox,i2c-mlxbf.yaml | 78 +++++++++++++++++++ + MAINTAINERS | 1 + + 3 files changed, 79 insertions(+), 42 deletions(-) + delete mode 100644 Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.txt + create mode 100644 Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml + +diff --git a/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.txt b/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.txt +deleted file mode 100644 +index 566ea861a..000000000 +--- a/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.txt ++++ /dev/null +@@ -1,42 +0,0 @@ +-Device tree configuration for the Mellanox I2C SMBus on BlueField SoCs +- +-Required Properties: +- +-- compatible : should be "mellanox,i2c-mlxbf1" or "mellanox,i2c-mlxbf2". +- +-- reg : address offset and length of the device registers. The +- registers consist of the following set of resources: +- 1) Smbus block registers. +- 2) Cause master registers. +- 3) Cause slave registers. +- 4) Cause coalesce registers (if compatible isn't set +- to "mellanox,i2c-mlxbf1"). +- +-- interrupts : interrupt number. +- +-Optional Properties: +- +-- clock-frequency : bus frequency used to configure timing registers; +- allowed values are 100000, 400000 and 1000000; +- those are expressed in Hz. Default is 100000. +- +-Example: +- +-i2c@2804000 { +- compatible = "mellanox,i2c-mlxbf1"; +- reg = <0x02804000 0x800>, +- <0x02801200 0x020>, +- <0x02801260 0x020>; +- interrupts = <57>; +- clock-frequency = <100000>; +-}; +- +-i2c@2808800 { +- compatible = "mellanox,i2c-mlxbf2"; +- reg = <0x02808800 0x600>, +- <0x02808e00 0x020>, +- <0x02808e20 0x020>, +- <0x02808e40 0x010>; +- interrupts = <57>; +- clock-frequency = <400000>; +-}; +diff --git a/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml b/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml +new file mode 100644 +index 000000000..d2b401d06 +--- /dev/null ++++ b/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml +@@ -0,0 +1,78 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/i2c/mellanox,i2c-mlxbf.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Mellanox I2C SMBus on BlueField SoCs ++ ++maintainers: ++ - Khalil Blaiech ++ ++allOf: ++ - $ref: /schemas/i2c/i2c-controller.yaml# ++ ++properties: ++ compatible: ++ enum: ++ - mellanox,i2c-mlxbf1 ++ - mellanox,i2c-mlxbf2 ++ ++ reg: ++ minItems: 3 ++ maxItems: 4 ++ items: ++ - description: Smbus block registers ++ - description: Cause master registers ++ - description: Cause slave registers ++ - description: Cause coalesce registers ++ ++ interrupts: ++ maxItems: 1 ++ ++ clock-frequency: ++ enum: [ 100000, 400000, 1000000 ] ++ description: ++ bus frequency used to configure timing registers; ++ The frequency is expressed in Hz. Default is 100000. ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ ++unevaluatedProperties: false ++ ++if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - mellanox,i2c-mlxbf1 ++ ++then: ++ properties: ++ reg: ++ maxItems: 3 ++ ++examples: ++ - | ++ i2c@2804000 { ++ compatible = "mellanox,i2c-mlxbf1"; ++ reg = <0x02804000 0x800>, ++ <0x02801200 0x020>, ++ <0x02801260 0x020>; ++ interrupts = <57>; ++ clock-frequency = <100000>; ++ }; ++ ++ - | ++ i2c@2808800 { ++ compatible = "mellanox,i2c-mlxbf2"; ++ reg = <0x02808800 0x600>, ++ <0x02808e00 0x020>, ++ <0x02808e20 0x020>, ++ <0x02808e40 0x010>; ++ interrupts = <57>; ++ clock-frequency = <400000>; ++ }; +diff --git a/MAINTAINERS b/MAINTAINERS +index 4fef10dd2..7db3e06ec 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -11177,6 +11177,7 @@ MELLANOX BLUEFIELD I2C DRIVER + M: Khalil Blaiech + L: linux-i2c@vger.kernel.org + S: Supported ++F: Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml + F: drivers/i2c/busses/i2c-mlxbf.c + + MELLANOX ETHERNET DRIVER (mlx4_en) +-- +2.20.1 + diff --git a/patch/0201-i2c-mlxbf-incorrect-base-address-passed-during-io-wr.patch b/patch/0201-i2c-mlxbf-incorrect-base-address-passed-during-io-wr.patch new file mode 100644 index 000000000..1933f8217 --- /dev/null +++ b/patch/0201-i2c-mlxbf-incorrect-base-address-passed-during-io-wr.patch @@ -0,0 +1,43 @@ +From e38eed5cc30d8025b3990273c965c3142fc4733a Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Thu, 8 Sep 2022 13:35:38 -0400 +Subject: [PATCH backport 5.10 02/63] i2c: mlxbf: incorrect base address passed + during io write + +BugLink: https://bugs.launchpad.net/bugs/1991551 + +Correct the base address used during io write. +This bug had no impact over the overall functionality of the read and write +transactions. MLXBF_I2C_CAUSE_OR_CLEAR=0x18 so writing to (smbus->io + 0x18) +instead of (mst_cause->ioi + 0x18) actually writes to the sc_low_timeout +register which just sets the timeout value before a read/write aborts. + +Fixes: b5b5b32081cd206b (i2c: mlxbf: I2C SMBus driver for Mellanox BlueField SoC) +Reviewed-by: Khalil Blaiech +Signed-off-by: Asmaa Mnebhi +Signed-off-by: Wolfram Sang +(cherry picked from commit 2a5be6d1340c0fefcee8a6489cff7fd88a0d5b85) +Signed-off-by: Asmaa Mnebhi +Acked-by: Tim Gardner +Acked-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/i2c/busses/i2c-mlxbf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c +index ab261d762..042c83b90 100644 +--- a/drivers/i2c/busses/i2c-mlxbf.c ++++ b/drivers/i2c/busses/i2c-mlxbf.c +@@ -675,7 +675,7 @@ static int mlxbf_i2c_smbus_enable(struct mlxbf_i2c_priv *priv, u8 slave, + /* Clear status bits. */ + writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_STATUS); + /* Set the cause data. */ +- writel(~0x0, priv->smbus->io + MLXBF_I2C_CAUSE_OR_CLEAR); ++ writel(~0x0, priv->mst_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR); + /* Zero PEC byte. */ + writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_PEC); + /* Zero byte count. */ +-- +2.20.1 + diff --git a/patch/0202-i2c-mlxbf-prevent-stack-overflow-in-mlxbf_i2c_smbus_.patch b/patch/0202-i2c-mlxbf-prevent-stack-overflow-in-mlxbf_i2c_smbus_.patch new file mode 100644 index 000000000..59db34bc6 --- /dev/null +++ b/patch/0202-i2c-mlxbf-prevent-stack-overflow-in-mlxbf_i2c_smbus_.patch @@ -0,0 +1,41 @@ +From cf835e1581883f7e90fa322efe2dd91a510e51df Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Thu, 8 Sep 2022 13:35:39 -0400 +Subject: [PATCH backport 5.10 03/63] i2c: mlxbf: prevent stack overflow in + mlxbf_i2c_smbus_start_transaction() + +BugLink: https://bugs.launchpad.net/bugs/1991551 + +memcpy() is called in a loop while 'operation->length' upper bound +is not checked and 'data_idx' also increments. + +Fixes: b5b5b32081cd206b ("i2c: mlxbf: I2C SMBus driver for Mellanox BlueField SoC") +Reviewed-by: Khalil Blaiech +Signed-off-by: Asmaa Mnebhi +Signed-off-by: Wolfram Sang +(cherry picked from commit de24aceb07d426b6f1c59f33889d6a964770547b) +Signed-off-by: Asmaa Mnebhi +Acked-by: Tim Gardner +Acked-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/i2c/busses/i2c-mlxbf.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c +index 042c83b90..d78fb24d5 100644 +--- a/drivers/i2c/busses/i2c-mlxbf.c ++++ b/drivers/i2c/busses/i2c-mlxbf.c +@@ -744,6 +744,9 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, + if (flags & MLXBF_I2C_F_WRITE) { + write_en = 1; + write_len += operation->length; ++ if (data_idx + operation->length > ++ MLXBF_I2C_MASTER_DATA_DESC_SIZE) ++ return -ENOBUFS; + memcpy(data_desc + data_idx, + operation->buffer, operation->length); + data_idx += operation->length; +-- +2.20.1 + diff --git a/patch/0203-i2c-mlxbf-remove-IRQF_ONESHOT.patch b/patch/0203-i2c-mlxbf-remove-IRQF_ONESHOT.patch new file mode 100644 index 000000000..369776a08 --- /dev/null +++ b/patch/0203-i2c-mlxbf-remove-IRQF_ONESHOT.patch @@ -0,0 +1,37 @@ +From 9cd9614ce49f3c793efcc47dbbbfa90d793ed543 Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Thu, 8 Sep 2022 13:35:37 -0400 +Subject: [PATCH backport 5.10 04/63] i2c: mlxbf: remove IRQF_ONESHOT + +BugLink: https://bugs.launchpad.net/bugs/1991551 + +IRQF_ONESHOT is not needed so remove it. + +Reviewed-by: Khalil Blaiech +Signed-off-by: Asmaa Mnebhi +Signed-off-by: Wolfram Sang +(cherry picked from commit 92be2c122e495f0249090c0048f4fd05fe1efa9e) +Signed-off-by: Asmaa Mnebhi +Acked-by: Tim Gardner +Acked-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/i2c/busses/i2c-mlxbf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c +index d78fb24d5..066bfeb8a 100644 +--- a/drivers/i2c/busses/i2c-mlxbf.c ++++ b/drivers/i2c/busses/i2c-mlxbf.c +@@ -2382,7 +2382,7 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + ret = devm_request_irq(dev, irq, mlxbf_smbus_irq, +- IRQF_ONESHOT | IRQF_SHARED | IRQF_PROBE_SHARED, ++ IRQF_SHARED | IRQF_PROBE_SHARED, + dev_name(dev), priv); + if (ret < 0) { + dev_err(dev, "Cannot get irq %d\n", irq); +-- +2.20.1 + diff --git a/patch/0204-i2c-mlxbf-Fix-frequency-calculation.patch b/patch/0204-i2c-mlxbf-Fix-frequency-calculation.patch new file mode 100644 index 000000000..36905d7bb --- /dev/null +++ b/patch/0204-i2c-mlxbf-Fix-frequency-calculation.patch @@ -0,0 +1,190 @@ +From 5c14aec2f54faa6400d0cfd3255853106afbd2d7 Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Tue, 20 Sep 2022 13:47:29 -0400 +Subject: [PATCH backport 5.10 05/63] i2c: mlxbf: Fix frequency calculation + +BugLink: https://bugs.launchpad.net/bugs/1991551 + +The i2c-mlxbf.c driver is currently broken because there is a bug +in the calculation of the frequency. core_f, core_r and core_od +are components read from hardware registers and are used to +compute the frequency used to compute different timing parameters. +The shifting mechanism used to get core_f, core_r and core_od is +wrong. Use FIELD_GET to mask and shift the bitfields properly. + +Fixes: b5b5b32081cd206b (i2c: mlxbf: I2C SMBus driver for Mellanox BlueField SoC) +Reviewed-by: Khalil Blaiech +Signed-off-by: Asmaa Mnebhi +Signed-off-by: Wolfram Sang +(cherry picked from commit 37f071ec327b04c83d47637c5e5c2199b39899ca) +Signed-off-by: Asmaa Mnebhi +Acked-by: Tim Gardner +Acked-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/i2c/busses/i2c-mlxbf.c | 63 +++++++++++++--------------------- + 1 file changed, 23 insertions(+), 40 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c +index 066bfeb8a..b4bf1e503 100644 +--- a/drivers/i2c/busses/i2c-mlxbf.c ++++ b/drivers/i2c/busses/i2c-mlxbf.c +@@ -6,6 +6,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -63,13 +64,14 @@ + */ + #define MLXBF_I2C_TYU_PLL_OUT_FREQ (400 * 1000 * 1000) + /* Reference clock for Bluefield - 156 MHz. */ +-#define MLXBF_I2C_PLL_IN_FREQ (156 * 1000 * 1000) ++#define MLXBF_I2C_PLL_IN_FREQ 156250000ULL + + /* Constant used to determine the PLL frequency. */ +-#define MLNXBF_I2C_COREPLL_CONST 16384 ++#define MLNXBF_I2C_COREPLL_CONST 16384ULL ++ ++#define MLXBF_I2C_FREQUENCY_1GHZ 1000000000ULL + + /* PLL registers. */ +-#define MLXBF_I2C_CORE_PLL_REG0 0x0 + #define MLXBF_I2C_CORE_PLL_REG1 0x4 + #define MLXBF_I2C_CORE_PLL_REG2 0x8 + +@@ -187,22 +189,15 @@ enum { + #define MLXBF_I2C_COREPLL_FREQ MLXBF_I2C_TYU_PLL_OUT_FREQ + + /* Core PLL TYU configuration. */ +-#define MLXBF_I2C_COREPLL_CORE_F_TYU_MASK GENMASK(12, 0) +-#define MLXBF_I2C_COREPLL_CORE_OD_TYU_MASK GENMASK(3, 0) +-#define MLXBF_I2C_COREPLL_CORE_R_TYU_MASK GENMASK(5, 0) +- +-#define MLXBF_I2C_COREPLL_CORE_F_TYU_SHIFT 3 +-#define MLXBF_I2C_COREPLL_CORE_OD_TYU_SHIFT 16 +-#define MLXBF_I2C_COREPLL_CORE_R_TYU_SHIFT 20 ++#define MLXBF_I2C_COREPLL_CORE_F_TYU_MASK GENMASK(15, 3) ++#define MLXBF_I2C_COREPLL_CORE_OD_TYU_MASK GENMASK(19, 16) ++#define MLXBF_I2C_COREPLL_CORE_R_TYU_MASK GENMASK(25, 20) + + /* Core PLL YU configuration. */ + #define MLXBF_I2C_COREPLL_CORE_F_YU_MASK GENMASK(25, 0) + #define MLXBF_I2C_COREPLL_CORE_OD_YU_MASK GENMASK(3, 0) +-#define MLXBF_I2C_COREPLL_CORE_R_YU_MASK GENMASK(5, 0) ++#define MLXBF_I2C_COREPLL_CORE_R_YU_MASK GENMASK(31, 26) + +-#define MLXBF_I2C_COREPLL_CORE_F_YU_SHIFT 0 +-#define MLXBF_I2C_COREPLL_CORE_OD_YU_SHIFT 1 +-#define MLXBF_I2C_COREPLL_CORE_R_YU_SHIFT 26 + + /* Core PLL frequency. */ + static u64 mlxbf_i2c_corepll_frequency; +@@ -485,8 +480,6 @@ static struct mutex mlxbf_i2c_bus_lock; + #define MLXBF_I2C_MASK_8 GENMASK(7, 0) + #define MLXBF_I2C_MASK_16 GENMASK(15, 0) + +-#define MLXBF_I2C_FREQUENCY_1GHZ 1000000000 +- + /* + * Function to poll a set of bits at a specific address; it checks whether + * the bits are equal to zero when eq_zero is set to 'true', and not equal +@@ -1416,24 +1409,19 @@ static int mlxbf_i2c_init_master(struct platform_device *pdev, + return 0; + } + +-static u64 mlxbf_calculate_freq_from_tyu(struct mlxbf_i2c_resource *corepll_res) ++static u64 mlxbf_i2c_calculate_freq_from_tyu(struct mlxbf_i2c_resource *corepll_res) + { +- u64 core_frequency, pad_frequency; ++ u64 core_frequency; + u8 core_od, core_r; + u32 corepll_val; + u16 core_f; + +- pad_frequency = MLXBF_I2C_PLL_IN_FREQ; +- + corepll_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG1); + + /* Get Core PLL configuration bits. */ +- core_f = rol32(corepll_val, MLXBF_I2C_COREPLL_CORE_F_TYU_SHIFT) & +- MLXBF_I2C_COREPLL_CORE_F_TYU_MASK; +- core_od = rol32(corepll_val, MLXBF_I2C_COREPLL_CORE_OD_TYU_SHIFT) & +- MLXBF_I2C_COREPLL_CORE_OD_TYU_MASK; +- core_r = rol32(corepll_val, MLXBF_I2C_COREPLL_CORE_R_TYU_SHIFT) & +- MLXBF_I2C_COREPLL_CORE_R_TYU_MASK; ++ core_f = FIELD_GET(MLXBF_I2C_COREPLL_CORE_F_TYU_MASK, corepll_val); ++ core_od = FIELD_GET(MLXBF_I2C_COREPLL_CORE_OD_TYU_MASK, corepll_val); ++ core_r = FIELD_GET(MLXBF_I2C_COREPLL_CORE_R_TYU_MASK, corepll_val); + + /* + * Compute PLL output frequency as follow: +@@ -1445,31 +1433,26 @@ static u64 mlxbf_calculate_freq_from_tyu(struct mlxbf_i2c_resource *corepll_res) + * Where PLL_OUT_FREQ and PLL_IN_FREQ refer to CoreFrequency + * and PadFrequency, respectively. + */ +- core_frequency = pad_frequency * (++core_f); ++ core_frequency = MLXBF_I2C_PLL_IN_FREQ * (++core_f); + core_frequency /= (++core_r) * (++core_od); + + return core_frequency; + } + +-static u64 mlxbf_calculate_freq_from_yu(struct mlxbf_i2c_resource *corepll_res) ++static u64 mlxbf_i2c_calculate_freq_from_yu(struct mlxbf_i2c_resource *corepll_res) + { + u32 corepll_reg1_val, corepll_reg2_val; +- u64 corepll_frequency, pad_frequency; ++ u64 corepll_frequency; + u8 core_od, core_r; + u32 core_f; + +- pad_frequency = MLXBF_I2C_PLL_IN_FREQ; +- + corepll_reg1_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG1); + corepll_reg2_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG2); + + /* Get Core PLL configuration bits */ +- core_f = rol32(corepll_reg1_val, MLXBF_I2C_COREPLL_CORE_F_YU_SHIFT) & +- MLXBF_I2C_COREPLL_CORE_F_YU_MASK; +- core_r = rol32(corepll_reg1_val, MLXBF_I2C_COREPLL_CORE_R_YU_SHIFT) & +- MLXBF_I2C_COREPLL_CORE_R_YU_MASK; +- core_od = rol32(corepll_reg2_val, MLXBF_I2C_COREPLL_CORE_OD_YU_SHIFT) & +- MLXBF_I2C_COREPLL_CORE_OD_YU_MASK; ++ core_f = FIELD_GET(MLXBF_I2C_COREPLL_CORE_F_YU_MASK, corepll_reg1_val); ++ core_r = FIELD_GET(MLXBF_I2C_COREPLL_CORE_R_YU_MASK, corepll_reg1_val); ++ core_od = FIELD_GET(MLXBF_I2C_COREPLL_CORE_OD_YU_MASK, corepll_reg2_val); + + /* + * Compute PLL output frequency as follow: +@@ -1481,7 +1464,7 @@ static u64 mlxbf_calculate_freq_from_yu(struct mlxbf_i2c_resource *corepll_res) + * Where PLL_OUT_FREQ and PLL_IN_FREQ refer to CoreFrequency + * and PadFrequency, respectively. + */ +- corepll_frequency = (pad_frequency * core_f) / MLNXBF_I2C_COREPLL_CONST; ++ corepll_frequency = (MLXBF_I2C_PLL_IN_FREQ * core_f) / MLNXBF_I2C_COREPLL_CONST; + corepll_frequency /= (++core_r) * (++core_od); + + return corepll_frequency; +@@ -2189,14 +2172,14 @@ static struct mlxbf_i2c_chip_info mlxbf_i2c_chip[] = { + [1] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_1], + [2] = &mlxbf_i2c_gpio_res[MLXBF_I2C_CHIP_TYPE_1] + }, +- .calculate_freq = mlxbf_calculate_freq_from_tyu ++ .calculate_freq = mlxbf_i2c_calculate_freq_from_tyu + }, + [MLXBF_I2C_CHIP_TYPE_2] = { + .type = MLXBF_I2C_CHIP_TYPE_2, + .shared_res = { + [0] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_2] + }, +- .calculate_freq = mlxbf_calculate_freq_from_yu ++ .calculate_freq = mlxbf_i2c_calculate_freq_from_yu + } + }; + +-- +2.20.1 + diff --git a/patch/0205-i2c-mlxbf-support-lock-mechanism.patch b/patch/0205-i2c-mlxbf-support-lock-mechanism.patch new file mode 100644 index 000000000..1314b8b28 --- /dev/null +++ b/patch/0205-i2c-mlxbf-support-lock-mechanism.patch @@ -0,0 +1,123 @@ +From 12a738e1d79fd3e37436a3477b03a778548eac64 Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Mon, 26 Sep 2022 15:45:04 -0400 +Subject: [PATCH backport 5.10 06/63] i2c: mlxbf: support lock mechanism + +BugLink: https://bugs.launchpad.net/bugs/1991551 + +Linux is not the only entity using the BlueField I2C busses so +support a lock mechanism provided by hardware to avoid issues +when multiple entities are trying to access the same bus. + +The lock is acquired whenever written explicitely or the lock +register is read. So make sure it is always released at the end +of a successful or failed transaction. + +Fixes: b5b5b32081cd206b (i2c: mlxbf: I2C SMBus driver for Mellanox BlueField SoC) +Reviewed-by: Khalil Blaiech +Signed-off-by: Asmaa Mnebhi +Signed-off-by: Wolfram Sang +(cherry picked from commit 86067ccfa1424a26491542d6f6d7546d40b61a10) +Signed-off-by: Asmaa Mnebhi +Acked-by: Tim Gardner +Acked-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/i2c/busses/i2c-mlxbf.c | 44 ++++++++++++++++++++++++++++++---- + 1 file changed, 39 insertions(+), 5 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c +index b4bf1e503..30b798e92 100644 +--- a/drivers/i2c/busses/i2c-mlxbf.c ++++ b/drivers/i2c/busses/i2c-mlxbf.c +@@ -312,6 +312,7 @@ static u64 mlxbf_i2c_corepll_frequency; + * exact. + */ + #define MLXBF_I2C_SMBUS_TIMEOUT (300 * 1000) /* 300ms */ ++#define MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT (300 * 1000) /* 300ms */ + + /* Encapsulates timing parameters. */ + struct mlxbf_i2c_timings { +@@ -520,6 +521,25 @@ static bool mlxbf_smbus_master_wait_for_idle(struct mlxbf_i2c_priv *priv) + return false; + } + ++/* ++ * wait for the lock to be released before acquiring it. ++ */ ++static bool mlxbf_i2c_smbus_master_lock(struct mlxbf_i2c_priv *priv) ++{ ++ if (mlxbf_smbus_poll(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_GW, ++ MLXBF_I2C_MASTER_LOCK_BIT, true, ++ MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT)) ++ return true; ++ ++ return false; ++} ++ ++static void mlxbf_i2c_smbus_master_unlock(struct mlxbf_i2c_priv *priv) ++{ ++ /* Clear the gw to clear the lock */ ++ writel(0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_GW); ++} ++ + static bool mlxbf_i2c_smbus_transaction_success(u32 master_status, + u32 cause_status) + { +@@ -711,10 +731,19 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, + slave = request->slave & GENMASK(6, 0); + addr = slave << 1; + +- /* First of all, check whether the HW is idle. */ +- if (WARN_ON(!mlxbf_smbus_master_wait_for_idle(priv))) ++ /* ++ * Try to acquire the smbus gw lock before any reads of the GW register since ++ * a read sets the lock. ++ */ ++ if (WARN_ON(!mlxbf_i2c_smbus_master_lock(priv))) + return -EBUSY; + ++ /* Check whether the HW is idle */ ++ if (WARN_ON(!mlxbf_smbus_master_wait_for_idle(priv))) { ++ ret = -EBUSY; ++ goto out_unlock; ++ } ++ + /* Set first byte. */ + data_desc[data_idx++] = addr; + +@@ -738,8 +767,10 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, + write_en = 1; + write_len += operation->length; + if (data_idx + operation->length > +- MLXBF_I2C_MASTER_DATA_DESC_SIZE) +- return -ENOBUFS; ++ MLXBF_I2C_MASTER_DATA_DESC_SIZE) { ++ ret = -ENOBUFS; ++ goto out_unlock; ++ } + memcpy(data_desc + data_idx, + operation->buffer, operation->length); + data_idx += operation->length; +@@ -771,7 +802,7 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, + ret = mlxbf_i2c_smbus_enable(priv, slave, write_len, block_en, + pec_en, 0); + if (ret) +- return ret; ++ goto out_unlock; + } + + if (read_en) { +@@ -798,6 +829,9 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, + priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_FSM); + } + ++out_unlock: ++ mlxbf_i2c_smbus_master_unlock(priv); ++ + return ret; + } + +-- +2.20.1 + diff --git a/patch/0206-i2c-mlxbf-add-multi-slave-functionality.patch b/patch/0206-i2c-mlxbf-add-multi-slave-functionality.patch new file mode 100644 index 000000000..a940755c9 --- /dev/null +++ b/patch/0206-i2c-mlxbf-add-multi-slave-functionality.patch @@ -0,0 +1,549 @@ +From 19c72b4450f4f76cec6030c2eabb87507a90f316 Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Mon, 26 Sep 2022 15:45:05 -0400 +Subject: [PATCH backport 5.10 07/63] i2c: mlxbf: add multi slave functionality + +BugLink: https://bugs.launchpad.net/bugs/1991551 + +Support the multi slave functionality which enables the BlueField +to be registered at up to 16 i2c slave addresses. + +Reviewed-by: Khalil Blaiech +Signed-off-by: Asmaa Mnebhi +Signed-off-by: Wolfram Sang +(cherry picked from commit bdc4af281b70b7fe2881fd08f1aa1b15f2b6adf0) +Signed-off-by: Asmaa Mnebhi +Acked-by: Tim Gardner +Acked-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/i2c/busses/i2c-mlxbf.c | 320 +++++++++++++++------------------ + 1 file changed, 149 insertions(+), 171 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c +index 30b798e92..32dbe1dab 100644 +--- a/drivers/i2c/busses/i2c-mlxbf.c ++++ b/drivers/i2c/busses/i2c-mlxbf.c +@@ -304,9 +304,6 @@ static u64 mlxbf_i2c_corepll_frequency; + #define MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT 7 + #define MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK GENMASK(6, 0) + +-#define MLXBF_I2C_SLAVE_ADDR_ENABLED(addr) \ +- ((addr) & (1 << MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT)) +- + /* + * Timeout is given in microsends. Note also that timeout handling is not + * exact. +@@ -432,7 +429,7 @@ struct mlxbf_i2c_priv { + u64 frequency; /* Core frequency in Hz. */ + int bus; /* Physical bus identifier. */ + int irq; +- struct i2c_client *slave; ++ struct i2c_client *slave[MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT]; + }; + + static struct mlxbf_i2c_resource mlxbf_i2c_coalesce_res[] = { +@@ -1549,25 +1546,23 @@ static int mlxbf_i2c_calculate_corepll_freq(struct platform_device *pdev, + return 0; + } + +-static int mlxbf_slave_enable(struct mlxbf_i2c_priv *priv, u8 addr) ++static int mlxbf_i2c_slave_enable(struct mlxbf_i2c_priv *priv, ++ struct i2c_client *slave) + { +- u32 slave_reg, slave_reg_tmp, slave_reg_avail, slave_addr_mask; +- u8 reg, reg_cnt, byte, addr_tmp, reg_avail, byte_avail; +- bool avail, disabled; +- +- disabled = false; +- avail = false; ++ u8 reg, reg_cnt, byte, addr_tmp; ++ u32 slave_reg, slave_reg_tmp; + + if (!priv) + return -EPERM; + + reg_cnt = MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT >> 2; +- slave_addr_mask = MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK; + + /* + * Read the slave registers. There are 4 * 32-bit slave registers. +- * Each slave register can hold up to 4 * 8-bit slave configuration +- * (7-bit address, 1 status bit (1 if enabled, 0 if not)). ++ * Each slave register can hold up to 4 * 8-bit slave configuration: ++ * 1) A 7-bit address ++ * 2) And a status bit (1 if enabled, 0 if not). ++ * Look for the next available slave register slot. + */ + for (reg = 0; reg < reg_cnt; reg++) { + slave_reg = readl(priv->smbus->io + +@@ -1582,121 +1577,87 @@ static int mlxbf_slave_enable(struct mlxbf_i2c_priv *priv, u8 addr) + addr_tmp = slave_reg_tmp & GENMASK(7, 0); + + /* +- * Mark the first available slave address slot, i.e. its +- * enabled bit should be unset. This slot might be used +- * later on to register our slave. +- */ +- if (!avail && !MLXBF_I2C_SLAVE_ADDR_ENABLED(addr_tmp)) { +- avail = true; +- reg_avail = reg; +- byte_avail = byte; +- slave_reg_avail = slave_reg; +- } +- +- /* +- * Parse slave address bytes and check whether the +- * slave address already exists and it's enabled, +- * i.e. most significant bit is set. ++ * If an enable bit is not set in the ++ * MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG register, then the ++ * slave address slot associated with that bit is ++ * free. So set the enable bit and write the ++ * slave address bits. + */ +- if ((addr_tmp & slave_addr_mask) == addr) { +- if (MLXBF_I2C_SLAVE_ADDR_ENABLED(addr_tmp)) +- return 0; +- disabled = true; +- break; ++ if (!(addr_tmp & MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT)) { ++ slave_reg &= ~(MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK << (byte * 8)); ++ slave_reg |= (slave->addr << (byte * 8)); ++ slave_reg |= MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT << (byte * 8); ++ writel(slave_reg, priv->smbus->io + ++ MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + ++ (reg * 0x4)); ++ ++ /* ++ * Set the slave at the corresponding index. ++ */ ++ priv->slave[(reg * 4) + byte] = slave; ++ ++ return 0; + } + + /* Parse next byte. */ + slave_reg_tmp >>= 8; + } +- +- /* Exit the loop if the slave address is found. */ +- if (disabled) +- break; + } + +- if (!avail && !disabled) +- return -EINVAL; /* No room for a new slave address. */ +- +- if (avail && !disabled) { +- reg = reg_avail; +- byte = byte_avail; +- /* Set the slave address. */ +- slave_reg_avail &= ~(slave_addr_mask << (byte * 8)); +- slave_reg_avail |= addr << (byte * 8); +- slave_reg = slave_reg_avail; +- } +- +- /* Enable the slave address and update the register. */ +- slave_reg |= (1 << MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT) << (byte * 8); +- writel(slave_reg, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + +- reg * 0x4); +- +- return 0; ++ return -EBUSY; + } + +-static int mlxbf_slave_disable(struct mlxbf_i2c_priv *priv) ++static int mlxbf_i2c_slave_disable(struct mlxbf_i2c_priv *priv, u8 addr) + { +- u32 slave_reg, slave_reg_tmp, slave_addr_mask; +- u8 addr, addr_tmp, reg, reg_cnt, slave_byte; +- struct i2c_client *client = priv->slave; +- bool exist; ++ u8 addr_tmp, reg, reg_cnt, byte; ++ u32 slave_reg, slave_reg_tmp; + +- exist = false; +- +- addr = client->addr; + reg_cnt = MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT >> 2; +- slave_addr_mask = MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK; + + /* + * Read the slave registers. There are 4 * 32-bit slave registers. +- * Each slave register can hold up to 4 * 8-bit slave configuration +- * (7-bit address, 1 status bit (1 if enabled, 0 if not)). ++ * Each slave register can hold up to 4 * 8-bit slave configuration: ++ * 1) A 7-bit address ++ * 2) And a status bit (1 if enabled, 0 if not). ++ * Check if addr is present in the registers. + */ + for (reg = 0; reg < reg_cnt; reg++) { + slave_reg = readl(priv->smbus->io + + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4); + + /* Check whether the address slots are empty. */ +- if (slave_reg == 0) ++ if (!slave_reg) + continue; + + /* +- * Each register holds 4 slave addresses. So, we have to keep +- * the byte order consistent with the value read in order to +- * update the register correctly, if needed. ++ * Check if addr matches any of the 4 slave addresses ++ * in the register. + */ + slave_reg_tmp = slave_reg; +- slave_byte = 0; +- while (slave_reg_tmp != 0) { +- addr_tmp = slave_reg_tmp & slave_addr_mask; ++ for (byte = 0; byte < 4; byte++) { ++ addr_tmp = slave_reg_tmp & MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK; + /* + * Parse slave address bytes and check whether the + * slave address already exists. + */ + if (addr_tmp == addr) { +- exist = true; +- break; ++ /* Clear the slave address slot. */ ++ slave_reg &= ~(GENMASK(7, 0) << (byte * 8)); ++ writel(slave_reg, priv->smbus->io + ++ MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + ++ (reg * 0x4)); ++ /* Free slave at the corresponding index */ ++ priv->slave[(reg * 4) + byte] = NULL; ++ ++ return 0; + } + + /* Parse next byte. */ + slave_reg_tmp >>= 8; +- slave_byte += 1; + } +- +- /* Exit the loop if the slave address is found. */ +- if (exist) +- break; + } + +- if (!exist) +- return 0; /* Slave is not registered, nothing to do. */ +- +- /* Cleanup the slave address slot. */ +- slave_reg &= ~(GENMASK(7, 0) << (slave_byte * 8)); +- writel(slave_reg, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + +- reg * 0x4); +- +- return 0; ++ return -ENXIO; + } + + static int mlxbf_i2c_init_coalesce(struct platform_device *pdev, +@@ -1858,72 +1819,81 @@ static bool mlxbf_smbus_slave_wait_for_idle(struct mlxbf_i2c_priv *priv, + return false; + } + +-/* Send byte to 'external' smbus master. */ +-static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) ++static struct i2c_client *mlxbf_i2c_get_slave_from_addr( ++ struct mlxbf_i2c_priv *priv, u8 addr) + { +- u8 data_desc[MLXBF_I2C_SLAVE_DATA_DESC_SIZE] = { 0 }; +- u8 write_size, pec_en, addr, byte, value, byte_cnt, desc_size; +- struct i2c_client *slave = priv->slave; +- u32 control32, data32; +- int ret; ++ int i; + +- if (!slave) +- return -EINVAL; ++ for (i = 0; i < MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT; i++) { ++ if (!priv->slave[i]) ++ continue; + +- addr = 0; +- byte = 0; +- desc_size = MLXBF_I2C_SLAVE_DATA_DESC_SIZE; ++ if (priv->slave[i]->addr == addr) ++ return priv->slave[i]; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Send byte to 'external' smbus master. This function is executed when ++ * an external smbus master wants to read data from the BlueField. ++ */ ++static int mlxbf_i2c_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) ++{ ++ u8 data_desc[MLXBF_I2C_SLAVE_DATA_DESC_SIZE] = { 0 }; ++ u8 write_size, pec_en, addr, value, byte_cnt; ++ struct i2c_client *slave; ++ u32 control32, data32; ++ int ret = 0; + + /* +- * Read bytes received from the external master. These bytes should +- * be located in the first data descriptor register of the slave GW. +- * These bytes are the slave address byte and the internal register +- * address, if supplied. ++ * Read the first byte received from the external master to ++ * determine the slave address. This byte is located in the ++ * first data descriptor register of the slave GW. + */ +- if (recv_bytes > 0) { +- data32 = ioread32be(priv->smbus->io + +- MLXBF_I2C_SLAVE_DATA_DESC_ADDR); +- +- /* Parse the received bytes. */ +- switch (recv_bytes) { +- case 2: +- byte = (data32 >> 8) & GENMASK(7, 0); +- fallthrough; +- case 1: +- addr = (data32 & GENMASK(7, 0)) >> 1; +- } ++ data32 = ioread32be(priv->smbus->io + ++ MLXBF_I2C_SLAVE_DATA_DESC_ADDR); ++ addr = (data32 & GENMASK(7, 0)) >> 1; + +- /* Check whether it's our slave address. */ +- if (slave->addr != addr) +- return -EINVAL; ++ /* ++ * Check if the slave address received in the data descriptor register ++ * matches any of the slave addresses registered. If there is a match, ++ * set the slave. ++ */ ++ slave = mlxbf_i2c_get_slave_from_addr(priv, addr); ++ if (!slave) { ++ ret = -ENXIO; ++ goto clear_csr; + } + + /* +- * I2C read transactions may start by a WRITE followed by a READ. +- * Indeed, most slave devices would expect the internal address +- * following the slave address byte. So, write that byte first, +- * and then, send the requested data bytes to the master. ++ * An I2C read can consist of a WRITE bit transaction followed by ++ * a READ bit transaction. Indeed, slave devices often expect ++ * the slave address to be followed by the internal address. ++ * So, write the internal address byte first, and then, send the ++ * requested data to the master. + */ + if (recv_bytes > 1) { + i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); +- value = byte; ++ value = (data32 >> 8) & GENMASK(7, 0); + ret = i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, + &value); + i2c_slave_event(slave, I2C_SLAVE_STOP, &value); + + if (ret < 0) +- return ret; ++ goto clear_csr; + } + + /* +- * Now, send data to the master; currently, the driver supports +- * READ_BYTE, READ_WORD and BLOCK READ protocols. Note that the +- * hardware can send up to 128 bytes per transfer. That is the +- * size of its data registers. ++ * Send data to the master. Currently, the driver supports ++ * READ_BYTE, READ_WORD and BLOCK READ protocols. The ++ * hardware can send up to 128 bytes per transfer which is ++ * the total size of the data registers. + */ + i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value); + +- for (byte_cnt = 0; byte_cnt < desc_size; byte_cnt++) { ++ for (byte_cnt = 0; byte_cnt < MLXBF_I2C_SLAVE_DATA_DESC_SIZE; byte_cnt++) { + data_desc[byte_cnt] = value; + i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value); + } +@@ -1931,8 +1901,6 @@ static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) + /* Send a stop condition to the backend. */ + i2c_slave_event(slave, I2C_SLAVE_STOP, &value); + +- /* Handle the actual transfer. */ +- + /* Set the number of bytes to write to master. */ + write_size = (byte_cnt - 1) & 0x7f; + +@@ -1955,38 +1923,44 @@ static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) + */ + mlxbf_smbus_slave_wait_for_idle(priv, MLXBF_I2C_SMBUS_TIMEOUT); + ++clear_csr: + /* Release the Slave GW. */ + writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); + writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC); + writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY); + +- return 0; ++ return ret; + } + +-/* Receive bytes from 'external' smbus master. */ +-static int mlxbf_smbus_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes) ++/* ++ * Receive bytes from 'external' smbus master. This function is executed when ++ * an external smbus master wants to write data to the BlueField. ++ */ ++static int mlxbf_i2c_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes) + { + u8 data_desc[MLXBF_I2C_SLAVE_DATA_DESC_SIZE] = { 0 }; +- struct i2c_client *slave = priv->slave; ++ struct i2c_client *slave; + u8 value, byte, addr; + int ret = 0; + +- if (!slave) +- return -EINVAL; +- + /* Read data from Slave GW data descriptor. */ + mlxbf_i2c_smbus_read_data(priv, data_desc, recv_bytes, + MLXBF_I2C_SLAVE_DATA_DESC_ADDR); +- +- /* Check whether its our slave address. */ + addr = data_desc[0] >> 1; +- if (slave->addr != addr) +- return -EINVAL; + + /* +- * Notify the slave backend; another I2C master wants to write data +- * to us. This event is sent once the slave address and the write bit +- * is detected. ++ * Check if the slave address received in the data descriptor register ++ * matches any of the slave addresses registered. ++ */ ++ slave = mlxbf_i2c_get_slave_from_addr(priv, addr); ++ if (!slave) { ++ ret = -EINVAL; ++ goto clear_csr; ++ } ++ ++ /* ++ * Notify the slave backend that an smbus master wants to write data ++ * to the BlueField. + */ + i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); + +@@ -1999,9 +1973,13 @@ static int mlxbf_smbus_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes) + break; + } + +- /* Send a stop condition to the backend. */ ++ /* ++ * Send a stop event to the slave backend, to signal ++ * the end of the write transactions. ++ */ + i2c_slave_event(slave, I2C_SLAVE_STOP, &value); + ++clear_csr: + /* Release the Slave GW. */ + writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); + writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC); +@@ -2010,7 +1988,7 @@ static int mlxbf_smbus_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes) + return ret; + } + +-static irqreturn_t mlxbf_smbus_irq(int irq, void *ptr) ++static irqreturn_t mlxbf_i2c_irq(int irq, void *ptr) + { + struct mlxbf_i2c_priv *priv = ptr; + bool read, write, irq_is_set; +@@ -2058,9 +2036,9 @@ static irqreturn_t mlxbf_smbus_irq(int irq, void *ptr) + MLXBF_I2C_SLAVE_DATA_DESC_SIZE : recv_bytes; + + if (read) +- mlxbf_smbus_irq_send(priv, recv_bytes); ++ mlxbf_i2c_irq_send(priv, recv_bytes); + else +- mlxbf_smbus_irq_recv(priv, recv_bytes); ++ mlxbf_i2c_irq_recv(priv, recv_bytes); + + return IRQ_HANDLED; + } +@@ -2155,23 +2133,21 @@ static s32 mlxbf_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, + static int mlxbf_i2c_reg_slave(struct i2c_client *slave) + { + struct mlxbf_i2c_priv *priv = i2c_get_adapdata(slave->adapter); ++ struct device *dev = &slave->dev; + int ret; + +- if (priv->slave) +- return -EBUSY; +- + /* + * Do not support ten bit chip address and do not use Packet Error + * Checking (PEC). + */ +- if (slave->flags & (I2C_CLIENT_TEN | I2C_CLIENT_PEC)) ++ if (slave->flags & (I2C_CLIENT_TEN | I2C_CLIENT_PEC)) { ++ dev_err(dev, "SMBus PEC and 10 bit address not supported\n"); + return -EAFNOSUPPORT; ++ } + +- ret = mlxbf_slave_enable(priv, slave->addr); +- if (ret < 0) +- return ret; +- +- priv->slave = slave; ++ ret = mlxbf_i2c_slave_enable(priv, slave); ++ if (ret) ++ dev_err(dev, "Surpassed max number of registered slaves allowed\n"); + + return 0; + } +@@ -2179,18 +2155,19 @@ static int mlxbf_i2c_reg_slave(struct i2c_client *slave) + static int mlxbf_i2c_unreg_slave(struct i2c_client *slave) + { + struct mlxbf_i2c_priv *priv = i2c_get_adapdata(slave->adapter); ++ struct device *dev = &slave->dev; + int ret; + +- WARN_ON(!priv->slave); +- +- /* Unregister slave, i.e. disable the slave address in hardware. */ +- ret = mlxbf_slave_disable(priv); +- if (ret < 0) +- return ret; +- +- priv->slave = NULL; ++ /* ++ * Unregister slave by: ++ * 1) Disabling the slave address in hardware ++ * 2) Freeing priv->slave at the corresponding index ++ */ ++ ret = mlxbf_i2c_slave_disable(priv, slave->addr); ++ if (ret) ++ dev_err(dev, "Unable to find slave 0x%x\n", slave->addr); + +- return 0; ++ return ret; + } + + static u32 mlxbf_i2c_functionality(struct i2c_adapter *adap) +@@ -2398,7 +2375,7 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; +- ret = devm_request_irq(dev, irq, mlxbf_smbus_irq, ++ ret = devm_request_irq(dev, irq, mlxbf_i2c_irq, + IRQF_SHARED | IRQF_PROBE_SHARED, + dev_name(dev), priv); + if (ret < 0) { +@@ -2493,4 +2470,5 @@ module_exit(mlxbf_i2c_exit); + + MODULE_DESCRIPTION("Mellanox BlueField I2C bus driver"); + MODULE_AUTHOR("Khalil Blaiech "); ++MODULE_AUTHOR("Asmaa Mnebhi "); + MODULE_LICENSE("GPL v2"); +-- +2.20.1 + diff --git a/patch/0207-i2c-mlxbf-support-BlueField-3-SoC.patch b/patch/0207-i2c-mlxbf-support-BlueField-3-SoC.patch new file mode 100644 index 000000000..e31600265 --- /dev/null +++ b/patch/0207-i2c-mlxbf-support-BlueField-3-SoC.patch @@ -0,0 +1,967 @@ +From 047991847c5ab4bc9763bb111f05bde863dac8b3 Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Tue, 27 Sep 2022 16:39:23 -0400 +Subject: [PATCH backport 5.10 08/63] i2c: mlxbf: support BlueField-3 SoC + +BugLink: https://bugs.launchpad.net/bugs/1991551 + +BlueField-3 SoC has the same I2C IP logic as previous +BlueField-1 and 2 SoCs but it has different registers' addresses. +This is an effort to keep this driver generic across all +BlueField generations. +This patch breaks down the "smbus" resource into 3 separate +resources to enable us to use common registers' offsets for all +BlueField SoCs: +struct mlxbf_i2c_resource *timer; +struct mlxbf_i2c_resource *mst; +struct mlxbf_i2c_resource *slv; + +Of course, all offsets had to be adjusted accordingly, and we took +this chance to reorganize the macros depending on the register block +they target. + +There are only 2 registers' offsets that do not fit within this +schema so their offsets are passed as SoC-specific parameters: +smbus_master_rs_bytes_off +smbus_master_fsm_off + +Reviewed-by: Khalil Blaiech +Signed-off-by: Asmaa Mnebhi +Signed-off-by: Wolfram Sang +(cherry picked from commit 19e13e1330c63506452eed80f473f344e6779b94) +Signed-off-by: Asmaa Mnebhi +Acked-by: Tim Gardner +Acked-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + MAINTAINERS | 1 + + drivers/i2c/busses/i2c-mlxbf.c | 461 ++++++++++++++++++++------------- + 2 files changed, 285 insertions(+), 177 deletions(-) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 7db3e06ec..f6a974ade 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -11175,6 +11175,7 @@ F: drivers/input/touchscreen/melfas_mip4.c + + MELLANOX BLUEFIELD I2C DRIVER + M: Khalil Blaiech ++M: Asmaa Mnebhi + L: linux-i2c@vger.kernel.org + S: Supported + F: Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml +diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c +index 32dbe1dab..75d8d00d1 100644 +--- a/drivers/i2c/busses/i2c-mlxbf.c ++++ b/drivers/i2c/busses/i2c-mlxbf.c +@@ -32,8 +32,6 @@ + (MLXBF_I2C_FUNC_SMBUS_DEFAULT | MLXBF_I2C_FUNC_SMBUS_BLOCK | \ + I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SLAVE) + +-#define MLXBF_I2C_SMBUS_MAX 3 +- + /* Shared resources info in BlueField platforms. */ + + #define MLXBF_I2C_COALESCE_TYU_ADDR 0x02801300 +@@ -48,6 +46,9 @@ + #define MLXBF_I2C_COREPLL_YU_ADDR 0x02800c30 + #define MLXBF_I2C_COREPLL_YU_SIZE 0x00c + ++#define MLXBF_I2C_COREPLL_RSH_YU_ADDR 0x13409824 ++#define MLXBF_I2C_COREPLL_RSH_YU_SIZE 0x00c ++ + #define MLXBF_I2C_SHARED_RES_MAX 3 + + /* +@@ -131,14 +132,10 @@ + /* Slave busy bit reset. */ + #define MLXBF_I2C_CAUSE_S_GW_BUSY_FALL BIT(18) + +-#define MLXBF_I2C_CAUSE_SLAVE_ARBITER_BITS_MASK GENMASK(20, 0) +- + /* Cause coalesce registers. */ + #define MLXBF_I2C_CAUSE_COALESCE_0 0x00 +-#define MLXBF_I2C_CAUSE_COALESCE_1 0x04 +-#define MLXBF_I2C_CAUSE_COALESCE_2 0x08 + +-#define MLXBF_I2C_CAUSE_TYU_SLAVE_BIT MLXBF_I2C_SMBUS_MAX ++#define MLXBF_I2C_CAUSE_TYU_SLAVE_BIT 3 + #define MLXBF_I2C_CAUSE_YU_SLAVE_BIT 1 + + /* Functional enable register. */ +@@ -165,21 +162,6 @@ + #define MLXBF_I2C_GPIO_SMBUS_GW_ASSERT_PINS(num, val) \ + ((val) | (0x3 << MLXBF_I2C_GPIO_SMBUS_GW_PINS(num))) + +-/* SMBus timing parameters. */ +-#define MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH 0x00 +-#define MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE 0x04 +-#define MLXBF_I2C_SMBUS_TIMER_THOLD 0x08 +-#define MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP 0x0c +-#define MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA 0x10 +-#define MLXBF_I2C_SMBUS_THIGH_MAX_TBUF 0x14 +-#define MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT 0x18 +- +-enum { +- MLXBF_I2C_TIMING_100KHZ = 100000, +- MLXBF_I2C_TIMING_400KHZ = 400000, +- MLXBF_I2C_TIMING_1000KHZ = 1000000, +-}; +- + /* + * Defines SMBus operating frequency and core clock frequency. + * According to ADB files, default values are compliant to 100KHz SMBus +@@ -198,26 +180,37 @@ enum { + #define MLXBF_I2C_COREPLL_CORE_OD_YU_MASK GENMASK(3, 0) + #define MLXBF_I2C_COREPLL_CORE_R_YU_MASK GENMASK(31, 26) + ++/* SMBus timing parameters. */ ++#define MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH 0x00 ++#define MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE 0x04 ++#define MLXBF_I2C_SMBUS_TIMER_THOLD 0x08 ++#define MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP 0x0c ++#define MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA 0x10 ++#define MLXBF_I2C_SMBUS_THIGH_MAX_TBUF 0x14 ++#define MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT 0x18 + +-/* Core PLL frequency. */ +-static u64 mlxbf_i2c_corepll_frequency; ++#define MLXBF_I2C_SHIFT_0 0 ++#define MLXBF_I2C_SHIFT_8 8 ++#define MLXBF_I2C_SHIFT_16 16 ++#define MLXBF_I2C_SHIFT_24 24 ++ ++#define MLXBF_I2C_MASK_8 GENMASK(7, 0) ++#define MLXBF_I2C_MASK_16 GENMASK(15, 0) ++ ++#define MLXBF_I2C_MST_ADDR_OFFSET 0x200 + + /* SMBus Master GW. */ +-#define MLXBF_I2C_SMBUS_MASTER_GW 0x200 ++#define MLXBF_I2C_SMBUS_MASTER_GW 0x0 + /* Number of bytes received and sent. */ +-#define MLXBF_I2C_SMBUS_RS_BYTES 0x300 ++#define MLXBF_I2C_YU_SMBUS_RS_BYTES 0x100 ++#define MLXBF_I2C_RSH_YU_SMBUS_RS_BYTES 0x10c + /* Packet error check (PEC) value. */ +-#define MLXBF_I2C_SMBUS_MASTER_PEC 0x304 ++#define MLXBF_I2C_SMBUS_MASTER_PEC 0x104 + /* Status bits (ACK/NACK/FW Timeout). */ +-#define MLXBF_I2C_SMBUS_MASTER_STATUS 0x308 ++#define MLXBF_I2C_SMBUS_MASTER_STATUS 0x108 + /* SMbus Master Finite State Machine. */ +-#define MLXBF_I2C_SMBUS_MASTER_FSM 0x310 +- +-/* +- * When enabled, the master will issue a stop condition in case of +- * timeout while waiting for FW response. +- */ +-#define MLXBF_I2C_SMBUS_EN_FW_TIMEOUT 0x31c ++#define MLXBF_I2C_YU_SMBUS_MASTER_FSM 0x110 ++#define MLXBF_I2C_RSH_YU_SMBUS_MASTER_FSM 0x100 + + /* SMBus master GW control bits offset in MLXBF_I2C_SMBUS_MASTER_GW[31:3]. */ + #define MLXBF_I2C_MASTER_LOCK_BIT BIT(31) /* Lock bit. */ +@@ -237,14 +230,14 @@ static u64 mlxbf_i2c_corepll_frequency; + #define MLXBF_I2C_MASTER_ENABLE_READ \ + (MLXBF_I2C_MASTER_ENABLE | MLXBF_I2C_MASTER_CTL_READ_BIT) + +-#define MLXBF_I2C_MASTER_SLV_ADDR_SHIFT 12 /* Slave address shift. */ +-#define MLXBF_I2C_MASTER_WRITE_SHIFT 21 /* Control write bytes shift. */ +-#define MLXBF_I2C_MASTER_SEND_PEC_SHIFT 20 /* Send PEC byte shift. */ +-#define MLXBF_I2C_MASTER_PARSE_EXP_SHIFT 11 /* Parse expected bytes shift. */ +-#define MLXBF_I2C_MASTER_READ_SHIFT 4 /* Control read bytes shift. */ ++#define MLXBF_I2C_MASTER_WRITE_SHIFT 21 /* Control write bytes */ ++#define MLXBF_I2C_MASTER_SEND_PEC_SHIFT 20 /* Send PEC byte when set to 1 */ ++#define MLXBF_I2C_MASTER_PARSE_EXP_SHIFT 11 /* Control parse expected bytes */ ++#define MLXBF_I2C_MASTER_SLV_ADDR_SHIFT 12 /* Slave address */ ++#define MLXBF_I2C_MASTER_READ_SHIFT 4 /* Control read bytes */ + + /* SMBus master GW Data descriptor. */ +-#define MLXBF_I2C_MASTER_DATA_DESC_ADDR 0x280 ++#define MLXBF_I2C_MASTER_DATA_DESC_ADDR 0x80 + #define MLXBF_I2C_MASTER_DATA_DESC_SIZE 0x80 /* Size in bytes. */ + + /* Maximum bytes to read/write per SMBus transaction. */ +@@ -270,19 +263,21 @@ static u64 mlxbf_i2c_corepll_frequency; + #define MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK BIT(31) + #define MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK BIT(15) + ++#define MLXBF_I2C_SLV_ADDR_OFFSET 0x400 ++ + /* SMBus slave GW. */ +-#define MLXBF_I2C_SMBUS_SLAVE_GW 0x400 ++#define MLXBF_I2C_SMBUS_SLAVE_GW 0x0 + /* Number of bytes received and sent from/to master. */ +-#define MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES 0x500 ++#define MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES 0x100 + /* Packet error check (PEC) value. */ +-#define MLXBF_I2C_SMBUS_SLAVE_PEC 0x504 ++#define MLXBF_I2C_SMBUS_SLAVE_PEC 0x104 + /* SMBus slave Finite State Machine (FSM). */ +-#define MLXBF_I2C_SMBUS_SLAVE_FSM 0x510 ++#define MLXBF_I2C_SMBUS_SLAVE_FSM 0x110 + /* + * Should be set when all raised causes handled, and cleared by HW on + * every new cause. + */ +-#define MLXBF_I2C_SMBUS_SLAVE_READY 0x52c ++#define MLXBF_I2C_SMBUS_SLAVE_READY 0x12c + + /* SMBus slave GW control bits offset in MLXBF_I2C_SMBUS_SLAVE_GW[31:19]. */ + #define MLXBF_I2C_SLAVE_BUSY_BIT BIT(30) /* Busy bit. */ +@@ -295,13 +290,13 @@ static u64 mlxbf_i2c_corepll_frequency; + #define MLXBF_I2C_SLAVE_SEND_PEC_SHIFT 21 /* Send PEC byte shift. */ + + /* SMBus slave GW Data descriptor. */ +-#define MLXBF_I2C_SLAVE_DATA_DESC_ADDR 0x480 ++#define MLXBF_I2C_SLAVE_DATA_DESC_ADDR 0x80 + #define MLXBF_I2C_SLAVE_DATA_DESC_SIZE 0x80 /* Size in bytes. */ + + /* SMbus slave configuration registers. */ +-#define MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG 0x514 ++#define MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG 0x114 + #define MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT 16 +-#define MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT 7 ++#define MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT BIT(7) + #define MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK GENMASK(6, 0) + + /* +@@ -311,6 +306,59 @@ static u64 mlxbf_i2c_corepll_frequency; + #define MLXBF_I2C_SMBUS_TIMEOUT (300 * 1000) /* 300ms */ + #define MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT (300 * 1000) /* 300ms */ + ++/* Polling frequency in microseconds. */ ++#define MLXBF_I2C_POLL_FREQ_IN_USEC 200 ++ ++#define MLXBF_I2C_SMBUS_OP_CNT_1 1 ++#define MLXBF_I2C_SMBUS_OP_CNT_2 2 ++#define MLXBF_I2C_SMBUS_OP_CNT_3 3 ++#define MLXBF_I2C_SMBUS_MAX_OP_CNT MLXBF_I2C_SMBUS_OP_CNT_3 ++ ++/* Helper macro to define an I2C resource parameters. */ ++#define MLXBF_I2C_RES_PARAMS(addr, size, str) \ ++ { \ ++ .start = (addr), \ ++ .end = (addr) + (size) - 1, \ ++ .name = (str) \ ++ } ++ ++enum { ++ MLXBF_I2C_TIMING_100KHZ = 100000, ++ MLXBF_I2C_TIMING_400KHZ = 400000, ++ MLXBF_I2C_TIMING_1000KHZ = 1000000, ++}; ++ ++enum { ++ MLXBF_I2C_F_READ = BIT(0), ++ MLXBF_I2C_F_WRITE = BIT(1), ++ MLXBF_I2C_F_NORESTART = BIT(3), ++ MLXBF_I2C_F_SMBUS_OPERATION = BIT(4), ++ MLXBF_I2C_F_SMBUS_BLOCK = BIT(5), ++ MLXBF_I2C_F_SMBUS_PEC = BIT(6), ++ MLXBF_I2C_F_SMBUS_PROCESS_CALL = BIT(7), ++}; ++ ++/* Mellanox BlueField chip type. */ ++enum mlxbf_i2c_chip_type { ++ MLXBF_I2C_CHIP_TYPE_1, /* Mellanox BlueField-1 chip. */ ++ MLXBF_I2C_CHIP_TYPE_2, /* Mellanox BlueField-2 chip. */ ++ MLXBF_I2C_CHIP_TYPE_3 /* Mellanox BlueField-3 chip. */ ++}; ++ ++/* List of chip resources that are being accessed by the driver. */ ++enum { ++ MLXBF_I2C_SMBUS_RES, ++ MLXBF_I2C_MST_CAUSE_RES, ++ MLXBF_I2C_SLV_CAUSE_RES, ++ MLXBF_I2C_COALESCE_RES, ++ MLXBF_I2C_SMBUS_TIMER_RES, ++ MLXBF_I2C_SMBUS_MST_RES, ++ MLXBF_I2C_SMBUS_SLV_RES, ++ MLXBF_I2C_COREPLL_RES, ++ MLXBF_I2C_GPIO_RES, ++ MLXBF_I2C_END_RES ++}; ++ + /* Encapsulates timing parameters. */ + struct mlxbf_i2c_timings { + u16 scl_high; /* Clock high period. */ +@@ -330,27 +378,12 @@ struct mlxbf_i2c_timings { + u32 timeout; /* Detect clock low timeout. */ + }; + +-enum { +- MLXBF_I2C_F_READ = BIT(0), +- MLXBF_I2C_F_WRITE = BIT(1), +- MLXBF_I2C_F_NORESTART = BIT(3), +- MLXBF_I2C_F_SMBUS_OPERATION = BIT(4), +- MLXBF_I2C_F_SMBUS_BLOCK = BIT(5), +- MLXBF_I2C_F_SMBUS_PEC = BIT(6), +- MLXBF_I2C_F_SMBUS_PROCESS_CALL = BIT(7), +-}; +- + struct mlxbf_i2c_smbus_operation { + u32 flags; + u32 length; /* Buffer length in bytes. */ + u8 *buffer; + }; + +-#define MLXBF_I2C_SMBUS_OP_CNT_1 1 +-#define MLXBF_I2C_SMBUS_OP_CNT_2 2 +-#define MLXBF_I2C_SMBUS_OP_CNT_3 3 +-#define MLXBF_I2C_SMBUS_MAX_OP_CNT MLXBF_I2C_SMBUS_OP_CNT_3 +- + struct mlxbf_i2c_smbus_request { + u8 slave; + u8 operation_cnt; +@@ -364,24 +397,38 @@ struct mlxbf_i2c_resource { + u8 type; + }; + +-/* List of chip resources that are being accessed by the driver. */ +-enum { +- MLXBF_I2C_SMBUS_RES, +- MLXBF_I2C_MST_CAUSE_RES, +- MLXBF_I2C_SLV_CAUSE_RES, +- MLXBF_I2C_COALESCE_RES, +- MLXBF_I2C_COREPLL_RES, +- MLXBF_I2C_GPIO_RES, +- MLXBF_I2C_END_RES, ++struct mlxbf_i2c_chip_info { ++ enum mlxbf_i2c_chip_type type; ++ /* Chip shared resources that are being used by the I2C controller. */ ++ struct mlxbf_i2c_resource *shared_res[MLXBF_I2C_SHARED_RES_MAX]; ++ ++ /* Callback to calculate the core PLL frequency. */ ++ u64 (*calculate_freq)(struct mlxbf_i2c_resource *corepll_res); ++ ++ /* Registers' address offset */ ++ u32 smbus_master_rs_bytes_off; ++ u32 smbus_master_fsm_off; + }; + +-/* Helper macro to define an I2C resource parameters. */ +-#define MLXBF_I2C_RES_PARAMS(addr, size, str) \ +- { \ +- .start = (addr), \ +- .end = (addr) + (size) - 1, \ +- .name = (str) \ +- } ++struct mlxbf_i2c_priv { ++ const struct mlxbf_i2c_chip_info *chip; ++ struct i2c_adapter adap; ++ struct mlxbf_i2c_resource *smbus; ++ struct mlxbf_i2c_resource *timer; ++ struct mlxbf_i2c_resource *mst; ++ struct mlxbf_i2c_resource *slv; ++ struct mlxbf_i2c_resource *mst_cause; ++ struct mlxbf_i2c_resource *slv_cause; ++ struct mlxbf_i2c_resource *coalesce; ++ u64 frequency; /* Core frequency in Hz. */ ++ int bus; /* Physical bus identifier. */ ++ int irq; ++ struct i2c_client *slave[MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT]; ++ u32 resource_version; ++}; ++ ++/* Core PLL frequency. */ ++static u64 mlxbf_i2c_corepll_frequency; + + static struct resource mlxbf_i2c_coalesce_tyu_params = + MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COALESCE_TYU_ADDR, +@@ -395,6 +442,10 @@ static struct resource mlxbf_i2c_corepll_yu_params = + MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COREPLL_YU_ADDR, + MLXBF_I2C_COREPLL_YU_SIZE, + "COREPLL_MEM"); ++static struct resource mlxbf_i2c_corepll_rsh_yu_params = ++ MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COREPLL_RSH_YU_ADDR, ++ MLXBF_I2C_COREPLL_RSH_YU_SIZE, ++ "COREPLL_MEM"); + static struct resource mlxbf_i2c_gpio_tyu_params = + MLXBF_I2C_RES_PARAMS(MLXBF_I2C_GPIO_TYU_ADDR, + MLXBF_I2C_GPIO_TYU_SIZE, +@@ -404,34 +455,6 @@ static struct mutex mlxbf_i2c_coalesce_lock; + static struct mutex mlxbf_i2c_corepll_lock; + static struct mutex mlxbf_i2c_gpio_lock; + +-/* Mellanox BlueField chip type. */ +-enum mlxbf_i2c_chip_type { +- MLXBF_I2C_CHIP_TYPE_1, /* Mellanox BlueField-1 chip. */ +- MLXBF_I2C_CHIP_TYPE_2, /* Mallanox BlueField-2 chip. */ +-}; +- +-struct mlxbf_i2c_chip_info { +- enum mlxbf_i2c_chip_type type; +- /* Chip shared resources that are being used by the I2C controller. */ +- struct mlxbf_i2c_resource *shared_res[MLXBF_I2C_SHARED_RES_MAX]; +- +- /* Callback to calculate the core PLL frequency. */ +- u64 (*calculate_freq)(struct mlxbf_i2c_resource *corepll_res); +-}; +- +-struct mlxbf_i2c_priv { +- const struct mlxbf_i2c_chip_info *chip; +- struct i2c_adapter adap; +- struct mlxbf_i2c_resource *smbus; +- struct mlxbf_i2c_resource *mst_cause; +- struct mlxbf_i2c_resource *slv_cause; +- struct mlxbf_i2c_resource *coalesce; +- u64 frequency; /* Core frequency in Hz. */ +- int bus; /* Physical bus identifier. */ +- int irq; +- struct i2c_client *slave[MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT]; +-}; +- + static struct mlxbf_i2c_resource mlxbf_i2c_coalesce_res[] = { + [MLXBF_I2C_CHIP_TYPE_1] = { + .params = &mlxbf_i2c_coalesce_tyu_params, +@@ -451,6 +474,11 @@ static struct mlxbf_i2c_resource mlxbf_i2c_corepll_res[] = { + .params = &mlxbf_i2c_corepll_yu_params, + .lock = &mlxbf_i2c_corepll_lock, + .type = MLXBF_I2C_COREPLL_RES, ++ }, ++ [MLXBF_I2C_CHIP_TYPE_3] = { ++ .params = &mlxbf_i2c_corepll_rsh_yu_params, ++ .lock = &mlxbf_i2c_corepll_lock, ++ .type = MLXBF_I2C_COREPLL_RES, + } + }; + +@@ -467,24 +495,13 @@ static u8 mlxbf_i2c_bus_count; + + static struct mutex mlxbf_i2c_bus_lock; + +-/* Polling frequency in microseconds. */ +-#define MLXBF_I2C_POLL_FREQ_IN_USEC 200 +- +-#define MLXBF_I2C_SHIFT_0 0 +-#define MLXBF_I2C_SHIFT_8 8 +-#define MLXBF_I2C_SHIFT_16 16 +-#define MLXBF_I2C_SHIFT_24 24 +- +-#define MLXBF_I2C_MASK_8 GENMASK(7, 0) +-#define MLXBF_I2C_MASK_16 GENMASK(15, 0) +- + /* + * Function to poll a set of bits at a specific address; it checks whether + * the bits are equal to zero when eq_zero is set to 'true', and not equal + * to zero when eq_zero is set to 'false'. + * Note that the timeout is given in microseconds. + */ +-static u32 mlxbf_smbus_poll(void __iomem *io, u32 addr, u32 mask, ++static u32 mlxbf_i2c_poll(void __iomem *io, u32 addr, u32 mask, + bool eq_zero, u32 timeout) + { + u32 bits; +@@ -506,13 +523,13 @@ static u32 mlxbf_smbus_poll(void __iomem *io, u32 addr, u32 mask, + * a transaction. Accordingly, this function polls the Master FSM stop + * bit; it returns false when the bit is asserted, true if not. + */ +-static bool mlxbf_smbus_master_wait_for_idle(struct mlxbf_i2c_priv *priv) ++static bool mlxbf_i2c_smbus_master_wait_for_idle(struct mlxbf_i2c_priv *priv) + { + u32 mask = MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK; +- u32 addr = MLXBF_I2C_SMBUS_MASTER_FSM; ++ u32 addr = priv->chip->smbus_master_fsm_off; + u32 timeout = MLXBF_I2C_SMBUS_TIMEOUT; + +- if (mlxbf_smbus_poll(priv->smbus->io, addr, mask, true, timeout)) ++ if (mlxbf_i2c_poll(priv->mst->io, addr, mask, true, timeout)) + return true; + + return false; +@@ -523,7 +540,7 @@ static bool mlxbf_smbus_master_wait_for_idle(struct mlxbf_i2c_priv *priv) + */ + static bool mlxbf_i2c_smbus_master_lock(struct mlxbf_i2c_priv *priv) + { +- if (mlxbf_smbus_poll(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_GW, ++ if (mlxbf_i2c_poll(priv->mst->io, MLXBF_I2C_SMBUS_MASTER_GW, + MLXBF_I2C_MASTER_LOCK_BIT, true, + MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT)) + return true; +@@ -534,7 +551,7 @@ static bool mlxbf_i2c_smbus_master_lock(struct mlxbf_i2c_priv *priv) + static void mlxbf_i2c_smbus_master_unlock(struct mlxbf_i2c_priv *priv) + { + /* Clear the gw to clear the lock */ +- writel(0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_GW); ++ writel(0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW); + } + + static bool mlxbf_i2c_smbus_transaction_success(u32 master_status, +@@ -574,7 +591,7 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv) + * then read the cause and master status bits to determine if + * errors occurred during the transaction. + */ +- mlxbf_smbus_poll(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_GW, ++ mlxbf_i2c_poll(priv->mst->io, MLXBF_I2C_SMBUS_MASTER_GW, + MLXBF_I2C_MASTER_BUSY_BIT, true, + MLXBF_I2C_SMBUS_TIMEOUT); + +@@ -587,7 +604,7 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv) + * Parse both Cause and Master GW bits, then return transaction status. + */ + +- master_status_bits = readl(priv->smbus->io + ++ master_status_bits = readl(priv->mst->io + + MLXBF_I2C_SMBUS_MASTER_STATUS); + master_status_bits &= MLXBF_I2C_SMBUS_MASTER_STATUS_MASK; + +@@ -612,7 +629,8 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv) + } + + static void mlxbf_i2c_smbus_write_data(struct mlxbf_i2c_priv *priv, +- const u8 *data, u8 length, u32 addr) ++ const u8 *data, u8 length, u32 addr, ++ bool is_master) + { + u8 offset, aligned_length; + u32 data32; +@@ -629,12 +647,16 @@ static void mlxbf_i2c_smbus_write_data(struct mlxbf_i2c_priv *priv, + */ + for (offset = 0; offset < aligned_length; offset += sizeof(u32)) { + data32 = *((u32 *)(data + offset)); +- iowrite32be(data32, priv->smbus->io + addr + offset); ++ if (is_master) ++ iowrite32be(data32, priv->mst->io + addr + offset); ++ else ++ iowrite32be(data32, priv->slv->io + addr + offset); + } + } + + static void mlxbf_i2c_smbus_read_data(struct mlxbf_i2c_priv *priv, +- u8 *data, u8 length, u32 addr) ++ u8 *data, u8 length, u32 addr, ++ bool is_master) + { + u32 data32, mask; + u8 byte, offset; +@@ -650,14 +672,20 @@ static void mlxbf_i2c_smbus_read_data(struct mlxbf_i2c_priv *priv, + */ + + for (offset = 0; offset < (length & ~mask); offset += sizeof(u32)) { +- data32 = ioread32be(priv->smbus->io + addr + offset); ++ if (is_master) ++ data32 = ioread32be(priv->mst->io + addr + offset); ++ else ++ data32 = ioread32be(priv->slv->io + addr + offset); + *((u32 *)(data + offset)) = data32; + } + + if (!(length & mask)) + return; + +- data32 = ioread32be(priv->smbus->io + addr + offset); ++ if (is_master) ++ data32 = ioread32be(priv->mst->io + addr + offset); ++ else ++ data32 = ioread32be(priv->slv->io + addr + offset); + + for (byte = 0; byte < (length & mask); byte++) { + data[offset + byte] = data32 & GENMASK(7, 0); +@@ -683,16 +711,16 @@ static int mlxbf_i2c_smbus_enable(struct mlxbf_i2c_priv *priv, u8 slave, + command |= rol32(pec_en, MLXBF_I2C_MASTER_SEND_PEC_SHIFT); + + /* Clear status bits. */ +- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_STATUS); ++ writel(0x0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_STATUS); + /* Set the cause data. */ + writel(~0x0, priv->mst_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR); + /* Zero PEC byte. */ +- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_PEC); ++ writel(0x0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_PEC); + /* Zero byte count. */ +- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_RS_BYTES); ++ writel(0x0, priv->mst->io + priv->chip->smbus_master_rs_bytes_off); + + /* GW activation. */ +- writel(command, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_GW); ++ writel(command, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW); + + /* + * Poll master status and check status bits. An ACK is sent when +@@ -736,7 +764,7 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, + return -EBUSY; + + /* Check whether the HW is idle */ +- if (WARN_ON(!mlxbf_smbus_master_wait_for_idle(priv))) { ++ if (WARN_ON(!mlxbf_i2c_smbus_master_wait_for_idle(priv))) { + ret = -EBUSY; + goto out_unlock; + } +@@ -793,7 +821,7 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, + * must be written to the data registers. + */ + mlxbf_i2c_smbus_write_data(priv, (const u8 *)data_desc, data_len, +- MLXBF_I2C_MASTER_DATA_DESC_ADDR); ++ MLXBF_I2C_MASTER_DATA_DESC_ADDR, true); + + if (write_en) { + ret = mlxbf_i2c_smbus_enable(priv, slave, write_len, block_en, +@@ -805,13 +833,13 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, + if (read_en) { + /* Write slave address to Master GW data descriptor. */ + mlxbf_i2c_smbus_write_data(priv, (const u8 *)&addr, 1, +- MLXBF_I2C_MASTER_DATA_DESC_ADDR); ++ MLXBF_I2C_MASTER_DATA_DESC_ADDR, true); + ret = mlxbf_i2c_smbus_enable(priv, slave, read_len, block_en, + pec_en, 1); + if (!ret) { + /* Get Master GW data descriptor. */ + mlxbf_i2c_smbus_read_data(priv, data_desc, read_len + 1, +- MLXBF_I2C_MASTER_DATA_DESC_ADDR); ++ MLXBF_I2C_MASTER_DATA_DESC_ADDR, true); + + /* Get data from Master GW data descriptor. */ + memcpy(read_buf, data_desc, read_len + 1); +@@ -823,7 +851,7 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, + * next tag integration. + */ + writel(MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK, +- priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_FSM); ++ priv->mst->io + priv->chip->smbus_master_fsm_off); + } + + out_unlock: +@@ -1115,7 +1143,7 @@ static void mlxbf_i2c_set_timings(struct mlxbf_i2c_priv *priv, + timer |= mlxbf_i2c_set_timer(priv, timings->scl_low, + false, MLXBF_I2C_MASK_16, + MLXBF_I2C_SHIFT_16); +- writel(timer, priv->smbus->io + ++ writel(timer, priv->timer->io + + MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH); + + timer = mlxbf_i2c_set_timer(priv, timings->sda_rise, false, +@@ -1126,34 +1154,34 @@ static void mlxbf_i2c_set_timings(struct mlxbf_i2c_priv *priv, + MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_16); + timer |= mlxbf_i2c_set_timer(priv, timings->scl_fall, false, + MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_24); +- writel(timer, priv->smbus->io + ++ writel(timer, priv->timer->io + + MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE); + + timer = mlxbf_i2c_set_timer(priv, timings->hold_start, true, + MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); + timer |= mlxbf_i2c_set_timer(priv, timings->hold_data, true, + MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); +- writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_TIMER_THOLD); ++ writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_TIMER_THOLD); + + timer = mlxbf_i2c_set_timer(priv, timings->setup_start, true, + MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); + timer |= mlxbf_i2c_set_timer(priv, timings->setup_stop, true, + MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); +- writel(timer, priv->smbus->io + ++ writel(timer, priv->timer->io + + MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP); + + timer = mlxbf_i2c_set_timer(priv, timings->setup_data, true, + MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); +- writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA); ++ writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA); + + timer = mlxbf_i2c_set_timer(priv, timings->buf, false, + MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); + timer |= mlxbf_i2c_set_timer(priv, timings->thigh_max, false, + MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); +- writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_THIGH_MAX_TBUF); ++ writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_THIGH_MAX_TBUF); + + timer = timings->timeout; +- writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT); ++ writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT); + } + + enum mlxbf_i2c_timings_config { +@@ -1565,7 +1593,7 @@ static int mlxbf_i2c_slave_enable(struct mlxbf_i2c_priv *priv, + * Look for the next available slave register slot. + */ + for (reg = 0; reg < reg_cnt; reg++) { +- slave_reg = readl(priv->smbus->io + ++ slave_reg = readl(priv->slv->io + + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4); + /* + * Each register holds 4 slave addresses. So, we have to keep +@@ -1587,7 +1615,7 @@ static int mlxbf_i2c_slave_enable(struct mlxbf_i2c_priv *priv, + slave_reg &= ~(MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK << (byte * 8)); + slave_reg |= (slave->addr << (byte * 8)); + slave_reg |= MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT << (byte * 8); +- writel(slave_reg, priv->smbus->io + ++ writel(slave_reg, priv->slv->io + + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + + (reg * 0x4)); + +@@ -1622,7 +1650,7 @@ static int mlxbf_i2c_slave_disable(struct mlxbf_i2c_priv *priv, u8 addr) + * Check if addr is present in the registers. + */ + for (reg = 0; reg < reg_cnt; reg++) { +- slave_reg = readl(priv->smbus->io + ++ slave_reg = readl(priv->slv->io + + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4); + + /* Check whether the address slots are empty. */ +@@ -1643,7 +1671,7 @@ static int mlxbf_i2c_slave_disable(struct mlxbf_i2c_priv *priv, u8 addr) + if (addr_tmp == addr) { + /* Clear the slave address slot. */ + slave_reg &= ~(GENMASK(7, 0) << (byte * 8)); +- writel(slave_reg, priv->smbus->io + ++ writel(slave_reg, priv->slv->io + + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + + (reg * 0x4)); + /* Free slave at the corresponding index */ +@@ -1747,7 +1775,7 @@ static int mlxbf_i2c_init_slave(struct platform_device *pdev, + int ret; + + /* Reset FSM. */ +- writel(0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_FSM); ++ writel(0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_FSM); + + /* + * Enable slave cause interrupt bits. Drive +@@ -1762,7 +1790,7 @@ static int mlxbf_i2c_init_slave(struct platform_device *pdev, + writel(int_reg, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_EVTEN0); + + /* Finally, set the 'ready' bit to start handling transactions. */ +- writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY); ++ writel(0x1, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_READY); + + /* Initialize the cause coalesce resource. */ + ret = mlxbf_i2c_init_coalesce(pdev, priv); +@@ -1807,13 +1835,13 @@ static bool mlxbf_i2c_has_coalesce(struct mlxbf_i2c_priv *priv, bool *read, + return true; + } + +-static bool mlxbf_smbus_slave_wait_for_idle(struct mlxbf_i2c_priv *priv, ++static bool mlxbf_i2c_slave_wait_for_idle(struct mlxbf_i2c_priv *priv, + u32 timeout) + { + u32 mask = MLXBF_I2C_CAUSE_S_GW_BUSY_FALL; + u32 addr = MLXBF_I2C_CAUSE_ARBITER; + +- if (mlxbf_smbus_poll(priv->slv_cause->io, addr, mask, false, timeout)) ++ if (mlxbf_i2c_poll(priv->slv_cause->io, addr, mask, false, timeout)) + return true; + + return false; +@@ -1852,7 +1880,7 @@ static int mlxbf_i2c_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) + * determine the slave address. This byte is located in the + * first data descriptor register of the slave GW. + */ +- data32 = ioread32be(priv->smbus->io + ++ data32 = ioread32be(priv->slv->io + + MLXBF_I2C_SLAVE_DATA_DESC_ADDR); + addr = (data32 & GENMASK(7, 0)) >> 1; + +@@ -1906,7 +1934,7 @@ static int mlxbf_i2c_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) + + /* Write data to Slave GW data descriptor. */ + mlxbf_i2c_smbus_write_data(priv, data_desc, byte_cnt, +- MLXBF_I2C_SLAVE_DATA_DESC_ADDR); ++ MLXBF_I2C_SLAVE_DATA_DESC_ADDR, false); + + pec_en = 0; /* Disable PEC since it is not supported. */ + +@@ -1915,19 +1943,19 @@ static int mlxbf_i2c_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) + control32 |= rol32(write_size, MLXBF_I2C_SLAVE_WRITE_BYTES_SHIFT); + control32 |= rol32(pec_en, MLXBF_I2C_SLAVE_SEND_PEC_SHIFT); + +- writel(control32, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_GW); ++ writel(control32, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_GW); + + /* + * Wait until the transfer is completed; the driver will wait + * until the GW is idle, a cause will rise on fall of GW busy. + */ +- mlxbf_smbus_slave_wait_for_idle(priv, MLXBF_I2C_SMBUS_TIMEOUT); ++ mlxbf_i2c_slave_wait_for_idle(priv, MLXBF_I2C_SMBUS_TIMEOUT); + + clear_csr: + /* Release the Slave GW. */ +- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); +- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC); +- writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY); ++ writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); ++ writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_PEC); ++ writel(0x1, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_READY); + + return ret; + } +@@ -1945,7 +1973,7 @@ static int mlxbf_i2c_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes) + + /* Read data from Slave GW data descriptor. */ + mlxbf_i2c_smbus_read_data(priv, data_desc, recv_bytes, +- MLXBF_I2C_SLAVE_DATA_DESC_ADDR); ++ MLXBF_I2C_SLAVE_DATA_DESC_ADDR, false); + addr = data_desc[0] >> 1; + + /* +@@ -1981,9 +2009,9 @@ static int mlxbf_i2c_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes) + + clear_csr: + /* Release the Slave GW. */ +- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); +- writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC); +- writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY); ++ writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); ++ writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_PEC); ++ writel(0x1, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_READY); + + return ret; + } +@@ -2018,7 +2046,7 @@ static irqreturn_t mlxbf_i2c_irq(int irq, void *ptr) + * slave, if the higher 8 bits are sent then the slave expect N bytes + * from the master. + */ +- rw_bytes_reg = readl(priv->smbus->io + ++ rw_bytes_reg = readl(priv->slv->io + + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); + recv_bytes = (rw_bytes_reg >> 8) & GENMASK(7, 0); + +@@ -2183,14 +2211,27 @@ static struct mlxbf_i2c_chip_info mlxbf_i2c_chip[] = { + [1] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_1], + [2] = &mlxbf_i2c_gpio_res[MLXBF_I2C_CHIP_TYPE_1] + }, +- .calculate_freq = mlxbf_i2c_calculate_freq_from_tyu ++ .calculate_freq = mlxbf_i2c_calculate_freq_from_tyu, ++ .smbus_master_rs_bytes_off = MLXBF_I2C_YU_SMBUS_RS_BYTES, ++ .smbus_master_fsm_off = MLXBF_I2C_YU_SMBUS_MASTER_FSM + }, + [MLXBF_I2C_CHIP_TYPE_2] = { + .type = MLXBF_I2C_CHIP_TYPE_2, + .shared_res = { + [0] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_2] + }, +- .calculate_freq = mlxbf_i2c_calculate_freq_from_yu ++ .calculate_freq = mlxbf_i2c_calculate_freq_from_yu, ++ .smbus_master_rs_bytes_off = MLXBF_I2C_YU_SMBUS_RS_BYTES, ++ .smbus_master_fsm_off = MLXBF_I2C_YU_SMBUS_MASTER_FSM ++ }, ++ [MLXBF_I2C_CHIP_TYPE_3] = { ++ .type = MLXBF_I2C_CHIP_TYPE_3, ++ .shared_res = { ++ [0] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_3] ++ }, ++ .calculate_freq = mlxbf_i2c_calculate_freq_from_yu, ++ .smbus_master_rs_bytes_off = MLXBF_I2C_RSH_YU_SMBUS_RS_BYTES, ++ .smbus_master_fsm_off = MLXBF_I2C_RSH_YU_SMBUS_MASTER_FSM + } + }; + +@@ -2215,6 +2256,10 @@ static const struct of_device_id mlxbf_i2c_dt_ids[] = { + .compatible = "mellanox,i2c-mlxbf2", + .data = &mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_2] + }, ++ { ++ .compatible = "mellanox,i2c-mlxbf3", ++ .data = &mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_3] ++ }, + {}, + }; + +@@ -2224,6 +2269,7 @@ MODULE_DEVICE_TABLE(of, mlxbf_i2c_dt_ids); + static const struct acpi_device_id mlxbf_i2c_acpi_ids[] = { + { "MLNXBF03", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_1] }, + { "MLNXBF23", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_2] }, ++ { "MLNXBF31", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_3] }, + {}, + }; + +@@ -2299,6 +2345,7 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct mlxbf_i2c_priv *priv; + struct i2c_adapter *adap; ++ u32 resource_version; + int irq, ret; + + priv = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_priv), GFP_KERNEL); +@@ -2312,11 +2359,60 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) + if (ret < 0) + return ret; + +- ret = mlxbf_i2c_init_resource(pdev, &priv->smbus, +- MLXBF_I2C_SMBUS_RES); +- if (ret < 0) { +- dev_err(dev, "Cannot fetch smbus resource info"); +- return ret; ++ /* This property allows the driver to stay backward compatible with older ++ * ACPI table and device trees versions. ++ * Starting BlueField-3 SoC, the "smbus" resource was broken down into 3 ++ * separate resources "timer", "master" and "slave". ++ */ ++ if (device_property_read_u32(dev, "resource_version", &resource_version)) ++ resource_version = 0; ++ ++ priv->resource_version = resource_version; ++ ++ if (priv->chip->type < MLXBF_I2C_CHIP_TYPE_3 && resource_version == 0) { ++ priv->timer = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), GFP_KERNEL); ++ if (!priv->timer) ++ return -ENOMEM; ++ ++ priv->mst = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), GFP_KERNEL); ++ if (!priv->mst) ++ return -ENOMEM; ++ ++ priv->slv = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), GFP_KERNEL); ++ if (!priv->slv) ++ return -ENOMEM; ++ ++ ret = mlxbf_i2c_init_resource(pdev, &priv->smbus, ++ MLXBF_I2C_SMBUS_RES); ++ if (ret < 0) { ++ dev_err(dev, "Cannot fetch smbus resource info"); ++ return ret; ++ } ++ ++ priv->timer->io = priv->smbus->io; ++ priv->mst->io = priv->smbus->io + MLXBF_I2C_MST_ADDR_OFFSET; ++ priv->slv->io = priv->smbus->io + MLXBF_I2C_SLV_ADDR_OFFSET; ++ } else { ++ ret = mlxbf_i2c_init_resource(pdev, &priv->timer, ++ MLXBF_I2C_SMBUS_TIMER_RES); ++ if (ret < 0) { ++ dev_err(dev, "Cannot fetch timer resource info"); ++ return ret; ++ } ++ ++ ret = mlxbf_i2c_init_resource(pdev, &priv->mst, ++ MLXBF_I2C_SMBUS_MST_RES); ++ if (ret < 0) { ++ dev_err(dev, "Cannot fetch master resource info"); ++ return ret; ++ } ++ ++ ret = mlxbf_i2c_init_resource(pdev, &priv->slv, ++ MLXBF_I2C_SMBUS_SLV_RES); ++ if (ret < 0) { ++ dev_err(dev, "Cannot fetch slave resource info"); ++ return ret; ++ } + } + + ret = mlxbf_i2c_init_resource(pdev, &priv->mst_cause, +@@ -2404,8 +2500,19 @@ static int mlxbf_i2c_remove(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct resource *params; + +- params = priv->smbus->params; +- devm_release_mem_region(dev, params->start, resource_size(params)); ++ if (priv->chip->type < MLXBF_I2C_CHIP_TYPE_3 && priv->resource_version == 0) { ++ params = priv->smbus->params; ++ devm_release_mem_region(dev, params->start, resource_size(params)); ++ } else { ++ params = priv->timer->params; ++ devm_release_mem_region(dev, params->start, resource_size(params)); ++ ++ params = priv->mst->params; ++ devm_release_mem_region(dev, params->start, resource_size(params)); ++ ++ params = priv->slv->params; ++ devm_release_mem_region(dev, params->start, resource_size(params)); ++ } + + params = priv->mst_cause->params; + devm_release_mem_region(dev, params->start, resource_size(params)); +-- +2.20.1 + diff --git a/patch/0208-i2c-mlxbf-remove-device-tree-support.patch b/patch/0208-i2c-mlxbf-remove-device-tree-support.patch new file mode 100644 index 000000000..c2642e7a9 --- /dev/null +++ b/patch/0208-i2c-mlxbf-remove-device-tree-support.patch @@ -0,0 +1,211 @@ +From e2f59de3801d0899bb4622079b2d927aaf2404b7 Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Tue, 27 Sep 2022 16:39:24 -0400 +Subject: [PATCH backport 5.10 09/63] i2c: mlxbf: remove device tree support + +BugLink: https://bugs.launchpad.net/bugs/1991551 + +BlueField customers have to use the BlueField firmware with +UEFI ACPI tables so there is no need to have device tree +support in the i2c-mlxbf.c driver. Remove the device tree +binding documentation as well. + +Signed-off-by: Asmaa Mnebhi +Reviewed-by: Khalil Blaiech +Signed-off-by: Wolfram Sang +(cherry picked from commit be18c5ede25da39a0eda541f6de3620a30cf731f) +Signed-off-by: Asmaa Mnebhi +Acked-by: Tim Gardner +Acked-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + .../bindings/i2c/mellanox,i2c-mlxbf.yaml | 78 ------------------- + MAINTAINERS | 1 - + drivers/i2c/busses/i2c-mlxbf.c | 49 +----------- + 3 files changed, 1 insertion(+), 127 deletions(-) + delete mode 100644 Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml + +diff --git a/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml b/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml +deleted file mode 100644 +index d2b401d06..000000000 +--- a/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml ++++ /dev/null +@@ -1,78 +0,0 @@ +-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +-%YAML 1.2 +---- +-$id: http://devicetree.org/schemas/i2c/mellanox,i2c-mlxbf.yaml# +-$schema: http://devicetree.org/meta-schemas/core.yaml# +- +-title: Mellanox I2C SMBus on BlueField SoCs +- +-maintainers: +- - Khalil Blaiech +- +-allOf: +- - $ref: /schemas/i2c/i2c-controller.yaml# +- +-properties: +- compatible: +- enum: +- - mellanox,i2c-mlxbf1 +- - mellanox,i2c-mlxbf2 +- +- reg: +- minItems: 3 +- maxItems: 4 +- items: +- - description: Smbus block registers +- - description: Cause master registers +- - description: Cause slave registers +- - description: Cause coalesce registers +- +- interrupts: +- maxItems: 1 +- +- clock-frequency: +- enum: [ 100000, 400000, 1000000 ] +- description: +- bus frequency used to configure timing registers; +- The frequency is expressed in Hz. Default is 100000. +- +-required: +- - compatible +- - reg +- - interrupts +- +-unevaluatedProperties: false +- +-if: +- properties: +- compatible: +- contains: +- enum: +- - mellanox,i2c-mlxbf1 +- +-then: +- properties: +- reg: +- maxItems: 3 +- +-examples: +- - | +- i2c@2804000 { +- compatible = "mellanox,i2c-mlxbf1"; +- reg = <0x02804000 0x800>, +- <0x02801200 0x020>, +- <0x02801260 0x020>; +- interrupts = <57>; +- clock-frequency = <100000>; +- }; +- +- - | +- i2c@2808800 { +- compatible = "mellanox,i2c-mlxbf2"; +- reg = <0x02808800 0x600>, +- <0x02808e00 0x020>, +- <0x02808e20 0x020>, +- <0x02808e40 0x010>; +- interrupts = <57>; +- clock-frequency = <400000>; +- }; +diff --git a/MAINTAINERS b/MAINTAINERS +index f6a974ade..1d43cd482 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -11178,7 +11178,6 @@ M: Khalil Blaiech + M: Asmaa Mnebhi + L: linux-i2c@vger.kernel.org + S: Supported +-F: Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml + F: drivers/i2c/busses/i2c-mlxbf.c + + MELLANOX ETHERNET DRIVER (mlx4_en) +diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c +index 75d8d00d1..67548702f 100644 +--- a/drivers/i2c/busses/i2c-mlxbf.c ++++ b/drivers/i2c/busses/i2c-mlxbf.c +@@ -2247,24 +2247,6 @@ static struct i2c_adapter_quirks mlxbf_i2c_quirks = { + .max_write_len = MLXBF_I2C_MASTER_DATA_W_LENGTH, + }; + +-static const struct of_device_id mlxbf_i2c_dt_ids[] = { +- { +- .compatible = "mellanox,i2c-mlxbf1", +- .data = &mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_1] +- }, +- { +- .compatible = "mellanox,i2c-mlxbf2", +- .data = &mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_2] +- }, +- { +- .compatible = "mellanox,i2c-mlxbf3", +- .data = &mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_3] +- }, +- {}, +-}; +- +-MODULE_DEVICE_TABLE(of, mlxbf_i2c_dt_ids); +- + #ifdef CONFIG_ACPI + static const struct acpi_device_id mlxbf_i2c_acpi_ids[] = { + { "MLNXBF03", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_1] }, +@@ -2315,31 +2297,6 @@ static int mlxbf_i2c_acpi_probe(struct device *dev, struct mlxbf_i2c_priv *priv) + } + #endif /* CONFIG_ACPI */ + +-static int mlxbf_i2c_of_probe(struct device *dev, struct mlxbf_i2c_priv *priv) +-{ +- const struct of_device_id *oid; +- int bus_id = -1; +- +- if (IS_ENABLED(CONFIG_OF) && dev->of_node) { +- oid = of_match_node(mlxbf_i2c_dt_ids, dev->of_node); +- if (!oid) +- return -ENODEV; +- +- priv->chip = oid->data; +- +- bus_id = of_alias_get_id(dev->of_node, "i2c"); +- if (bus_id >= 0) +- priv->bus = bus_id; +- } +- +- if (bus_id < 0) { +- dev_err(dev, "Cannot get bus id"); +- return bus_id; +- } +- +- return 0; +-} +- + static int mlxbf_i2c_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -2353,14 +2310,11 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) + return -ENOMEM; + + ret = mlxbf_i2c_acpi_probe(dev, priv); +- if (ret < 0 && ret != -ENOENT && ret != -ENXIO) +- ret = mlxbf_i2c_of_probe(dev, priv); +- + if (ret < 0) + return ret; + + /* This property allows the driver to stay backward compatible with older +- * ACPI table and device trees versions. ++ * ACPI tables. + * Starting BlueField-3 SoC, the "smbus" resource was broken down into 3 + * separate resources "timer", "master" and "slave". + */ +@@ -2544,7 +2498,6 @@ static struct platform_driver mlxbf_i2c_driver = { + .remove = mlxbf_i2c_remove, + .driver = { + .name = "i2c-mlxbf", +- .of_match_table = mlxbf_i2c_dt_ids, + #ifdef CONFIG_ACPI + .acpi_match_table = ACPI_PTR(mlxbf_i2c_acpi_ids), + #endif /* CONFIG_ACPI */ +-- +2.20.1 + diff --git a/patch/0209-UBUNTU-SAUCE-i2c-mlxbf.c-Add-driver-version.patch b/patch/0209-UBUNTU-SAUCE-i2c-mlxbf.c-Add-driver-version.patch new file mode 100644 index 000000000..50e96af71 --- /dev/null +++ b/patch/0209-UBUNTU-SAUCE-i2c-mlxbf.c-Add-driver-version.patch @@ -0,0 +1,37 @@ +From c78abc95294213920e386abb941df6e23ba1ede3 Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Tue, 11 Oct 2022 14:28:57 -0400 +Subject: [PATCH backport 5.10 10/63] UBUNTU: SAUCE: i2c-mlxbf.c: Add driver + version + +BugLink: https://bugs.launchpad.net/bugs/1991551 + +Signed-off-by: Asmaa Mnebhi +Acked-by: Tim Gardner +Acked-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/i2c/busses/i2c-mlxbf.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c +index 67548702f..0eb92bbc1 100644 +--- a/drivers/i2c/busses/i2c-mlxbf.c ++++ b/drivers/i2c/busses/i2c-mlxbf.c +@@ -19,6 +19,8 @@ + #include + #include + ++#define DRV_VERSION "3.2" ++ + /* Defines what functionality is present. */ + #define MLXBF_I2C_FUNC_SMBUS_BLOCK \ + (I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL) +@@ -2532,3 +2534,4 @@ MODULE_DESCRIPTION("Mellanox BlueField I2C bus driver"); + MODULE_AUTHOR("Khalil Blaiech "); + MODULE_AUTHOR("Asmaa Mnebhi "); + MODULE_LICENSE("GPL v2"); ++MODULE_VERSION(DRV_VERSION); +-- +2.20.1 + diff --git a/patch/0210-platform-mellanox-Typo-fix-in-the-file-mlxbf-bootctl.patch b/patch/0210-platform-mellanox-Typo-fix-in-the-file-mlxbf-bootctl.patch new file mode 100644 index 000000000..43b606c26 --- /dev/null +++ b/patch/0210-platform-mellanox-Typo-fix-in-the-file-mlxbf-bootctl.patch @@ -0,0 +1,32 @@ +From 4c700c6b83fa8bf6347537279a0a5134d09cf004 Mon Sep 17 00:00:00 2001 +From: Bhaskar Chowdhury +Date: Wed, 17 Mar 2021 15:26:50 +0530 +Subject: [PATCH backport 5.10 11/63] platform/mellanox: Typo fix in the file + mlxbf-bootctl.c + +s/progamming/programming/ + +Signed-off-by: Bhaskar Chowdhury +Acked-by: Randy Dunlap +Link: https://lore.kernel.org/r/20210317095650.2036419-1-unixbhaskar@gmail.com +Signed-off-by: Hans de Goede +--- + drivers/platform/mellanox/mlxbf-bootctl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/platform/mellanox/mlxbf-bootctl.c b/drivers/platform/mellanox/mlxbf-bootctl.c +index 5d21c6adf..1c7a288b5 100644 +--- a/drivers/platform/mellanox/mlxbf-bootctl.c ++++ b/drivers/platform/mellanox/mlxbf-bootctl.c +@@ -208,7 +208,7 @@ static ssize_t secure_boot_fuse_state_show(struct device *dev, + * 0011 = version 1, 0111 = version 2, 1111 = version 3). Upper 4 bits + * are a thermometer code indicating key programming has completed for + * key n (same encodings as the start bits). This allows for detection +- * of an interruption in the progamming process which has left the key ++ * of an interruption in the programming process which has left the key + * partially programmed (and thus invalid). The process is to burn the + * eFuse for the new key start bit, burn the key eFuses, then burn the + * eFuse for the new key complete bit. +-- +2.20.1 + diff --git a/patch/0211-UBUNTU-SAUCE-platform-mellanox-Updates-to-mlxbf-boot.patch b/patch/0211-UBUNTU-SAUCE-platform-mellanox-Updates-to-mlxbf-boot.patch new file mode 100644 index 000000000..d2f8e5ef2 --- /dev/null +++ b/patch/0211-UBUNTU-SAUCE-platform-mellanox-Updates-to-mlxbf-boot.patch @@ -0,0 +1,1719 @@ +From 988b360c98ef157e37818f5f7db322c129d3dfb9 Mon Sep 17 00:00:00 2001 +From: Shravan Kumar Ramani +Date: Wed, 6 Jul 2022 07:37:22 -0400 +Subject: [PATCH backport 5.10 12/63] UBUNTU: SAUCE: platform/mellanox: Updates + to mlxbf-bootctl + +BugLink: https://launchpad.net/bugs/1980832 + +The driver supports the VPD fields in the EEPROM and exposes +sysfs files for configuring and reading the same. +Also address buffer overflow and exclusion issues. + +Signed-off-by: Shravan Kumar Ramani +Signed-off-by: Ike Panhc +--- + drivers/platform/mellanox/mlxbf-bootctl.c | 1410 ++++++++++++++++++--- + drivers/platform/mellanox/mlxbf-bootctl.h | 88 +- + 2 files changed, 1268 insertions(+), 230 deletions(-) + +diff --git a/drivers/platform/mellanox/mlxbf-bootctl.c b/drivers/platform/mellanox/mlxbf-bootctl.c +index 1c7a288b5..2302e1e09 100644 +--- a/drivers/platform/mellanox/mlxbf-bootctl.c ++++ b/drivers/platform/mellanox/mlxbf-bootctl.c +@@ -1,51 +1,129 @@ +-// SPDX-License-Identifier: GPL-2.0+ ++// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause + /* +- * Mellanox boot control driver ++ * Mellanox boot control driver ++ * This driver provides a sysfs interface for systems management ++ * software to manage reset-time actions. + * +- * This driver provides a sysfs interface for systems management +- * software to manage reset-time actions. ++ * Copyright (C) 2020 Mellanox Technologies. All rights reserved. + * +- * Copyright (C) 2019 Mellanox Technologies ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License v2.0 as published by ++ * the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. + */ + + #include + #include ++#include ++#include + #include + #include +- + #include "mlxbf-bootctl.h" + +-#define MLXBF_BOOTCTL_SB_SECURE_MASK 0x03 +-#define MLXBF_BOOTCTL_SB_TEST_MASK 0x0c ++#define DRIVER_NAME "mlxbf-bootctl" ++#define DRIVER_VERSION "1.5" ++#define DRIVER_DESCRIPTION "Mellanox boot control driver" ++ ++#define SB_MODE_SECURE_MASK 0x03 ++#define SB_MODE_TEST_MASK 0x0c ++#define SB_MODE_DEV_MASK 0x10 + +-#define MLXBF_SB_KEY_NUM 4 ++#define SB_KEY_NUM 4 ++ ++struct boot_name { ++ int value; ++ const char name[12]; ++}; + +-/* UUID used to probe ATF service. */ +-static const char *mlxbf_bootctl_svc_uuid_str = +- "89c036b4-e7d7-11e6-8797-001aca00bfc4"; ++static struct boot_name boot_names[] = { ++ { MLNX_BOOT_EXTERNAL, "external" }, ++ { MLNX_BOOT_EMMC, "emmc" }, ++ { MLNX_BOOT_SWAP_EMMC, "swap_emmc" }, ++ { MLNX_BOOT_EMMC_LEGACY, "emmc_legacy" }, ++ { MLNX_BOOT_NONE, "none" }, ++ { -1, "" } ++}; + +-struct mlxbf_bootctl_name { +- u32 value; +- const char *name; ++enum { ++ SB_LIFECYCLE_PRODUCTION = 0, ++ SB_LIFECYCLE_GA_SECURE = 1, ++ SB_LIFECYCLE_GA_NON_SECURE = 2, ++ SB_LIFECYCLE_RMA = 3 + }; + +-static struct mlxbf_bootctl_name boot_names[] = { +- { MLXBF_BOOTCTL_EXTERNAL, "external" }, +- { MLXBF_BOOTCTL_EMMC, "emmc" }, +- { MLNX_BOOTCTL_SWAP_EMMC, "swap_emmc" }, +- { MLXBF_BOOTCTL_EMMC_LEGACY, "emmc_legacy" }, +- { MLXBF_BOOTCTL_NONE, "none" }, ++static char lifecycle_states[][16] = { ++ [SB_LIFECYCLE_PRODUCTION] = "Production", ++ [SB_LIFECYCLE_GA_SECURE] = "GA Secured", ++ [SB_LIFECYCLE_GA_NON_SECURE] = "GA Non-Secured", ++ [SB_LIFECYCLE_RMA] = "RMA", + }; + +-static const char * const mlxbf_bootctl_lifecycle_states[] = { +- [0] = "Production", +- [1] = "GA Secured", +- [2] = "GA Non-Secured", +- [3] = "RMA", ++/* ctl/data register within the resource. */ ++#define RSH_SCRATCH_BUF_CTL_OFF 0 ++#define RSH_SCRATCH_BUF_DATA_OFF 0x10 ++ ++static void __iomem *rsh_boot_data; ++static void __iomem *rsh_boot_cnt; ++static void __iomem *rsh_semaphore; ++static void __iomem *rsh_scratch_buf_ctl; ++static void __iomem *rsh_scratch_buf_data; ++ ++static int rsh_log_clear_on_read; ++module_param(rsh_log_clear_on_read, int, 0644); ++MODULE_PARM_DESC(rsh_log_clear_on_read, "Clear rshim logging buffer after read."); ++ ++/* ++ * Objects are stored within the MFG partition per type. Type 0 is not ++ * supported. ++ */ ++enum { ++ MLNX_MFG_TYPE_OOB_MAC = 1, ++ MLNX_MFG_TYPE_OPN_0, ++ MLNX_MFG_TYPE_OPN_1, ++ MLNX_MFG_TYPE_OPN_2, ++ MLNX_MFG_TYPE_SKU_0, ++ MLNX_MFG_TYPE_SKU_1, ++ MLNX_MFG_TYPE_SKU_2, ++ MLNX_MFG_TYPE_MODL_0, ++ MLNX_MFG_TYPE_MODL_1, ++ MLNX_MFG_TYPE_MODL_2, ++ MLNX_MFG_TYPE_SN_0, ++ MLNX_MFG_TYPE_SN_1, ++ MLNX_MFG_TYPE_SN_2, ++ MLNX_MFG_TYPE_UUID_0, ++ MLNX_MFG_TYPE_UUID_1, ++ MLNX_MFG_TYPE_UUID_2, ++ MLNX_MFG_TYPE_UUID_3, ++ MLNX_MFG_TYPE_UUID_4, ++ MLNX_MFG_TYPE_REV, + }; + +-/* ARM SMC call which is atomic and no need for lock. */ +-static int mlxbf_bootctl_smc(unsigned int smc_op, int smc_arg) ++/* This mutex is used to serialize MFG write and lock operations. */ ++static DEFINE_MUTEX(mfg_ops_lock); ++ ++#define MLNX_MFG_OOB_MAC_LEN ETH_ALEN ++#define MLNX_MFG_OPN_VAL_LEN 24 ++#define MLNX_MFG_SKU_VAL_LEN 24 ++#define MLNX_MFG_MODL_VAL_LEN 24 ++#define MLNX_MFG_SN_VAL_LEN 24 ++#define MLNX_MFG_UUID_VAL_LEN 40 ++#define MLNX_MFG_REV_VAL_LEN 8 ++#define MLNX_MFG_VAL_QWORD_CNT(type) \ ++ (MLNX_MFG_##type##_VAL_LEN / sizeof(u64)) ++ ++/* ++ * The MAC address consists of 6 bytes (2 digits each) separated by ':'. ++ * The expected format is: "XX:XX:XX:XX:XX:XX" ++ */ ++#define MLNX_MFG_OOB_MAC_FORMAT_LEN \ ++ ((MLNX_MFG_OOB_MAC_LEN * 2) + (MLNX_MFG_OOB_MAC_LEN - 1)) ++ ++/* The SMC calls in question are atomic, so we don't have to lock here. */ ++static int smc_call1(unsigned int smc_op, int smc_arg) + { + struct arm_smccc_res res; + +@@ -54,268 +132,1212 @@ static int mlxbf_bootctl_smc(unsigned int smc_op, int smc_arg) + return res.a0; + } + +-/* Return the action in integer or an error code. */ +-static int mlxbf_bootctl_reset_action_to_val(const char *action) ++/* Syntactic sugar to avoid having to specify an unused argument. */ ++#define smc_call0(smc_op) smc_call1(smc_op, 0) ++ ++static int reset_action_to_val(const char *action, size_t len) + { +- int i; ++ struct boot_name *bn; ++ ++ /* Accept string either with or without a newline terminator */ ++ if (action[len-1] == '\n') ++ --len; + +- for (i = 0; i < ARRAY_SIZE(boot_names); i++) +- if (sysfs_streq(boot_names[i].name, action)) +- return boot_names[i].value; ++ for (bn = boot_names; bn->value >= 0; ++bn) ++ if (strncmp(bn->name, action, len) == 0) ++ break; + +- return -EINVAL; ++ return bn->value; + } + +-/* Return the action in string. */ +-static const char *mlxbf_bootctl_action_to_string(int action) ++static const char *reset_action_to_string(int action) + { +- int i; ++ struct boot_name *bn; + +- for (i = 0; i < ARRAY_SIZE(boot_names); i++) +- if (boot_names[i].value == action) +- return boot_names[i].name; ++ for (bn = boot_names; bn->value >= 0; ++bn) ++ if (bn->value == action) ++ break; + +- return "invalid action"; ++ return bn->name; + } + +-static ssize_t post_reset_wdog_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t post_reset_wdog_show(struct device_driver *drv, ++ char *buf) + { +- int ret; ++ return snprintf(buf, PAGE_SIZE, "%d\n", ++ smc_call0(MLNX_GET_POST_RESET_WDOG)); ++} + +- ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_POST_RESET_WDOG, 0); +- if (ret < 0) +- return ret; ++static ssize_t post_reset_wdog_store(struct device_driver *drv, ++ const char *buf, size_t count) ++{ ++ int err; ++ unsigned long watchdog; ++ ++ err = kstrtoul(buf, 10, &watchdog); ++ if (err) ++ return err; ++ ++ if (smc_call1(MLNX_SET_POST_RESET_WDOG, watchdog) < 0) ++ return -EINVAL; + +- return sprintf(buf, "%d\n", ret); ++ return count; + } + +-static ssize_t post_reset_wdog_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) ++static ssize_t reset_action_show(struct device_driver *drv, ++ char *buf) + { +- unsigned long value; +- int ret; ++ return snprintf(buf, PAGE_SIZE, "%s\n", reset_action_to_string( ++ smc_call0(MLNX_GET_RESET_ACTION))); ++} + +- ret = kstrtoul(buf, 10, &value); +- if (ret) +- return ret; ++static ssize_t reset_action_store(struct device_driver *drv, ++ const char *buf, size_t count) ++{ ++ int action = reset_action_to_val(buf, count); + +- ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_SET_POST_RESET_WDOG, value); +- if (ret < 0) +- return ret; ++ if (action < 0 || action == MLNX_BOOT_NONE) ++ return -EINVAL; ++ ++ if (smc_call1(MLNX_SET_RESET_ACTION, action) < 0) ++ return -EINVAL; + + return count; + } + +-static ssize_t mlxbf_bootctl_show(int smc_op, char *buf) ++static ssize_t second_reset_action_show(struct device_driver *drv, ++ char *buf) + { +- int action; ++ return snprintf(buf, PAGE_SIZE, "%s\n", reset_action_to_string( ++ smc_call0(MLNX_GET_SECOND_RESET_ACTION))); ++} ++ ++static ssize_t second_reset_action_store(struct device_driver *drv, ++ const char *buf, size_t count) ++{ ++ int action = reset_action_to_val(buf, count); + +- action = mlxbf_bootctl_smc(smc_op, 0); + if (action < 0) +- return action; ++ return -EINVAL; ++ ++ if (smc_call1(MLNX_SET_SECOND_RESET_ACTION, action) < 0) ++ return -EINVAL; + +- return sprintf(buf, "%s\n", mlxbf_bootctl_action_to_string(action)); ++ return count; + } + +-static int mlxbf_bootctl_store(int smc_op, const char *buf, size_t count) ++static ssize_t lifecycle_state_show(struct device_driver *drv, ++ char *buf) + { +- int ret, action; ++ int lc_state = smc_call1(MLNX_GET_TBB_FUSE_STATUS, ++ MLNX_FUSE_STATUS_LIFECYCLE); + +- action = mlxbf_bootctl_reset_action_to_val(buf); +- if (action < 0) +- return action; ++ if (lc_state < 0) ++ return -EINVAL; ++ ++ lc_state &= (SB_MODE_TEST_MASK | ++ SB_MODE_SECURE_MASK | ++ SB_MODE_DEV_MASK); + +- ret = mlxbf_bootctl_smc(smc_op, action); +- if (ret < 0) +- return ret; ++ /* ++ * If the test bits are set, we specify that the current state may be ++ * due to using the test bits. ++ */ ++ if ((lc_state & SB_MODE_TEST_MASK) != 0) { ++ ++ lc_state &= SB_MODE_SECURE_MASK; ++ ++ return snprintf(buf, PAGE_SIZE, "%s(test)\n", ++ lifecycle_states[lc_state]); ++ } else if ((lc_state & SB_MODE_SECURE_MASK) == SB_LIFECYCLE_GA_SECURE ++ && (lc_state & SB_MODE_DEV_MASK)) { ++ return snprintf(buf, PAGE_SIZE, "Secured (development)\n"); ++ } ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", lifecycle_states[lc_state]); ++} ++ ++static ssize_t secure_boot_fuse_state_show(struct device_driver *drv, ++ char *buf) ++{ ++ int key; ++ int buf_len = 0; ++ int upper_key_used = 0; ++ int sb_key_state = smc_call1(MLNX_GET_TBB_FUSE_STATUS, ++ MLNX_FUSE_STATUS_KEYS); ++ ++ if (sb_key_state < 0) ++ return -EINVAL; ++ ++ for (key = SB_KEY_NUM - 1; key >= 0; key--) { ++ int burnt = ((sb_key_state & (1 << key)) != 0); ++ int valid = ((sb_key_state & (1 << (key + SB_KEY_NUM))) != 0); ++ ++ buf_len += sprintf(buf + buf_len, "Ver%d:", key); ++ if (upper_key_used) { ++ if (burnt) { ++ if (valid) ++ buf_len += sprintf(buf + buf_len, ++ "Used"); ++ else ++ buf_len += sprintf(buf + buf_len, ++ "Wasted"); ++ } else { ++ if (valid) ++ buf_len += sprintf(buf + buf_len, ++ "Invalid"); ++ else ++ buf_len += sprintf(buf + buf_len, ++ "Skipped"); ++ } ++ } else { ++ if (burnt) { ++ if (valid) { ++ upper_key_used = 1; ++ buf_len += sprintf(buf + buf_len, ++ "In use"); ++ } else ++ buf_len += sprintf(buf + buf_len, ++ "Burn incomplete"); ++ } else { ++ if (valid) ++ buf_len += sprintf(buf + buf_len, ++ "Invalid"); ++ else ++ buf_len += sprintf(buf + buf_len, ++ "Free"); ++ } ++ } ++ buf_len += sprintf(buf + buf_len, "\n"); ++ } ++ ++ return buf_len; ++} ++ ++static ssize_t fw_reset_store(struct device_driver *drv, ++ const char *buf, size_t count) ++{ ++ int err; ++ unsigned long key; ++ ++ err = kstrtoul(buf, 16, &key); ++ if (err) ++ return err; ++ ++ if (smc_call1(MLNX_HANDLE_FW_RESET, key) < 0) ++ return -EINVAL; + + return count; + } + +-static ssize_t reset_action_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t oob_mac_show(struct device_driver *drv, char *buf) + { +- return mlxbf_bootctl_show(MLXBF_BOOTCTL_GET_RESET_ACTION, buf); ++ char mac_str[MLNX_MFG_OOB_MAC_FORMAT_LEN + 1] = { 0 }; ++ struct arm_smccc_res res; ++ u8 *mac_byte_ptr; ++ ++ mutex_lock(&mfg_ops_lock); ++ arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, MLNX_MFG_TYPE_OOB_MAC, 0, 0, 0, ++ 0, 0, 0, &res); ++ mutex_unlock(&mfg_ops_lock); ++ if (res.a0) ++ return -EPERM; ++ ++ mac_byte_ptr = (u8 *)&res.a1; ++ ++ sprintf(mac_str, "%02X:%02X:%02X:%02X:%02X:%02X", ++ mac_byte_ptr[0], mac_byte_ptr[1], mac_byte_ptr[2], ++ mac_byte_ptr[3], mac_byte_ptr[4], mac_byte_ptr[5]); ++ ++ return snprintf(buf, PAGE_SIZE, "%s", mac_str); + } + +-static ssize_t reset_action_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) ++static ssize_t oob_mac_store(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ int byte[MLNX_MFG_OOB_MAC_FORMAT_LEN] = { 0 }; ++ struct arm_smccc_res res; ++ u64 mac_addr = 0; ++ u8 *mac_byte_ptr; ++ int byte_idx, len; ++ ++ if ((count - 1) != MLNX_MFG_OOB_MAC_FORMAT_LEN) ++ return -EINVAL; ++ ++ len = sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", ++ &byte[0], &byte[1], &byte[2], ++ &byte[3], &byte[4], &byte[5]); ++ if (len != MLNX_MFG_OOB_MAC_LEN) ++ return -EINVAL; ++ ++ mac_byte_ptr = (u8 *)&mac_addr; ++ ++ for (byte_idx = 0; byte_idx < MLNX_MFG_OOB_MAC_LEN; byte_idx++) ++ mac_byte_ptr[byte_idx] = (u8) byte[byte_idx]; ++ ++ mutex_lock(&mfg_ops_lock); ++ arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, MLNX_MFG_TYPE_OOB_MAC, ++ MLNX_MFG_OOB_MAC_LEN, mac_addr, 0, 0, 0, 0, &res); ++ mutex_unlock(&mfg_ops_lock); ++ ++ return res.a0 ? -EPERM : count; ++} ++ ++static ssize_t opn_show(struct device_driver *drv, char *buf) + { +- return mlxbf_bootctl_store(MLXBF_BOOTCTL_SET_RESET_ACTION, buf, count); ++ u64 opn_data[MLNX_MFG_VAL_QWORD_CNT(OPN)] = { 0 }; ++ char opn[MLNX_MFG_OPN_VAL_LEN + 1] = { 0 }; ++ struct arm_smccc_res res; ++ int word; ++ ++ mutex_lock(&mfg_ops_lock); ++ for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(OPN); word++) { ++ arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, ++ MLNX_MFG_TYPE_OPN_0 + word, ++ 0, 0, 0, 0, 0, 0, &res); ++ if (res.a0) { ++ mutex_unlock(&mfg_ops_lock); ++ return -EPERM; ++ } ++ opn_data[word] = res.a1; ++ } ++ mutex_unlock(&mfg_ops_lock); ++ memcpy(opn, opn_data, MLNX_MFG_OPN_VAL_LEN); ++ ++ return snprintf(buf, PAGE_SIZE, "%s", opn); + } + +-static ssize_t second_reset_action_show(struct device *dev, +- struct device_attribute *attr, +- char *buf) ++static ssize_t opn_store(struct device_driver *drv, const char *buf, ++ size_t count) + { +- return mlxbf_bootctl_show(MLXBF_BOOTCTL_GET_SECOND_RESET_ACTION, buf); ++ u64 opn[MLNX_MFG_VAL_QWORD_CNT(OPN)] = { 0 }; ++ struct arm_smccc_res res; ++ int word; ++ ++ if (count > MLNX_MFG_OPN_VAL_LEN) ++ return -EINVAL; ++ ++ memcpy(opn, buf, count); ++ ++ mutex_lock(&mfg_ops_lock); ++ for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(OPN); word++) { ++ arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, ++ MLNX_MFG_TYPE_OPN_0 + word, ++ sizeof(u64), opn[word], 0, 0, 0, 0, &res); ++ if (res.a0) { ++ mutex_unlock(&mfg_ops_lock); ++ return -EPERM; ++ } ++ } ++ mutex_unlock(&mfg_ops_lock); ++ ++ return count; + } + +-static ssize_t second_reset_action_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) ++static ssize_t sku_show(struct device_driver *drv, char *buf) + { +- return mlxbf_bootctl_store(MLXBF_BOOTCTL_SET_SECOND_RESET_ACTION, buf, +- count); ++ u64 sku_data[MLNX_MFG_VAL_QWORD_CNT(SKU)] = { 0 }; ++ char sku[MLNX_MFG_SKU_VAL_LEN + 1] = { 0 }; ++ struct arm_smccc_res res; ++ int word; ++ ++ mutex_lock(&mfg_ops_lock); ++ for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(SKU); word++) { ++ arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, ++ MLNX_MFG_TYPE_SKU_0 + word, ++ 0, 0, 0, 0, 0, 0, &res); ++ if (res.a0) { ++ mutex_unlock(&mfg_ops_lock); ++ return -EPERM; ++ } ++ sku_data[word] = res.a1; ++ } ++ mutex_unlock(&mfg_ops_lock); ++ memcpy(sku, sku_data, MLNX_MFG_SKU_VAL_LEN); ++ ++ return snprintf(buf, PAGE_SIZE, "%s", sku); + } + +-static ssize_t lifecycle_state_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t sku_store(struct device_driver *drv, const char *buf, ++ size_t count) + { +- int lc_state; ++ u64 sku[MLNX_MFG_VAL_QWORD_CNT(SKU)] = { 0 }; ++ struct arm_smccc_res res; ++ int word; + +- lc_state = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_TBB_FUSE_STATUS, +- MLXBF_BOOTCTL_FUSE_STATUS_LIFECYCLE); +- if (lc_state < 0) +- return lc_state; ++ if (count > MLNX_MFG_SKU_VAL_LEN) ++ return -EINVAL; + +- lc_state &= +- MLXBF_BOOTCTL_SB_TEST_MASK | MLXBF_BOOTCTL_SB_SECURE_MASK; ++ memcpy(sku, buf, count); + +- /* +- * If the test bits are set, we specify that the current state may be +- * due to using the test bits. +- */ +- if (lc_state & MLXBF_BOOTCTL_SB_TEST_MASK) { +- lc_state &= MLXBF_BOOTCTL_SB_SECURE_MASK; ++ mutex_lock(&mfg_ops_lock); ++ for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(SKU); word++) { ++ arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, ++ MLNX_MFG_TYPE_SKU_0 + word, ++ sizeof(u64), sku[word], 0, 0, 0, 0, &res); ++ if (res.a0) { ++ mutex_unlock(&mfg_ops_lock); ++ return -EPERM; ++ } ++ } ++ mutex_unlock(&mfg_ops_lock); + +- return sprintf(buf, "%s(test)\n", +- mlxbf_bootctl_lifecycle_states[lc_state]); ++ return count; ++} ++ ++static ssize_t modl_show(struct device_driver *drv, char *buf) ++{ ++ u64 modl_data[MLNX_MFG_VAL_QWORD_CNT(MODL)] = { 0 }; ++ char modl[MLNX_MFG_MODL_VAL_LEN + 1] = { 0 }; ++ struct arm_smccc_res res; ++ int word; ++ ++ mutex_lock(&mfg_ops_lock); ++ for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(MODL); word++) { ++ arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, ++ MLNX_MFG_TYPE_MODL_0 + word, ++ 0, 0, 0, 0, 0, 0, &res); ++ if (res.a0) { ++ mutex_unlock(&mfg_ops_lock); ++ return -EPERM; ++ } ++ modl_data[word] = res.a1; + } ++ mutex_unlock(&mfg_ops_lock); ++ memcpy(modl, modl_data, MLNX_MFG_MODL_VAL_LEN); + +- return sprintf(buf, "%s\n", mlxbf_bootctl_lifecycle_states[lc_state]); ++ return snprintf(buf, PAGE_SIZE, "%s", modl); + } + +-static ssize_t secure_boot_fuse_state_show(struct device *dev, +- struct device_attribute *attr, +- char *buf) ++static ssize_t modl_store(struct device_driver *drv, const char *buf, ++ size_t count) + { +- int burnt, valid, key, key_state, buf_len = 0, upper_key_used = 0; +- const char *status; ++ u64 modl[MLNX_MFG_VAL_QWORD_CNT(MODL)] = { 0 }; ++ struct arm_smccc_res res; ++ int word; ++ ++ if (count > MLNX_MFG_MODL_VAL_LEN) ++ return -EINVAL; ++ ++ memcpy(modl, buf, count); ++ ++ mutex_lock(&mfg_ops_lock); ++ for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(MODL); word++) { ++ arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, ++ MLNX_MFG_TYPE_MODL_0 + word, ++ sizeof(u64), modl[word], 0, 0, 0, 0, &res); ++ if (res.a0) { ++ mutex_unlock(&mfg_ops_lock); ++ return -EPERM; ++ } ++ } ++ mutex_unlock(&mfg_ops_lock); ++ ++ return count; ++} ++ ++static ssize_t sn_show(struct device_driver *drv, char *buf) ++{ ++ u64 sn_data[MLNX_MFG_VAL_QWORD_CNT(SN)] = { 0 }; ++ char sn[MLNX_MFG_SN_VAL_LEN + 1] = { 0 }; ++ struct arm_smccc_res res; ++ int word; ++ ++ mutex_lock(&mfg_ops_lock); ++ for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(SN); word++) { ++ arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, ++ MLNX_MFG_TYPE_SN_0 + word, ++ 0, 0, 0, 0, 0, 0, &res); ++ if (res.a0) { ++ mutex_unlock(&mfg_ops_lock); ++ return -EPERM; ++ } ++ sn_data[word] = res.a1; ++ } ++ mutex_unlock(&mfg_ops_lock); ++ memcpy(sn, sn_data, MLNX_MFG_SN_VAL_LEN); ++ ++ return snprintf(buf, PAGE_SIZE, "%s", sn); ++} ++ ++static ssize_t sn_store(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ u64 sn[MLNX_MFG_VAL_QWORD_CNT(SN)] = { 0 }; ++ struct arm_smccc_res res; ++ int word; ++ ++ if (count > MLNX_MFG_SN_VAL_LEN) ++ return -EINVAL; ++ ++ memcpy(sn, buf, count); ++ ++ mutex_lock(&mfg_ops_lock); ++ for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(SN); word++) { ++ arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, ++ MLNX_MFG_TYPE_SN_0 + word, ++ sizeof(u64), sn[word], 0, 0, 0, 0, &res); ++ if (res.a0) { ++ mutex_unlock(&mfg_ops_lock); ++ return -EPERM; ++ } ++ } ++ mutex_unlock(&mfg_ops_lock); ++ ++ return count; ++} ++ ++static ssize_t uuid_show(struct device_driver *drv, char *buf) ++{ ++ u64 uuid_data[MLNX_MFG_VAL_QWORD_CNT(UUID)] = { 0 }; ++ char uuid[MLNX_MFG_UUID_VAL_LEN + 1] = { 0 }; ++ struct arm_smccc_res res; ++ int word; ++ ++ mutex_lock(&mfg_ops_lock); ++ for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(UUID); word++) { ++ arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, ++ MLNX_MFG_TYPE_UUID_0 + word, ++ 0, 0, 0, 0, 0, 0, &res); ++ if (res.a0) { ++ mutex_unlock(&mfg_ops_lock); ++ return -EPERM; ++ } ++ uuid_data[word] = res.a1; ++ } ++ mutex_unlock(&mfg_ops_lock); ++ memcpy(uuid, uuid_data, MLNX_MFG_UUID_VAL_LEN); ++ ++ return snprintf(buf, PAGE_SIZE, "%s", uuid); ++} ++ ++static ssize_t uuid_store(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ u64 uuid[MLNX_MFG_VAL_QWORD_CNT(UUID)] = { 0 }; ++ struct arm_smccc_res res; ++ int word; + +- key_state = mlxbf_bootctl_smc(MLXBF_BOOTCTL_GET_TBB_FUSE_STATUS, +- MLXBF_BOOTCTL_FUSE_STATUS_KEYS); +- if (key_state < 0) +- return key_state; ++ if (count > MLNX_MFG_UUID_VAL_LEN) ++ return -EINVAL; ++ ++ memcpy(uuid, buf, count); ++ ++ mutex_lock(&mfg_ops_lock); ++ for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(UUID); word++) { ++ arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, ++ MLNX_MFG_TYPE_UUID_0 + word, ++ sizeof(u64), uuid[word], 0, 0, 0, 0, &res); ++ if (res.a0) { ++ mutex_unlock(&mfg_ops_lock); ++ return -EPERM; ++ } ++ } ++ mutex_unlock(&mfg_ops_lock); ++ ++ return count; ++} ++ ++static ssize_t rev_show(struct device_driver *drv, char *buf) ++{ ++ u64 rev_data[MLNX_MFG_VAL_QWORD_CNT(REV)] = { 0 }; ++ char rev[MLNX_MFG_REV_VAL_LEN + 1] = { 0 }; ++ struct arm_smccc_res res; ++ int word; ++ ++ mutex_lock(&mfg_ops_lock); ++ for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(REV); word++) { ++ arm_smccc_smc(MLNX_HANDLE_GET_MFG_INFO, ++ MLNX_MFG_TYPE_REV + word, ++ 0, 0, 0, 0, 0, 0, &res); ++ if (res.a0) { ++ mutex_unlock(&mfg_ops_lock); ++ return -EPERM; ++ } ++ rev_data[word] = res.a1; ++ } ++ mutex_unlock(&mfg_ops_lock); ++ memcpy(rev, rev_data, MLNX_MFG_REV_VAL_LEN); ++ ++ return snprintf(buf, PAGE_SIZE, "%s", rev); ++} ++ ++static ssize_t rev_store(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ u64 rev[MLNX_MFG_VAL_QWORD_CNT(REV)] = { 0 }; ++ struct arm_smccc_res res; ++ int word; ++ ++ if (count > MLNX_MFG_REV_VAL_LEN) ++ return -EINVAL; ++ ++ memcpy(rev, buf, count); ++ ++ mutex_lock(&mfg_ops_lock); ++ for (word = 0; word < MLNX_MFG_VAL_QWORD_CNT(REV); word++) { ++ arm_smccc_smc(MLNX_HANDLE_SET_MFG_INFO, ++ MLNX_MFG_TYPE_REV + word, ++ sizeof(u64), rev[word], 0, 0, 0, 0, &res); ++ if (res.a0) { ++ mutex_unlock(&mfg_ops_lock); ++ return -EPERM; ++ } ++ } ++ mutex_unlock(&mfg_ops_lock); ++ ++ return count; ++} ++ ++static ssize_t mfg_lock_store(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ unsigned long val; ++ int err; ++ ++ err = kstrtoul(buf, 10, &val); ++ if (err) ++ return err; ++ ++ if (val != 1) ++ return -EINVAL; ++ ++ mutex_lock(&mfg_ops_lock); ++ smc_call0(MLNX_HANDLE_LOCK_MFG_INFO); ++ mutex_unlock(&mfg_ops_lock); ++ ++ return count; ++} ++ ++/* Log header format. */ ++#define RSH_LOG_TYPE_SHIFT 56 ++#define RSH_LOG_LEN_SHIFT 48 ++#define RSH_LOG_LEVEL_SHIFT 0 ++ ++/* Module ID and type used here. */ ++#define BF_RSH_LOG_TYPE_UNKNOWN 0x00ULL ++#define BF_RSH_LOG_TYPE_PANIC 0x01ULL ++#define BF_RSH_LOG_TYPE_EXCEPTION 0x02ULL ++#define BF_RSH_LOG_TYPE_UNUSED 0x03ULL ++#define BF_RSH_LOG_TYPE_MSG 0x04ULL ++ ++/* Utility macro. */ ++#define BF_RSH_LOG_MOD_MASK 0x0FULL ++#define BF_RSH_LOG_MOD_SHIFT 60 ++#define BF_RSH_LOG_TYPE_MASK 0x0FULL ++#define BF_RSH_LOG_TYPE_SHIFT 56 ++#define BF_RSH_LOG_LEN_MASK 0x7FULL ++#define BF_RSH_LOG_LEN_SHIFT 48 ++#define BF_RSH_LOG_ARG_MASK 0xFFFFFFFFULL ++#define BF_RSH_LOG_ARG_SHIFT 16 ++#define BF_RSH_LOG_HAS_ARG_MASK 0xFFULL ++#define BF_RSH_LOG_HAS_ARG_SHIFT 8 ++#define BF_RSH_LOG_LEVEL_MASK 0xFFULL ++#define BF_RSH_LOG_LEVEL_SHIFT 0 ++#define BF_RSH_LOG_PC_MASK 0xFFFFFFFFULL ++#define BF_RSH_LOG_PC_SHIFT 0 ++#define BF_RSH_LOG_SYNDROME_MASK 0xFFFFFFFFULL ++#define BF_RSH_LOG_SYNDROME_SHIFT 0 ++ ++#define BF_RSH_LOG_HEADER_GET(f, h) \ ++ (((h) >> BF_RSH_LOG_##f##_SHIFT) & BF_RSH_LOG_##f##_MASK) ++ ++/* Log message level. */ ++enum { ++ RSH_LOG_INFO, ++ RSH_LOG_WARN, ++ RSH_LOG_ERR ++}; ++ ++/* Log module */ ++const char * const rsh_log_mod[] = { ++ "MISC", "BL1", "BL2", "BL2R", "BL31", "UEFI" ++}; ++ ++const char *rsh_log_level[] = {"INFO", "WARN", "ERR", "ASSERT"}; ++ ++#define AARCH64_MRS_REG_SHIFT 5 ++#define AARCH64_MRS_REG_MASK 0xffff ++#define AARCH64_ESR_ELX_EXCEPTION_CLASS_SHIFT 26 ++ ++struct rsh_log_reg { ++ char *name; ++ u32 opcode; ++} rsh_log_reg; ++ ++static struct rsh_log_reg rsh_log_regs[] = { ++ {"actlr_el1", 0b1100000010000001}, ++ {"actlr_el2", 0b1110000010000001}, ++ {"actlr_el3", 0b1111000010000001}, ++ {"afsr0_el1", 0b1100001010001000}, ++ {"afsr0_el2", 0b1110001010001000}, ++ {"afsr0_el3", 0b1111001010001000}, ++ {"afsr1_el1", 0b1100001010001001}, ++ {"afsr1_el2", 0b1110001010001001}, ++ {"afsr1_el3", 0b1111001010001001}, ++ {"amair_el1", 0b1100010100011000}, ++ {"amair_el2", 0b1110010100011000}, ++ {"amair_el3", 0b1111010100011000}, ++ {"ccsidr_el1", 0b1100100000000000}, ++ {"clidr_el1", 0b1100100000000001}, ++ {"cntkctl_el1", 0b1100011100001000}, ++ {"cntp_ctl_el0", 0b1101111100010001}, ++ {"cntp_cval_el0", 0b1101111100010010}, ++ {"cntv_ctl_el0", 0b1101111100011001}, ++ {"cntv_cval_el0", 0b1101111100011010}, ++ {"contextidr_el1", 0b1100011010000001}, ++ {"cpacr_el1", 0b1100000010000010}, ++ {"cptr_el2", 0b1110000010001010}, ++ {"cptr_el3", 0b1111000010001010}, ++ {"vtcr_el2", 0b1110000100001010}, ++ {"ctr_el0", 0b1101100000000001}, ++ {"currentel", 0b1100001000010010}, ++ {"dacr32_el2", 0b1110000110000000}, ++ {"daif", 0b1101101000010001}, ++ {"dczid_el0", 0b1101100000000111}, ++ {"dlr_el0", 0b1101101000101001}, ++ {"dspsr_el0", 0b1101101000101000}, ++ {"elr_el1", 0b1100001000000001}, ++ {"elr_el2", 0b1110001000000001}, ++ {"elr_el3", 0b1111001000000001}, ++ {"esr_el1", 0b1100001010010000}, ++ {"esr_el2", 0b1110001010010000}, ++ {"esr_el3", 0b1111001010010000}, ++ {"esselr_el1", 0b1101000000000000}, ++ {"far_el1", 0b1100001100000000}, ++ {"far_el2", 0b1110001100000000}, ++ {"far_el3", 0b1111001100000000}, ++ {"fpcr", 0b1101101000100000}, ++ {"fpexc32_el2", 0b1110001010011000}, ++ {"fpsr", 0b1101101000100001}, ++ {"hacr_el2", 0b1110000010001111}, ++ {"har_el2", 0b1110000010001000}, ++ {"hpfar_el2", 0b1110001100000100}, ++ {"hstr_el2", 0b1110000010001011}, ++ {"far_el1", 0b1100001100000000}, ++ {"far_el2", 0b1110001100000000}, ++ {"far_el3", 0b1111001100000000}, ++ {"hcr_el2", 0b1110000010001000}, ++ {"hpfar_el2", 0b1110001100000100}, ++ {"id_aa64afr0_el1", 0b1100000000101100}, ++ {"id_aa64afr1_el1", 0b1100000000101101}, ++ {"id_aa64dfr0_el1", 0b1100000000101100}, ++ {"id_aa64isar0_el1", 0b1100000000110000}, ++ {"id_aa64isar1_el1", 0b1100000000110001}, ++ {"id_aa64mmfr0_el1", 0b1100000000111000}, ++ {"id_aa64mmfr1_el1", 0b1100000000111001}, ++ {"id_aa64pfr0_el1", 0b1100000000100000}, ++ {"id_aa64pfr1_el1", 0b1100000000100001}, ++ {"ifsr32_el2", 0b1110001010000001}, ++ {"isr_el1", 0b1100011000001000}, ++ {"mair_el1", 0b1100010100010000}, ++ {"mair_el2", 0b1110010100010000}, ++ {"mair_el3", 0b1111010100010000}, ++ {"midr_el1", 0b1100000000000000}, ++ {"mpidr_el1", 0b1100000000000101}, ++ {"nzcv", 0b1101101000010000}, ++ {"revidr_el1", 0b1100000000000110}, ++ {"rmr_el3", 0b1111011000000010}, ++ {"par_el1", 0b1100001110100000}, ++ {"rvbar_el3", 0b1111011000000001}, ++ {"scr_el3", 0b1111000010001000}, ++ {"sctlr_el1", 0b1100000010000000}, ++ {"sctlr_el2", 0b1110000010000000}, ++ {"sctlr_el3", 0b1111000010000000}, ++ {"sp_el0", 0b1100001000001000}, ++ {"sp_el1", 0b1110001000001000}, ++ {"spsel", 0b1100001000010000}, ++ {"spsr_abt", 0b1110001000011001}, ++ {"spsr_el1", 0b1100001000000000}, ++ {"spsr_el2", 0b1110001000000000}, ++ {"spsr_el3", 0b1111001000000000}, ++ {"spsr_fiq", 0b1110001000011011}, ++ {"spsr_irq", 0b1110001000011000}, ++ {"spsr_und", 0b1110001000011010}, ++ {"tcr_el1", 0b1100000100000010}, ++ {"tcr_el2", 0b1110000100000010}, ++ {"tcr_el3", 0b1111000100000010}, ++ {"tpidr_el0", 0b1101111010000010}, ++ {"tpidr_el1", 0b1100011010000100}, ++ {"tpidr_el2", 0b1110011010000010}, ++ {"tpidr_el3", 0b1111011010000010}, ++ {"tpidpro_el0", 0b1101111010000011}, ++ {"vbar_el1", 0b1100011000000000}, ++ {"vbar_el2", 0b1110011000000000}, ++ {"vbar_el3", 0b1111011000000000}, ++ {"vmpidr_el2", 0b1110000000000101}, ++ {"vpidr_el2", 0b1110000000000000}, ++ {"ttbr0_el1", 0b1100000100000000}, ++ {"ttbr0_el2", 0b1110000100000000}, ++ {"ttbr0_el3", 0b1111000100000000}, ++ {"ttbr1_el1", 0b1100000100000001}, ++ {"vtcr_el2", 0b1110000100001010}, ++ {"vttbr_el2", 0b1110000100001000}, ++ {NULL, 0b0000000000000000}, ++}; ++ ++/* Size(8-byte words) of the log buffer. */ ++#define RSH_SCRATCH_BUF_CTL_IDX_MASK 0x7f ++ ++static int rsh_log_sem_lock(void) ++{ ++ unsigned long timeout; ++ ++ /* Take the semaphore. */ ++ timeout = jiffies + msecs_to_jiffies(100); ++ while (readq(rsh_semaphore)) { ++ if (time_after(jiffies, timeout)) ++ return -ETIMEDOUT; ++ } ++ ++ return 0; ++} ++ ++static void rsh_log_sem_unlock(void) ++{ ++ writeq(0, rsh_semaphore); ++} ++ ++static ssize_t rsh_log_store(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ int idx, num, len, size = (int)count, level = RSH_LOG_INFO, rc; ++ u64 data; ++ ++ if (!size) ++ return -EINVAL; ++ ++ if (!rsh_semaphore || !rsh_scratch_buf_ctl) ++ return -EOPNOTSUPP; ++ ++ /* Ignore line break at the end. */ ++ if (buf[size-1] == 0xa) ++ size--; ++ ++ /* Check the message prefix. */ ++ for (idx = 0; idx < ARRAY_SIZE(rsh_log_level); idx++) { ++ len = strlen(rsh_log_level[idx]); ++ if (len + 1 < size && !strncmp(buf, rsh_log_level[idx], len)) { ++ buf += len + 1; ++ size -= len + 1; ++ level = idx; ++ break; ++ } ++ } ++ ++ /* Ignore leading spaces. */ ++ while (size > 0 && buf[0] == ' ') { ++ size--; ++ buf++; ++ } ++ ++ /* Take the semaphore. */ ++ rc = rsh_log_sem_lock(); ++ if (rc) ++ return rc; ++ ++ /* Calculate how many words are available. */ ++ num = (size + sizeof(u64) - 1) / sizeof(u64); ++ idx = readq(rsh_scratch_buf_ctl); ++ if (idx + num + 1 >= RSH_SCRATCH_BUF_CTL_IDX_MASK) ++ num = RSH_SCRATCH_BUF_CTL_IDX_MASK - idx - 1; ++ if (num <= 0) ++ goto done; ++ ++ /* Write Header. */ ++ data = (BF_RSH_LOG_TYPE_MSG << RSH_LOG_TYPE_SHIFT) | ++ ((u64)num << RSH_LOG_LEN_SHIFT) | ++ ((u64)level << RSH_LOG_LEVEL_SHIFT); ++ writeq(data, rsh_scratch_buf_data); ++ ++ /* Write message. */ ++ for (idx = 0, len = size; idx < num && len > 0; idx++) { ++ if (len <= sizeof(u64)) { ++ data = 0; ++ memcpy(&data, buf, len); ++ len = 0; ++ } else { ++ memcpy(&data, buf, sizeof(u64)); ++ len -= sizeof(u64); ++ buf += sizeof(u64); ++ } ++ writeq(data, rsh_scratch_buf_data); ++ } ++ ++done: ++ /* Release the semaphore. */ ++ rsh_log_sem_unlock(); ++ ++ /* Ignore the rest if no more space. */ ++ return count; ++} ++ ++static char *rsh_log_get_reg_name(u64 opcode) ++{ ++ struct rsh_log_reg *reg = rsh_log_regs; ++ ++ while (reg->name) { ++ if (reg->opcode == opcode) ++ return reg->name; ++ reg++; ++ } ++ ++ return "unknown"; ++} ++ ++static int rsh_log_show_crash(u64 hdr, char *buf, int size) ++{ ++ int i, module, type, len, n = 0; ++ u32 pc, syndrome, ec; ++ u64 opcode, data; ++ char *p = buf; ++ ++ module = BF_RSH_LOG_HEADER_GET(MOD, hdr); ++ if (module >= ARRAY_SIZE(rsh_log_mod)) ++ module = 0; ++ type = BF_RSH_LOG_HEADER_GET(TYPE, hdr); ++ len = BF_RSH_LOG_HEADER_GET(LEN, hdr); ++ ++ if (type == BF_RSH_LOG_TYPE_EXCEPTION) { ++ syndrome = BF_RSH_LOG_HEADER_GET(SYNDROME, hdr); ++ ec = syndrome >> AARCH64_ESR_ELX_EXCEPTION_CLASS_SHIFT; ++ n = snprintf(p, size, " Exception(%s): syndrome = 0x%x%s\n", ++ rsh_log_mod[module], syndrome, ++ (ec == 0x24 || ec == 0x25) ? "(Data Abort)" : ++ (ec == 0x2f) ? "(SError)" : ""); ++ } else if (type == BF_RSH_LOG_TYPE_PANIC) { ++ pc = BF_RSH_LOG_HEADER_GET(PC, hdr); ++ n = snprintf(p, size, ++ " PANIC(%s): PC = 0x%x\n", rsh_log_mod[module], ++ pc); ++ } ++ if (n > 0) { ++ p += n; ++ size -= n; ++ } + + /* +- * key_state contains the bits for 4 Key versions, loaded from eFuses +- * after a hard reset. Lower 4 bits are a thermometer code indicating +- * key programming has started for key n (0000 = none, 0001 = version 0, +- * 0011 = version 1, 0111 = version 2, 1111 = version 3). Upper 4 bits +- * are a thermometer code indicating key programming has completed for +- * key n (same encodings as the start bits). This allows for detection +- * of an interruption in the programming process which has left the key +- * partially programmed (and thus invalid). The process is to burn the +- * eFuse for the new key start bit, burn the key eFuses, then burn the +- * eFuse for the new key complete bit. +- * +- * For example 0000_0000: no key valid, 0001_0001: key version 0 valid, +- * 0011_0011: key 1 version valid, 0011_0111: key version 2 started +- * programming but did not complete, etc. The most recent key for which +- * both start and complete bit is set is loaded. On soft reset, this +- * register is not modified. ++ * Read the registers in a loop. 'len' is the total number of words in ++ * 8-bytes. Two words are read in each loop. + */ +- for (key = MLXBF_SB_KEY_NUM - 1; key >= 0; key--) { +- burnt = key_state & BIT(key); +- valid = key_state & BIT(key + MLXBF_SB_KEY_NUM); ++ for (i = 0; i < len/2; i++) { ++ opcode = readq(rsh_scratch_buf_data); ++ data = readq(rsh_scratch_buf_data); ++ ++ opcode = (opcode >> AARCH64_MRS_REG_SHIFT) & ++ AARCH64_MRS_REG_MASK; ++ n = snprintf(p, size, ++ " %-16s0x%llx\n", rsh_log_get_reg_name(opcode), ++ (unsigned long long)data); ++ if (n > 0) { ++ p += n; ++ size -= n; ++ } ++ } + +- if (burnt && valid) +- upper_key_used = 1; ++ return p - buf; ++} + +- if (upper_key_used) { +- if (burnt) +- status = valid ? "Used" : "Wasted"; +- else +- status = valid ? "Invalid" : "Skipped"; +- } else { +- if (burnt) +- status = valid ? "InUse" : "Incomplete"; +- else +- status = valid ? "Invalid" : "Free"; ++static int rsh_log_format_msg(char *buf, int size, const char *msg, ...) ++{ ++ va_list args; ++ int len; ++ ++ va_start(args, msg); ++ len = vsnprintf(buf, size, msg, args); ++ va_end(args); ++ ++ return len; ++} ++ ++static int rsh_log_show_msg(u64 hdr, char *buf, int size) ++{ ++ int has_arg = BF_RSH_LOG_HEADER_GET(HAS_ARG, hdr); ++ int level = BF_RSH_LOG_HEADER_GET(LEVEL, hdr); ++ int module = BF_RSH_LOG_HEADER_GET(MOD, hdr); ++ int len = BF_RSH_LOG_HEADER_GET(LEN, hdr); ++ u32 arg = BF_RSH_LOG_HEADER_GET(ARG, hdr); ++ char *msg, *p; ++ u64 data; ++ ++ if (len <= 0) ++ return -EINVAL; ++ ++ if (module >= ARRAY_SIZE(rsh_log_mod)) ++ module = 0; ++ ++ if (level >= ARRAY_SIZE(rsh_log_level)) ++ level = 0; ++ ++ msg = kmalloc(len * sizeof(u64) + 1, GFP_KERNEL); ++ if (!msg) ++ return 0; ++ p = msg; ++ ++ while (len--) { ++ data = readq(rsh_scratch_buf_data); ++ memcpy(p, &data, sizeof(data)); ++ p += sizeof(data); ++ } ++ *p = '\0'; ++ if (!has_arg) { ++ len = snprintf(buf, size, " %s[%s]: %s\n", rsh_log_level[level], ++ rsh_log_mod[module], msg); ++ } else { ++ len = snprintf(buf, size, " %s[%s]: ", rsh_log_level[level], ++ rsh_log_mod[module]); ++ len += rsh_log_format_msg(buf + len, size - len, msg, arg); ++ len += snprintf(buf + len, size - len, "\n"); ++ } ++ ++ kfree(msg); ++ return len; ++} ++ ++static ssize_t rsh_log_show(struct device_driver *drv, char *buf) ++{ ++ u64 hdr; ++ char *p = buf; ++ int i, n, rc, idx, type, len, size = PAGE_SIZE; ++ ++ if (!rsh_semaphore || !rsh_scratch_buf_ctl) ++ return -EOPNOTSUPP; ++ ++ /* Take the semaphore. */ ++ rc = rsh_log_sem_lock(); ++ if (rc) ++ return rc; ++ ++ /* Save the current index and read from 0. */ ++ idx = readq(rsh_scratch_buf_ctl) & RSH_SCRATCH_BUF_CTL_IDX_MASK; ++ if (!idx) ++ goto done; ++ writeq(0, rsh_scratch_buf_ctl); ++ ++ i = 0; ++ while (i < idx) { ++ hdr = readq(rsh_scratch_buf_data); ++ type = BF_RSH_LOG_HEADER_GET(TYPE, hdr); ++ len = BF_RSH_LOG_HEADER_GET(LEN, hdr); ++ i += 1 + len; ++ if (i > idx) ++ break; ++ ++ switch (type) { ++ case BF_RSH_LOG_TYPE_PANIC: ++ case BF_RSH_LOG_TYPE_EXCEPTION: ++ n = rsh_log_show_crash(hdr, p, size); ++ p += n; ++ size -= n; ++ break; ++ case BF_RSH_LOG_TYPE_MSG: ++ n = rsh_log_show_msg(hdr, p, size); ++ p += n; ++ size -= n; ++ break; ++ default: ++ /* Drain this message. */ ++ while (len--) ++ (void) readq(rsh_scratch_buf_data); ++ break; + } +- buf_len += sprintf(buf + buf_len, "%d:%s ", key, status); + } +- buf_len += sprintf(buf + buf_len, "\n"); + +- return buf_len; ++ if (rsh_log_clear_on_read) ++ writeq(0, rsh_scratch_buf_ctl); ++ else ++ writeq(idx, rsh_scratch_buf_ctl); ++ ++done: ++ /* Release the semaphore. */ ++ rsh_log_sem_unlock(); ++ ++ return p - buf; + } + +-static DEVICE_ATTR_RW(post_reset_wdog); +-static DEVICE_ATTR_RW(reset_action); +-static DEVICE_ATTR_RW(second_reset_action); +-static DEVICE_ATTR_RO(lifecycle_state); +-static DEVICE_ATTR_RO(secure_boot_fuse_state); ++static DRIVER_ATTR_RW(post_reset_wdog); ++static DRIVER_ATTR_RW(reset_action); ++static DRIVER_ATTR_RW(second_reset_action); ++static DRIVER_ATTR_RO(lifecycle_state); ++static DRIVER_ATTR_RO(secure_boot_fuse_state); ++static DRIVER_ATTR_WO(fw_reset); ++static DRIVER_ATTR_RW(oob_mac); ++static DRIVER_ATTR_RW(opn); ++static DRIVER_ATTR_RW(sku); ++static DRIVER_ATTR_RW(modl); ++static DRIVER_ATTR_RW(sn); ++static DRIVER_ATTR_RW(uuid); ++static DRIVER_ATTR_RW(rev); ++static DRIVER_ATTR_WO(mfg_lock); ++static DRIVER_ATTR_RW(rsh_log); + +-static struct attribute *mlxbf_bootctl_attrs[] = { +- &dev_attr_post_reset_wdog.attr, +- &dev_attr_reset_action.attr, +- &dev_attr_second_reset_action.attr, +- &dev_attr_lifecycle_state.attr, +- &dev_attr_secure_boot_fuse_state.attr, ++static struct attribute *mbc_dev_attrs[] = { ++ &driver_attr_post_reset_wdog.attr, ++ &driver_attr_reset_action.attr, ++ &driver_attr_second_reset_action.attr, ++ &driver_attr_lifecycle_state.attr, ++ &driver_attr_secure_boot_fuse_state.attr, ++ &driver_attr_fw_reset.attr, ++ &driver_attr_oob_mac.attr, ++ &driver_attr_opn.attr, ++ &driver_attr_sku.attr, ++ &driver_attr_modl.attr, ++ &driver_attr_sn.attr, ++ &driver_attr_uuid.attr, ++ &driver_attr_rev.attr, ++ &driver_attr_mfg_lock.attr, ++ &driver_attr_rsh_log.attr, + NULL + }; + +-ATTRIBUTE_GROUPS(mlxbf_bootctl); ++static struct attribute_group mbc_attr_group = { ++ .attrs = mbc_dev_attrs ++}; + +-static const struct acpi_device_id mlxbf_bootctl_acpi_ids[] = { ++static const struct attribute_group *mbc_attr_groups[] = { ++ &mbc_attr_group, ++ NULL ++}; ++ ++static const struct of_device_id mbc_dt_ids[] = { ++ {.compatible = "mellanox,bootctl"}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, mbc_dt_ids); ++ ++static const struct acpi_device_id mbc_acpi_ids[] = { + {"MLNXBF04", 0}, +- {} ++ {}, + }; + +-MODULE_DEVICE_TABLE(acpi, mlxbf_bootctl_acpi_ids); ++MODULE_DEVICE_TABLE(acpi, mbc_acpi_ids); + +-static bool mlxbf_bootctl_guid_match(const guid_t *guid, +- const struct arm_smccc_res *res) ++static ssize_t mbc_bootfifo_read_raw(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *bin_attr, ++ char *buf, loff_t pos, size_t count) + { +- guid_t id = GUID_INIT(res->a0, res->a1, res->a1 >> 16, +- res->a2, res->a2 >> 8, res->a2 >> 16, +- res->a2 >> 24, res->a3, res->a3 >> 8, +- res->a3 >> 16, res->a3 >> 24); ++ unsigned long timeout = jiffies + HZ / 2; ++ char *p = buf; ++ int cnt = 0; ++ u64 data; + +- return guid_equal(guid, &id); ++ /* Give up reading if no more data within 500ms. */ ++ while (count >= sizeof(data)) { ++ if (!cnt) { ++ cnt = readq(rsh_boot_cnt); ++ if (!cnt) { ++ if (time_after(jiffies, timeout)) ++ break; ++ udelay(10); ++ continue; ++ } ++ } ++ ++ data = readq(rsh_boot_data); ++ memcpy(p, &data, sizeof(data)); ++ count -= sizeof(data); ++ p += sizeof(data); ++ cnt--; ++ timeout = jiffies + HZ / 2; ++ } ++ ++ return p - buf; + } + +-static int mlxbf_bootctl_probe(struct platform_device *pdev) ++static struct bin_attribute mbc_bootfifo_sysfs_attr = { ++ .attr = { .name = "bootfifo", .mode = 0400 }, ++ .read = mbc_bootfifo_read_raw, ++}; ++ ++static int mbc_probe(struct platform_device *pdev) + { +- struct arm_smccc_res res = { 0 }; +- guid_t guid; +- int ret; ++ struct resource *resource; ++ struct arm_smccc_res res; ++ void __iomem *data; ++ int err; + +- /* Ensure we have the UUID we expect for this service. */ +- arm_smccc_smc(MLXBF_BOOTCTL_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res); +- guid_parse(mlxbf_bootctl_svc_uuid_str, &guid); +- if (!mlxbf_bootctl_guid_match(&guid, &res)) ++ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!resource) + return -ENODEV; ++ rsh_boot_data = devm_ioremap_resource(&pdev->dev, resource); ++ if (IS_ERR(rsh_boot_data)) ++ return PTR_ERR(rsh_boot_data); ++ ++ resource = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!resource) ++ return -ENODEV; ++ rsh_boot_cnt = devm_ioremap_resource(&pdev->dev, resource); ++ if (IS_ERR(rsh_boot_cnt)) ++ return PTR_ERR(rsh_boot_cnt); ++ ++ resource = platform_get_resource(pdev, IORESOURCE_MEM, 2); ++ if (resource) { ++ data = devm_ioremap_resource(&pdev->dev, resource); ++ if (!IS_ERR(data)) ++ rsh_semaphore = data; ++ } ++ ++ resource = platform_get_resource(pdev, IORESOURCE_MEM, 3); ++ if (resource) { ++ data = devm_ioremap_resource(&pdev->dev, resource); ++ if (!IS_ERR(data)) { ++ rsh_scratch_buf_ctl = data + RSH_SCRATCH_BUF_CTL_OFF; ++ rsh_scratch_buf_data = data + RSH_SCRATCH_BUF_DATA_OFF; ++ } ++ } + + /* +- * When watchdog is used, it sets boot mode to MLXBF_BOOTCTL_SWAP_EMMC ++ * Ensure we have the UUID we expect for this service. ++ * Note that the functionality we want is present in the first ++ * released version of this service, so we don't check the version. ++ */ ++ arm_smccc_smc(MLNX_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res); ++ if (res.a0 != 0x89c036b4 || res.a1 != 0x11e6e7d7 || ++ res.a2 != 0x1a009787 || res.a3 != 0xc4bf00ca) ++ return -ENODEV; ++ ++ /* ++ * When watchdog is used, it sets the boot mode to MLNX_BOOT_SWAP_EMMC + * in case of boot failures. However it doesn't clear the state if there + * is no failure. Restore the default boot mode here to avoid any + * unnecessary boot partition swapping. + */ +- ret = mlxbf_bootctl_smc(MLXBF_BOOTCTL_SET_RESET_ACTION, +- MLXBF_BOOTCTL_EMMC); +- if (ret < 0) +- dev_warn(&pdev->dev, "Unable to reset the EMMC boot mode\n"); ++ if (smc_call1(MLNX_SET_RESET_ACTION, MLNX_BOOT_EMMC) < 0) ++ pr_err("Unable to reset the EMMC boot mode\n"); ++ ++ err = sysfs_create_bin_file(&pdev->dev.kobj, &mbc_bootfifo_sysfs_attr); ++ if (err) { ++ pr_err("Unable to create bootfifo sysfs file, error %d\n", err); ++ return err; ++ } ++ ++ pr_info("%s (version %s)\n", DRIVER_DESCRIPTION, DRIVER_VERSION); ++ ++ return 0; ++} ++ ++static int mbc_remove(struct platform_device *pdev) ++{ ++ sysfs_remove_bin_file(&pdev->dev.kobj, &mbc_bootfifo_sysfs_attr); + + return 0; + } + +-static struct platform_driver mlxbf_bootctl_driver = { +- .probe = mlxbf_bootctl_probe, ++static struct platform_driver mbc_driver = { ++ .probe = mbc_probe, ++ .remove = mbc_remove, + .driver = { +- .name = "mlxbf-bootctl", +- .dev_groups = mlxbf_bootctl_groups, +- .acpi_match_table = mlxbf_bootctl_acpi_ids, ++ .name = DRIVER_NAME, ++ .groups = mbc_attr_groups, ++ .of_match_table = mbc_dt_ids, ++ .acpi_match_table = ACPI_PTR(mbc_acpi_ids), + } + }; + +-module_platform_driver(mlxbf_bootctl_driver); ++module_platform_driver(mbc_driver); + +-MODULE_DESCRIPTION("Mellanox boot control driver"); +-MODULE_LICENSE("GPL v2"); +-MODULE_AUTHOR("Mellanox Technologies"); ++MODULE_DESCRIPTION(DRIVER_DESCRIPTION); ++MODULE_VERSION(DRIVER_VERSION); ++MODULE_AUTHOR("Shravan Kumar Ramani "); ++MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/platform/mellanox/mlxbf-bootctl.h b/drivers/platform/mellanox/mlxbf-bootctl.h +index 148fdb43b..3e9dda829 100644 +--- a/drivers/platform/mellanox/mlxbf-bootctl.h ++++ b/drivers/platform/mellanox/mlxbf-bootctl.h +@@ -1,11 +1,22 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ ++// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause + /* +- * Copyright (c) 2019, Mellanox Technologies. All rights reserved. ++ * Copyright (C) 2020 Mellanox Technologies. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License v2.0 as published by ++ * the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. + */ + + #ifndef __MLXBF_BOOTCTL_H__ + #define __MLXBF_BOOTCTL_H__ + ++/* BlueField-specific SMC function IDs */ ++ + /* + * Request that the on-chip watchdog be enabled, or disabled, after + * the next chip soft reset. This call does not affect the current +@@ -14,14 +25,14 @@ + * will not be enabled after the next soft reset. Non-zero errors are + * returned as documented below. + */ +-#define MLXBF_BOOTCTL_SET_POST_RESET_WDOG 0x82000000 ++#define MLNX_SET_POST_RESET_WDOG 0x82000000 + + /* + * Query the status which has been requested for the on-chip watchdog + * after the next chip soft reset. Returns the interval as set by +- * MLXBF_BOOTCTL_SET_POST_RESET_WDOG. ++ * MLNX_SET_POST_RESET_WDOG. + */ +-#define MLXBF_BOOTCTL_GET_POST_RESET_WDOG 0x82000001 ++#define MLNX_GET_POST_RESET_WDOG 0x82000001 + + /* + * Request that a specific boot action be taken at the next soft +@@ -32,72 +43,77 @@ + * invoked. See below for the available MLNX_BOOT_xxx parameter + * values. Non-zero errors are returned as documented below. + */ +-#define MLXBF_BOOTCTL_SET_RESET_ACTION 0x82000002 ++#define MLNX_SET_RESET_ACTION 0x82000002 + + /* + * Return the specific boot action which will be taken at the next + * soft reset. Returns the reset action (see below for the parameter +- * values for MLXBF_BOOTCTL_SET_RESET_ACTION). ++ * values for MLNX_SET_RESET_ACTION). + */ +-#define MLXBF_BOOTCTL_GET_RESET_ACTION 0x82000003 ++#define MLNX_GET_RESET_ACTION 0x82000003 + + /* + * Request that a specific boot action be taken at the soft reset + * after the next soft reset. For a specified valid boot mode, the + * effect of this call is identical to that of invoking +- * MLXBF_BOOTCTL_SET_RESET_ACTION after the next chip soft reset; in ++ * MLNX_SET_RESET_ACTION after the next chip soft reset; in + * particular, after that reset, the action for the now next reset can +- * be queried with MLXBF_BOOTCTL_GET_RESET_ACTION and modified with +- * MLXBF_BOOTCTL_SET_RESET_ACTION. You may also specify the parameter as ++ * be queried with MLNX_GET_RESET_ACTION and modified with ++ * MLNX_SET_RESET_ACTION. You may also specify the parameter as + * MLNX_BOOT_NONE, which is equivalent to specifying that no call to +- * MLXBF_BOOTCTL_SET_RESET_ACTION be taken after the next chip soft reset. ++ * MLNX_SET_RESET_ACTION be taken after the next chip soft reset. + * This call does not affect the action to be taken at the next soft + * reset. Non-zero errors are returned as documented below. + */ +-#define MLXBF_BOOTCTL_SET_SECOND_RESET_ACTION 0x82000004 ++#define MLNX_SET_SECOND_RESET_ACTION 0x82000004 + + /* + * Return the specific boot action which will be taken at the soft + * reset after the next soft reset; this will be one of the valid +- * actions for MLXBF_BOOTCTL_SET_SECOND_RESET_ACTION. ++ * actions for MLNX_SET_SECOND_RESET_ACTION. + */ +-#define MLXBF_BOOTCTL_GET_SECOND_RESET_ACTION 0x82000005 ++#define MLNX_GET_SECOND_RESET_ACTION 0x82000005 + + /* + * Return the fuse status of the current chip. The caller should specify + * with the second argument if the state of the lifecycle fuses or the + * version of secure boot fuse keys left should be returned. + */ +-#define MLXBF_BOOTCTL_GET_TBB_FUSE_STATUS 0x82000006 ++#define MLNX_GET_TBB_FUSE_STATUS 0x82000006 + +-/* Reset eMMC by programming the RST_N register. */ +-#define MLXBF_BOOTCTL_SET_EMMC_RST_N 0x82000007 ++/* ++ * Initiate Firmware Reset via TYU. This might be invoked during the reset ++ * flow in isolation mode. ++ */ ++#define MLNX_HANDLE_FW_RESET 0x8200000D + +-#define MLXBF_BOOTCTL_GET_DIMM_INFO 0x82000008 ++/* ++ * SMC function IDs to set, get and reset the manufacturing information ++ * stored within the eeprom. ++ */ ++#define MLNX_HANDLE_SET_MFG_INFO 0x8200000E ++#define MLNX_HANDLE_GET_MFG_INFO 0x8200000F ++#define MLNX_HANDLE_LOCK_MFG_INFO 0x82000011 + + /* SMC function IDs for SiP Service queries */ +-#define MLXBF_BOOTCTL_SIP_SVC_CALL_COUNT 0x8200ff00 +-#define MLXBF_BOOTCTL_SIP_SVC_UID 0x8200ff01 +-#define MLXBF_BOOTCTL_SIP_SVC_VERSION 0x8200ff03 +- +-/* ARM Standard Service Calls version numbers */ +-#define MLXBF_BOOTCTL_SVC_VERSION_MAJOR 0x0 +-#define MLXBF_BOOTCTL_SVC_VERSION_MINOR 0x2 ++#define MLNX_SIP_SVC_CALL_COUNT 0x8200ff00 ++#define MLNX_SIP_SVC_UID 0x8200ff01 ++#define MLNX_SIP_SVC_VERSION 0x8200ff03 + + /* Number of svc calls defined. */ +-#define MLXBF_BOOTCTL_NUM_SVC_CALLS 12 ++#define MLNX_NUM_SVC_CALLS 16 + +-/* Valid reset actions for MLXBF_BOOTCTL_SET_RESET_ACTION. */ +-#define MLXBF_BOOTCTL_EXTERNAL 0 /* Not boot from eMMC */ +-#define MLXBF_BOOTCTL_EMMC 1 /* From primary eMMC boot partition */ +-#define MLNX_BOOTCTL_SWAP_EMMC 2 /* Swap eMMC boot partitions and reboot */ +-#define MLXBF_BOOTCTL_EMMC_LEGACY 3 /* From primary eMMC in legacy mode */ ++/* Valid reset actions for MLNX_SET_RESET_ACTION. */ ++#define MLNX_BOOT_EXTERNAL 0 /* Do not boot from eMMC */ ++#define MLNX_BOOT_EMMC 1 /* Boot from primary eMMC boot partition */ ++#define MLNX_BOOT_SWAP_EMMC 2 /* Swap eMMC boot partitions and reboot */ ++#define MLNX_BOOT_EMMC_LEGACY 3 /* Boot from primary eMMC in legacy mode */ + + /* Valid arguments for requesting the fuse status. */ +-#define MLXBF_BOOTCTL_FUSE_STATUS_LIFECYCLE 0 /* Return lifecycle status. */ +-#define MLXBF_BOOTCTL_FUSE_STATUS_KEYS 1 /* Return secure boot key status */ ++#define MLNX_FUSE_STATUS_LIFECYCLE 0 /* Return the lifecycle status. */ ++#define MLNX_FUSE_STATUS_KEYS 1 /* Return secure boot key status */ + +-/* Additional value to disable the MLXBF_BOOTCTL_SET_SECOND_RESET_ACTION. */ +-#define MLXBF_BOOTCTL_NONE 0x7fffffff /* Don't change next boot action */ ++/* Additional parameter value to disable the MLNX_SET_SECOND_RESET_ACTION. */ ++#define MLNX_BOOT_NONE 0x7fffffff /* Don't change next boot action */ + + #endif /* __MLXBF_BOOTCTL_H__ */ +-- +2.20.1 + diff --git a/patch/0212-platform-mellanox-mlxbf-pmc-Add-Mellanox-BlueField-P.patch b/patch/0212-platform-mellanox-mlxbf-pmc-Add-Mellanox-BlueField-P.patch new file mode 100644 index 000000000..03e53f059 --- /dev/null +++ b/patch/0212-platform-mellanox-mlxbf-pmc-Add-Mellanox-BlueField-P.patch @@ -0,0 +1,1560 @@ +From 4a2c58ddcfdcff3afbc62c170c4fc7bbf73a5a9f Mon Sep 17 00:00:00 2001 +From: Shravan Kumar Ramani +Date: Thu, 8 Oct 2020 08:37:17 -0400 +Subject: [PATCH backport 5.10 13/63] platform/mellanox: mlxbf-pmc: Add + Mellanox BlueField PMC driver + +The performance modules in BlueField are present in several hardware +blocks and each block provides access to these stats either through +counters that can be programmed to monitor supported events or +through memory-mapped registers that hold the relevant information. +The hardware blocks that include a performance module are: + * Tile (block containing 2 cores and a shared L2 cache) + * TRIO (PCIe root complex) + * MSS (Memory Sub-system containing the Memory Controller and L3 cache) + * GIC (Interrupt controller) + * SMMU (System Memory Management Unit) +The mlx_pmc driver provides access to all of these performance modules +through a hwmon sysfs interface. + +v2 --> v3 +Update copyright info. + +v1 --> v2 +Remove unused headers. +Add comma to arrays where last line is not a termination. +Use kstrtoint in place of sscanf. +UUID manipulation follows drivers/platform/mellanox/mlxbf-bootctl.c + +Signed-off-by: Shravan Kumar Ramani +Reviewed-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Link: https://lore.kernel.org/r/4e19a1e5bf4197ad27fc57981fd280eaebd23577.1602160468.git.shravankr@nvidia.com +Signed-off-by: Hans de Goede +--- + drivers/platform/mellanox/Kconfig | 10 + + drivers/platform/mellanox/Makefile | 1 + + drivers/platform/mellanox/mlxbf-pmc.c | 1478 +++++++++++++++++++++++++ + 3 files changed, 1489 insertions(+) + create mode 100644 drivers/platform/mellanox/mlxbf-pmc.c + +diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig +index 5bd6ddd42..b0d2c3343 100644 +--- a/drivers/platform/mellanox/Kconfig ++++ b/drivers/platform/mellanox/Kconfig +@@ -80,6 +80,16 @@ config MLXBF_BOOTCTL + to the userspace tools, to be used in conjunction with the eMMC + device driver to do necessary initial swap of the boot partition. + ++config MLXBF_PMC ++ tristate "Mellanox BlueField Performance Monitoring Counters driver" ++ depends on ARM64 ++ depends on HWMON ++ depends on ACPI ++ help ++ Say y here to enable PMC support. The PMC driver provides access ++ to performance monitoring counters within various blocks in the ++ Mellanox BlueField SoC via a sysfs interface. ++ + config NVSW_SN2201 + tristate "Nvidia SN2201 platform driver support" + depends on REGMAP +diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile +index 23919e56a..ba56485cb 100644 +--- a/drivers/platform/mellanox/Makefile ++++ b/drivers/platform/mellanox/Makefile +@@ -5,6 +5,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_HOTPLUG) += mlxreg-hotplug.o + obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o +diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c +new file mode 100644 +index 000000000..358839842 +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf-pmc.c +@@ -0,0 +1,1478 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB ++/* ++ * Mellanox BlueField Performance Monitoring Counters driver ++ * ++ * This driver provides a sysfs interface for monitoring ++ * performance statistics in BlueField SoC. ++ * ++ * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MLXBF_PMC_WRITE_REG_32 0x82000009 ++#define MLXBF_PMC_READ_REG_32 0x8200000A ++#define MLXBF_PMC_WRITE_REG_64 0x8200000B ++#define MLXBF_PMC_READ_REG_64 0x8200000C ++#define MLXBF_PMC_SIP_SVC_UID 0x8200ff01 ++#define MLXBF_PMC_SIP_SVC_VERSION 0x8200ff03 ++#define MLXBF_PMC_SVC_REQ_MAJOR 0 ++#define MLXBF_PMC_SVC_MIN_MINOR 3 ++ ++#define MLXBF_PMC_SMCCC_ACCESS_VIOLATION -4 ++ ++#define MLXBF_PMC_EVENT_SET_BF1 0 ++#define MLXBF_PMC_EVENT_SET_BF2 1 ++#define MLXBF_PMC_EVENT_INFO_LEN 100 ++ ++#define MLXBF_PMC_MAX_BLOCKS 30 ++#define MLXBF_PMC_MAX_ATTRS 30 ++#define MLXBF_PMC_INFO_SZ 4 ++#define MLXBF_PMC_REG_SIZE 8 ++#define MLXBF_PMC_L3C_REG_SIZE 4 ++ ++#define MLXBF_PMC_TYPE_COUNTER 1 ++#define MLXBF_PMC_TYPE_REGISTER 0 ++ ++#define MLXBF_PMC_PERFCTL 0 ++#define MLXBF_PMC_PERFEVT 1 ++#define MLXBF_PMC_PERFACC0 4 ++ ++#define MLXBF_PMC_PERFMON_CONFIG_WR_R_B BIT(0) ++#define MLXBF_PMC_PERFMON_CONFIG_STROBE BIT(1) ++#define MLXBF_PMC_PERFMON_CONFIG_ADDR GENMASK_ULL(4, 2) ++#define MLXBF_PMC_PERFMON_CONFIG_WDATA GENMASK_ULL(60, 5) ++ ++#define MLXBF_PMC_PERFCTL_FM0 GENMASK_ULL(18, 16) ++#define MLXBF_PMC_PERFCTL_MS0 GENMASK_ULL(21, 20) ++#define MLXBF_PMC_PERFCTL_ACCM0 GENMASK_ULL(26, 24) ++#define MLXBF_PMC_PERFCTL_AD0 BIT(27) ++#define MLXBF_PMC_PERFCTL_ETRIG0 GENMASK_ULL(29, 28) ++#define MLXBF_PMC_PERFCTL_EB0 BIT(30) ++#define MLXBF_PMC_PERFCTL_EN0 BIT(31) ++ ++#define MLXBF_PMC_PERFEVT_EVTSEL GENMASK_ULL(31, 24) ++ ++#define MLXBF_PMC_L3C_PERF_CNT_CFG 0x0 ++#define MLXBF_PMC_L3C_PERF_CNT_SEL 0x10 ++#define MLXBF_PMC_L3C_PERF_CNT_SEL_1 0x14 ++#define MLXBF_PMC_L3C_PERF_CNT_LOW 0x40 ++#define MLXBF_PMC_L3C_PERF_CNT_HIGH 0x60 ++ ++#define MLXBF_PMC_L3C_PERF_CNT_CFG_EN BIT(0) ++#define MLXBF_PMC_L3C_PERF_CNT_CFG_RST BIT(1) ++#define MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0 GENMASK(5, 0) ++#define MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1 GENMASK(13, 8) ++#define MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2 GENMASK(21, 16) ++#define MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3 GENMASK(29, 24) ++ ++#define MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4 GENMASK(5, 0) ++ ++#define MLXBF_PMC_L3C_PERF_CNT_LOW_VAL GENMASK(31, 0) ++#define MLXBF_PMC_L3C_PERF_CNT_HIGH_VAL GENMASK(24, 0) ++ ++/** ++ * Structure to hold attribute and block info for each sysfs entry ++ * @dev_attr: Device attribute struct ++ * @index: index to identify counter number within a block ++ * @nr: block number to which the sysfs belongs ++ */ ++struct mlxbf_pmc_attribute { ++ struct device_attribute dev_attr; ++ int index; ++ int nr; ++}; ++ ++/** ++ * Structure to hold info for each HW block ++ * ++ * @mmio_base: The VA at which the PMC block is mapped ++ * @blk_size: Size of each mapped region ++ * @counters: Number of counters in the block ++ * @type: Type of counters in the block ++ * @attr_counter: Attributes for "counter" sysfs files ++ * @attr_event: Attributes for "event" sysfs files ++ * @attr_event_list: Attributes for "event_list" sysfs files ++ * @attr_enable: Attributes for "enable" sysfs files ++ * @block_attr: All attributes needed for the block ++ * @blcok_attr_grp: Attribute group for the block ++ */ ++struct mlxbf_pmc_block_info { ++ void __iomem *mmio_base; ++ size_t blk_size; ++ size_t counters; ++ int type; ++ struct mlxbf_pmc_attribute *attr_counter; ++ struct mlxbf_pmc_attribute *attr_event; ++ struct mlxbf_pmc_attribute attr_event_list; ++ struct mlxbf_pmc_attribute attr_enable; ++ struct attribute *block_attr[MLXBF_PMC_MAX_ATTRS]; ++ struct attribute_group block_attr_grp; ++}; ++ ++/** ++ * Structure to hold PMC context info ++ * ++ * @pdev: The kernel structure representing the device ++ * @total_blocks: Total number of blocks ++ * @tile_count: Number of tiles in the system ++ * @hwmon_dev: Hwmon device for bfperf ++ * @block_name: Block name ++ * @block: Block info ++ * @groups: Attribute groups from each block ++ * @sv_sreg_support: Whether SMCs are used to access performance registers ++ * @sreg_tbl_perf: Secure register access table number ++ * @event_set: Event set to use ++ */ ++struct mlxbf_pmc_context { ++ struct platform_device *pdev; ++ uint32_t total_blocks; ++ uint32_t tile_count; ++ struct device *hwmon_dev; ++ const char *block_name[MLXBF_PMC_MAX_BLOCKS]; ++ struct mlxbf_pmc_block_info block[MLXBF_PMC_MAX_BLOCKS]; ++ const struct attribute_group *groups[MLXBF_PMC_MAX_BLOCKS]; ++ bool svc_sreg_support; ++ uint32_t sreg_tbl_perf; ++ unsigned int event_set; ++}; ++ ++/** ++ * Structure to hold supported events for each block ++ * @evt_num: Event number used to program counters ++ * @evt_name: Name of the event ++ */ ++struct mlxbf_pmc_events { ++ int evt_num; ++ char *evt_name; ++}; ++ ++static const struct mlxbf_pmc_events mlxbf_pmc_pcie_events[] = { ++ { 0x0, "IN_P_PKT_CNT" }, ++ { 0x10, "IN_NP_PKT_CNT" }, ++ { 0x18, "IN_C_PKT_CNT" }, ++ { 0x20, "OUT_P_PKT_CNT" }, ++ { 0x28, "OUT_NP_PKT_CNT" }, ++ { 0x30, "OUT_C_PKT_CNT" }, ++ { 0x38, "IN_P_BYTE_CNT" }, ++ { 0x40, "IN_NP_BYTE_CNT" }, ++ { 0x48, "IN_C_BYTE_CNT" }, ++ { 0x50, "OUT_P_BYTE_CNT" }, ++ { 0x58, "OUT_NP_BYTE_CNT" }, ++ { 0x60, "OUT_C_BYTE_CNT" }, ++}; ++ ++static const struct mlxbf_pmc_events mlxbf_pmc_smgen_events[] = { ++ { 0x0, "AW_REQ" }, ++ { 0x1, "AW_BEATS" }, ++ { 0x2, "AW_TRANS" }, ++ { 0x3, "AW_RESP" }, ++ { 0x4, "AW_STL" }, ++ { 0x5, "AW_LAT" }, ++ { 0x6, "AW_REQ_TBU" }, ++ { 0x8, "AR_REQ" }, ++ { 0x9, "AR_BEATS" }, ++ { 0xa, "AR_TRANS" }, ++ { 0xb, "AR_STL" }, ++ { 0xc, "AR_LAT" }, ++ { 0xd, "AR_REQ_TBU" }, ++ { 0xe, "TBU_MISS" }, ++ { 0xf, "TX_DAT_AF" }, ++ { 0x10, "RX_DAT_AF" }, ++ { 0x11, "RETRYQ_CRED" }, ++}; ++ ++static const struct mlxbf_pmc_events mlxbf_pmc_trio_events_1[] = { ++ { 0xa0, "TPIO_DATA_BEAT" }, ++ { 0xa1, "TDMA_DATA_BEAT" }, ++ { 0xa2, "MAP_DATA_BEAT" }, ++ { 0xa3, "TXMSG_DATA_BEAT" }, ++ { 0xa4, "TPIO_DATA_PACKET" }, ++ { 0xa5, "TDMA_DATA_PACKET" }, ++ { 0xa6, "MAP_DATA_PACKET" }, ++ { 0xa7, "TXMSG_DATA_PACKET" }, ++ { 0xa8, "TDMA_RT_AF" }, ++ { 0xa9, "TDMA_PBUF_MAC_AF" }, ++ { 0xaa, "TRIO_MAP_WRQ_BUF_EMPTY" }, ++ { 0xab, "TRIO_MAP_CPL_BUF_EMPTY" }, ++ { 0xac, "TRIO_MAP_RDQ0_BUF_EMPTY" }, ++ { 0xad, "TRIO_MAP_RDQ1_BUF_EMPTY" }, ++ { 0xae, "TRIO_MAP_RDQ2_BUF_EMPTY" }, ++ { 0xaf, "TRIO_MAP_RDQ3_BUF_EMPTY" }, ++ { 0xb0, "TRIO_MAP_RDQ4_BUF_EMPTY" }, ++ { 0xb1, "TRIO_MAP_RDQ5_BUF_EMPTY" }, ++ { 0xb2, "TRIO_MAP_RDQ6_BUF_EMPTY" }, ++ { 0xb3, "TRIO_MAP_RDQ7_BUF_EMPTY" }, ++}; ++ ++static const struct mlxbf_pmc_events mlxbf_pmc_trio_events_2[] = { ++ { 0xa0, "TPIO_DATA_BEAT" }, ++ { 0xa1, "TDMA_DATA_BEAT" }, ++ { 0xa2, "MAP_DATA_BEAT" }, ++ { 0xa3, "TXMSG_DATA_BEAT" }, ++ { 0xa4, "TPIO_DATA_PACKET" }, ++ { 0xa5, "TDMA_DATA_PACKET" }, ++ { 0xa6, "MAP_DATA_PACKET" }, ++ { 0xa7, "TXMSG_DATA_PACKET" }, ++ { 0xa8, "TDMA_RT_AF" }, ++ { 0xa9, "TDMA_PBUF_MAC_AF" }, ++ { 0xaa, "TRIO_MAP_WRQ_BUF_EMPTY" }, ++ { 0xab, "TRIO_MAP_CPL_BUF_EMPTY" }, ++ { 0xac, "TRIO_MAP_RDQ0_BUF_EMPTY" }, ++ { 0xad, "TRIO_MAP_RDQ1_BUF_EMPTY" }, ++ { 0xae, "TRIO_MAP_RDQ2_BUF_EMPTY" }, ++ { 0xaf, "TRIO_MAP_RDQ3_BUF_EMPTY" }, ++ { 0xb0, "TRIO_MAP_RDQ4_BUF_EMPTY" }, ++ { 0xb1, "TRIO_MAP_RDQ5_BUF_EMPTY" }, ++ { 0xb2, "TRIO_MAP_RDQ6_BUF_EMPTY" }, ++ { 0xb3, "TRIO_MAP_RDQ7_BUF_EMPTY" }, ++ { 0xb4, "TRIO_RING_TX_FLIT_CH0" }, ++ { 0xb5, "TRIO_RING_TX_FLIT_CH1" }, ++ { 0xb6, "TRIO_RING_TX_FLIT_CH2" }, ++ { 0xb7, "TRIO_RING_TX_FLIT_CH3" }, ++ { 0xb8, "TRIO_RING_TX_FLIT_CH4" }, ++ { 0xb9, "TRIO_RING_RX_FLIT_CH0" }, ++ { 0xba, "TRIO_RING_RX_FLIT_CH1" }, ++ { 0xbb, "TRIO_RING_RX_FLIT_CH2" }, ++ { 0xbc, "TRIO_RING_RX_FLIT_CH3" }, ++}; ++ ++static const struct mlxbf_pmc_events mlxbf_pmc_ecc_events[] = { ++ { 0x100, "ECC_SINGLE_ERROR_CNT" }, ++ { 0x104, "ECC_DOUBLE_ERROR_CNT" }, ++ { 0x114, "SERR_INJ" }, ++ { 0x118, "DERR_INJ" }, ++ { 0x124, "ECC_SINGLE_ERROR_0" }, ++ { 0x164, "ECC_DOUBLE_ERROR_0" }, ++ { 0x340, "DRAM_ECC_COUNT" }, ++ { 0x344, "DRAM_ECC_INJECT" }, ++ { 0x348, "DRAM_ECC_ERROR" }, ++}; ++ ++static const struct mlxbf_pmc_events mlxbf_pmc_mss_events[] = { ++ { 0xc0, "RXREQ_MSS" }, ++ { 0xc1, "RXDAT_MSS" }, ++ { 0xc2, "TXRSP_MSS" }, ++ { 0xc3, "TXDAT_MSS" }, ++}; ++ ++static const struct mlxbf_pmc_events mlxbf_pmc_hnf_events[] = { ++ { 0x45, "HNF_REQUESTS" }, ++ { 0x46, "HNF_REJECTS" }, ++ { 0x47, "ALL_BUSY" }, ++ { 0x48, "MAF_BUSY" }, ++ { 0x49, "MAF_REQUESTS" }, ++ { 0x4a, "RNF_REQUESTS" }, ++ { 0x4b, "REQUEST_TYPE" }, ++ { 0x4c, "MEMORY_READS" }, ++ { 0x4d, "MEMORY_WRITES" }, ++ { 0x4e, "VICTIM_WRITE" }, ++ { 0x4f, "POC_FULL" }, ++ { 0x50, "POC_FAIL" }, ++ { 0x51, "POC_SUCCESS" }, ++ { 0x52, "POC_WRITES" }, ++ { 0x53, "POC_READS" }, ++ { 0x54, "FORWARD" }, ++ { 0x55, "RXREQ_HNF" }, ++ { 0x56, "RXRSP_HNF" }, ++ { 0x57, "RXDAT_HNF" }, ++ { 0x58, "TXREQ_HNF" }, ++ { 0x59, "TXRSP_HNF" }, ++ { 0x5a, "TXDAT_HNF" }, ++ { 0x5b, "TXSNP_HNF" }, ++ { 0x5c, "INDEX_MATCH" }, ++ { 0x5d, "A72_ACCESS" }, ++ { 0x5e, "IO_ACCESS" }, ++ { 0x5f, "TSO_WRITE" }, ++ { 0x60, "TSO_CONFLICT" }, ++ { 0x61, "DIR_HIT" }, ++ { 0x62, "HNF_ACCEPTS" }, ++ { 0x63, "REQ_BUF_EMPTY" }, ++ { 0x64, "REQ_BUF_IDLE_MAF" }, ++ { 0x65, "TSO_NOARB" }, ++ { 0x66, "TSO_NOARB_CYCLES" }, ++ { 0x67, "MSS_NO_CREDIT" }, ++ { 0x68, "TXDAT_NO_LCRD" }, ++ { 0x69, "TXSNP_NO_LCRD" }, ++ { 0x6a, "TXRSP_NO_LCRD" }, ++ { 0x6b, "TXREQ_NO_LCRD" }, ++ { 0x6c, "TSO_CL_MATCH" }, ++ { 0x6d, "MEMORY_READS_BYPASS" }, ++ { 0x6e, "TSO_NOARB_TIMEOUT" }, ++ { 0x6f, "ALLOCATE" }, ++ { 0x70, "VICTIM" }, ++ { 0x71, "A72_WRITE" }, ++ { 0x72, "A72_READ" }, ++ { 0x73, "IO_WRITE" }, ++ { 0x74, "IO_READ" }, ++ { 0x75, "TSO_REJECT" }, ++ { 0x80, "TXREQ_RN" }, ++ { 0x81, "TXRSP_RN" }, ++ { 0x82, "TXDAT_RN" }, ++ { 0x83, "RXSNP_RN" }, ++ { 0x84, "RXRSP_RN" }, ++ { 0x85, "RXDAT_RN" }, ++}; ++ ++static const struct mlxbf_pmc_events mlxbf_pmc_hnfnet_events[] = { ++ { 0x12, "CDN_REQ" }, ++ { 0x13, "DDN_REQ" }, ++ { 0x14, "NDN_REQ" }, ++ { 0x15, "CDN_DIAG_N_OUT_OF_CRED" }, ++ { 0x16, "CDN_DIAG_S_OUT_OF_CRED" }, ++ { 0x17, "CDN_DIAG_E_OUT_OF_CRED" }, ++ { 0x18, "CDN_DIAG_W_OUT_OF_CRED" }, ++ { 0x19, "CDN_DIAG_C_OUT_OF_CRED" }, ++ { 0x1a, "CDN_DIAG_N_EGRESS" }, ++ { 0x1b, "CDN_DIAG_S_EGRESS" }, ++ { 0x1c, "CDN_DIAG_E_EGRESS" }, ++ { 0x1d, "CDN_DIAG_W_EGRESS" }, ++ { 0x1e, "CDN_DIAG_C_EGRESS" }, ++ { 0x1f, "CDN_DIAG_N_INGRESS" }, ++ { 0x20, "CDN_DIAG_S_INGRESS" }, ++ { 0x21, "CDN_DIAG_E_INGRESS" }, ++ { 0x22, "CDN_DIAG_W_INGRESS" }, ++ { 0x23, "CDN_DIAG_C_INGRESS" }, ++ { 0x24, "CDN_DIAG_CORE_SENT" }, ++ { 0x25, "DDN_DIAG_N_OUT_OF_CRED" }, ++ { 0x26, "DDN_DIAG_S_OUT_OF_CRED" }, ++ { 0x27, "DDN_DIAG_E_OUT_OF_CRED" }, ++ { 0x28, "DDN_DIAG_W_OUT_OF_CRED" }, ++ { 0x29, "DDN_DIAG_C_OUT_OF_CRED" }, ++ { 0x2a, "DDN_DIAG_N_EGRESS" }, ++ { 0x2b, "DDN_DIAG_S_EGRESS" }, ++ { 0x2c, "DDN_DIAG_E_EGRESS" }, ++ { 0x2d, "DDN_DIAG_W_EGRESS" }, ++ { 0x2e, "DDN_DIAG_C_EGRESS" }, ++ { 0x2f, "DDN_DIAG_N_INGRESS" }, ++ { 0x30, "DDN_DIAG_S_INGRESS" }, ++ { 0x31, "DDN_DIAG_E_INGRESS" }, ++ { 0x32, "DDN_DIAG_W_INGRESS" }, ++ { 0x33, "DDN_DIAG_C_INGRESS" }, ++ { 0x34, "DDN_DIAG_CORE_SENT" }, ++ { 0x35, "NDN_DIAG_S_OUT_OF_CRED" }, ++ { 0x36, "NDN_DIAG_S_OUT_OF_CRED" }, ++ { 0x37, "NDN_DIAG_E_OUT_OF_CRED" }, ++ { 0x38, "NDN_DIAG_W_OUT_OF_CRED" }, ++ { 0x39, "NDN_DIAG_C_OUT_OF_CRED" }, ++ { 0x3a, "NDN_DIAG_N_EGRESS" }, ++ { 0x3b, "NDN_DIAG_S_EGRESS" }, ++ { 0x3c, "NDN_DIAG_E_EGRESS" }, ++ { 0x3d, "NDN_DIAG_W_EGRESS" }, ++ { 0x3e, "NDN_DIAG_C_EGRESS" }, ++ { 0x3f, "NDN_DIAG_N_INGRESS" }, ++ { 0x40, "NDN_DIAG_S_INGRESS" }, ++ { 0x41, "NDN_DIAG_E_INGRESS" }, ++ { 0x42, "NDN_DIAG_W_INGRESS" }, ++ { 0x43, "NDN_DIAG_C_INGRESS" }, ++ { 0x44, "NDN_DIAG_CORE_SENT" }, ++}; ++ ++static const struct mlxbf_pmc_events mlxbf_pmc_l3c_events[] = { ++ { 0x00, "DISABLE" }, ++ { 0x01, "CYCLES" }, ++ { 0x02, "TOTAL_RD_REQ_IN" }, ++ { 0x03, "TOTAL_WR_REQ_IN" }, ++ { 0x04, "TOTAL_WR_DBID_ACK" }, ++ { 0x05, "TOTAL_WR_DATA_IN" }, ++ { 0x06, "TOTAL_WR_COMP" }, ++ { 0x07, "TOTAL_RD_DATA_OUT" }, ++ { 0x08, "TOTAL_CDN_REQ_IN_BANK0" }, ++ { 0x09, "TOTAL_CDN_REQ_IN_BANK1" }, ++ { 0x0a, "TOTAL_DDN_REQ_IN_BANK0" }, ++ { 0x0b, "TOTAL_DDN_REQ_IN_BANK1" }, ++ { 0x0c, "TOTAL_EMEM_RD_RES_IN_BANK0" }, ++ { 0x0d, "TOTAL_EMEM_RD_RES_IN_BANK1" }, ++ { 0x0e, "TOTAL_CACHE_RD_RES_IN_BANK0" }, ++ { 0x0f, "TOTAL_CACHE_RD_RES_IN_BANK1" }, ++ { 0x10, "TOTAL_EMEM_RD_REQ_BANK0" }, ++ { 0x11, "TOTAL_EMEM_RD_REQ_BANK1" }, ++ { 0x12, "TOTAL_EMEM_WR_REQ_BANK0" }, ++ { 0x13, "TOTAL_EMEM_WR_REQ_BANK1" }, ++ { 0x14, "TOTAL_RD_REQ_OUT" }, ++ { 0x15, "TOTAL_WR_REQ_OUT" }, ++ { 0x16, "TOTAL_RD_RES_IN" }, ++ { 0x17, "HITS_BANK0" }, ++ { 0x18, "HITS_BANK1" }, ++ { 0x19, "MISSES_BANK0" }, ++ { 0x1a, "MISSES_BANK1" }, ++ { 0x1b, "ALLOCATIONS_BANK0" }, ++ { 0x1c, "ALLOCATIONS_BANK1" }, ++ { 0x1d, "EVICTIONS_BANK0" }, ++ { 0x1e, "EVICTIONS_BANK1" }, ++ { 0x1f, "DBID_REJECT" }, ++ { 0x20, "WRDB_REJECT_BANK0" }, ++ { 0x21, "WRDB_REJECT_BANK1" }, ++ { 0x22, "CMDQ_REJECT_BANK0" }, ++ { 0x23, "CMDQ_REJECT_BANK1" }, ++ { 0x24, "COB_REJECT_BANK0" }, ++ { 0x25, "COB_REJECT_BANK1" }, ++ { 0x26, "TRB_REJECT_BANK0" }, ++ { 0x27, "TRB_REJECT_BANK1" }, ++ { 0x28, "TAG_REJECT_BANK0" }, ++ { 0x29, "TAG_REJECT_BANK1" }, ++ { 0x2a, "ANY_REJECT_BANK0" }, ++ { 0x2b, "ANY_REJECT_BANK1" }, ++}; ++ ++static struct mlxbf_pmc_context *pmc; ++ ++/* UUID used to probe ATF service. */ ++static const char *mlxbf_pmc_svc_uuid_str = "89c036b4-e7d7-11e6-8797-001aca00bfc4"; ++ ++/* Calls an SMC to access a performance register */ ++static int mlxbf_pmc_secure_read(void __iomem *addr, uint32_t command, ++ uint64_t *result) ++{ ++ struct arm_smccc_res res; ++ int status, err = 0; ++ ++ arm_smccc_smc(command, pmc->sreg_tbl_perf, (uintptr_t)addr, 0, 0, 0, 0, ++ 0, &res); ++ ++ status = res.a0; ++ ++ switch (status) { ++ case PSCI_RET_NOT_SUPPORTED: ++ err = -EINVAL; ++ break; ++ case MLXBF_PMC_SMCCC_ACCESS_VIOLATION: ++ err = -EACCES; ++ break; ++ default: ++ *result = res.a1; ++ break; ++ } ++ ++ return err; ++} ++ ++/* Read from a performance counter */ ++static int mlxbf_pmc_read(void __iomem *addr, uint32_t command, ++ uint64_t *result) ++{ ++ if (pmc->svc_sreg_support) ++ return mlxbf_pmc_secure_read(addr, command, result); ++ ++ if (command == MLXBF_PMC_READ_REG_32) ++ *result = readl(addr); ++ else ++ *result = readq(addr); ++ ++ return 0; ++} ++ ++/* Convenience function for 32-bit reads */ ++static int mlxbf_pmc_readl(void __iomem *addr, uint32_t *result) ++{ ++ uint64_t read_out; ++ int status; ++ ++ status = mlxbf_pmc_read(addr, MLXBF_PMC_READ_REG_32, &read_out); ++ if (status) ++ return status; ++ *result = (uint32_t)read_out; ++ ++ return 0; ++} ++ ++/* Calls an SMC to access a performance register */ ++static int mlxbf_pmc_secure_write(void __iomem *addr, uint32_t command, ++ uint64_t value) ++{ ++ struct arm_smccc_res res; ++ int status, err = 0; ++ ++ arm_smccc_smc(command, pmc->sreg_tbl_perf, value, (uintptr_t)addr, 0, 0, ++ 0, 0, &res); ++ ++ status = res.a0; ++ ++ switch (status) { ++ case PSCI_RET_NOT_SUPPORTED: ++ err = -EINVAL; ++ break; ++ case MLXBF_PMC_SMCCC_ACCESS_VIOLATION: ++ err = -EACCES; ++ break; ++ } ++ ++ return err; ++} ++ ++/* Write to a performance counter */ ++static int mlxbf_pmc_write(void __iomem *addr, int command, uint64_t value) ++{ ++ if (pmc->svc_sreg_support) ++ return mlxbf_pmc_secure_write(addr, command, value); ++ ++ if (command == MLXBF_PMC_WRITE_REG_32) ++ writel(value, addr); ++ else ++ writeq(value, addr); ++ ++ return 0; ++} ++ ++/* Check if the register offset is within the mapped region for the block */ ++static bool mlxbf_pmc_valid_range(int blk_num, uint32_t offset) ++{ ++ if ((offset >= 0) && !(offset % MLXBF_PMC_REG_SIZE) && ++ (offset + MLXBF_PMC_REG_SIZE <= pmc->block[blk_num].blk_size)) ++ return true; /* inside the mapped PMC space */ ++ ++ return false; ++} ++ ++/* Get the event list corresponding to a certain block */ ++static const struct mlxbf_pmc_events *mlxbf_pmc_event_list(const char *blk, ++ int *size) ++{ ++ const struct mlxbf_pmc_events *events; ++ ++ if (strstr(blk, "tilenet")) { ++ events = mlxbf_pmc_hnfnet_events; ++ *size = ARRAY_SIZE(mlxbf_pmc_hnfnet_events); ++ } else if (strstr(blk, "tile")) { ++ events = mlxbf_pmc_hnf_events; ++ *size = ARRAY_SIZE(mlxbf_pmc_hnf_events); ++ } else if (strstr(blk, "triogen")) { ++ events = mlxbf_pmc_smgen_events; ++ *size = ARRAY_SIZE(mlxbf_pmc_smgen_events); ++ } else if (strstr(blk, "trio")) { ++ switch (pmc->event_set) { ++ case MLXBF_PMC_EVENT_SET_BF1: ++ events = mlxbf_pmc_trio_events_1; ++ *size = ARRAY_SIZE(mlxbf_pmc_trio_events_1); ++ break; ++ case MLXBF_PMC_EVENT_SET_BF2: ++ events = mlxbf_pmc_trio_events_2; ++ *size = ARRAY_SIZE(mlxbf_pmc_trio_events_2); ++ break; ++ default: ++ events = NULL; ++ *size = 0; ++ break; ++ } ++ } else if (strstr(blk, "mss")) { ++ events = mlxbf_pmc_mss_events; ++ *size = ARRAY_SIZE(mlxbf_pmc_mss_events); ++ } else if (strstr(blk, "ecc")) { ++ events = mlxbf_pmc_ecc_events; ++ *size = ARRAY_SIZE(mlxbf_pmc_ecc_events); ++ } else if (strstr(blk, "pcie")) { ++ events = mlxbf_pmc_pcie_events; ++ *size = ARRAY_SIZE(mlxbf_pmc_pcie_events); ++ } else if (strstr(blk, "l3cache")) { ++ events = mlxbf_pmc_l3c_events; ++ *size = ARRAY_SIZE(mlxbf_pmc_l3c_events); ++ } else if (strstr(blk, "gic")) { ++ events = mlxbf_pmc_smgen_events; ++ *size = ARRAY_SIZE(mlxbf_pmc_smgen_events); ++ } else if (strstr(blk, "smmu")) { ++ events = mlxbf_pmc_smgen_events; ++ *size = ARRAY_SIZE(mlxbf_pmc_smgen_events); ++ } else { ++ events = NULL; ++ *size = 0; ++ } ++ ++ return events; ++} ++ ++/* Get the event number given the name */ ++static int mlxbf_pmc_get_event_num(const char *blk, const char *evt) ++{ ++ const struct mlxbf_pmc_events *events; ++ int i, size; ++ ++ events = mlxbf_pmc_event_list(blk, &size); ++ if (!events) ++ return -EINVAL; ++ ++ for (i = 0; i < size; ++i) { ++ if (!strcmp(evt, events[i].evt_name)) ++ return events[i].evt_num; ++ } ++ ++ return -ENODEV; ++} ++ ++/* Get the event number given the name */ ++static char *mlxbf_pmc_get_event_name(const char *blk, int evt) ++{ ++ const struct mlxbf_pmc_events *events; ++ int i, size; ++ ++ events = mlxbf_pmc_event_list(blk, &size); ++ if (!events) ++ return NULL; ++ ++ for (i = 0; i < size; ++i) { ++ if (evt == events[i].evt_num) ++ return events[i].evt_name; ++ } ++ ++ return NULL; ++} ++ ++/* Method to enable/disable/reset l3cache counters */ ++static int mlxbf_pmc_config_l3_counters(int blk_num, bool enable, bool reset) ++{ ++ uint32_t perfcnt_cfg = 0; ++ ++ if (enable) ++ perfcnt_cfg |= MLXBF_PMC_L3C_PERF_CNT_CFG_EN; ++ if (reset) ++ perfcnt_cfg |= MLXBF_PMC_L3C_PERF_CNT_CFG_RST; ++ ++ return mlxbf_pmc_write(pmc->block[blk_num].mmio_base + ++ MLXBF_PMC_L3C_PERF_CNT_CFG, ++ MLXBF_PMC_WRITE_REG_32, perfcnt_cfg); ++} ++ ++/* Method to handle l3cache counter programming */ ++static int mlxbf_pmc_program_l3_counter(int blk_num, uint32_t cnt_num, ++ uint32_t evt) ++{ ++ uint32_t perfcnt_sel_1 = 0; ++ uint32_t perfcnt_sel = 0; ++ uint32_t *wordaddr; ++ void __iomem *pmcaddr; ++ int ret; ++ ++ /* Disable all counters before programming them */ ++ if (mlxbf_pmc_config_l3_counters(blk_num, false, false)) ++ return -EINVAL; ++ ++ /* Select appropriate register information */ ++ switch (cnt_num) { ++ case 0 ... 3: ++ pmcaddr = pmc->block[blk_num].mmio_base + ++ MLXBF_PMC_L3C_PERF_CNT_SEL; ++ wordaddr = &perfcnt_sel; ++ break; ++ case 4: ++ pmcaddr = pmc->block[blk_num].mmio_base + ++ MLXBF_PMC_L3C_PERF_CNT_SEL_1; ++ wordaddr = &perfcnt_sel_1; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ ret = mlxbf_pmc_readl(pmcaddr, wordaddr); ++ if (ret) ++ return ret; ++ ++ switch (cnt_num) { ++ case 0: ++ perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0; ++ perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0, ++ evt); ++ break; ++ case 1: ++ perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1; ++ perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1, ++ evt); ++ break; ++ case 2: ++ perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2; ++ perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2, ++ evt); ++ break; ++ case 3: ++ perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3; ++ perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3, ++ evt); ++ break; ++ case 4: ++ perfcnt_sel_1 &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4; ++ perfcnt_sel_1 |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4, ++ evt); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return mlxbf_pmc_write(pmcaddr, MLXBF_PMC_WRITE_REG_32, *wordaddr); ++} ++ ++/* Method to program a counter to monitor an event */ ++static int mlxbf_pmc_program_counter(int blk_num, uint32_t cnt_num, ++ uint32_t evt, bool is_l3) ++{ ++ uint64_t perfctl, perfevt, perfmon_cfg; ++ ++ if (cnt_num >= pmc->block[blk_num].counters) ++ return -ENODEV; ++ ++ if (is_l3) ++ return mlxbf_pmc_program_l3_counter(blk_num, cnt_num, evt); ++ ++ /* Configure the counter */ ++ perfctl = FIELD_PREP(MLXBF_PMC_PERFCTL_EN0, 1); ++ perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_EB0, 0); ++ perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_ETRIG0, 1); ++ perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_AD0, 0); ++ perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_ACCM0, 0); ++ perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_MS0, 0); ++ perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_FM0, 0); ++ ++ perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WDATA, perfctl); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, ++ MLXBF_PMC_PERFCTL); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 1); ++ ++ if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + ++ cnt_num * MLXBF_PMC_REG_SIZE, ++ MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) ++ return -EFAULT; ++ ++ /* Select the event */ ++ perfevt = FIELD_PREP(MLXBF_PMC_PERFEVT_EVTSEL, evt); ++ ++ perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WDATA, perfevt); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, ++ MLXBF_PMC_PERFEVT); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 1); ++ ++ if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + ++ cnt_num * MLXBF_PMC_REG_SIZE, ++ MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) ++ return -EFAULT; ++ ++ /* Clear the accumulator */ ++ perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, ++ MLXBF_PMC_PERFACC0); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 1); ++ ++ if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + ++ cnt_num * MLXBF_PMC_REG_SIZE, ++ MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++/* Method to handle l3 counter reads */ ++static int mlxbf_pmc_read_l3_counter(int blk_num, uint32_t cnt_num, ++ uint64_t *result) ++{ ++ uint32_t perfcnt_low = 0, perfcnt_high = 0; ++ uint64_t value; ++ int status = 0; ++ ++ status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + ++ MLXBF_PMC_L3C_PERF_CNT_LOW + ++ cnt_num * MLXBF_PMC_L3C_REG_SIZE, ++ &perfcnt_low); ++ ++ if (status) ++ return status; ++ ++ status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + ++ MLXBF_PMC_L3C_PERF_CNT_HIGH + ++ cnt_num * MLXBF_PMC_L3C_REG_SIZE, ++ &perfcnt_high); ++ ++ if (status) ++ return status; ++ ++ value = perfcnt_high; ++ value = value << 32; ++ value |= perfcnt_low; ++ *result = value; ++ ++ return 0; ++} ++ ++/* Method to read the counter value */ ++static int mlxbf_pmc_read_counter(int blk_num, uint32_t cnt_num, bool is_l3, ++ uint64_t *result) ++{ ++ uint32_t perfcfg_offset, perfval_offset; ++ uint64_t perfmon_cfg; ++ int status; ++ ++ if (cnt_num >= pmc->block[blk_num].counters) ++ return -EINVAL; ++ ++ if (is_l3) ++ return mlxbf_pmc_read_l3_counter(blk_num, cnt_num, result); ++ ++ perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE; ++ perfval_offset = perfcfg_offset + ++ pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE; ++ ++ /* Set counter in "read" mode */ ++ perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, ++ MLXBF_PMC_PERFACC0); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 0); ++ ++ status = mlxbf_pmc_write(pmc->block[blk_num].mmio_base + perfcfg_offset, ++ MLXBF_PMC_WRITE_REG_64, perfmon_cfg); ++ ++ if (status) ++ return status; ++ ++ /* Get the counter value */ ++ return mlxbf_pmc_read(pmc->block[blk_num].mmio_base + perfval_offset, ++ MLXBF_PMC_READ_REG_64, result); ++} ++ ++/* Method to read L3 block event */ ++static int mlxbf_pmc_read_l3_event(int blk_num, uint32_t cnt_num, ++ uint64_t *result) ++{ ++ uint32_t perfcnt_sel = 0, perfcnt_sel_1 = 0; ++ uint32_t *wordaddr; ++ void __iomem *pmcaddr; ++ uint64_t evt; ++ ++ /* Select appropriate register information */ ++ switch (cnt_num) { ++ case 0 ... 3: ++ pmcaddr = pmc->block[blk_num].mmio_base + ++ MLXBF_PMC_L3C_PERF_CNT_SEL; ++ wordaddr = &perfcnt_sel; ++ break; ++ case 4: ++ pmcaddr = pmc->block[blk_num].mmio_base + ++ MLXBF_PMC_L3C_PERF_CNT_SEL_1; ++ wordaddr = &perfcnt_sel_1; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (mlxbf_pmc_readl(pmcaddr, wordaddr)) ++ return -EINVAL; ++ ++ /* Read from appropriate register field for the counter */ ++ switch (cnt_num) { ++ case 0: ++ evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0, perfcnt_sel); ++ break; ++ case 1: ++ evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1, perfcnt_sel); ++ break; ++ case 2: ++ evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2, perfcnt_sel); ++ break; ++ case 3: ++ evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3, perfcnt_sel); ++ break; ++ case 4: ++ evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4, ++ perfcnt_sel_1); ++ break; ++ default: ++ return -EINVAL; ++ } ++ *result = evt; ++ ++ return 0; ++} ++ ++/* Method to find the event currently being monitored by a counter */ ++static int mlxbf_pmc_read_event(int blk_num, uint32_t cnt_num, bool is_l3, ++ uint64_t *result) ++{ ++ uint32_t perfcfg_offset, perfval_offset; ++ uint64_t perfmon_cfg, perfevt, perfctl; ++ ++ if (cnt_num >= pmc->block[blk_num].counters) ++ return -EINVAL; ++ ++ if (is_l3) ++ return mlxbf_pmc_read_l3_event(blk_num, cnt_num, result); ++ ++ perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE; ++ perfval_offset = perfcfg_offset + ++ pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE; ++ ++ /* Set counter in "read" mode */ ++ perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, ++ MLXBF_PMC_PERFCTL); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 0); ++ ++ if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + perfcfg_offset, ++ MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) ++ return -EFAULT; ++ ++ /* Check if the counter is enabled */ ++ ++ if (mlxbf_pmc_read(pmc->block[blk_num].mmio_base + perfval_offset, ++ MLXBF_PMC_READ_REG_64, &perfctl)) ++ return -EFAULT; ++ ++ if (!FIELD_GET(MLXBF_PMC_PERFCTL_EN0, perfctl)) ++ return -EINVAL; ++ ++ /* Set counter in "read" mode */ ++ perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, ++ MLXBF_PMC_PERFEVT); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); ++ perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 0); ++ ++ if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + perfcfg_offset, ++ MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) ++ return -EFAULT; ++ ++ /* Get the event number */ ++ if (mlxbf_pmc_read(pmc->block[blk_num].mmio_base + perfval_offset, ++ MLXBF_PMC_READ_REG_64, &perfevt)) ++ return -EFAULT; ++ ++ *result = FIELD_GET(MLXBF_PMC_PERFEVT_EVTSEL, perfevt); ++ ++ return 0; ++} ++ ++/* Method to read a register */ ++static int mlxbf_pmc_read_reg(int blk_num, uint32_t offset, uint64_t *result) ++{ ++ uint32_t ecc_out; ++ ++ if (strstr(pmc->block_name[blk_num], "ecc")) { ++ if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + offset, ++ &ecc_out)) ++ return -EFAULT; ++ ++ *result = ecc_out; ++ return 0; ++ } ++ ++ if (mlxbf_pmc_valid_range(blk_num, offset)) ++ return mlxbf_pmc_read(pmc->block[blk_num].mmio_base + offset, ++ MLXBF_PMC_READ_REG_64, result); ++ ++ return -EINVAL; ++} ++ ++/* Method to write to a register */ ++static int mlxbf_pmc_write_reg(int blk_num, uint32_t offset, uint64_t data) ++{ ++ if (strstr(pmc->block_name[blk_num], "ecc")) { ++ return mlxbf_pmc_write(pmc->block[blk_num].mmio_base + offset, ++ MLXBF_PMC_WRITE_REG_32, data); ++ } ++ ++ if (mlxbf_pmc_valid_range(blk_num, offset)) ++ return mlxbf_pmc_write(pmc->block[blk_num].mmio_base + offset, ++ MLXBF_PMC_WRITE_REG_64, data); ++ ++ return -EINVAL; ++} ++ ++/* Show function for "counter" sysfs files */ ++static ssize_t mlxbf_pmc_counter_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct mlxbf_pmc_attribute *attr_counter = container_of( ++ attr, struct mlxbf_pmc_attribute, dev_attr); ++ int blk_num, cnt_num, offset; ++ bool is_l3 = false; ++ uint64_t value; ++ ++ blk_num = attr_counter->nr; ++ cnt_num = attr_counter->index; ++ ++ if (strstr(pmc->block_name[blk_num], "l3cache")) ++ is_l3 = true; ++ ++ if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) { ++ if (mlxbf_pmc_read_counter(blk_num, cnt_num, is_l3, &value)) ++ return -EINVAL; ++ } else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) { ++ offset = mlxbf_pmc_get_event_num(pmc->block_name[blk_num], ++ attr->attr.name); ++ if (offset < 0) ++ return -EINVAL; ++ if (mlxbf_pmc_read_reg(blk_num, offset, &value)) ++ return -EINVAL; ++ } else ++ return -EINVAL; ++ ++ return sprintf(buf, "0x%llx\n", value); ++} ++ ++/* Store function for "counter" sysfs files */ ++static ssize_t mlxbf_pmc_counter_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct mlxbf_pmc_attribute *attr_counter = container_of( ++ attr, struct mlxbf_pmc_attribute, dev_attr); ++ int blk_num, cnt_num, offset, err, data; ++ bool is_l3 = false; ++ uint64_t evt_num; ++ ++ blk_num = attr_counter->nr; ++ cnt_num = attr_counter->index; ++ ++ err = kstrtoint(buf, 0, &data); ++ if (err < 0) ++ return err; ++ ++ /* Allow non-zero writes only to the ecc regs */ ++ if (!(strstr(pmc->block_name[blk_num], "ecc")) && data) ++ return -EINVAL; ++ ++ /* Do not allow writes to the L3C regs */ ++ if (strstr(pmc->block_name[blk_num], "l3cache")) ++ return -EINVAL; ++ ++ if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) { ++ err = mlxbf_pmc_read_event(blk_num, cnt_num, is_l3, &evt_num); ++ if (err) ++ return err; ++ err = mlxbf_pmc_program_counter(blk_num, cnt_num, evt_num, ++ is_l3); ++ if (err) ++ return err; ++ } else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) { ++ offset = mlxbf_pmc_get_event_num(pmc->block_name[blk_num], ++ attr->attr.name); ++ if (offset < 0) ++ return -EINVAL; ++ err = mlxbf_pmc_write_reg(blk_num, offset, data); ++ if (err) ++ return err; ++ } else ++ return -EINVAL; ++ ++ return count; ++} ++ ++/* Show function for "event" sysfs files */ ++static ssize_t mlxbf_pmc_event_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct mlxbf_pmc_attribute *attr_event = container_of( ++ attr, struct mlxbf_pmc_attribute, dev_attr); ++ int blk_num, cnt_num, err; ++ bool is_l3 = false; ++ uint64_t evt_num; ++ char *evt_name; ++ ++ blk_num = attr_event->nr; ++ cnt_num = attr_event->index; ++ ++ if (strstr(pmc->block_name[blk_num], "l3cache")) ++ is_l3 = true; ++ ++ err = mlxbf_pmc_read_event(blk_num, cnt_num, is_l3, &evt_num); ++ if (err) ++ return sprintf(buf, "No event being monitored\n"); ++ ++ evt_name = mlxbf_pmc_get_event_name(pmc->block_name[blk_num], evt_num); ++ if (!evt_name) ++ return -EINVAL; ++ ++ return sprintf(buf, "0x%llx: %s\n", evt_num, evt_name); ++} ++ ++/* Store function for "event" sysfs files */ ++static ssize_t mlxbf_pmc_event_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct mlxbf_pmc_attribute *attr_event = container_of( ++ attr, struct mlxbf_pmc_attribute, dev_attr); ++ int blk_num, cnt_num, evt_num, err; ++ bool is_l3 = false; ++ ++ blk_num = attr_event->nr; ++ cnt_num = attr_event->index; ++ ++ if (isalpha(buf[0])) { ++ evt_num = mlxbf_pmc_get_event_num(pmc->block_name[blk_num], ++ buf); ++ if (evt_num < 0) ++ return -EINVAL; ++ } else { ++ err = kstrtoint(buf, 0, &evt_num); ++ if (err < 0) ++ return err; ++ } ++ ++ if (strstr(pmc->block_name[blk_num], "l3cache")) ++ is_l3 = true; ++ ++ err = mlxbf_pmc_program_counter(blk_num, cnt_num, evt_num, is_l3); ++ if (err) ++ return err; ++ ++ return count; ++} ++ ++/* Show function for "event_list" sysfs files */ ++static ssize_t mlxbf_pmc_event_list_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct mlxbf_pmc_attribute *attr_event_list = container_of( ++ attr, struct mlxbf_pmc_attribute, dev_attr); ++ int blk_num, i, size, len = 0, ret = 0; ++ const struct mlxbf_pmc_events *events; ++ char e_info[MLXBF_PMC_EVENT_INFO_LEN]; ++ ++ blk_num = attr_event_list->nr; ++ ++ events = mlxbf_pmc_event_list(pmc->block_name[blk_num], &size); ++ if (!events) ++ return -EINVAL; ++ ++ for (i = 0, buf[0] = '\0'; i < size; ++i) { ++ len += sprintf(e_info, "0x%x: %s\n", events[i].evt_num, ++ events[i].evt_name); ++ if (len > PAGE_SIZE) ++ break; ++ strcat(buf, e_info); ++ ret = len; ++ } ++ ++ return ret; ++} ++ ++/* Show function for "enable" sysfs files - only for l3cache */ ++static ssize_t mlxbf_pmc_enable_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct mlxbf_pmc_attribute *attr_enable = container_of( ++ attr, struct mlxbf_pmc_attribute, dev_attr); ++ uint32_t perfcnt_cfg; ++ int blk_num, value; ++ ++ blk_num = attr_enable->nr; ++ ++ if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + ++ MLXBF_PMC_L3C_PERF_CNT_CFG, ++ &perfcnt_cfg)) ++ return -EINVAL; ++ ++ value = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_CFG_EN, perfcnt_cfg); ++ ++ return sprintf(buf, "%d\n", value); ++} ++ ++/* Store function for "enable" sysfs files - only for l3cache */ ++static ssize_t mlxbf_pmc_enable_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct mlxbf_pmc_attribute *attr_enable = container_of( ++ attr, struct mlxbf_pmc_attribute, dev_attr); ++ int err, en, blk_num; ++ ++ blk_num = attr_enable->nr; ++ ++ err = kstrtoint(buf, 0, &en); ++ if (err < 0) ++ return err; ++ ++ if (!en) { ++ err = mlxbf_pmc_config_l3_counters(blk_num, false, false); ++ if (err) ++ return err; ++ } else if (en == 1) { ++ err = mlxbf_pmc_config_l3_counters(blk_num, false, true); ++ if (err) ++ return err; ++ err = mlxbf_pmc_config_l3_counters(blk_num, true, false); ++ if (err) ++ return err; ++ } else ++ return -EINVAL; ++ ++ return count; ++} ++ ++/* Populate attributes for blocks with counters to monitor performance */ ++static int mlxbf_pmc_init_perftype_counter(struct device *dev, int blk_num) ++{ ++ struct mlxbf_pmc_attribute *attr; ++ int i = 0, j = 0; ++ ++ /* "event_list" sysfs to list events supported by the block */ ++ attr = &pmc->block[blk_num].attr_event_list; ++ attr->dev_attr.attr.mode = 0444; ++ attr->dev_attr.show = mlxbf_pmc_event_list_show; ++ attr->nr = blk_num; ++ attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, "event_list"); ++ pmc->block[blk_num].block_attr[i] = &attr->dev_attr.attr; ++ attr = NULL; ++ ++ /* "enable" sysfs to start/stop the counters. Only in L3C blocks */ ++ if (strstr(pmc->block_name[blk_num], "l3cache")) { ++ attr = &pmc->block[blk_num].attr_enable; ++ attr->dev_attr.attr.mode = 0644; ++ attr->dev_attr.show = mlxbf_pmc_enable_show; ++ attr->dev_attr.store = mlxbf_pmc_enable_store; ++ attr->nr = blk_num; ++ attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, ++ "enable"); ++ pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr; ++ attr = NULL; ++ } ++ ++ pmc->block[blk_num].attr_counter = devm_kcalloc( ++ dev, pmc->block[blk_num].counters, ++ sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL); ++ if (!pmc->block[blk_num].attr_counter) ++ return -ENOMEM; ++ ++ pmc->block[blk_num].attr_event = devm_kcalloc( ++ dev, pmc->block[blk_num].counters, ++ sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL); ++ if (!pmc->block[blk_num].attr_event) ++ return -ENOMEM; ++ ++ /* "eventX" and "counterX" sysfs to program and read counter values */ ++ for (j = 0; j < pmc->block[blk_num].counters; ++j) { ++ attr = &pmc->block[blk_num].attr_counter[j]; ++ attr->dev_attr.attr.mode = 0644; ++ attr->dev_attr.show = mlxbf_pmc_counter_show; ++ attr->dev_attr.store = mlxbf_pmc_counter_store; ++ attr->index = j; ++ attr->nr = blk_num; ++ attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, ++ "counter%d", j); ++ pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr; ++ attr = NULL; ++ ++ attr = &pmc->block[blk_num].attr_event[j]; ++ attr->dev_attr.attr.mode = 0644; ++ attr->dev_attr.show = mlxbf_pmc_event_show; ++ attr->dev_attr.store = mlxbf_pmc_event_store; ++ attr->index = j; ++ attr->nr = blk_num; ++ attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, ++ "event%d", j); ++ pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr; ++ attr = NULL; ++ } ++ ++ return 0; ++} ++ ++/* Populate attributes for blocks with registers to monitor performance */ ++static int mlxbf_pmc_init_perftype_reg(struct device *dev, int blk_num) ++{ ++ struct mlxbf_pmc_attribute *attr; ++ const struct mlxbf_pmc_events *events; ++ int i = 0, j = 0; ++ ++ events = mlxbf_pmc_event_list(pmc->block_name[blk_num], &j); ++ if (!events) ++ return -EINVAL; ++ ++ pmc->block[blk_num].attr_event = devm_kcalloc( ++ dev, j, sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL); ++ if (!pmc->block[blk_num].attr_event) ++ return -ENOMEM; ++ ++ while (j > 0) { ++ --j; ++ attr = &pmc->block[blk_num].attr_event[j]; ++ attr->dev_attr.attr.mode = 0644; ++ attr->dev_attr.show = mlxbf_pmc_counter_show; ++ attr->dev_attr.store = mlxbf_pmc_counter_store; ++ attr->nr = blk_num; ++ attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, ++ events[j].evt_name); ++ pmc->block[blk_num].block_attr[i] = &attr->dev_attr.attr; ++ attr = NULL; ++ i++; ++ } ++ ++ return 0; ++} ++ ++/* Helper to create the bfperf sysfs sub-directories and files */ ++static int mlxbf_pmc_create_groups(struct device *dev, int blk_num) ++{ ++ int err; ++ ++ /* Populate attributes based on counter type */ ++ if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) ++ err = mlxbf_pmc_init_perftype_counter(dev, blk_num); ++ else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) ++ err = mlxbf_pmc_init_perftype_reg(dev, blk_num); ++ else ++ err = -EINVAL; ++ ++ if (err) ++ return err; ++ ++ /* Add a new attribute_group for the block */ ++ pmc->block[blk_num].block_attr_grp.attrs = pmc->block[blk_num].block_attr; ++ pmc->block[blk_num].block_attr_grp.name = devm_kasprintf( ++ dev, GFP_KERNEL, pmc->block_name[blk_num]); ++ pmc->groups[blk_num] = &pmc->block[blk_num].block_attr_grp; ++ ++ return 0; ++} ++ ++static bool mlxbf_pmc_guid_match(const guid_t *guid, ++ const struct arm_smccc_res *res) ++{ ++ guid_t id = GUID_INIT(res->a0, res->a1, res->a1 >> 16, res->a2, ++ res->a2 >> 8, res->a2 >> 16, res->a2 >> 24, ++ res->a3, res->a3 >> 8, res->a3 >> 16, ++ res->a3 >> 24); ++ ++ return guid_equal(guid, &id); ++} ++ ++/* Helper to map the Performance Counters from the varios blocks */ ++static int mlxbf_pmc_map_counters(struct device *dev) ++{ ++ uint64_t info[MLXBF_PMC_INFO_SZ]; ++ int i, tile_num, ret; ++ ++ for (i = 0; i < pmc->total_blocks; ++i) { ++ if (strstr(pmc->block_name[i], "tile")) { ++ ret = sscanf(pmc->block_name[i], "tile%d", &tile_num); ++ if (ret < 0) ++ return ret; ++ ++ if (tile_num >= pmc->tile_count) ++ continue; ++ } ++ ret = device_property_read_u64_array(dev, pmc->block_name[i], ++ info, MLXBF_PMC_INFO_SZ); ++ if (ret) ++ return ret; ++ ++ /* ++ * Do not remap if the proper SMC calls are supported, ++ * since the SMC calls expect physical addresses. ++ */ ++ if (pmc->svc_sreg_support) ++ pmc->block[i].mmio_base = (void __iomem *)info[0]; ++ else ++ pmc->block[i].mmio_base = ++ devm_ioremap(dev, info[0], info[1]); ++ ++ pmc->block[i].blk_size = info[1]; ++ pmc->block[i].counters = info[2]; ++ pmc->block[i].type = info[3]; ++ ++ if (IS_ERR(pmc->block[i].mmio_base)) ++ return PTR_ERR(pmc->block[i].mmio_base); ++ ++ ret = mlxbf_pmc_create_groups(dev, i); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int mlxbf_pmc_probe(struct platform_device *pdev) ++{ ++ struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev); ++ const char *hid = acpi_device_hid(acpi_dev); ++ struct device *dev = &pdev->dev; ++ struct arm_smccc_res res; ++ guid_t guid; ++ int ret; ++ ++ /* Ensure we have the UUID we expect for this service. */ ++ arm_smccc_smc(MLXBF_PMC_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res); ++ guid_parse(mlxbf_pmc_svc_uuid_str, &guid); ++ if (!mlxbf_pmc_guid_match(&guid, &res)) ++ return -ENODEV; ++ ++ pmc = devm_kzalloc(dev, sizeof(struct mlxbf_pmc_context), GFP_KERNEL); ++ if (!pmc) ++ return -ENOMEM; ++ ++ /* ++ * ACPI indicates whether we use SMCs to access registers or not. ++ * If sreg_tbl_perf is not present, just assume we're not using SMCs. ++ */ ++ ret = device_property_read_u32(dev, "sec_reg_block", ++ &pmc->sreg_tbl_perf); ++ if (ret) { ++ pmc->svc_sreg_support = false; ++ } else { ++ /* ++ * Check service version to see if we actually do support the ++ * needed SMCs. If we have the calls we need, mark support for ++ * them in the pmc struct. ++ */ ++ arm_smccc_smc(MLXBF_PMC_SIP_SVC_VERSION, 0, 0, 0, 0, 0, 0, 0, ++ &res); ++ if (res.a0 == MLXBF_PMC_SVC_REQ_MAJOR && ++ res.a1 >= MLXBF_PMC_SVC_MIN_MINOR) ++ pmc->svc_sreg_support = true; ++ else ++ return -EINVAL; ++ } ++ ++ if (!strcmp(hid, "MLNXBFD0")) ++ pmc->event_set = MLXBF_PMC_EVENT_SET_BF1; ++ else if (!strcmp(hid, "MLNXBFD1")) ++ pmc->event_set = MLXBF_PMC_EVENT_SET_BF2; ++ else ++ return -ENODEV; ++ ++ ret = device_property_read_u32(dev, "block_num", &pmc->total_blocks); ++ if (ret) ++ return ret; ++ ++ ret = device_property_read_string_array(dev, "block_name", ++ pmc->block_name, ++ pmc->total_blocks); ++ if (ret != pmc->total_blocks) ++ return -EFAULT; ++ ++ ret = device_property_read_u32(dev, "tile_num", &pmc->tile_count); ++ if (ret) ++ return ret; ++ ++ pmc->pdev = pdev; ++ ++ ret = mlxbf_pmc_map_counters(dev); ++ if (ret) ++ return ret; ++ ++ pmc->hwmon_dev = devm_hwmon_device_register_with_groups( ++ dev, "bfperf", pmc, pmc->groups); ++ platform_set_drvdata(pdev, pmc); ++ ++ return 0; ++} ++ ++static const struct acpi_device_id mlxbf_pmc_acpi_ids[] = { { "MLNXBFD0", 0 }, ++ { "MLNXBFD1", 0 }, ++ {}, }; ++ ++MODULE_DEVICE_TABLE(acpi, mlxbf_pmc_acpi_ids); ++static struct platform_driver pmc_driver = { ++ .driver = { .name = "mlxbf-pmc", ++ .acpi_match_table = ACPI_PTR(mlxbf_pmc_acpi_ids), }, ++ .probe = mlxbf_pmc_probe, ++}; ++ ++module_platform_driver(pmc_driver); ++ ++MODULE_AUTHOR("Shravan Kumar Ramani "); ++MODULE_DESCRIPTION("Mellanox PMC driver"); ++MODULE_LICENSE("Dual BSD/GPL"); +-- +2.20.1 + diff --git a/patch/0213-platform-mellanox-mlxbf-pmc-fix-kernel-doc-notation.patch b/patch/0213-platform-mellanox-mlxbf-pmc-fix-kernel-doc-notation.patch new file mode 100644 index 000000000..cfb80ac32 --- /dev/null +++ b/patch/0213-platform-mellanox-mlxbf-pmc-fix-kernel-doc-notation.patch @@ -0,0 +1,94 @@ +From 1494c3af245d1298a2fc7027c0724f8703820396 Mon Sep 17 00:00:00 2001 +From: Randy Dunlap +Date: Sun, 22 Aug 2021 10:17:42 -0700 +Subject: [PATCH backport 5.10 14/63] platform/mellanox: mlxbf-pmc: fix + kernel-doc notation + +Fix kernel-doc warnings reported by the kernel test robot: + +drivers/platform/mellanox/mlxbf-pmc.c:82: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst + * Structure to hold attribute and block info for each sysfs entry +drivers/platform/mellanox/mlxbf-pmc.c:94: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst + * Structure to hold info for each HW block +drivers/platform/mellanox/mlxbf-pmc.c:121: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst + * Structure to hold PMC context info +drivers/platform/mellanox/mlxbf-pmc.c:148: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst + * Structure to hold supported events for each block + +Also fix typos in a few struct member names. + +Signed-off-by: Randy Dunlap +Reported-by: kernel test robot +Cc: Aditya Srivastava +Cc: Hans de Goede +Cc: Mark Gross +Cc: Vadim Pasternak +Cc: platform-driver-x86@vger.kernel.org +Link: https://lore.kernel.org/r/20210822171742.26921-1-rdunlap@infradead.org +Signed-off-by: Hans de Goede +--- + drivers/platform/mellanox/mlxbf-pmc.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c +index 358839842..04bc3b50a 100644 +--- a/drivers/platform/mellanox/mlxbf-pmc.c ++++ b/drivers/platform/mellanox/mlxbf-pmc.c +@@ -79,7 +79,8 @@ + #define MLXBF_PMC_L3C_PERF_CNT_HIGH_VAL GENMASK(24, 0) + + /** +- * Structure to hold attribute and block info for each sysfs entry ++ * struct mlxbf_pmc_attribute - Structure to hold attribute and block info ++ * for each sysfs entry + * @dev_attr: Device attribute struct + * @index: index to identify counter number within a block + * @nr: block number to which the sysfs belongs +@@ -91,7 +92,7 @@ struct mlxbf_pmc_attribute { + }; + + /** +- * Structure to hold info for each HW block ++ * struct mlxbf_pmc_block_info - Structure to hold info for each HW block + * + * @mmio_base: The VA at which the PMC block is mapped + * @blk_size: Size of each mapped region +@@ -102,7 +103,7 @@ struct mlxbf_pmc_attribute { + * @attr_event_list: Attributes for "event_list" sysfs files + * @attr_enable: Attributes for "enable" sysfs files + * @block_attr: All attributes needed for the block +- * @blcok_attr_grp: Attribute group for the block ++ * @block_attr_grp: Attribute group for the block + */ + struct mlxbf_pmc_block_info { + void __iomem *mmio_base; +@@ -118,7 +119,7 @@ struct mlxbf_pmc_block_info { + }; + + /** +- * Structure to hold PMC context info ++ * struct mlxbf_pmc_context - Structure to hold PMC context info + * + * @pdev: The kernel structure representing the device + * @total_blocks: Total number of blocks +@@ -127,7 +128,7 @@ struct mlxbf_pmc_block_info { + * @block_name: Block name + * @block: Block info + * @groups: Attribute groups from each block +- * @sv_sreg_support: Whether SMCs are used to access performance registers ++ * @svc_sreg_support: Whether SMCs are used to access performance registers + * @sreg_tbl_perf: Secure register access table number + * @event_set: Event set to use + */ +@@ -145,7 +146,7 @@ struct mlxbf_pmc_context { + }; + + /** +- * Structure to hold supported events for each block ++ * struct mlxbf_pmc_events - Structure to hold supported events for each block + * @evt_num: Event number used to program counters + * @evt_name: Name of the event + */ +-- +2.20.1 + diff --git a/patch/0214-platform-mellanox-mlxbf-pmc-Fix-an-IS_ERR-vs-NULL-bu.patch b/patch/0214-platform-mellanox-mlxbf-pmc-Fix-an-IS_ERR-vs-NULL-bu.patch new file mode 100644 index 000000000..b1308c8f6 --- /dev/null +++ b/patch/0214-platform-mellanox-mlxbf-pmc-Fix-an-IS_ERR-vs-NULL-bu.patch @@ -0,0 +1,42 @@ +From fd81d5b65715344eeb492dfb3d818551446021c9 Mon Sep 17 00:00:00 2001 +From: Miaoqian Lin +Date: Fri, 10 Dec 2021 07:07:53 +0000 +Subject: [PATCH backport 5.10 15/63] platform/mellanox: mlxbf-pmc: Fix an + IS_ERR() vs NULL bug in mlxbf_pmc_map_counters + +BugLink: https://bugs.launchpad.net/bugs/1956926 + +[ Upstream commit 804034c4ffc502795cea9b3867acb2ec7fad99ba ] + +The devm_ioremap() function returns NULL on error, it doesn't return +error pointers. Also according to doc of device_property_read_u64_array, +values in info array are properties of device or NULL. + +Signed-off-by: Miaoqian Lin +Link: https://lore.kernel.org/r/20211210070753.10761-1-linmq006@gmail.com +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +Signed-off-by: Sasha Levin +Signed-off-by: Paolo Pisati +--- + drivers/platform/mellanox/mlxbf-pmc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c +index 04bc3b50a..65b4a819f 100644 +--- a/drivers/platform/mellanox/mlxbf-pmc.c ++++ b/drivers/platform/mellanox/mlxbf-pmc.c +@@ -1374,8 +1374,8 @@ static int mlxbf_pmc_map_counters(struct device *dev) + pmc->block[i].counters = info[2]; + pmc->block[i].type = info[3]; + +- if (IS_ERR(pmc->block[i].mmio_base)) +- return PTR_ERR(pmc->block[i].mmio_base); ++ if (!pmc->block[i].mmio_base) ++ return -ENOMEM; + + ret = mlxbf_pmc_create_groups(dev, i); + if (ret) +-- +2.20.1 + diff --git a/patch/0215-UBUNTU-SAUCE-platform-mellanox-Updates-to-mlxbf-pmc.patch b/patch/0215-UBUNTU-SAUCE-platform-mellanox-Updates-to-mlxbf-pmc.patch new file mode 100644 index 000000000..91d0f9e7a --- /dev/null +++ b/patch/0215-UBUNTU-SAUCE-platform-mellanox-Updates-to-mlxbf-pmc.patch @@ -0,0 +1,2674 @@ +From cc23dfd2e05d8e9ef59bcd5f760cc613e72bb80b Mon Sep 17 00:00:00 2001 +From: Shravan Kumar Ramani +Date: Tue, 5 Jul 2022 10:52:05 -0400 +Subject: [PATCH backport 5.10 16/63] UBUNTU: SAUCE: platform/mellanox: Updates + to mlxbf-pmc + +BugLink: https://launchpad.net/bugs/1980746 + +This commit reorganizes the code by moving all the macros +to a header file, and fixes bugs with reprogramming the +counters. + +Signed-off-by: Shravan Kumar Ramani +Signed-off-by: Ike Panhc +--- + drivers/platform/mellanox/mlxbf-pmc.c | 1722 +++++++++++-------------- + drivers/platform/mellanox/mlxbf-pmc.h | 428 ++++++ + 2 files changed, 1176 insertions(+), 974 deletions(-) + create mode 100644 drivers/platform/mellanox/mlxbf-pmc.h + +diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c +index 65b4a819f..a9debcdf9 100644 +--- a/drivers/platform/mellanox/mlxbf-pmc.c ++++ b/drivers/platform/mellanox/mlxbf-pmc.c +@@ -1,482 +1,111 @@ +-// SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB +-/* +- * Mellanox BlueField Performance Monitoring Counters driver +- * +- * This driver provides a sysfs interface for monitoring +- * performance statistics in BlueField SoC. +- * +- * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. +- */ ++// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause + + #include + #include + #include + #include + #include ++#include ++#include ++#include ++#include ++#include + #include +-#include ++#include ++#include ++#include ++#include + #include + +-#define MLXBF_PMC_WRITE_REG_32 0x82000009 +-#define MLXBF_PMC_READ_REG_32 0x8200000A +-#define MLXBF_PMC_WRITE_REG_64 0x8200000B +-#define MLXBF_PMC_READ_REG_64 0x8200000C +-#define MLXBF_PMC_SIP_SVC_UID 0x8200ff01 +-#define MLXBF_PMC_SIP_SVC_VERSION 0x8200ff03 +-#define MLXBF_PMC_SVC_REQ_MAJOR 0 +-#define MLXBF_PMC_SVC_MIN_MINOR 3 +- +-#define MLXBF_PMC_SMCCC_ACCESS_VIOLATION -4 +- +-#define MLXBF_PMC_EVENT_SET_BF1 0 +-#define MLXBF_PMC_EVENT_SET_BF2 1 +-#define MLXBF_PMC_EVENT_INFO_LEN 100 +- +-#define MLXBF_PMC_MAX_BLOCKS 30 +-#define MLXBF_PMC_MAX_ATTRS 30 +-#define MLXBF_PMC_INFO_SZ 4 +-#define MLXBF_PMC_REG_SIZE 8 +-#define MLXBF_PMC_L3C_REG_SIZE 4 +- +-#define MLXBF_PMC_TYPE_COUNTER 1 +-#define MLXBF_PMC_TYPE_REGISTER 0 +- +-#define MLXBF_PMC_PERFCTL 0 +-#define MLXBF_PMC_PERFEVT 1 +-#define MLXBF_PMC_PERFACC0 4 +- +-#define MLXBF_PMC_PERFMON_CONFIG_WR_R_B BIT(0) +-#define MLXBF_PMC_PERFMON_CONFIG_STROBE BIT(1) +-#define MLXBF_PMC_PERFMON_CONFIG_ADDR GENMASK_ULL(4, 2) +-#define MLXBF_PMC_PERFMON_CONFIG_WDATA GENMASK_ULL(60, 5) +- +-#define MLXBF_PMC_PERFCTL_FM0 GENMASK_ULL(18, 16) +-#define MLXBF_PMC_PERFCTL_MS0 GENMASK_ULL(21, 20) +-#define MLXBF_PMC_PERFCTL_ACCM0 GENMASK_ULL(26, 24) +-#define MLXBF_PMC_PERFCTL_AD0 BIT(27) +-#define MLXBF_PMC_PERFCTL_ETRIG0 GENMASK_ULL(29, 28) +-#define MLXBF_PMC_PERFCTL_EB0 BIT(30) +-#define MLXBF_PMC_PERFCTL_EN0 BIT(31) +- +-#define MLXBF_PMC_PERFEVT_EVTSEL GENMASK_ULL(31, 24) +- +-#define MLXBF_PMC_L3C_PERF_CNT_CFG 0x0 +-#define MLXBF_PMC_L3C_PERF_CNT_SEL 0x10 +-#define MLXBF_PMC_L3C_PERF_CNT_SEL_1 0x14 +-#define MLXBF_PMC_L3C_PERF_CNT_LOW 0x40 +-#define MLXBF_PMC_L3C_PERF_CNT_HIGH 0x60 +- +-#define MLXBF_PMC_L3C_PERF_CNT_CFG_EN BIT(0) +-#define MLXBF_PMC_L3C_PERF_CNT_CFG_RST BIT(1) +-#define MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0 GENMASK(5, 0) +-#define MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1 GENMASK(13, 8) +-#define MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2 GENMASK(21, 16) +-#define MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3 GENMASK(29, 24) +- +-#define MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4 GENMASK(5, 0) +- +-#define MLXBF_PMC_L3C_PERF_CNT_LOW_VAL GENMASK(31, 0) +-#define MLXBF_PMC_L3C_PERF_CNT_HIGH_VAL GENMASK(24, 0) +- +-/** +- * struct mlxbf_pmc_attribute - Structure to hold attribute and block info +- * for each sysfs entry +- * @dev_attr: Device attribute struct +- * @index: index to identify counter number within a block +- * @nr: block number to which the sysfs belongs +- */ +-struct mlxbf_pmc_attribute { +- struct device_attribute dev_attr; +- int index; +- int nr; +-}; +- +-/** +- * struct mlxbf_pmc_block_info - Structure to hold info for each HW block +- * +- * @mmio_base: The VA at which the PMC block is mapped +- * @blk_size: Size of each mapped region +- * @counters: Number of counters in the block +- * @type: Type of counters in the block +- * @attr_counter: Attributes for "counter" sysfs files +- * @attr_event: Attributes for "event" sysfs files +- * @attr_event_list: Attributes for "event_list" sysfs files +- * @attr_enable: Attributes for "enable" sysfs files +- * @block_attr: All attributes needed for the block +- * @block_attr_grp: Attribute group for the block +- */ +-struct mlxbf_pmc_block_info { +- void __iomem *mmio_base; +- size_t blk_size; +- size_t counters; +- int type; +- struct mlxbf_pmc_attribute *attr_counter; +- struct mlxbf_pmc_attribute *attr_event; +- struct mlxbf_pmc_attribute attr_event_list; +- struct mlxbf_pmc_attribute attr_enable; +- struct attribute *block_attr[MLXBF_PMC_MAX_ATTRS]; +- struct attribute_group block_attr_grp; +-}; +- +-/** +- * struct mlxbf_pmc_context - Structure to hold PMC context info +- * +- * @pdev: The kernel structure representing the device +- * @total_blocks: Total number of blocks +- * @tile_count: Number of tiles in the system +- * @hwmon_dev: Hwmon device for bfperf +- * @block_name: Block name +- * @block: Block info +- * @groups: Attribute groups from each block +- * @svc_sreg_support: Whether SMCs are used to access performance registers +- * @sreg_tbl_perf: Secure register access table number +- * @event_set: Event set to use +- */ +-struct mlxbf_pmc_context { +- struct platform_device *pdev; +- uint32_t total_blocks; +- uint32_t tile_count; +- struct device *hwmon_dev; +- const char *block_name[MLXBF_PMC_MAX_BLOCKS]; +- struct mlxbf_pmc_block_info block[MLXBF_PMC_MAX_BLOCKS]; +- const struct attribute_group *groups[MLXBF_PMC_MAX_BLOCKS]; +- bool svc_sreg_support; +- uint32_t sreg_tbl_perf; +- unsigned int event_set; +-}; +- +-/** +- * struct mlxbf_pmc_events - Structure to hold supported events for each block +- * @evt_num: Event number used to program counters +- * @evt_name: Name of the event +- */ +-struct mlxbf_pmc_events { +- int evt_num; +- char *evt_name; +-}; +- +-static const struct mlxbf_pmc_events mlxbf_pmc_pcie_events[] = { +- { 0x0, "IN_P_PKT_CNT" }, +- { 0x10, "IN_NP_PKT_CNT" }, +- { 0x18, "IN_C_PKT_CNT" }, +- { 0x20, "OUT_P_PKT_CNT" }, +- { 0x28, "OUT_NP_PKT_CNT" }, +- { 0x30, "OUT_C_PKT_CNT" }, +- { 0x38, "IN_P_BYTE_CNT" }, +- { 0x40, "IN_NP_BYTE_CNT" }, +- { 0x48, "IN_C_BYTE_CNT" }, +- { 0x50, "OUT_P_BYTE_CNT" }, +- { 0x58, "OUT_NP_BYTE_CNT" }, +- { 0x60, "OUT_C_BYTE_CNT" }, +-}; +- +-static const struct mlxbf_pmc_events mlxbf_pmc_smgen_events[] = { +- { 0x0, "AW_REQ" }, +- { 0x1, "AW_BEATS" }, +- { 0x2, "AW_TRANS" }, +- { 0x3, "AW_RESP" }, +- { 0x4, "AW_STL" }, +- { 0x5, "AW_LAT" }, +- { 0x6, "AW_REQ_TBU" }, +- { 0x8, "AR_REQ" }, +- { 0x9, "AR_BEATS" }, +- { 0xa, "AR_TRANS" }, +- { 0xb, "AR_STL" }, +- { 0xc, "AR_LAT" }, +- { 0xd, "AR_REQ_TBU" }, +- { 0xe, "TBU_MISS" }, +- { 0xf, "TX_DAT_AF" }, +- { 0x10, "RX_DAT_AF" }, +- { 0x11, "RETRYQ_CRED" }, +-}; +- +-static const struct mlxbf_pmc_events mlxbf_pmc_trio_events_1[] = { +- { 0xa0, "TPIO_DATA_BEAT" }, +- { 0xa1, "TDMA_DATA_BEAT" }, +- { 0xa2, "MAP_DATA_BEAT" }, +- { 0xa3, "TXMSG_DATA_BEAT" }, +- { 0xa4, "TPIO_DATA_PACKET" }, +- { 0xa5, "TDMA_DATA_PACKET" }, +- { 0xa6, "MAP_DATA_PACKET" }, +- { 0xa7, "TXMSG_DATA_PACKET" }, +- { 0xa8, "TDMA_RT_AF" }, +- { 0xa9, "TDMA_PBUF_MAC_AF" }, +- { 0xaa, "TRIO_MAP_WRQ_BUF_EMPTY" }, +- { 0xab, "TRIO_MAP_CPL_BUF_EMPTY" }, +- { 0xac, "TRIO_MAP_RDQ0_BUF_EMPTY" }, +- { 0xad, "TRIO_MAP_RDQ1_BUF_EMPTY" }, +- { 0xae, "TRIO_MAP_RDQ2_BUF_EMPTY" }, +- { 0xaf, "TRIO_MAP_RDQ3_BUF_EMPTY" }, +- { 0xb0, "TRIO_MAP_RDQ4_BUF_EMPTY" }, +- { 0xb1, "TRIO_MAP_RDQ5_BUF_EMPTY" }, +- { 0xb2, "TRIO_MAP_RDQ6_BUF_EMPTY" }, +- { 0xb3, "TRIO_MAP_RDQ7_BUF_EMPTY" }, +-}; +- +-static const struct mlxbf_pmc_events mlxbf_pmc_trio_events_2[] = { +- { 0xa0, "TPIO_DATA_BEAT" }, +- { 0xa1, "TDMA_DATA_BEAT" }, +- { 0xa2, "MAP_DATA_BEAT" }, +- { 0xa3, "TXMSG_DATA_BEAT" }, +- { 0xa4, "TPIO_DATA_PACKET" }, +- { 0xa5, "TDMA_DATA_PACKET" }, +- { 0xa6, "MAP_DATA_PACKET" }, +- { 0xa7, "TXMSG_DATA_PACKET" }, +- { 0xa8, "TDMA_RT_AF" }, +- { 0xa9, "TDMA_PBUF_MAC_AF" }, +- { 0xaa, "TRIO_MAP_WRQ_BUF_EMPTY" }, +- { 0xab, "TRIO_MAP_CPL_BUF_EMPTY" }, +- { 0xac, "TRIO_MAP_RDQ0_BUF_EMPTY" }, +- { 0xad, "TRIO_MAP_RDQ1_BUF_EMPTY" }, +- { 0xae, "TRIO_MAP_RDQ2_BUF_EMPTY" }, +- { 0xaf, "TRIO_MAP_RDQ3_BUF_EMPTY" }, +- { 0xb0, "TRIO_MAP_RDQ4_BUF_EMPTY" }, +- { 0xb1, "TRIO_MAP_RDQ5_BUF_EMPTY" }, +- { 0xb2, "TRIO_MAP_RDQ6_BUF_EMPTY" }, +- { 0xb3, "TRIO_MAP_RDQ7_BUF_EMPTY" }, +- { 0xb4, "TRIO_RING_TX_FLIT_CH0" }, +- { 0xb5, "TRIO_RING_TX_FLIT_CH1" }, +- { 0xb6, "TRIO_RING_TX_FLIT_CH2" }, +- { 0xb7, "TRIO_RING_TX_FLIT_CH3" }, +- { 0xb8, "TRIO_RING_TX_FLIT_CH4" }, +- { 0xb9, "TRIO_RING_RX_FLIT_CH0" }, +- { 0xba, "TRIO_RING_RX_FLIT_CH1" }, +- { 0xbb, "TRIO_RING_RX_FLIT_CH2" }, +- { 0xbc, "TRIO_RING_RX_FLIT_CH3" }, +-}; +- +-static const struct mlxbf_pmc_events mlxbf_pmc_ecc_events[] = { +- { 0x100, "ECC_SINGLE_ERROR_CNT" }, +- { 0x104, "ECC_DOUBLE_ERROR_CNT" }, +- { 0x114, "SERR_INJ" }, +- { 0x118, "DERR_INJ" }, +- { 0x124, "ECC_SINGLE_ERROR_0" }, +- { 0x164, "ECC_DOUBLE_ERROR_0" }, +- { 0x340, "DRAM_ECC_COUNT" }, +- { 0x344, "DRAM_ECC_INJECT" }, +- { 0x348, "DRAM_ECC_ERROR" }, +-}; ++#include "mlxbf-pmc.h" + +-static const struct mlxbf_pmc_events mlxbf_pmc_mss_events[] = { +- { 0xc0, "RXREQ_MSS" }, +- { 0xc1, "RXDAT_MSS" }, +- { 0xc2, "TXRSP_MSS" }, +- { 0xc3, "TXDAT_MSS" }, +-}; +- +-static const struct mlxbf_pmc_events mlxbf_pmc_hnf_events[] = { +- { 0x45, "HNF_REQUESTS" }, +- { 0x46, "HNF_REJECTS" }, +- { 0x47, "ALL_BUSY" }, +- { 0x48, "MAF_BUSY" }, +- { 0x49, "MAF_REQUESTS" }, +- { 0x4a, "RNF_REQUESTS" }, +- { 0x4b, "REQUEST_TYPE" }, +- { 0x4c, "MEMORY_READS" }, +- { 0x4d, "MEMORY_WRITES" }, +- { 0x4e, "VICTIM_WRITE" }, +- { 0x4f, "POC_FULL" }, +- { 0x50, "POC_FAIL" }, +- { 0x51, "POC_SUCCESS" }, +- { 0x52, "POC_WRITES" }, +- { 0x53, "POC_READS" }, +- { 0x54, "FORWARD" }, +- { 0x55, "RXREQ_HNF" }, +- { 0x56, "RXRSP_HNF" }, +- { 0x57, "RXDAT_HNF" }, +- { 0x58, "TXREQ_HNF" }, +- { 0x59, "TXRSP_HNF" }, +- { 0x5a, "TXDAT_HNF" }, +- { 0x5b, "TXSNP_HNF" }, +- { 0x5c, "INDEX_MATCH" }, +- { 0x5d, "A72_ACCESS" }, +- { 0x5e, "IO_ACCESS" }, +- { 0x5f, "TSO_WRITE" }, +- { 0x60, "TSO_CONFLICT" }, +- { 0x61, "DIR_HIT" }, +- { 0x62, "HNF_ACCEPTS" }, +- { 0x63, "REQ_BUF_EMPTY" }, +- { 0x64, "REQ_BUF_IDLE_MAF" }, +- { 0x65, "TSO_NOARB" }, +- { 0x66, "TSO_NOARB_CYCLES" }, +- { 0x67, "MSS_NO_CREDIT" }, +- { 0x68, "TXDAT_NO_LCRD" }, +- { 0x69, "TXSNP_NO_LCRD" }, +- { 0x6a, "TXRSP_NO_LCRD" }, +- { 0x6b, "TXREQ_NO_LCRD" }, +- { 0x6c, "TSO_CL_MATCH" }, +- { 0x6d, "MEMORY_READS_BYPASS" }, +- { 0x6e, "TSO_NOARB_TIMEOUT" }, +- { 0x6f, "ALLOCATE" }, +- { 0x70, "VICTIM" }, +- { 0x71, "A72_WRITE" }, +- { 0x72, "A72_READ" }, +- { 0x73, "IO_WRITE" }, +- { 0x74, "IO_READ" }, +- { 0x75, "TSO_REJECT" }, +- { 0x80, "TXREQ_RN" }, +- { 0x81, "TXRSP_RN" }, +- { 0x82, "TXDAT_RN" }, +- { 0x83, "RXSNP_RN" }, +- { 0x84, "RXRSP_RN" }, +- { 0x85, "RXDAT_RN" }, +-}; +- +-static const struct mlxbf_pmc_events mlxbf_pmc_hnfnet_events[] = { +- { 0x12, "CDN_REQ" }, +- { 0x13, "DDN_REQ" }, +- { 0x14, "NDN_REQ" }, +- { 0x15, "CDN_DIAG_N_OUT_OF_CRED" }, +- { 0x16, "CDN_DIAG_S_OUT_OF_CRED" }, +- { 0x17, "CDN_DIAG_E_OUT_OF_CRED" }, +- { 0x18, "CDN_DIAG_W_OUT_OF_CRED" }, +- { 0x19, "CDN_DIAG_C_OUT_OF_CRED" }, +- { 0x1a, "CDN_DIAG_N_EGRESS" }, +- { 0x1b, "CDN_DIAG_S_EGRESS" }, +- { 0x1c, "CDN_DIAG_E_EGRESS" }, +- { 0x1d, "CDN_DIAG_W_EGRESS" }, +- { 0x1e, "CDN_DIAG_C_EGRESS" }, +- { 0x1f, "CDN_DIAG_N_INGRESS" }, +- { 0x20, "CDN_DIAG_S_INGRESS" }, +- { 0x21, "CDN_DIAG_E_INGRESS" }, +- { 0x22, "CDN_DIAG_W_INGRESS" }, +- { 0x23, "CDN_DIAG_C_INGRESS" }, +- { 0x24, "CDN_DIAG_CORE_SENT" }, +- { 0x25, "DDN_DIAG_N_OUT_OF_CRED" }, +- { 0x26, "DDN_DIAG_S_OUT_OF_CRED" }, +- { 0x27, "DDN_DIAG_E_OUT_OF_CRED" }, +- { 0x28, "DDN_DIAG_W_OUT_OF_CRED" }, +- { 0x29, "DDN_DIAG_C_OUT_OF_CRED" }, +- { 0x2a, "DDN_DIAG_N_EGRESS" }, +- { 0x2b, "DDN_DIAG_S_EGRESS" }, +- { 0x2c, "DDN_DIAG_E_EGRESS" }, +- { 0x2d, "DDN_DIAG_W_EGRESS" }, +- { 0x2e, "DDN_DIAG_C_EGRESS" }, +- { 0x2f, "DDN_DIAG_N_INGRESS" }, +- { 0x30, "DDN_DIAG_S_INGRESS" }, +- { 0x31, "DDN_DIAG_E_INGRESS" }, +- { 0x32, "DDN_DIAG_W_INGRESS" }, +- { 0x33, "DDN_DIAG_C_INGRESS" }, +- { 0x34, "DDN_DIAG_CORE_SENT" }, +- { 0x35, "NDN_DIAG_S_OUT_OF_CRED" }, +- { 0x36, "NDN_DIAG_S_OUT_OF_CRED" }, +- { 0x37, "NDN_DIAG_E_OUT_OF_CRED" }, +- { 0x38, "NDN_DIAG_W_OUT_OF_CRED" }, +- { 0x39, "NDN_DIAG_C_OUT_OF_CRED" }, +- { 0x3a, "NDN_DIAG_N_EGRESS" }, +- { 0x3b, "NDN_DIAG_S_EGRESS" }, +- { 0x3c, "NDN_DIAG_E_EGRESS" }, +- { 0x3d, "NDN_DIAG_W_EGRESS" }, +- { 0x3e, "NDN_DIAG_C_EGRESS" }, +- { 0x3f, "NDN_DIAG_N_INGRESS" }, +- { 0x40, "NDN_DIAG_S_INGRESS" }, +- { 0x41, "NDN_DIAG_E_INGRESS" }, +- { 0x42, "NDN_DIAG_W_INGRESS" }, +- { 0x43, "NDN_DIAG_C_INGRESS" }, +- { 0x44, "NDN_DIAG_CORE_SENT" }, +-}; +- +-static const struct mlxbf_pmc_events mlxbf_pmc_l3c_events[] = { +- { 0x00, "DISABLE" }, +- { 0x01, "CYCLES" }, +- { 0x02, "TOTAL_RD_REQ_IN" }, +- { 0x03, "TOTAL_WR_REQ_IN" }, +- { 0x04, "TOTAL_WR_DBID_ACK" }, +- { 0x05, "TOTAL_WR_DATA_IN" }, +- { 0x06, "TOTAL_WR_COMP" }, +- { 0x07, "TOTAL_RD_DATA_OUT" }, +- { 0x08, "TOTAL_CDN_REQ_IN_BANK0" }, +- { 0x09, "TOTAL_CDN_REQ_IN_BANK1" }, +- { 0x0a, "TOTAL_DDN_REQ_IN_BANK0" }, +- { 0x0b, "TOTAL_DDN_REQ_IN_BANK1" }, +- { 0x0c, "TOTAL_EMEM_RD_RES_IN_BANK0" }, +- { 0x0d, "TOTAL_EMEM_RD_RES_IN_BANK1" }, +- { 0x0e, "TOTAL_CACHE_RD_RES_IN_BANK0" }, +- { 0x0f, "TOTAL_CACHE_RD_RES_IN_BANK1" }, +- { 0x10, "TOTAL_EMEM_RD_REQ_BANK0" }, +- { 0x11, "TOTAL_EMEM_RD_REQ_BANK1" }, +- { 0x12, "TOTAL_EMEM_WR_REQ_BANK0" }, +- { 0x13, "TOTAL_EMEM_WR_REQ_BANK1" }, +- { 0x14, "TOTAL_RD_REQ_OUT" }, +- { 0x15, "TOTAL_WR_REQ_OUT" }, +- { 0x16, "TOTAL_RD_RES_IN" }, +- { 0x17, "HITS_BANK0" }, +- { 0x18, "HITS_BANK1" }, +- { 0x19, "MISSES_BANK0" }, +- { 0x1a, "MISSES_BANK1" }, +- { 0x1b, "ALLOCATIONS_BANK0" }, +- { 0x1c, "ALLOCATIONS_BANK1" }, +- { 0x1d, "EVICTIONS_BANK0" }, +- { 0x1e, "EVICTIONS_BANK1" }, +- { 0x1f, "DBID_REJECT" }, +- { 0x20, "WRDB_REJECT_BANK0" }, +- { 0x21, "WRDB_REJECT_BANK1" }, +- { 0x22, "CMDQ_REJECT_BANK0" }, +- { 0x23, "CMDQ_REJECT_BANK1" }, +- { 0x24, "COB_REJECT_BANK0" }, +- { 0x25, "COB_REJECT_BANK1" }, +- { 0x26, "TRB_REJECT_BANK0" }, +- { 0x27, "TRB_REJECT_BANK1" }, +- { 0x28, "TAG_REJECT_BANK0" }, +- { 0x29, "TAG_REJECT_BANK1" }, +- { 0x2a, "ANY_REJECT_BANK0" }, +- { 0x2b, "ANY_REJECT_BANK1" }, +-}; ++#define DRIVER_VERSION 2.2 + + static struct mlxbf_pmc_context *pmc; + +-/* UUID used to probe ATF service. */ +-static const char *mlxbf_pmc_svc_uuid_str = "89c036b4-e7d7-11e6-8797-001aca00bfc4"; ++#define SIZE_64 0 ++#define SIZE_32 1 + + /* Calls an SMC to access a performance register */ +-static int mlxbf_pmc_secure_read(void __iomem *addr, uint32_t command, +- uint64_t *result) ++static int mlxbf_pmc_secure_read(void *addr, int size, uint64_t *result) + { + struct arm_smccc_res res; +- int status, err = 0; ++ uint32_t command; ++ int status; ++ ++ switch (size) { ++ case SIZE_32: ++ command = MLNX_READ_REG_32; ++ break; ++ case SIZE_64: ++ command = MLNX_READ_REG_64; ++ break; ++ default: ++ dev_err(pmc->hwmon_dev, ++ "%s: invalid size: %d\n", __func__, size); ++ return -EINVAL; ++ } + +- arm_smccc_smc(command, pmc->sreg_tbl_perf, (uintptr_t)addr, 0, 0, 0, 0, +- 0, &res); ++ arm_smccc_smc( ++ command, ++ pmc->sreg_tbl_perf, ++ (uintptr_t) addr, ++ 0, 0, 0, 0, 0, &res); + + status = res.a0; + + switch (status) { ++ /* ++ * Note: PSCI_RET_NOT_SUPPORTED is used here to maintain compatibility ++ * with older kernels that do not have SMCCC_RET_NOT_SUPPORTED ++ */ + case PSCI_RET_NOT_SUPPORTED: +- err = -EINVAL; +- break; +- case MLXBF_PMC_SMCCC_ACCESS_VIOLATION: +- err = -EACCES; +- break; ++ dev_err(pmc->hwmon_dev, ++ "%s: required SMC unsupported", __func__); ++ return -EINVAL; ++ case SMCCC_ACCESS_VIOLATION: ++ dev_err(pmc->hwmon_dev, ++ "%s: could not read register %p. Is it perf?", ++ __func__, ++ addr); ++ return -EACCES; + default: +- *result = res.a1; +- break; ++ *result = (uint64_t)res.a1; ++ return 0; + } +- +- return err; + } + + /* Read from a performance counter */ +-static int mlxbf_pmc_read(void __iomem *addr, uint32_t command, +- uint64_t *result) ++static int mlxbf_pmc_read(void *addr, int size, uint64_t *result) + { +- if (pmc->svc_sreg_support) +- return mlxbf_pmc_secure_read(addr, command, result); +- +- if (command == MLXBF_PMC_READ_REG_32) +- *result = readl(addr); +- else +- *result = readq(addr); +- +- return 0; ++ if (pmc->svc_sreg_support) { ++ if (mlxbf_pmc_secure_read(addr, size, result)) ++ return -EINVAL; ++ else ++ return 0; ++ } else { ++ switch (size) { ++ case SIZE_32: ++ *result = (uint64_t)readl(addr); ++ return 0; ++ case SIZE_64: ++ *result = readq(addr); ++ return 0; ++ default: ++ dev_err(pmc->hwmon_dev, ++ "%s: invalid size: %d\n", __func__, size); ++ return -EINVAL; ++ } ++ } + } + + /* Convenience function for 32-bit reads */ +-static int mlxbf_pmc_readl(void __iomem *addr, uint32_t *result) ++static int mlxbf_pmc_readl(uint32_t *result, void *addr) + { + uint64_t read_out; + int status; + +- status = mlxbf_pmc_read(addr, MLXBF_PMC_READ_REG_32, &read_out); ++ status = mlxbf_pmc_read(addr, SIZE_32, &read_out); + if (status) + return status; + *result = (uint32_t)read_out; +@@ -484,231 +113,274 @@ static int mlxbf_pmc_readl(void __iomem *addr, uint32_t *result) + return 0; + } + ++/* Convenience function for 64-bit reads */ ++static int mlxbf_pmc_readq(uint64_t *result, void *addr) ++{ ++ return mlxbf_pmc_read(addr, SIZE_64, result); ++} ++ + /* Calls an SMC to access a performance register */ +-static int mlxbf_pmc_secure_write(void __iomem *addr, uint32_t command, +- uint64_t value) ++static int mlxbf_pmc_secure_write(uint64_t value, void *addr, int size) + { + struct arm_smccc_res res; +- int status, err = 0; ++ uint32_t command; ++ int status; + +- arm_smccc_smc(command, pmc->sreg_tbl_perf, value, (uintptr_t)addr, 0, 0, +- 0, 0, &res); ++ switch (size) { ++ case SIZE_32: ++ command = MLNX_WRITE_REG_32; ++ break; ++ case SIZE_64: ++ command = MLNX_WRITE_REG_64; ++ break; ++ default: ++ dev_err(pmc->hwmon_dev, ++ "%s: invalid size: %d\n", __func__, size); ++ return -EINVAL; ++ } ++ ++ arm_smccc_smc( ++ command, ++ pmc->sreg_tbl_perf, ++ value, ++ (uintptr_t) addr, ++ 0, 0, 0, 0, &res); + + status = res.a0; + + switch (status) { + case PSCI_RET_NOT_SUPPORTED: +- err = -EINVAL; +- break; +- case MLXBF_PMC_SMCCC_ACCESS_VIOLATION: +- err = -EACCES; +- break; ++ dev_err(pmc->hwmon_dev, ++ "%s: required SMC unsupported", __func__); ++ return -EINVAL; ++ case SMCCC_ACCESS_VIOLATION: ++ dev_err(pmc->hwmon_dev, ++ "%s: could not write register %p. Is it perf?", ++ __func__, ++ addr); ++ return -EACCES; ++ default: ++ return 0; + } +- +- return err; + } + + /* Write to a performance counter */ +-static int mlxbf_pmc_write(void __iomem *addr, int command, uint64_t value) ++static int mlxbf_pmc_write(uint64_t value, void *addr, int size) + { + if (pmc->svc_sreg_support) +- return mlxbf_pmc_secure_write(addr, command, value); ++ return mlxbf_pmc_secure_write(value, addr, size); + +- if (command == MLXBF_PMC_WRITE_REG_32) +- writel(value, addr); +- else ++ switch (size) { ++ case SIZE_32: ++ writel((uint32_t)value, addr); ++ return 0; ++ case SIZE_64: + writeq(value, addr); ++ return 0; ++ default: ++ dev_err(pmc->hwmon_dev, ++ "%s: invalid size: %d\n", __func__, size); ++ return -EINVAL; ++ } ++} + +- return 0; ++/* Convenience function for 32-bit writes */ ++static int mlxbf_pmc_writel(uint32_t value, void *addr) ++{ ++ return mlxbf_pmc_write((uint64_t) value, addr, SIZE_32); ++} ++ ++/* Convenience function for 64-bit writes */ ++static int mlxbf_pmc_writeq(uint64_t value, void *addr) ++{ ++ return mlxbf_pmc_write(value, addr, SIZE_64); + } + + /* Check if the register offset is within the mapped region for the block */ + static bool mlxbf_pmc_valid_range(int blk_num, uint32_t offset) + { +- if ((offset >= 0) && !(offset % MLXBF_PMC_REG_SIZE) && +- (offset + MLXBF_PMC_REG_SIZE <= pmc->block[blk_num].blk_size)) +- return true; /* inside the mapped PMC space */ ++ if (offset % 8 != 0) ++ return false; /* unaligned */ ++ if (offset >= 0 && offset + 8 <= pmc->block[blk_num].blk_size) ++ return true; /* inside the mapped PMC space */ + + return false; + } + ++/* Get the block number using the name */ ++static int mlxbf_pmc_get_block_num(const char *name) ++{ ++ int i; ++ ++ for (i = 0; i < pmc->total_blocks; ++i) ++ if (strcmp((char *)name, pmc->block_name[i]) == 0) ++ return i; ++ ++ return -ENODEV; ++} ++ + /* Get the event list corresponding to a certain block */ +-static const struct mlxbf_pmc_events *mlxbf_pmc_event_list(const char *blk, +- int *size) ++struct mlxbf_pmc_events *mlxbf_pmc_event_list(char *blk) + { +- const struct mlxbf_pmc_events *events; +- +- if (strstr(blk, "tilenet")) { +- events = mlxbf_pmc_hnfnet_events; +- *size = ARRAY_SIZE(mlxbf_pmc_hnfnet_events); +- } else if (strstr(blk, "tile")) { +- events = mlxbf_pmc_hnf_events; +- *size = ARRAY_SIZE(mlxbf_pmc_hnf_events); +- } else if (strstr(blk, "triogen")) { +- events = mlxbf_pmc_smgen_events; +- *size = ARRAY_SIZE(mlxbf_pmc_smgen_events); +- } else if (strstr(blk, "trio")) { ++ struct mlxbf_pmc_events *events; ++ ++ if (strstr(blk, "tilenet")) ++ events = mlxbf2_hnfnet_events; ++ else if (strstr(blk, "tile")) ++ events = mlxbf_hnf_events; ++ else if (strstr(blk, "triogen")) ++ events = mlxbf_smgen_events; ++ else if (strstr(blk, "trio")) + switch (pmc->event_set) { +- case MLXBF_PMC_EVENT_SET_BF1: +- events = mlxbf_pmc_trio_events_1; +- *size = ARRAY_SIZE(mlxbf_pmc_trio_events_1); ++ case MLNX_EVENT_SET_BF1: ++ events = mlxbf1_trio_events; + break; +- case MLXBF_PMC_EVENT_SET_BF2: +- events = mlxbf_pmc_trio_events_2; +- *size = ARRAY_SIZE(mlxbf_pmc_trio_events_2); ++ case MLNX_EVENT_SET_BF2: ++ events = mlxbf2_trio_events; + break; + default: + events = NULL; +- *size = 0; + break; + } +- } else if (strstr(blk, "mss")) { +- events = mlxbf_pmc_mss_events; +- *size = ARRAY_SIZE(mlxbf_pmc_mss_events); +- } else if (strstr(blk, "ecc")) { +- events = mlxbf_pmc_ecc_events; +- *size = ARRAY_SIZE(mlxbf_pmc_ecc_events); +- } else if (strstr(blk, "pcie")) { +- events = mlxbf_pmc_pcie_events; +- *size = ARRAY_SIZE(mlxbf_pmc_pcie_events); +- } else if (strstr(blk, "l3cache")) { +- events = mlxbf_pmc_l3c_events; +- *size = ARRAY_SIZE(mlxbf_pmc_l3c_events); +- } else if (strstr(blk, "gic")) { +- events = mlxbf_pmc_smgen_events; +- *size = ARRAY_SIZE(mlxbf_pmc_smgen_events); +- } else if (strstr(blk, "smmu")) { +- events = mlxbf_pmc_smgen_events; +- *size = ARRAY_SIZE(mlxbf_pmc_smgen_events); +- } else { ++ else if (strstr(blk, "mss")) ++ events = mlxbf_mss_events; ++ else if (strstr(blk, "ecc")) ++ events = mlxbf_ecc_events; ++ else if (strstr(blk, "pcie")) ++ events = mlxbf_pcie_events; ++ else if (strstr(blk, "l3cache")) ++ events = mlxbf_l3cache_events; ++ else if (strstr(blk, "gic")) ++ events = mlxbf_smgen_events; ++ else if (strstr(blk, "smmu")) ++ events = mlxbf_smgen_events; ++ else + events = NULL; +- *size = 0; +- } + + return events; + } + + /* Get the event number given the name */ +-static int mlxbf_pmc_get_event_num(const char *blk, const char *evt) ++static int mlxbf_pmc_get_event_num(char *blk, char *evt) + { +- const struct mlxbf_pmc_events *events; +- int i, size; ++ struct mlxbf_pmc_events *events; ++ int i = 0; + +- events = mlxbf_pmc_event_list(blk, &size); +- if (!events) ++ events = mlxbf_pmc_event_list(blk); ++ if (events == NULL) + return -EINVAL; + +- for (i = 0; i < size; ++i) { +- if (!strcmp(evt, events[i].evt_name)) ++ while (events[i].evt_name != NULL) { ++ if (strcmp(evt, events[i].evt_name) == 0) + return events[i].evt_num; ++ ++i; + } + + return -ENODEV; + } + + /* Get the event number given the name */ +-static char *mlxbf_pmc_get_event_name(const char *blk, int evt) ++static char *mlxbf_pmc_get_event_name(char *blk, int evt) + { +- const struct mlxbf_pmc_events *events; +- int i, size; ++ struct mlxbf_pmc_events *events; ++ int i = 0; + +- events = mlxbf_pmc_event_list(blk, &size); +- if (!events) ++ events = mlxbf_pmc_event_list(blk); ++ if (events == NULL) + return NULL; + +- for (i = 0; i < size; ++i) { ++ while (events[i].evt_name != NULL) { + if (evt == events[i].evt_num) + return events[i].evt_name; ++ ++i; + } + + return NULL; + } + + /* Method to enable/disable/reset l3cache counters */ +-static int mlxbf_pmc_config_l3_counters(int blk_num, bool enable, bool reset) ++int mlxbf_config_l3_counters(int blk_num, bool enable, bool reset) + { + uint32_t perfcnt_cfg = 0; + + if (enable) +- perfcnt_cfg |= MLXBF_PMC_L3C_PERF_CNT_CFG_EN; ++ perfcnt_cfg |= MLXBF_L3C_PERF_CNT_CFG__EN; + if (reset) +- perfcnt_cfg |= MLXBF_PMC_L3C_PERF_CNT_CFG_RST; ++ perfcnt_cfg |= MLXBF_L3C_PERF_CNT_CFG__RST; + +- return mlxbf_pmc_write(pmc->block[blk_num].mmio_base + +- MLXBF_PMC_L3C_PERF_CNT_CFG, +- MLXBF_PMC_WRITE_REG_32, perfcnt_cfg); ++ return mlxbf_pmc_writel(perfcnt_cfg, pmc->block[blk_num].mmio_base + ++ MLXBF_L3C_PERF_CNT_CFG); + } + ++ + /* Method to handle l3cache counter programming */ +-static int mlxbf_pmc_program_l3_counter(int blk_num, uint32_t cnt_num, +- uint32_t evt) ++int mlxbf_program_l3_counter(int blk_num, uint32_t cnt_num, uint32_t evt) + { + uint32_t perfcnt_sel_1 = 0; + uint32_t perfcnt_sel = 0; + uint32_t *wordaddr; +- void __iomem *pmcaddr; ++ void *pmcaddr; + int ret; + + /* Disable all counters before programming them */ +- if (mlxbf_pmc_config_l3_counters(blk_num, false, false)) ++ if (mlxbf_config_l3_counters(blk_num, false, false)) + return -EINVAL; + + /* Select appropriate register information */ + switch (cnt_num) { +- case 0 ... 3: ++ case 0: ++ case 1: ++ case 2: ++ case 3: + pmcaddr = pmc->block[blk_num].mmio_base + +- MLXBF_PMC_L3C_PERF_CNT_SEL; ++ MLXBF_L3C_PERF_CNT_SEL; + wordaddr = &perfcnt_sel; + break; + case 4: + pmcaddr = pmc->block[blk_num].mmio_base + +- MLXBF_PMC_L3C_PERF_CNT_SEL_1; ++ MLXBF_L3C_PERF_CNT_SEL_1; + wordaddr = &perfcnt_sel_1; + break; + default: + return -EINVAL; + } + +- ret = mlxbf_pmc_readl(pmcaddr, wordaddr); ++ ret = mlxbf_pmc_readl(wordaddr, pmcaddr); + if (ret) + return ret; + + switch (cnt_num) { + case 0: +- perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0; +- perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0, +- evt); ++ perfcnt_sel &= ~MLXBF_L3C_PERF_CNT_SEL__CNT_0; ++ perfcnt_sel |= FIELD_PREP(MLXBF_L3C_PERF_CNT_SEL__CNT_0, evt); + break; + case 1: +- perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1; +- perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1, +- evt); ++ perfcnt_sel &= ~MLXBF_L3C_PERF_CNT_SEL__CNT_1; ++ perfcnt_sel |= FIELD_PREP(MLXBF_L3C_PERF_CNT_SEL__CNT_1, evt); + break; + case 2: +- perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2; +- perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2, +- evt); ++ perfcnt_sel &= ~MLXBF_L3C_PERF_CNT_SEL__CNT_2; ++ perfcnt_sel |= FIELD_PREP(MLXBF_L3C_PERF_CNT_SEL__CNT_2, evt); + break; + case 3: +- perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3; +- perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3, +- evt); ++ perfcnt_sel &= ~MLXBF_L3C_PERF_CNT_SEL__CNT_3; ++ perfcnt_sel |= FIELD_PREP(MLXBF_L3C_PERF_CNT_SEL__CNT_3, evt); + break; + case 4: +- perfcnt_sel_1 &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4; +- perfcnt_sel_1 |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4, ++ perfcnt_sel_1 &= ~MLXBF_L3C_PERF_CNT_SEL_1__CNT_4; ++ perfcnt_sel_1 |= FIELD_PREP(MLXBF_L3C_PERF_CNT_SEL_1__CNT_4, + evt); + break; + default: + return -EINVAL; + } + +- return mlxbf_pmc_write(pmcaddr, MLXBF_PMC_WRITE_REG_32, *wordaddr); ++ return mlxbf_pmc_writel(*wordaddr, pmcaddr); + } + + /* Method to program a counter to monitor an event */ +-static int mlxbf_pmc_program_counter(int blk_num, uint32_t cnt_num, +- uint32_t evt, bool is_l3) ++int mlxbf_program_counter(int blk_num, uint32_t cnt_num, uint32_t evt, ++ bool is_l3) + { + uint64_t perfctl, perfevt, perfmon_cfg; + +@@ -716,76 +388,73 @@ static int mlxbf_pmc_program_counter(int blk_num, uint32_t cnt_num, + return -ENODEV; + + if (is_l3) +- return mlxbf_pmc_program_l3_counter(blk_num, cnt_num, evt); ++ return mlxbf_program_l3_counter(blk_num, cnt_num, evt); + + /* Configure the counter */ +- perfctl = FIELD_PREP(MLXBF_PMC_PERFCTL_EN0, 1); +- perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_EB0, 0); +- perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_ETRIG0, 1); +- perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_AD0, 0); +- perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_ACCM0, 0); +- perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_MS0, 0); +- perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_FM0, 0); +- +- perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WDATA, perfctl); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, +- MLXBF_PMC_PERFCTL); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 1); +- +- if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + +- cnt_num * MLXBF_PMC_REG_SIZE, +- MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) ++ perfctl = 0; ++ perfctl |= FIELD_PREP(MLXBF_GEN_PERFCTL__EN0, 1); ++ perfctl |= FIELD_PREP(MLXBF_GEN_PERFCTL__EB0, 0); ++ perfctl |= FIELD_PREP(MLXBF_GEN_PERFCTL__ETRIG0, 1); ++ perfctl |= FIELD_PREP(MLXBF_GEN_PERFCTL__AD0, 0); ++ perfctl |= FIELD_PREP(MLXBF_GEN_PERFCTL__ACCM0, 0); ++ perfctl |= FIELD_PREP(MLXBF_GEN_PERFCTL__MS0, 0); ++ perfctl |= FIELD_PREP(MLXBF_GEN_PERFCTL__FM0, 0); ++ ++ perfmon_cfg = 0; ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__WDATA, perfctl); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__ADDR, ++ MLXBF_PERFCTL); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__STROBE, 1); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__WR_R_B, 1); ++ ++ if (mlxbf_pmc_writeq(perfmon_cfg, ++ pmc->block[blk_num].mmio_base + cnt_num * 8)) + return -EFAULT; + + /* Select the event */ +- perfevt = FIELD_PREP(MLXBF_PMC_PERFEVT_EVTSEL, evt); +- +- perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WDATA, perfevt); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, +- MLXBF_PMC_PERFEVT); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 1); +- +- if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + +- cnt_num * MLXBF_PMC_REG_SIZE, +- MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) ++ perfevt = 0; ++ perfevt |= FIELD_PREP(MLXBF_GEN_PERFEVT__EVTSEL, evt); ++ ++ perfmon_cfg = 0; ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__WDATA, perfevt); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__ADDR, ++ MLXBF_PERFEVT); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__STROBE, 1); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__WR_R_B, 1); ++ ++ if (mlxbf_pmc_writeq(perfmon_cfg, ++ pmc->block[blk_num].mmio_base + cnt_num * 8)) + return -EFAULT; + + /* Clear the accumulator */ +- perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, +- MLXBF_PMC_PERFACC0); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 1); +- +- if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + +- cnt_num * MLXBF_PMC_REG_SIZE, +- MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) ++ perfmon_cfg = 0; ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__ADDR, ++ MLXBF_PERFACC0); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__STROBE, 1); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__WR_R_B, 1); ++ ++ if (mlxbf_pmc_writeq(perfmon_cfg, pmc->block[blk_num].mmio_base ++ + cnt_num * 8)) + return -EFAULT; + + return 0; + } + + /* Method to handle l3 counter reads */ +-static int mlxbf_pmc_read_l3_counter(int blk_num, uint32_t cnt_num, +- uint64_t *result) ++int mlxbf_read_l3_counter(int blk_num, uint32_t cnt_num, uint64_t *result) + { + uint32_t perfcnt_low = 0, perfcnt_high = 0; + uint64_t value; + int status = 0; + +- status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + +- MLXBF_PMC_L3C_PERF_CNT_LOW + +- cnt_num * MLXBF_PMC_L3C_REG_SIZE, +- &perfcnt_low); ++ status = mlxbf_pmc_readl(&perfcnt_low, pmc->block[blk_num].mmio_base + ++ MLXBF_L3C_PERF_CNT_LOW + cnt_num * 4); + + if (status) + return status; + +- status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + +- MLXBF_PMC_L3C_PERF_CNT_HIGH + +- cnt_num * MLXBF_PMC_L3C_REG_SIZE, +- &perfcnt_high); ++ status = mlxbf_pmc_readl(&perfcnt_high, pmc->block[blk_num].mmio_base + ++ MLXBF_L3C_PERF_CNT_HIGH + cnt_num * 4); + + if (status) + return status; +@@ -799,8 +468,8 @@ static int mlxbf_pmc_read_l3_counter(int blk_num, uint32_t cnt_num, + } + + /* Method to read the counter value */ +-static int mlxbf_pmc_read_counter(int blk_num, uint32_t cnt_num, bool is_l3, +- uint64_t *result) ++int mlxbf_read_counter(int blk_num, uint32_t cnt_num, bool is_l3, ++ uint64_t *result) + { + uint32_t perfcfg_offset, perfval_offset; + uint64_t perfmon_cfg; +@@ -810,73 +479,74 @@ static int mlxbf_pmc_read_counter(int blk_num, uint32_t cnt_num, bool is_l3, + return -EINVAL; + + if (is_l3) +- return mlxbf_pmc_read_l3_counter(blk_num, cnt_num, result); ++ return mlxbf_read_l3_counter(blk_num, cnt_num, result); + +- perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE; +- perfval_offset = perfcfg_offset + +- pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE; ++ perfcfg_offset = cnt_num * 8; ++ perfval_offset = perfcfg_offset + pmc->block[blk_num].counters * 8; + + /* Set counter in "read" mode */ +- perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, +- MLXBF_PMC_PERFACC0); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 0); ++ perfmon_cfg = 0; ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__ADDR, ++ MLXBF_PERFACC0); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__STROBE, 1); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__WR_R_B, 0); + +- status = mlxbf_pmc_write(pmc->block[blk_num].mmio_base + perfcfg_offset, +- MLXBF_PMC_WRITE_REG_64, perfmon_cfg); ++ status = mlxbf_pmc_writeq(perfmon_cfg, pmc->block[blk_num].mmio_base + ++ perfcfg_offset); + + if (status) + return status; + + /* Get the counter value */ +- return mlxbf_pmc_read(pmc->block[blk_num].mmio_base + perfval_offset, +- MLXBF_PMC_READ_REG_64, result); ++ return mlxbf_pmc_readq(result, ++ pmc->block[blk_num].mmio_base + perfval_offset); + } + +-/* Method to read L3 block event */ +-static int mlxbf_pmc_read_l3_event(int blk_num, uint32_t cnt_num, +- uint64_t *result) ++int mlxbf_read_l3_event(int blk_num, uint32_t cnt_num, uint64_t *result) + { + uint32_t perfcnt_sel = 0, perfcnt_sel_1 = 0; + uint32_t *wordaddr; +- void __iomem *pmcaddr; ++ void *pmcaddr; + uint64_t evt; + + /* Select appropriate register information */ + switch (cnt_num) { +- case 0 ... 3: ++ case 0: ++ case 1: ++ case 2: ++ case 3: + pmcaddr = pmc->block[blk_num].mmio_base + +- MLXBF_PMC_L3C_PERF_CNT_SEL; ++ MLXBF_L3C_PERF_CNT_SEL; + wordaddr = &perfcnt_sel; + break; + case 4: + pmcaddr = pmc->block[blk_num].mmio_base + +- MLXBF_PMC_L3C_PERF_CNT_SEL_1; ++ MLXBF_L3C_PERF_CNT_SEL_1; + wordaddr = &perfcnt_sel_1; + break; + default: + return -EINVAL; + } + +- if (mlxbf_pmc_readl(pmcaddr, wordaddr)) ++ if (mlxbf_pmc_readl(wordaddr, pmcaddr)) + return -EINVAL; + + /* Read from appropriate register field for the counter */ + switch (cnt_num) { + case 0: +- evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0, perfcnt_sel); ++ evt = FIELD_GET(MLXBF_L3C_PERF_CNT_SEL__CNT_0, perfcnt_sel); + break; + case 1: +- evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1, perfcnt_sel); ++ evt = FIELD_GET(MLXBF_L3C_PERF_CNT_SEL__CNT_1, perfcnt_sel); + break; + case 2: +- evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2, perfcnt_sel); ++ evt = FIELD_GET(MLXBF_L3C_PERF_CNT_SEL__CNT_2, perfcnt_sel); + break; + case 3: +- evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3, perfcnt_sel); ++ evt = FIELD_GET(MLXBF_L3C_PERF_CNT_SEL__CNT_3, perfcnt_sel); + break; + case 4: +- evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4, ++ evt = FIELD_GET(MLXBF_L3C_PERF_CNT_SEL_1__CNT_4, + perfcnt_sel_1); + break; + default: +@@ -888,8 +558,8 @@ static int mlxbf_pmc_read_l3_event(int blk_num, uint32_t cnt_num, + } + + /* Method to find the event currently being monitored by a counter */ +-static int mlxbf_pmc_read_event(int blk_num, uint32_t cnt_num, bool is_l3, +- uint64_t *result) ++int mlxbf_read_event(int blk_num, uint32_t cnt_num, bool is_l3, ++ uint64_t *result) + { + uint32_t perfcfg_offset, perfval_offset; + uint64_t perfmon_cfg, perfevt, perfctl; +@@ -898,112 +568,115 @@ static int mlxbf_pmc_read_event(int blk_num, uint32_t cnt_num, bool is_l3, + return -EINVAL; + + if (is_l3) +- return mlxbf_pmc_read_l3_event(blk_num, cnt_num, result); ++ return mlxbf_read_l3_event(blk_num, cnt_num, result); + +- perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE; +- perfval_offset = perfcfg_offset + +- pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE; ++ perfcfg_offset = cnt_num * 8; ++ perfval_offset = perfcfg_offset + pmc->block[blk_num].counters * 8; + + /* Set counter in "read" mode */ +- perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, +- MLXBF_PMC_PERFCTL); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 0); +- +- if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + perfcfg_offset, +- MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) ++ perfmon_cfg = 0; ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__ADDR, ++ MLXBF_PERFCTL); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__STROBE, 1); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__WR_R_B, 0); ++ ++ if (mlxbf_pmc_writeq(perfmon_cfg, ++ pmc->block[blk_num].mmio_base + perfcfg_offset)) + return -EFAULT; + + /* Check if the counter is enabled */ + +- if (mlxbf_pmc_read(pmc->block[blk_num].mmio_base + perfval_offset, +- MLXBF_PMC_READ_REG_64, &perfctl)) ++ if (mlxbf_pmc_readq(&perfctl, ++ pmc->block[blk_num].mmio_base + perfval_offset)) + return -EFAULT; + +- if (!FIELD_GET(MLXBF_PMC_PERFCTL_EN0, perfctl)) ++ if (FIELD_GET(MLXBF_GEN_PERFCTL__EN0, perfctl) == 0) + return -EINVAL; + + /* Set counter in "read" mode */ +- perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, +- MLXBF_PMC_PERFEVT); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); +- perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 0); +- +- if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + perfcfg_offset, +- MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) ++ perfmon_cfg = 0; ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__ADDR, ++ MLXBF_PERFEVT); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__STROBE, 1); ++ perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__WR_R_B, 0); ++ ++ if (mlxbf_pmc_writeq(perfmon_cfg, pmc->block[blk_num].mmio_base + ++ perfcfg_offset)) + return -EFAULT; + + /* Get the event number */ +- if (mlxbf_pmc_read(pmc->block[blk_num].mmio_base + perfval_offset, +- MLXBF_PMC_READ_REG_64, &perfevt)) ++ if (mlxbf_pmc_readq(&perfevt, pmc->block[blk_num].mmio_base + ++ perfval_offset)) + return -EFAULT; + +- *result = FIELD_GET(MLXBF_PMC_PERFEVT_EVTSEL, perfevt); ++ *result = FIELD_GET(MLXBF_GEN_PERFEVT__EVTSEL, perfevt); + + return 0; + } + + /* Method to read a register */ +-static int mlxbf_pmc_read_reg(int blk_num, uint32_t offset, uint64_t *result) ++int mlxbf_read_reg(int blk_num, uint32_t offset, uint64_t *result) + { + uint32_t ecc_out; + + if (strstr(pmc->block_name[blk_num], "ecc")) { +- if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + offset, +- &ecc_out)) ++ if (mlxbf_pmc_readl(&ecc_out, ++ pmc->block[blk_num].mmio_base + offset)) + return -EFAULT; + +- *result = ecc_out; ++ *result = (uint64_t) ecc_out; + return 0; + } + + if (mlxbf_pmc_valid_range(blk_num, offset)) +- return mlxbf_pmc_read(pmc->block[blk_num].mmio_base + offset, +- MLXBF_PMC_READ_REG_64, result); ++ return mlxbf_pmc_readq(result, ++ pmc->block[blk_num].mmio_base + offset); + + return -EINVAL; + } + + /* Method to write to a register */ +-static int mlxbf_pmc_write_reg(int blk_num, uint32_t offset, uint64_t data) ++int mlxbf_write_reg(int blk_num, uint32_t offset, uint64_t data) + { + if (strstr(pmc->block_name[blk_num], "ecc")) { +- return mlxbf_pmc_write(pmc->block[blk_num].mmio_base + offset, +- MLXBF_PMC_WRITE_REG_32, data); ++ return mlxbf_pmc_writel((uint32_t)data, ++ pmc->block[blk_num].mmio_base + offset); + } + + if (mlxbf_pmc_valid_range(blk_num, offset)) +- return mlxbf_pmc_write(pmc->block[blk_num].mmio_base + offset, +- MLXBF_PMC_WRITE_REG_64, data); ++ return mlxbf_pmc_writeq(data, ++ pmc->block[blk_num].mmio_base + offset); + + return -EINVAL; + } + + /* Show function for "counter" sysfs files */ +-static ssize_t mlxbf_pmc_counter_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t mlxbf_counter_read(struct kobject *ko, ++ struct kobj_attribute *attr, char *buf) + { +- struct mlxbf_pmc_attribute *attr_counter = container_of( +- attr, struct mlxbf_pmc_attribute, dev_attr); +- int blk_num, cnt_num, offset; ++ int blk_num, cnt_num, offset, err; + bool is_l3 = false; + uint64_t value; + +- blk_num = attr_counter->nr; +- cnt_num = attr_counter->index; ++ blk_num = mlxbf_pmc_get_block_num(ko->name); ++ if (blk_num < 0) ++ return -EINVAL; + +- if (strstr(pmc->block_name[blk_num], "l3cache")) ++ if (strstr(ko->name, "l3cache")) + is_l3 = true; + +- if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) { +- if (mlxbf_pmc_read_counter(blk_num, cnt_num, is_l3, &value)) ++ if (pmc->block[blk_num].type == MLXBF_PERFTYPE_COUNTER) { ++ err = sscanf(attr->attr.name, "counter%d", &cnt_num); ++ if (err < 0) ++ return -EINVAL; ++ if (mlxbf_read_counter(blk_num, cnt_num, is_l3, &value)) + return -EINVAL; +- } else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) { +- offset = mlxbf_pmc_get_event_num(pmc->block_name[blk_num], +- attr->attr.name); ++ } else if (pmc->block[blk_num].type == MLXBF_PERFTYPE_REGISTER) { ++ offset = mlxbf_pmc_get_event_num((char *)ko->name, ++ (char *)attr->attr.name); + if (offset < 0) + return -EINVAL; +- if (mlxbf_pmc_read_reg(blk_num, offset, &value)) ++ if (mlxbf_read_reg(blk_num, offset, &value)) + return -EINVAL; + } else + return -EINVAL; +@@ -1012,47 +685,47 @@ static ssize_t mlxbf_pmc_counter_show(struct device *dev, + } + + /* Store function for "counter" sysfs files */ +-static ssize_t mlxbf_pmc_counter_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) ++static ssize_t mlxbf_counter_clear(struct kobject *ko, ++ struct kobj_attribute *attr, ++ const char *buf, size_t count) + { +- struct mlxbf_pmc_attribute *attr_counter = container_of( +- attr, struct mlxbf_pmc_attribute, dev_attr); + int blk_num, cnt_num, offset, err, data; + bool is_l3 = false; + uint64_t evt_num; + +- blk_num = attr_counter->nr; +- cnt_num = attr_counter->index; ++ blk_num = mlxbf_pmc_get_block_num(ko->name); ++ if (blk_num < 0) ++ return -EINVAL; + +- err = kstrtoint(buf, 0, &data); ++ err = sscanf(buf, "%x\n", &data); + if (err < 0) +- return err; ++ return -EINVAL; + + /* Allow non-zero writes only to the ecc regs */ +- if (!(strstr(pmc->block_name[blk_num], "ecc")) && data) ++ if (!(strstr(ko->name, "ecc")) && (data != 0)) + return -EINVAL; + +- /* Do not allow writes to the L3C regs */ +- if (strstr(pmc->block_name[blk_num], "l3cache")) ++ if (strstr(ko->name, "l3cache")) + return -EINVAL; + +- if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) { +- err = mlxbf_pmc_read_event(blk_num, cnt_num, is_l3, &evt_num); +- if (err) +- return err; +- err = mlxbf_pmc_program_counter(blk_num, cnt_num, evt_num, +- is_l3); +- if (err) +- return err; +- } else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) { +- offset = mlxbf_pmc_get_event_num(pmc->block_name[blk_num], +- attr->attr.name); ++ if (pmc->block[blk_num].type == MLXBF_PERFTYPE_COUNTER) { ++ err = sscanf(attr->attr.name, "counter%d", &cnt_num); ++ if (err < 0) ++ return -EINVAL; ++ err = mlxbf_read_event(blk_num, cnt_num, is_l3, &evt_num); ++ if (err < 0) ++ return -EINVAL; ++ err = mlxbf_program_counter(blk_num, cnt_num, evt_num, is_l3); ++ if (err < 0) ++ return -EINVAL; ++ } else if (pmc->block[blk_num].type == MLXBF_PERFTYPE_REGISTER) { ++ offset = mlxbf_pmc_get_event_num((char *)ko->name, ++ (char *)attr->attr.name); + if (offset < 0) + return -EINVAL; +- err = mlxbf_pmc_write_reg(blk_num, offset, data); +- if (err) +- return err; ++ err = mlxbf_write_reg(blk_num, offset, data); ++ if (err < 0) ++ return -EINVAL; + } else + return -EINVAL; + +@@ -1060,141 +733,140 @@ static ssize_t mlxbf_pmc_counter_store(struct device *dev, + } + + /* Show function for "event" sysfs files */ +-static ssize_t mlxbf_pmc_event_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t mlxbf_event_find(struct kobject *ko, ++ struct kobj_attribute *attr, char *buf) + { +- struct mlxbf_pmc_attribute *attr_event = container_of( +- attr, struct mlxbf_pmc_attribute, dev_attr); + int blk_num, cnt_num, err; + bool is_l3 = false; + uint64_t evt_num; + char *evt_name; + +- blk_num = attr_event->nr; +- cnt_num = attr_event->index; ++ blk_num = mlxbf_pmc_get_block_num(ko->name); ++ if (blk_num < 0) ++ return -EINVAL; + +- if (strstr(pmc->block_name[blk_num], "l3cache")) ++ if (strstr(ko->name, "l3cache")) + is_l3 = true; + +- err = mlxbf_pmc_read_event(blk_num, cnt_num, is_l3, &evt_num); +- if (err) +- return sprintf(buf, "No event being monitored\n"); ++ err = sscanf(attr->attr.name, "event%d", &cnt_num); ++ if (err < 0) ++ return -EINVAL; + +- evt_name = mlxbf_pmc_get_event_name(pmc->block_name[blk_num], evt_num); +- if (!evt_name) ++ err = mlxbf_read_event(blk_num, cnt_num, is_l3, &evt_num); ++ if (err < 0) + return -EINVAL; + ++ evt_name = mlxbf_pmc_get_event_name((char *)ko->name, evt_num); ++ + return sprintf(buf, "0x%llx: %s\n", evt_num, evt_name); + } + + /* Store function for "event" sysfs files */ +-static ssize_t mlxbf_pmc_event_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) ++static ssize_t mlxbf_event_set(struct kobject *ko, struct kobj_attribute *attr, ++ const char *buf, size_t count) + { +- struct mlxbf_pmc_attribute *attr_event = container_of( +- attr, struct mlxbf_pmc_attribute, dev_attr); + int blk_num, cnt_num, evt_num, err; + bool is_l3 = false; + +- blk_num = attr_event->nr; +- cnt_num = attr_event->index; +- + if (isalpha(buf[0])) { +- evt_num = mlxbf_pmc_get_event_num(pmc->block_name[blk_num], +- buf); ++ evt_num = mlxbf_pmc_get_event_num((char *)ko->name, ++ (char *)buf); + if (evt_num < 0) + return -EINVAL; + } else { +- err = kstrtoint(buf, 0, &evt_num); ++ err = sscanf(buf, "%x\n", &evt_num); + if (err < 0) +- return err; ++ return -EINVAL; + } + +- if (strstr(pmc->block_name[blk_num], "l3cache")) ++ blk_num = mlxbf_pmc_get_block_num(ko->name); ++ if (blk_num < 0) ++ return -EINVAL; ++ ++ err = sscanf(attr->attr.name, "event%d", &cnt_num); ++ if (err < 0) ++ return -EINVAL; ++ ++ if (strstr(ko->name, "l3cache")) + is_l3 = true; + +- err = mlxbf_pmc_program_counter(blk_num, cnt_num, evt_num, is_l3); +- if (err) +- return err; ++ err = mlxbf_program_counter(blk_num, cnt_num, evt_num, is_l3); ++ if (err < 0) ++ return -EINVAL; + + return count; + } + + /* Show function for "event_list" sysfs files */ +-static ssize_t mlxbf_pmc_event_list_show(struct device *dev, +- struct device_attribute *attr, +- char *buf) ++static ssize_t mlxbf_print_event_list(struct kobject *ko, ++ struct kobj_attribute *attr, char *buf) + { +- struct mlxbf_pmc_attribute *attr_event_list = container_of( +- attr, struct mlxbf_pmc_attribute, dev_attr); +- int blk_num, i, size, len = 0, ret = 0; +- const struct mlxbf_pmc_events *events; +- char e_info[MLXBF_PMC_EVENT_INFO_LEN]; +- +- blk_num = attr_event_list->nr; ++ struct mlxbf_pmc_events *events; ++ int i = 0, size = 0, ret = 0; ++ char e_info[100]; + +- events = mlxbf_pmc_event_list(pmc->block_name[blk_num], &size); +- if (!events) ++ events = mlxbf_pmc_event_list((char *)ko->name); ++ if (events == NULL) + return -EINVAL; + +- for (i = 0, buf[0] = '\0'; i < size; ++i) { +- len += sprintf(e_info, "0x%x: %s\n", events[i].evt_num, +- events[i].evt_name); +- if (len > PAGE_SIZE) ++ buf[0] = '\0'; ++ while (events[i].evt_name != NULL) { ++ size += sprintf(e_info, "%x: %s\n", events[i].evt_num, ++ events[i].evt_name); ++ if (size > PAGE_SIZE) + break; + strcat(buf, e_info); +- ret = len; ++ ret = size; ++ ++i; + } + + return ret; + } + + /* Show function for "enable" sysfs files - only for l3cache */ +-static ssize_t mlxbf_pmc_enable_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t mlxbf_show_counter_state(struct kobject *ko, ++ struct kobj_attribute *attr, char *buf) + { +- struct mlxbf_pmc_attribute *attr_enable = container_of( +- attr, struct mlxbf_pmc_attribute, dev_attr); + uint32_t perfcnt_cfg; + int blk_num, value; + +- blk_num = attr_enable->nr; ++ blk_num = mlxbf_pmc_get_block_num(ko->name); ++ if (blk_num < 0) ++ return -EINVAL; + +- if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + +- MLXBF_PMC_L3C_PERF_CNT_CFG, +- &perfcnt_cfg)) ++ if (mlxbf_pmc_readl(&perfcnt_cfg, ++ pmc->block[blk_num].mmio_base + MLXBF_L3C_PERF_CNT_CFG)) + return -EINVAL; + +- value = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_CFG_EN, perfcnt_cfg); ++ value = FIELD_GET(MLXBF_L3C_PERF_CNT_CFG__EN, perfcnt_cfg); + + return sprintf(buf, "%d\n", value); + } + + /* Store function for "enable" sysfs files - only for l3cache */ +-static ssize_t mlxbf_pmc_enable_store(struct device *dev, +- struct device_attribute *attr, +- const char *buf, size_t count) ++static ssize_t mlxbf_enable_counters(struct kobject *ko, ++ struct kobj_attribute *attr, ++ const char *buf, size_t count) + { +- struct mlxbf_pmc_attribute *attr_enable = container_of( +- attr, struct mlxbf_pmc_attribute, dev_attr); + int err, en, blk_num; + +- blk_num = attr_enable->nr; ++ blk_num = mlxbf_pmc_get_block_num(ko->name); ++ if (blk_num < 0) ++ return -EINVAL; + +- err = kstrtoint(buf, 0, &en); ++ err = sscanf(buf, "%x\n", &en); + if (err < 0) + return err; + +- if (!en) { +- err = mlxbf_pmc_config_l3_counters(blk_num, false, false); ++ if (en == 0) { ++ err = mlxbf_config_l3_counters(blk_num, false, false); + if (err) + return err; + } else if (en == 1) { +- err = mlxbf_pmc_config_l3_counters(blk_num, false, true); ++ err = mlxbf_config_l3_counters(blk_num, false, true); + if (err) + return err; +- err = mlxbf_pmc_config_l3_counters(blk_num, true, false); ++ err = mlxbf_config_l3_counters(blk_num, true, false); + if (err) + return err; + } else +@@ -1203,277 +875,379 @@ static ssize_t mlxbf_pmc_enable_store(struct device *dev, + return count; + } + +-/* Populate attributes for blocks with counters to monitor performance */ +-static int mlxbf_pmc_init_perftype_counter(struct device *dev, int blk_num) ++/* Helper to create the bfperf sysfs sub-directories and files */ ++int mlxbf_pmc_create_sysfs(struct device *dev, struct kobject *ko, int blk_num) + { +- struct mlxbf_pmc_attribute *attr; +- int i = 0, j = 0; +- +- /* "event_list" sysfs to list events supported by the block */ +- attr = &pmc->block[blk_num].attr_event_list; +- attr->dev_attr.attr.mode = 0444; +- attr->dev_attr.show = mlxbf_pmc_event_list_show; +- attr->nr = blk_num; +- attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, "event_list"); +- pmc->block[blk_num].block_attr[i] = &attr->dev_attr.attr; +- attr = NULL; +- +- /* "enable" sysfs to start/stop the counters. Only in L3C blocks */ +- if (strstr(pmc->block_name[blk_num], "l3cache")) { +- attr = &pmc->block[blk_num].attr_enable; +- attr->dev_attr.attr.mode = 0644; +- attr->dev_attr.show = mlxbf_pmc_enable_show; +- attr->dev_attr.store = mlxbf_pmc_enable_store; +- attr->nr = blk_num; +- attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, +- "enable"); +- pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr; +- attr = NULL; ++ int err = 0, j = 0; ++ ++ pmc->block[blk_num].block_dir = ++ kobject_create_and_add(pmc->block_name[blk_num], ko); ++ if (pmc->block[blk_num].block_dir == NULL) { ++ dev_err(dev, ++ "PMC: Error creating subdirectories\n"); ++ return -EFAULT; + } + +- pmc->block[blk_num].attr_counter = devm_kcalloc( +- dev, pmc->block[blk_num].counters, +- sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL); +- if (!pmc->block[blk_num].attr_counter) +- return -ENOMEM; ++ if (pmc->block[blk_num].type == MLXBF_PERFTYPE_COUNTER) { ++ pmc->block[blk_num].attr_event_list.attr.mode = 0444; ++ pmc->block[blk_num].attr_event_list.show = ++ mlxbf_print_event_list; ++ pmc->block[blk_num].attr_event_list.attr.name = ++ kzalloc(20, GFP_KERNEL); ++ snprintf((char *)pmc->block[blk_num].attr_event_list.attr.name, ++ 20, "event_list"); ++ ++ err = sysfs_create_file(pmc->block[blk_num].block_dir, ++ &pmc->block[blk_num].attr_event_list.attr); ++ if (err < 0) { ++ dev_err(dev, ++ "PMC: Error creating sysfs entries\n"); ++ return err; ++ } + +- pmc->block[blk_num].attr_event = devm_kcalloc( +- dev, pmc->block[blk_num].counters, +- sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL); +- if (!pmc->block[blk_num].attr_event) +- return -ENOMEM; ++ if (strstr(pmc->block_name[blk_num], "l3cache")) { ++ pmc->block[blk_num].attr_enable.attr.mode = ++ 0644; ++ pmc->block[blk_num].attr_enable.show = ++ mlxbf_show_counter_state; ++ pmc->block[blk_num].attr_enable.store = ++ mlxbf_enable_counters; ++ pmc->block[blk_num].attr_enable.attr.name = ++ kzalloc(20, GFP_KERNEL); ++ snprintf((char *) ++ pmc->block[blk_num].attr_enable.attr.name, ++ 20, "enable"); ++ ++ err = sysfs_create_file( ++ pmc->block[blk_num].block_dir, ++ &pmc->block[blk_num].attr_enable.attr); ++ if (err < 0) { ++ dev_err(dev, ++ "PMC: Error creating sysfs entries\n"); ++ return err; ++ } + +- /* "eventX" and "counterX" sysfs to program and read counter values */ +- for (j = 0; j < pmc->block[blk_num].counters; ++j) { +- attr = &pmc->block[blk_num].attr_counter[j]; +- attr->dev_attr.attr.mode = 0644; +- attr->dev_attr.show = mlxbf_pmc_counter_show; +- attr->dev_attr.store = mlxbf_pmc_counter_store; +- attr->index = j; +- attr->nr = blk_num; +- attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, +- "counter%d", j); +- pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr; +- attr = NULL; +- +- attr = &pmc->block[blk_num].attr_event[j]; +- attr->dev_attr.attr.mode = 0644; +- attr->dev_attr.show = mlxbf_pmc_event_show; +- attr->dev_attr.store = mlxbf_pmc_event_store; +- attr->index = j; +- attr->nr = blk_num; +- attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, +- "event%d", j); +- pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr; +- attr = NULL; +- } ++ } + +- return 0; ++ pmc->block[blk_num].attr_counter = ++ kcalloc(pmc->block[blk_num].counters, ++ sizeof(struct kobj_attribute), GFP_KERNEL); ++ if (!pmc->block[blk_num].attr_counter) ++ return -ENOMEM; ++ pmc->block[blk_num].attr_event = ++ kcalloc(pmc->block[blk_num].counters, ++ sizeof(struct kobj_attribute), GFP_KERNEL); ++ if (!pmc->block[blk_num].attr_event) ++ return -ENOMEM; ++ pmc->block[blk_num].sysfs_event_cnt = ++ pmc->block[blk_num].counters; ++ ++ for (j = 0; j < pmc->block[blk_num].counters; ++j) { ++ pmc->block[blk_num].attr_counter[j].attr.mode = 0644; ++ pmc->block[blk_num].attr_counter[j].show = ++ mlxbf_counter_read; ++ pmc->block[blk_num].attr_counter[j].store = ++ mlxbf_counter_clear; ++ pmc->block[blk_num].attr_counter[j].attr.name = ++ kzalloc(20, GFP_KERNEL); ++ snprintf((char *) ++ pmc->block[blk_num].attr_counter[j].attr.name, ++ 20, "counter%d", j); ++ ++ err = sysfs_create_file( ++ pmc->block[blk_num].block_dir, ++ &pmc->block[blk_num].attr_counter[j].attr); ++ if (err < 0) { ++ dev_err(dev, ++ "PMC: Error creating sysfs entries\n"); ++ return err; ++ } ++ ++ pmc->block[blk_num].attr_event[j].attr.mode = 0644; ++ pmc->block[blk_num].attr_event[j].show = ++ mlxbf_event_find; ++ pmc->block[blk_num].attr_event[j].store = ++ mlxbf_event_set; ++ pmc->block[blk_num].attr_event[j].attr.name = ++ kzalloc(20, GFP_KERNEL); ++ snprintf((char *) ++ pmc->block[blk_num].attr_event[j].attr.name, ++ 20, "event%d", j); ++ ++ err = sysfs_create_file( ++ pmc->block[blk_num].block_dir, ++ &pmc->block[blk_num].attr_event[j].attr); ++ if (err < 0) { ++ dev_err(dev, ++ "PMC: Error creating sysfs entries\n"); ++ return err; ++ } ++ } ++ } else if (pmc->block[blk_num].type == MLXBF_PERFTYPE_REGISTER) { ++ struct mlxbf_pmc_events *events; ++ ++ events = mlxbf_pmc_event_list((char *)pmc->block_name[blk_num]); ++ if (events == NULL) ++ return -EINVAL; ++ ++ while (events[j].evt_name != NULL) ++ ++j; ++ ++ pmc->block[blk_num].sysfs_event_cnt = j; ++ pmc->block[blk_num].attr_event = ++ kcalloc(j, sizeof(struct kobj_attribute), GFP_KERNEL); ++ if (!pmc->block[blk_num].attr_event) ++ return -ENOMEM; ++ ++ while (j > 0) { ++ --j; ++ pmc->block[blk_num].attr_event[j].attr.mode = 0644; ++ pmc->block[blk_num].attr_event[j].show = ++ mlxbf_counter_read; ++ pmc->block[blk_num].attr_event[j].store = ++ mlxbf_counter_clear; ++ pmc->block[blk_num].attr_event[j].attr.name = ++ kzalloc(30, GFP_KERNEL); ++ strcpy((char *) ++ pmc->block[blk_num].attr_event[j].attr.name, ++ events[j].evt_name); ++ ++ err = sysfs_create_file( ++ pmc->block[blk_num].block_dir, ++ &pmc->block[blk_num].attr_event[j].attr); ++ if (err < 0) { ++ dev_err(dev, ++ "PMC: Error creating sysfs entries\n"); ++ return err; ++ } ++ } ++ } else ++ err = -EINVAL; ++ ++ return err; + } + +-/* Populate attributes for blocks with registers to monitor performance */ +-static int mlxbf_pmc_init_perftype_reg(struct device *dev, int blk_num) ++void mlxbf_pmc_delete(void) + { +- struct mlxbf_pmc_attribute *attr; +- const struct mlxbf_pmc_events *events; +- int i = 0, j = 0; ++ hwmon_device_unregister(pmc->hwmon_dev); ++ kfree(pmc); ++} + +- events = mlxbf_pmc_event_list(pmc->block_name[blk_num], &j); +- if (!events) +- return -EINVAL; ++static int mlxbf_pmc_probe(struct platform_device *pdev) ++{ ++ struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev); ++ const char *hid = acpi_device_hid(acpi_dev); ++ int i, version, err = 0, ret = 0; ++ struct device *dev = &pdev->dev; ++ struct arm_smccc_res res; ++ uint64_t info[4]; + +- pmc->block[blk_num].attr_event = devm_kcalloc( +- dev, j, sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL); +- if (!pmc->block[blk_num].attr_event) ++ /* ++ * Ensure we have the UUID we expect for the Mellanox service. ++ */ ++ arm_smccc_smc(MLNX_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res); ++ if (res.a0 != 0x89c036b4 || res.a1 != 0x11e6e7d7 || ++ res.a2 != 0x1a009787 || res.a3 != 0xc4bf00ca) ++ return -ENODEV; ++ ++ pmc = kzalloc(sizeof(struct mlxbf_pmc_context), GFP_KERNEL); ++ if (!pmc) + return -ENOMEM; + +- while (j > 0) { +- --j; +- attr = &pmc->block[blk_num].attr_event[j]; +- attr->dev_attr.attr.mode = 0644; +- attr->dev_attr.show = mlxbf_pmc_counter_show; +- attr->dev_attr.store = mlxbf_pmc_counter_store; +- attr->nr = blk_num; +- attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, +- events[j].evt_name); +- pmc->block[blk_num].block_attr[i] = &attr->dev_attr.attr; +- attr = NULL; +- i++; +- } ++ platform_set_drvdata(pdev, pmc); ++ pmc->pdev = pdev; + +- return 0; +-} ++ pmc->hwmon_dev = hwmon_device_register_with_info(dev, "bfperf", pmc, ++ NULL, NULL); ++ pmc->ko = &pmc->hwmon_dev->kobj; + +-/* Helper to create the bfperf sysfs sub-directories and files */ +-static int mlxbf_pmc_create_groups(struct device *dev, int blk_num) +-{ +- int err; ++ /* ++ * ACPI indicates whether we use SMCs to access registers or not. ++ * If sreg_tbl_perf is not present, just assume we're not using SMCs. ++ */ ++ if (device_property_read_u32(dev, ++ "sec_reg_block", &pmc->sreg_tbl_perf)) { ++ pmc->svc_sreg_support = false; ++ } else { ++ /* ++ * Check service version to see if we actually do support the ++ * needed SMCs. If we have the calls we need, mark support for ++ * them in the pmc struct. ++ */ ++ arm_smccc_smc(MLNX_SIP_SVC_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); ++ if (res.a0 == MLNX_PMC_SVC_REQ_MAJOR && ++ res.a1 >= MLNX_PMC_SVC_MIN_MINOR) ++ pmc->svc_sreg_support = true; ++ else { ++ dev_err(dev, "Required SMCs are not supported.\n"); + +- /* Populate attributes based on counter type */ +- if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) +- err = mlxbf_pmc_init_perftype_counter(dev, blk_num); +- else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) +- err = mlxbf_pmc_init_perftype_reg(dev, blk_num); +- else +- err = -EINVAL; ++ err = -EINVAL; ++ goto error; ++ } ++ } + +- if (err) +- return err; ++ if (pmc->ko == NULL) { ++ dev_err(dev, "Sysfs creation failed\n"); ++ err = -EFAULT; ++ goto error; ++ } + +- /* Add a new attribute_group for the block */ +- pmc->block[blk_num].block_attr_grp.attrs = pmc->block[blk_num].block_attr; +- pmc->block[blk_num].block_attr_grp.name = devm_kasprintf( +- dev, GFP_KERNEL, pmc->block_name[blk_num]); +- pmc->groups[blk_num] = &pmc->block[blk_num].block_attr_grp; ++ if (device_property_read_u32(dev, "version", &version)) { ++ dev_err(dev, "Version Info not found\n"); ++ err = -EINVAL; ++ goto error; ++ } + +- return 0; +-} ++ if (version != (int)DRIVER_VERSION) { ++ dev_err(dev, "Version Mismatch. Expected %d Returned %d\n", ++ (int)DRIVER_VERSION, version); ++ err = -EINVAL; ++ goto error; ++ } + +-static bool mlxbf_pmc_guid_match(const guid_t *guid, +- const struct arm_smccc_res *res) +-{ +- guid_t id = GUID_INIT(res->a0, res->a1, res->a1 >> 16, res->a2, +- res->a2 >> 8, res->a2 >> 16, res->a2 >> 24, +- res->a3, res->a3 >> 8, res->a3 >> 16, +- res->a3 >> 24); ++ if (strcmp(hid, "MLNXBFD0") == 0) ++ pmc->event_set = MLNX_EVENT_SET_BF1; ++ else if (strcmp(hid, "MLNXBFD1") == 0) ++ pmc->event_set = MLNX_EVENT_SET_BF2; ++ else { ++ dev_err(dev, "Invalid device ID %s\n", hid); ++ err = -ENODEV; ++ goto error; ++ } + +- return guid_equal(guid, &id); +-} ++ if (device_property_read_u32(dev, "block_num", &pmc->total_blocks)) { ++ dev_err(dev, "Number of performance blocks undefined\n"); ++ err = -EINVAL; ++ goto error; ++ } + +-/* Helper to map the Performance Counters from the varios blocks */ +-static int mlxbf_pmc_map_counters(struct device *dev) +-{ +- uint64_t info[MLXBF_PMC_INFO_SZ]; +- int i, tile_num, ret; ++ ret = device_property_read_string_array(dev, "block_name", ++ pmc->block_name, pmc->total_blocks); ++ if (ret != pmc->total_blocks) { ++ dev_err(dev, ++ "Block count mismatch. Expected %d Returned %d\n", ++ pmc->total_blocks, ret); ++ err = -EFAULT; ++ goto error; ++ } ++ ++ if (device_property_read_u32(dev, "tile_num", &pmc->tile_count)) { ++ dev_err(dev, "Number of tiles undefined\n"); ++ err = -EINVAL; ++ goto error; ++ } + ++ /* Map the Performance Counters from the varios blocks */ + for (i = 0; i < pmc->total_blocks; ++i) { + if (strstr(pmc->block_name[i], "tile")) { +- ret = sscanf(pmc->block_name[i], "tile%d", &tile_num); +- if (ret < 0) +- return ret; ++ int tile_num; + ++ ret = sscanf(pmc->block_name[i], "tile%d", &tile_num); ++ if (ret < 0) { ++ err = -EINVAL; ++ goto error; ++ } + if (tile_num >= pmc->tile_count) + continue; + } +- ret = device_property_read_u64_array(dev, pmc->block_name[i], +- info, MLXBF_PMC_INFO_SZ); +- if (ret) +- return ret; ++ err = device_property_read_u64_array(dev, pmc->block_name[i], ++ info, 4); ++ if (err) { ++ dev_err(dev, "Failed to find %s block info\n", ++ pmc->block_name[i]); ++ goto error; ++ } + + /* + * Do not remap if the proper SMC calls are supported, + * since the SMC calls expect physical addresses. + */ + if (pmc->svc_sreg_support) +- pmc->block[i].mmio_base = (void __iomem *)info[0]; ++ pmc->block[i].mmio_base = (void *)info[0]; + else +- pmc->block[i].mmio_base = +- devm_ioremap(dev, info[0], info[1]); ++ pmc->block[i].mmio_base = ioremap(info[0], info[1]); + + pmc->block[i].blk_size = info[1]; + pmc->block[i].counters = info[2]; + pmc->block[i].type = info[3]; + +- if (!pmc->block[i].mmio_base) +- return -ENOMEM; ++ if (IS_ERR(pmc->block[i].mmio_base)) { ++ dev_err(dev, "%s: ioremap failed base %llx err %p\n", ++ __func__, info[0], pmc->block[i].mmio_base); ++ err = PTR_ERR(pmc->block[i].mmio_base); ++ goto error; ++ } + +- ret = mlxbf_pmc_create_groups(dev, i); +- if (ret) +- return ret; ++ err = mlxbf_pmc_create_sysfs(dev, pmc->ko, i); + } + ++ dev_info(&pdev->dev, "v%d probed\n", (int)DRIVER_VERSION); + return 0; ++ ++error: ++ mlxbf_pmc_delete(); ++ return err; + } + +-static int mlxbf_pmc_probe(struct platform_device *pdev) ++static int mlxbf_pmc_remove(struct platform_device *pdev) + { +- struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev); +- const char *hid = acpi_device_hid(acpi_dev); +- struct device *dev = &pdev->dev; +- struct arm_smccc_res res; +- guid_t guid; +- int ret; +- +- /* Ensure we have the UUID we expect for this service. */ +- arm_smccc_smc(MLXBF_PMC_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res); +- guid_parse(mlxbf_pmc_svc_uuid_str, &guid); +- if (!mlxbf_pmc_guid_match(&guid, &res)) +- return -ENODEV; +- +- pmc = devm_kzalloc(dev, sizeof(struct mlxbf_pmc_context), GFP_KERNEL); +- if (!pmc) +- return -ENOMEM; +- +- /* +- * ACPI indicates whether we use SMCs to access registers or not. +- * If sreg_tbl_perf is not present, just assume we're not using SMCs. +- */ +- ret = device_property_read_u32(dev, "sec_reg_block", +- &pmc->sreg_tbl_perf); +- if (ret) { +- pmc->svc_sreg_support = false; +- } else { +- /* +- * Check service version to see if we actually do support the +- * needed SMCs. If we have the calls we need, mark support for +- * them in the pmc struct. +- */ +- arm_smccc_smc(MLXBF_PMC_SIP_SVC_VERSION, 0, 0, 0, 0, 0, 0, 0, +- &res); +- if (res.a0 == MLXBF_PMC_SVC_REQ_MAJOR && +- res.a1 >= MLXBF_PMC_SVC_MIN_MINOR) +- pmc->svc_sreg_support = true; +- else +- return -EINVAL; +- } ++ struct mlxbf_pmc_context *pmc = platform_get_drvdata(pdev); ++ int i, j, err; + +- if (!strcmp(hid, "MLNXBFD0")) +- pmc->event_set = MLXBF_PMC_EVENT_SET_BF1; +- else if (!strcmp(hid, "MLNXBFD1")) +- pmc->event_set = MLXBF_PMC_EVENT_SET_BF2; +- else +- return -ENODEV; +- +- ret = device_property_read_u32(dev, "block_num", &pmc->total_blocks); +- if (ret) +- return ret; +- +- ret = device_property_read_string_array(dev, "block_name", +- pmc->block_name, +- pmc->total_blocks); +- if (ret != pmc->total_blocks) +- return -EFAULT; ++ for (i = 0; i < pmc->total_blocks; ++i) { ++ if (strstr(pmc->block_name[i], "tile")) { ++ int tile_num; + +- ret = device_property_read_u32(dev, "tile_num", &pmc->tile_count); +- if (ret) +- return ret; ++ err = sscanf(pmc->block_name[i], "tile%d", &tile_num); ++ if (err < 0) ++ return -EINVAL; ++ if (tile_num >= pmc->tile_count) ++ continue; ++ } ++ kfree(pmc->block[i].attr_event_list.attr.name); ++ if (pmc->block[i].type == MLXBF_PERFTYPE_COUNTER) { ++ for (j = 0; j < pmc->block[i].counters; ++j) { ++ kfree(pmc->block[i].attr_counter[j].attr.name); ++ kfree(pmc->block[i].attr_event[j].attr.name); ++ } ++ } else if (pmc->block[i].type == MLXBF_PERFTYPE_REGISTER) { ++ for (j = 0; j < pmc->block[i].sysfs_event_cnt; ++j) ++ kfree(pmc->block[i].attr_event[j].attr.name); ++ } + +- pmc->pdev = pdev; ++ /* Unmap if SMCs weren't used for access */ ++ if (pmc->block[i].mmio_base && !(pmc->svc_sreg_support)) ++ iounmap(pmc->block[i].mmio_base); + +- ret = mlxbf_pmc_map_counters(dev); +- if (ret) +- return ret; ++ kobject_put(pmc->block[i].block_dir); ++ kfree(pmc->block[i].attr_event); ++ kfree(pmc->block[i].attr_counter); ++ } + +- pmc->hwmon_dev = devm_hwmon_device_register_with_groups( +- dev, "bfperf", pmc, pmc->groups); +- platform_set_drvdata(pdev, pmc); ++ mlxbf_pmc_delete(); + + return 0; + } + +-static const struct acpi_device_id mlxbf_pmc_acpi_ids[] = { { "MLNXBFD0", 0 }, +- { "MLNXBFD1", 0 }, +- {}, }; ++static const struct acpi_device_id pmc_acpi_ids[] = { ++ {"MLNXBFD0", 0}, ++ {"MLNXBFD1", 0}, ++ {}, ++}; + +-MODULE_DEVICE_TABLE(acpi, mlxbf_pmc_acpi_ids); ++MODULE_DEVICE_TABLE(acpi, pmc_acpi_ids); + static struct platform_driver pmc_driver = { +- .driver = { .name = "mlxbf-pmc", +- .acpi_match_table = ACPI_PTR(mlxbf_pmc_acpi_ids), }, ++ .driver = { ++ .name = "mlxbf-pmc", ++ .acpi_match_table = ACPI_PTR(pmc_acpi_ids), ++ }, + .probe = mlxbf_pmc_probe, ++ .remove = mlxbf_pmc_remove, + }; + + module_platform_driver(pmc_driver); + +-MODULE_AUTHOR("Shravan Kumar Ramani "); ++MODULE_AUTHOR("Shravan Kumar Ramani "); + MODULE_DESCRIPTION("Mellanox PMC driver"); + MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_VERSION(__stringify(DRIVER_VERSION)); +diff --git a/drivers/platform/mellanox/mlxbf-pmc.h b/drivers/platform/mellanox/mlxbf-pmc.h +new file mode 100644 +index 000000000..b15614e90 +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf-pmc.h +@@ -0,0 +1,428 @@ ++// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause ++ ++#ifndef __MLXBF_PMC_H__ ++#define __MLXBF_PMC_H__ ++ ++#define MLNX_WRITE_REG_32 (0x82000009) ++#define MLNX_READ_REG_32 (0x8200000A) ++#define MLNX_WRITE_REG_64 (0x8200000B) ++#define MLNX_READ_REG_64 (0x8200000C) ++#define MLNX_SIP_SVC_UID (0x8200ff01) ++#define MLNX_SIP_SVC_VERSION (0x8200ff03) ++ ++#define SMCCC_INVALID_PARAMETERS (-2) ++#define SMCCC_OUT_OF_RANGE (-3) ++#define SMCCC_ACCESS_VIOLATION (-4) ++ ++#define MLNX_EVENT_SET_BF1 0 ++#define MLNX_EVENT_SET_BF2 1 ++ ++#define MLNX_PMC_SVC_REQ_MAJOR 0 ++#define MLNX_PMC_SVC_MIN_MINOR 3 ++ ++#define MLXBF_PMC_MAX_BLOCKS 30 ++ ++/** ++ * Structure to hold info for each HW block ++ * ++ * @mmio_base: The VA at which the PMC block is mapped ++ * @blk_size: Size of each mapped region ++ * @counters: Number of counters in the block ++ * @type: Type of counters in the block ++ * @block_dir: Kobjects to create sub-directories ++ * @attr_counter: Attributes for "counter" sysfs files ++ * @attr_event: Attributes for "event" sysfs files ++ * @attr_event_list: Attributes for "event_list" sysfs files ++ * @attr_enable: Attributes for "enable" sysfs files ++ * @sysfs_event_cnt: Number of sysfs event files in the block ++ */ ++struct mlxbf_pmc_block_info { ++ void *mmio_base; ++ size_t blk_size; ++ size_t counters; ++ int type; ++ struct kobject *block_dir; ++ struct kobj_attribute *attr_counter; ++ struct kobj_attribute *attr_event; ++ struct kobj_attribute attr_event_list; ++ struct kobj_attribute attr_enable; ++ int sysfs_event_cnt; ++}; ++ ++/** ++ * Structure to hold PMC context info ++ * ++ * @pdev: The kernel structure representing the device ++ * @total_blocks: Total number of blocks ++ * @tile_count: Number of tiles in the system ++ * @hwmon_dev: Hwmon device for bfperf ++ * @ko: Kobject for bfperf ++ * @block_name: Block name ++ * @block_name: Block info ++ * @sv_sreg_support: Whether SMCs are used to access performance registers ++ * @sreg_tbl_perf: Secure register access table number ++ * @event_set: Event set to use ++ */ ++struct mlxbf_pmc_context { ++ struct platform_device *pdev; ++ uint32_t total_blocks; ++ uint32_t tile_count; ++ struct device *hwmon_dev; ++ struct kobject *ko; ++ const char *block_name[MLXBF_PMC_MAX_BLOCKS]; ++ struct mlxbf_pmc_block_info block[MLXBF_PMC_MAX_BLOCKS]; ++ bool svc_sreg_support; ++ uint32_t sreg_tbl_perf; ++ unsigned int event_set; ++}; ++ ++#define MLXBF_PERFTYPE_COUNTER 1 ++#define MLXBF_PERFTYPE_REGISTER 0 ++ ++#define MLXBF_PERFCTL 0 ++#define MLXBF_PERFEVT 1 ++#define MLXBF_PERFVALEXT 2 ++#define MLXBF_PERFACC0 4 ++#define MLXBF_PERFACC1 5 ++#define MLXBF_PERFMVAL0 6 ++#define MLXBF_PERFMVAL1 7 ++ ++#define MLXBF_GEN_PERFMON_CONFIG__WR_R_B BIT(0) ++#define MLXBF_GEN_PERFMON_CONFIG__STROBE BIT(1) ++#define MLXBF_GEN_PERFMON_CONFIG__ADDR GENMASK_ULL(4, 2) ++#define MLXBF_GEN_PERFMON_CONFIG__WDATA GENMASK_ULL(60, 5) ++ ++#define MLXBF_GEN_PERFCTL__FM1 GENMASK_ULL(2, 0) ++#define MLXBF_GEN_PERFCTL__MS1 GENMASK_ULL(5, 4) ++#define MLXBF_GEN_PERFCTL__ACCM1 GENMASK_ULL(10, 8) ++#define MLXBF_GEN_PERFCTL__AD1 BIT(11) ++#define MLXBF_GEN_PERFCTL__ETRIG1 GENMASK_ULL(13, 12) ++#define MLXBF_GEN_PERFCTL__EB1 BIT(14) ++#define MLXBF_GEN_PERFCTL__EN1 BIT(15) ++#define MLXBF_GEN_PERFCTL__FM0 GENMASK_ULL(18, 16) ++#define MLXBF_GEN_PERFCTL__MS0 GENMASK_ULL(21, 20) ++#define MLXBF_GEN_PERFCTL__ACCM0 GENMASK_ULL(26, 24) ++#define MLXBF_GEN_PERFCTL__AD0 BIT(27) ++#define MLXBF_GEN_PERFCTL__ETRIG0 GENMASK_ULL(29, 28) ++#define MLXBF_GEN_PERFCTL__EB0 BIT(30) ++#define MLXBF_GEN_PERFCTL__EN0 BIT(31) ++ ++#define MLXBF_GEN_PERFEVT__PVALSEL GENMASK_ULL(19, 16) ++#define MLXBF_GEN_PERFEVT__MODSEL GENMASK_ULL(23, 20) ++#define MLXBF_GEN_PERFEVT__EVTSEL GENMASK_ULL(31, 24) ++ ++#define MLXBF_L3C_PERF_CNT_CFG 0x0 ++#define MLXBF_L3C_PERF_CNT_CFG_1 0x4 ++#define MLXBF_L3C_PERF_CNT_CFG_2 0x8 ++#define MLXBF_L3C_PERF_CNT_SEL 0x10 ++#define MLXBF_L3C_PERF_CNT_SEL_1 0x14 ++#define MLXBF_L3C_PERF_CNT_LOW 0x40 ++#define MLXBF_L3C_PERF_CNT_HIGH 0x60 ++ ++#define MLXBF_L3C_PERF_CNT_CFG__EN BIT(0) ++#define MLXBF_L3C_PERF_CNT_CFG__RST BIT(1) ++#define MLXBF_L3C_PERF_CNT_CFG__SRCID_SEL GENMASK(14, 8) ++#define MLXBF_L3C_PERF_CNT_CFG__SRCID_MASK GENMASK(22, 16) ++#define MLXBF_L3C_PERF_CNT_CFG__PRF_SEL GENMASK(27, 24) ++#define MLXBF_L3C_PERF_CNT_CFG__PRF_MASK GENMASK(31, 28) ++ ++#define MLXBF_L3C_PERF_CNT_CFG_1__SET_SEL GENMASK(10,0) ++#define MLXBF_L3C_PERF_CNT_CFG_1__SET_MASK GENMASK(22,12) ++#define MLXBF_L3C_PERF_CNT_CFG_1__EMEM_USAGE_TH GENMASK(30, 24) ++ ++#define MLXBF_L3C_PERF_CNT_CFG_2__STRM_SEL GENMASK(7, 0) ++#define MLXBF_L3C_PERF_CNT_CFG_2__STRM_MASK GENMASK(15, 8) ++ ++#define MLXBF_L3C_PERF_CNT_SEL__CNT_0 GENMASK(5, 0) ++#define MLXBF_L3C_PERF_CNT_SEL__CNT_1 GENMASK(13, 8) ++#define MLXBF_L3C_PERF_CNT_SEL__CNT_2 GENMASK(21, 16) ++#define MLXBF_L3C_PERF_CNT_SEL__CNT_3 GENMASK(29, 24) ++ ++#define MLXBF_L3C_PERF_CNT_SEL_1__CNT_4 GENMASK(5, 0) ++ ++#define MLXBF_L3C_PERF_CNT_LOW__VAL GENMASK(31, 0) ++#define MLXBF_L3C_PERF_CNT_HIGH__VAL GENMASK(24, 0) ++ ++struct mlxbf_pmc_events { ++ uint32_t evt_num; ++ char *evt_name; ++}; ++ ++struct mlxbf_pmc_events mlxbf_pcie_events[] = { ++{0x0, "IN_P_PKT_CNT"}, ++{0x10, "IN_NP_PKT_CNT"}, ++{0x18, "IN_C_PKT_CNT"}, ++{0x20, "OUT_P_PKT_CNT"}, ++{0x28, "OUT_NP_PKT_CNT"}, ++{0x30, "OUT_C_PKT_CNT"}, ++{0x38, "IN_P_BYTE_CNT"}, ++{0x40, "IN_NP_BYTE_CNT"}, ++{0x48, "IN_C_BYTE_CNT"}, ++{0x50, "OUT_P_BYTE_CNT"}, ++{0x58, "OUT_NP_BYTE_CNT"}, ++{0x60, "OUT_C_BYTE_CNT"}, ++{-1, NULL} ++}; ++ ++struct mlxbf_pmc_events mlxbf_smgen_events[] = { ++{0x0, "AW_REQ"}, ++{0x1, "AW_BEATS"}, ++{0x2, "AW_TRANS"}, ++{0x3, "AW_RESP"}, ++{0x4, "AW_STL"}, ++{0x5, "AW_LAT"}, ++{0x6, "AW_REQ_TBU"}, ++{0x8, "AR_REQ"}, ++{0x9, "AR_BEATS"}, ++{0xa, "AR_TRANS"}, ++{0xb, "AR_STL"}, ++{0xc, "AR_LAT"}, ++{0xd, "AR_REQ_TBU"}, ++{0xe, "TBU_MISS"}, ++{0xf, "TX_DAT_AF"}, ++{0x10, "RX_DAT_AF"}, ++{0x11, "RETRYQ_CRED"}, ++{-1, NULL} ++}; ++ ++struct mlxbf_pmc_events mlxbf1_trio_events[] = { ++{0xa0, "TPIO_DATA_BEAT"}, ++{0xa1, "TDMA_DATA_BEAT"}, ++{0xa2, "MAP_DATA_BEAT"}, ++{0xa3, "TXMSG_DATA_BEAT"}, ++{0xa4, "TPIO_DATA_PACKET"}, ++{0xa5, "TDMA_DATA_PACKET"}, ++{0xa6, "MAP_DATA_PACKET"}, ++{0xa7, "TXMSG_DATA_PACKET"}, ++{0xa8, "TDMA_RT_AF"}, ++{0xa9, "TDMA_PBUF_MAC_AF"}, ++{0xaa, "TRIO_MAP_WRQ_BUF_EMPTY"}, ++{0xab, "TRIO_MAP_CPL_BUF_EMPTY"}, ++{0xac, "TRIO_MAP_RDQ0_BUF_EMPTY"}, ++{0xad, "TRIO_MAP_RDQ1_BUF_EMPTY"}, ++{0xae, "TRIO_MAP_RDQ2_BUF_EMPTY"}, ++{0xaf, "TRIO_MAP_RDQ3_BUF_EMPTY"}, ++{0xb0, "TRIO_MAP_RDQ4_BUF_EMPTY"}, ++{0xb1, "TRIO_MAP_RDQ5_BUF_EMPTY"}, ++{0xb2, "TRIO_MAP_RDQ6_BUF_EMPTY"}, ++{0xb3, "TRIO_MAP_RDQ7_BUF_EMPTY"}, ++{-1, NULL} ++}; ++ ++struct mlxbf_pmc_events mlxbf2_trio_events[] = { ++{0xa0, "TPIO_DATA_BEAT"}, ++{0xa1, "TDMA_DATA_BEAT"}, ++{0xa2, "MAP_DATA_BEAT"}, ++{0xa3, "TXMSG_DATA_BEAT"}, ++{0xa4, "TPIO_DATA_PACKET"}, ++{0xa5, "TDMA_DATA_PACKET"}, ++{0xa6, "MAP_DATA_PACKET"}, ++{0xa7, "TXMSG_DATA_PACKET"}, ++{0xa8, "TDMA_RT_AF"}, ++{0xa9, "TDMA_PBUF_MAC_AF"}, ++{0xaa, "TRIO_MAP_WRQ_BUF_EMPTY"}, ++{0xab, "TRIO_MAP_CPL_BUF_EMPTY"}, ++{0xac, "TRIO_MAP_RDQ0_BUF_EMPTY"}, ++{0xad, "TRIO_MAP_RDQ1_BUF_EMPTY"}, ++{0xae, "TRIO_MAP_RDQ2_BUF_EMPTY"}, ++{0xaf, "TRIO_MAP_RDQ3_BUF_EMPTY"}, ++{0xb0, "TRIO_MAP_RDQ4_BUF_EMPTY"}, ++{0xb1, "TRIO_MAP_RDQ5_BUF_EMPTY"}, ++{0xb2, "TRIO_MAP_RDQ6_BUF_EMPTY"}, ++{0xb3, "TRIO_MAP_RDQ7_BUF_EMPTY"}, ++{0xb4, "TRIO_RING_TX_FLIT_CH0"}, ++{0xb5, "TRIO_RING_TX_FLIT_CH1"}, ++{0xb6, "TRIO_RING_TX_FLIT_CH2"}, ++{0xb7, "TRIO_RING_TX_FLIT_CH3"}, ++{0xb8, "TRIO_RING_TX_FLIT_CH4"}, ++{0xb9, "TRIO_RING_RX_FLIT_CH0"}, ++{0xba, "TRIO_RING_RX_FLIT_CH1"}, ++{0xbb, "TRIO_RING_RX_FLIT_CH2"}, ++{0xbc, "TRIO_RING_RX_FLIT_CH3"}, ++{-1, NULL} ++}; ++ ++struct mlxbf_pmc_events mlxbf_ecc_events[] = { ++{0x100, "ECC_SINGLE_ERROR_CNT"}, ++{0x104, "ECC_DOUBLE_ERROR_CNT"}, ++{0x114, "SERR_INJ"}, ++{0x118, "DERR_INJ"}, ++{0x124, "ECC_SINGLE_ERROR_0"}, ++{0x164, "ECC_DOUBLE_ERROR_0"}, ++{0x340, "DRAM_ECC_COUNT"}, ++{0x344, "DRAM_ECC_INJECT"}, ++{0x348, "DRAM_ECC_ERROR",}, ++{-1, NULL} ++}; ++ ++struct mlxbf_pmc_events mlxbf_mss_events[] = { ++{0xc0, "RXREQ_MSS"}, ++{0xc1, "RXDAT_MSS"}, ++{0xc2, "TXRSP_MSS"}, ++{0xc3, "TXDAT_MSS"}, ++{-1, NULL} ++}; ++ ++struct mlxbf_pmc_events mlxbf_hnf_events[] = { ++{0x45, "HNF_REQUESTS"}, ++{0x46, "HNF_REJECTS"}, ++{0x47, "ALL_BUSY"}, ++{0x48, "MAF_BUSY"}, ++{0x49, "MAF_REQUESTS"}, ++{0x4a, "RNF_REQUESTS"}, ++{0x4b, "REQUEST_TYPE"}, ++{0x4c, "MEMORY_READS"}, ++{0x4d, "MEMORY_WRITES"}, ++{0x4e, "VICTIM_WRITE"}, ++{0x4f, "POC_FULL"}, ++{0x50, "POC_FAIL"}, ++{0x51, "POC_SUCCESS"}, ++{0x52, "POC_WRITES"}, ++{0x53, "POC_READS"}, ++{0x54, "FORWARD"}, ++{0x55, "RXREQ_HNF"}, ++{0x56, "RXRSP_HNF"}, ++{0x57, "RXDAT_HNF"}, ++{0x58, "TXREQ_HNF"}, ++{0x59, "TXRSP_HNF"}, ++{0x5a, "TXDAT_HNF"}, ++{0x5b, "TXSNP_HNF"}, ++{0x5c, "INDEX_MATCH"}, ++{0x5d, "A72_ACCESS"}, ++{0x5e, "IO_ACCESS"}, ++{0x5f, "TSO_WRITE"}, ++{0x60, "TSO_CONFLICT"}, ++{0x61, "DIR_HIT"}, ++{0x62, "HNF_ACCEPTS"}, ++{0x63, "REQ_BUF_EMPTY"}, ++{0x64, "REQ_BUF_IDLE_MAF"}, ++{0x65, "TSO_NOARB"}, ++{0x66, "TSO_NOARB_CYCLES"}, ++{0x67, "MSS_NO_CREDIT"}, ++{0x68, "TXDAT_NO_LCRD"}, ++{0x69, "TXSNP_NO_LCRD"}, ++{0x6a, "TXRSP_NO_LCRD"}, ++{0x6b, "TXREQ_NO_LCRD"}, ++{0x6c, "TSO_CL_MATCH"}, ++{0x6d, "MEMORY_READS_BYPASS"}, ++{0x6e, "TSO_NOARB_TIMEOUT"}, ++{0x6f, "ALLOCATE"}, ++{0x70, "VICTIM"}, ++{0x71, "A72_WRITE"}, ++{0x72, "A72_Read"}, ++{0x73, "IO_WRITE"}, ++{0x74, "IO_READ"}, ++{0x75, "TSO_REJECT"}, ++{0x80, "TXREQ_RN"}, ++{0x81, "TXRSP_RN"}, ++{0x82, "TXDAT_RN"}, ++{0x83, "RXSNP_RN"}, ++{0x84, "RXRSP_RN"}, ++{0x85, "RXDAT_RN"}, ++{-1, NULL} ++}; ++ ++struct mlxbf_pmc_events mlxbf2_hnfnet_events[] = { ++{0x12, "CDN_REQ"}, ++{0x13, "DDN_REQ"}, ++{0x14, "NDN_REQ"}, ++{0x15, "CDN_DIAG_N_OUT_OF_CRED"}, ++{0x16, "CDN_DIAG_S_OUT_OF_CRED"}, ++{0x17, "CDN_DIAG_E_OUT_OF_CRED"}, ++{0x18, "CDN_DIAG_W_OUT_OF_CRED"}, ++{0x19, "CDN_DIAG_C_OUT_OF_CRED"}, ++{0x1a, "CDN_DIAG_N_EGRESS"}, ++{0x1b, "CDN_DIAG_S_EGRESS"}, ++{0x1c, "CDN_DIAG_E_EGRESS"}, ++{0x1d, "CDN_DIAG_W_EGRESS"}, ++{0x1e, "CDN_DIAG_C_EGRESS"}, ++{0x1f, "CDN_DIAG_N_INGRESS"}, ++{0x20, "CDN_DIAG_S_INGRESS"}, ++{0x21, "CDN_DIAG_E_INGRESS"}, ++{0x22, "CDN_DIAG_W_INGRESS"}, ++{0x23, "CDN_DIAG_C_INGRESS"}, ++{0x24, "CDN_DIAG_CORE_SENT"}, ++{0x25, "DDN_DIAG_N_OUT_OF_CRED"}, ++{0x26, "DDN_DIAG_S_OUT_OF_CRED"}, ++{0x27, "DDN_DIAG_E_OUT_OF_CRED"}, ++{0x28, "DDN_DIAG_W_OUT_OF_CRED"}, ++{0x29, "DDN_DIAG_C_OUT_OF_CRED"}, ++{0x2a, "DDN_DIAG_N_EGRESS"}, ++{0x2b, "DDN_DIAG_S_EGRESS"}, ++{0x2c, "DDN_DIAG_E_EGRESS"}, ++{0x2d, "DDN_DIAG_W_EGRESS"}, ++{0x2e, "DDN_DIAG_C_EGRESS"}, ++{0x2f, "DDN_DIAG_N_INGRESS"}, ++{0x30, "DDN_DIAG_S_INGRESS"}, ++{0x31, "DDN_DIAG_E_INGRESS"}, ++{0x32, "DDN_DIAG_W_INGRESS"}, ++{0x33, "DDN_DIAG_C_INGRESS"}, ++{0x34, "DDN_DIAG_CORE_SENT"}, ++{0x35, "NDN_DIAG_S_OUT_OF_CRED"}, ++{0x36, "NDN_DIAG_S_OUT_OF_CRED"}, ++{0x37, "NDN_DIAG_E_OUT_OF_CRED"}, ++{0x38, "NDN_DIAG_W_OUT_OF_CRED"}, ++{0x39, "NDN_DIAG_C_OUT_OF_CRED"}, ++{0x3a, "NDN_DIAG_N_EGRESS"}, ++{0x3b, "NDN_DIAG_S_EGRESS"}, ++{0x3c, "NDN_DIAG_E_EGRESS"}, ++{0x3d, "NDN_DIAG_W_EGRESS"}, ++{0x3e, "NDN_DIAG_C_EGRESS"}, ++{0x3f, "NDN_DIAG_N_INGRESS"}, ++{0x40, "NDN_DIAG_S_INGRESS"}, ++{0x41, "NDN_DIAG_E_INGRESS"}, ++{0x42, "NDN_DIAG_W_INGRESS"}, ++{0x43, "NDN_DIAG_C_INGRESS"}, ++{0x44, "NDN_DIAG_CORE_SENT"}, ++{-1, NULL} ++}; ++ ++struct mlxbf_pmc_events mlxbf_l3cache_events[] = { ++{0x00, "DISABLE"}, ++{0x01, "CYCLES"}, ++{0x02, "TOTAL_RD_REQ_IN"}, ++{0x03, "TOTAL_WR_REQ_IN"}, ++{0x04, "TOTAL_WR_DBID_ACK"}, ++{0x05, "TOTAL_WR_DATA_IN"}, ++{0x06, "TOTAL_WR_COMP"}, ++{0x07, "TOTAL_RD_DATA_OUT"}, ++{0x08, "TOTAL_CDN_REQ_IN_BANK0"}, ++{0x09, "TOTAL_CDN_REQ_IN_BANK1"}, ++{0x0a, "TOTAL_DDN_REQ_IN_BANK0"}, ++{0x0b, "TOTAL_DDN_REQ_IN_BANK1"}, ++{0x0c, "TOTAL_EMEM_RD_RES_IN_BANK0"}, ++{0x0d, "TOTAL_EMEM_RD_RES_IN_BANK1"}, ++{0x0e, "TOTAL_CACHE_RD_RES_IN_BANK0"}, ++{0x0f, "TOTAL_CACHE_RD_RES_IN_BANK1"}, ++{0x10, "TOTAL_EMEM_RD_REQ_BANK0"}, ++{0x11, "TOTAL_EMEM_RD_REQ_BANK1"}, ++{0x12, "TOTAL_EMEM_WR_REQ_BANK0"}, ++{0x13, "TOTAL_EMEM_WR_REQ_BANK1"}, ++{0x14, "TOTAL_RD_REQ_OUT"}, ++{0x15, "TOTAL_WR_REQ_OUT"}, ++{0x16, "TOTAL_RD_RES_IN"}, ++{0x17, "HITS_BANK0"}, ++{0x18, "HITS_BANK1"}, ++{0x19, "MISSES_BANK0"}, ++{0x1a, "MISSES_BANK1"}, ++{0x1b, "ALLOCATIONS_BANK0"}, ++{0x1c, "ALLOCATIONS_BANK1"}, ++{0x1d, "EVICTIONS_BANK0"}, ++{0x1e, "EVICTIONS_BANK1"}, ++{0x1f, "DBID_REJECT"}, ++{0x20, "WRDB_REJECT_BANK0"}, ++{0x21, "WRDB_REJECT_BANK1"}, ++{0x22, "CMDQ_REJECT_BANK0"}, ++{0x23, "CMDQ_REJECT_BANK1"}, ++{0x24, "COB_REJECT_BANK0"}, ++{0x25, "COB_REJECT_BANK1"}, ++{0x26, "TRB_REJECT_BANK0"}, ++{0x27, "TRB_REJECT_BANK1"}, ++{0x28, "TAG_REJECT_BANK0"}, ++{0x29, "TAG_REJECT_BANK1"}, ++{0x2a, "ANY_REJECT_BANK0"}, ++{0x2b, "ANY_REJECT_BANK1"}, ++{-1, NULL} ++}; ++ ++#endif /* __MLXBF_PMC_H__ */ +-- +2.20.1 + diff --git a/patch/0216-UBUNTU-SAUCE-mlxbf_pmc-Fix-references-to-sprintf.patch b/patch/0216-UBUNTU-SAUCE-mlxbf_pmc-Fix-references-to-sprintf.patch new file mode 100644 index 000000000..8aa9cf291 --- /dev/null +++ b/patch/0216-UBUNTU-SAUCE-mlxbf_pmc-Fix-references-to-sprintf.patch @@ -0,0 +1,69 @@ +From 597a665f88fd16c595dd804c7567ccd5aab34ad9 Mon Sep 17 00:00:00 2001 +From: Jitendra Lanka +Date: Tue, 16 Aug 2022 16:18:39 -0400 +Subject: [PATCH backport 5.10 17/63] UBUNTU: SAUCE: mlxbf_pmc: Fix references + to sprintf + +BugLink: https://bugs.launchpad.net/bugs/1986849 + +Replace sprintf with snprintf with a defined upper boundary of +PAGE_SIZE for sysfs store/show functions and max array size defined +otherwise. + +Change-Id: If586302684d60a435abc9f5aaf28b08de9b2df16 +Signed-off-by: Jitendra Lanka +Signed-off-by: Ike Panhc +--- + drivers/platform/mellanox/mlxbf-pmc.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c +index a9debcdf9..3305d2a5d 100644 +--- a/drivers/platform/mellanox/mlxbf-pmc.c ++++ b/drivers/platform/mellanox/mlxbf-pmc.c +@@ -681,7 +681,7 @@ static ssize_t mlxbf_counter_read(struct kobject *ko, + } else + return -EINVAL; + +- return sprintf(buf, "0x%llx\n", value); ++ return snprintf(buf, PAGE_SIZE, "0x%llx\n", value); + } + + /* Store function for "counter" sysfs files */ +@@ -758,7 +758,7 @@ static ssize_t mlxbf_event_find(struct kobject *ko, + + evt_name = mlxbf_pmc_get_event_name((char *)ko->name, evt_num); + +- return sprintf(buf, "0x%llx: %s\n", evt_num, evt_name); ++ return snprintf(buf, PAGE_SIZE, "0x%llx: %s\n", evt_num, evt_name); + } + + /* Store function for "event" sysfs files */ +@@ -811,9 +811,12 @@ static ssize_t mlxbf_print_event_list(struct kobject *ko, + + buf[0] = '\0'; + while (events[i].evt_name != NULL) { +- size += sprintf(e_info, "%x: %s\n", events[i].evt_num, +- events[i].evt_name); +- if (size > PAGE_SIZE) ++ size += snprintf(e_info, ++ sizeof(e_info), ++ "%x: %s\n", ++ events[i].evt_num, ++ events[i].evt_name); ++ if (size >= PAGE_SIZE) + break; + strcat(buf, e_info); + ret = size; +@@ -840,7 +843,7 @@ static ssize_t mlxbf_show_counter_state(struct kobject *ko, + + value = FIELD_GET(MLXBF_L3C_PERF_CNT_CFG__EN, perfcnt_cfg); + +- return sprintf(buf, "%d\n", value); ++ return snprintf(buf, PAGE_SIZE, "%d\n", value); + } + + /* Store function for "enable" sysfs files - only for l3cache */ +-- +2.20.1 + diff --git a/patch/0217-UBUNTU-SAUCE-mlxbf-pmc-Fix-error-when-reading-unprog.patch b/patch/0217-UBUNTU-SAUCE-mlxbf-pmc-Fix-error-when-reading-unprog.patch new file mode 100644 index 000000000..3607501b5 --- /dev/null +++ b/patch/0217-UBUNTU-SAUCE-mlxbf-pmc-Fix-error-when-reading-unprog.patch @@ -0,0 +1,140 @@ +From f88fbeabee18fbd15de2e717fe45d9bf2c287468 Mon Sep 17 00:00:00 2001 +From: Shravan Kumar Ramani +Date: Fri, 9 Sep 2022 05:31:43 -0400 +Subject: [PATCH backport 5.10 18/63] UBUNTU: SAUCE: mlxbf-pmc: Fix error when + reading unprogrammed events + +BugLink: https://bugs.launchpad.net/bugs/1989172 + +Firstly, all events have a reset value of 0, which is not a valid +event as per the event_list for most blocks and hence seen as an +error. Add a "disable" event with event_number 0 for all blocks. +Second, the enable bit for each counter need not be checked before +reading the event info, and hence removed. + +Signed-off-by: Shravan Kumar Ramani +Signed-off-by: Ike Panhc +--- + drivers/platform/mellanox/mlxbf-pmc.c | 32 +++++---------------------- + drivers/platform/mellanox/mlxbf-pmc.h | 6 +++++ + 2 files changed, 12 insertions(+), 26 deletions(-) + +diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c +index 3305d2a5d..106acea8c 100644 +--- a/drivers/platform/mellanox/mlxbf-pmc.c ++++ b/drivers/platform/mellanox/mlxbf-pmc.c +@@ -19,7 +19,7 @@ + + #include "mlxbf-pmc.h" + +-#define DRIVER_VERSION 2.2 ++#define DRIVER_VERSION 2.3 + + static struct mlxbf_pmc_context *pmc; + +@@ -562,7 +562,7 @@ int mlxbf_read_event(int blk_num, uint32_t cnt_num, bool is_l3, + uint64_t *result) + { + uint32_t perfcfg_offset, perfval_offset; +- uint64_t perfmon_cfg, perfevt, perfctl; ++ uint64_t perfmon_cfg, perfevt; + + if (cnt_num >= pmc->block[blk_num].counters) + return -EINVAL; +@@ -573,26 +573,6 @@ int mlxbf_read_event(int blk_num, uint32_t cnt_num, bool is_l3, + perfcfg_offset = cnt_num * 8; + perfval_offset = perfcfg_offset + pmc->block[blk_num].counters * 8; + +- /* Set counter in "read" mode */ +- perfmon_cfg = 0; +- perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__ADDR, +- MLXBF_PERFCTL); +- perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__STROBE, 1); +- perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__WR_R_B, 0); +- +- if (mlxbf_pmc_writeq(perfmon_cfg, +- pmc->block[blk_num].mmio_base + perfcfg_offset)) +- return -EFAULT; +- +- /* Check if the counter is enabled */ +- +- if (mlxbf_pmc_readq(&perfctl, +- pmc->block[blk_num].mmio_base + perfval_offset)) +- return -EFAULT; +- +- if (FIELD_GET(MLXBF_GEN_PERFCTL__EN0, perfctl) == 0) +- return -EINVAL; +- + /* Set counter in "read" mode */ + perfmon_cfg = 0; + perfmon_cfg |= FIELD_PREP(MLXBF_GEN_PERFMON_CONFIG__ADDR, +@@ -812,10 +792,10 @@ static ssize_t mlxbf_print_event_list(struct kobject *ko, + buf[0] = '\0'; + while (events[i].evt_name != NULL) { + size += snprintf(e_info, +- sizeof(e_info), +- "%x: %s\n", +- events[i].evt_num, +- events[i].evt_name); ++ sizeof(e_info), ++ "%x: %s\n", ++ events[i].evt_num, ++ events[i].evt_name); + if (size >= PAGE_SIZE) + break; + strcat(buf, e_info); +diff --git a/drivers/platform/mellanox/mlxbf-pmc.h b/drivers/platform/mellanox/mlxbf-pmc.h +index b15614e90..894c3cc88 100644 +--- a/drivers/platform/mellanox/mlxbf-pmc.h ++++ b/drivers/platform/mellanox/mlxbf-pmc.h +@@ -186,6 +186,7 @@ struct mlxbf_pmc_events mlxbf_smgen_events[] = { + }; + + struct mlxbf_pmc_events mlxbf1_trio_events[] = { ++{0x00, "DISABLE"}, + {0xa0, "TPIO_DATA_BEAT"}, + {0xa1, "TDMA_DATA_BEAT"}, + {0xa2, "MAP_DATA_BEAT"}, +@@ -210,6 +211,7 @@ struct mlxbf_pmc_events mlxbf1_trio_events[] = { + }; + + struct mlxbf_pmc_events mlxbf2_trio_events[] = { ++{0x00, "DISABLE"}, + {0xa0, "TPIO_DATA_BEAT"}, + {0xa1, "TDMA_DATA_BEAT"}, + {0xa2, "MAP_DATA_BEAT"}, +@@ -243,6 +245,7 @@ struct mlxbf_pmc_events mlxbf2_trio_events[] = { + }; + + struct mlxbf_pmc_events mlxbf_ecc_events[] = { ++{0x00, "DISABLE"}, + {0x100, "ECC_SINGLE_ERROR_CNT"}, + {0x104, "ECC_DOUBLE_ERROR_CNT"}, + {0x114, "SERR_INJ"}, +@@ -256,6 +259,7 @@ struct mlxbf_pmc_events mlxbf_ecc_events[] = { + }; + + struct mlxbf_pmc_events mlxbf_mss_events[] = { ++{0x00, "DISABLE"}, + {0xc0, "RXREQ_MSS"}, + {0xc1, "RXDAT_MSS"}, + {0xc2, "TXRSP_MSS"}, +@@ -264,6 +268,7 @@ struct mlxbf_pmc_events mlxbf_mss_events[] = { + }; + + struct mlxbf_pmc_events mlxbf_hnf_events[] = { ++{0x00, "DISABLE"}, + {0x45, "HNF_REQUESTS"}, + {0x46, "HNF_REJECTS"}, + {0x47, "ALL_BUSY"}, +@@ -323,6 +328,7 @@ struct mlxbf_pmc_events mlxbf_hnf_events[] = { + }; + + struct mlxbf_pmc_events mlxbf2_hnfnet_events[] = { ++{0x00, "DISABLE"}, + {0x12, "CDN_REQ"}, + {0x13, "DDN_REQ"}, + {0x14, "NDN_REQ"}, +-- +2.20.1 + diff --git a/patch/0218-UBUNTU-SAUCE-platform-mellanox-Add-mlx-trio-driver.patch b/patch/0218-UBUNTU-SAUCE-platform-mellanox-Add-mlx-trio-driver.patch new file mode 100644 index 000000000..104c33198 --- /dev/null +++ b/patch/0218-UBUNTU-SAUCE-platform-mellanox-Add-mlx-trio-driver.patch @@ -0,0 +1,955 @@ +From 15bbb9ee03e015587b9bd704f36c85177fba563a Mon Sep 17 00:00:00 2001 +From: Shravan Kumar Ramani +Date: Tue, 5 Jul 2022 11:11:45 -0400 +Subject: [PATCH backport 5.10 19/63] UBUNTU: SAUCE: platform/mellanox: Add + mlx-trio driver + +BugLink: https://bugs.launchpad.net/bugs/1980754 + +The mlx-trio driver allows users to configure the TRIO PCIe root +complex of Mellanox BlueField SoCs to select an L3 cache profile. +It also handles TRIO IRQs and prints debug info. + +Signed-off-by: Shravan Kumar Ramani +Signed-off-by: Ike Panhc +--- + drivers/platform/mellanox/Kconfig | 7 + + drivers/platform/mellanox/Makefile | 1 + + drivers/platform/mellanox/mlx-trio.c | 651 ++++++++++++++++++++++++++ + drivers/platform/mellanox/trio_regs.h | 236 ++++++++++ + 4 files changed, 895 insertions(+) + create mode 100644 drivers/platform/mellanox/mlx-trio.c + create mode 100644 drivers/platform/mellanox/trio_regs.h + +diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig +index b0d2c3343..5d329350a 100644 +--- a/drivers/platform/mellanox/Kconfig ++++ b/drivers/platform/mellanox/Kconfig +@@ -90,6 +90,13 @@ config MLXBF_PMC + to performance monitoring counters within various blocks in the + Mellanox BlueField SoC via a sysfs interface. + ++config MLXBF_TRIO ++ tristate "Mellanox TRIO driver" ++ depends on ARM64 ++ help ++ This driver supports the TRIO PCIe root complex interface on ++ Mellanox BlueField SoCs. ++ + config NVSW_SN2201 + tristate "Nvidia SN2201 platform driver support" + depends on REGMAP +diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile +index ba56485cb..161fad566 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_MLXBF_TRIO) += mlx-trio.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/mlx-trio.c b/drivers/platform/mellanox/mlx-trio.c +new file mode 100644 +index 000000000..849006e9c +--- /dev/null ++++ b/drivers/platform/mellanox/mlx-trio.c +@@ -0,0 +1,651 @@ ++// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause ++/* ++ * TRIO driver for Mellanox BlueField SoC ++ * ++ * Copyright (c) 2018, Mellanox Technologies. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "trio_regs.h" ++ ++#define DRIVER_NAME "mlx-trio" ++#define DRIVER_VERSION "0.4" ++#define DRIVER_DESCRIPTION "Mellanox TRIO PCIe host controller driver" ++ ++/* SMC return codes */ ++#define SMCCC_ACCESS_VIOLATION (-4) ++ ++/* SMC function identifiers */ ++#define MLNX_WRITE_REG_64 (0x8200000B) ++#define MLNX_READ_REG_64 (0x8200000C) ++#define MLNX_SIP_SVC_UID (0x8200ff01) ++#define MLNX_SIP_SVC_VERSION (0x8200ff03) ++ ++#define MLNX_TRIO_SVC_REQ_MAJOR 0 ++#define MLNX_TRIO_SVC_MIN_MINOR 4 ++ ++#define TRIO_NUM_IRQS 17 ++#define L3_PROFILE_NUM (L3C_PROF_RD_MISS__LENGTH / L3C_PROF_RD_MISS__STRIDE) ++ ++/* The PUSH_DMA_EVT_CTR wrapped. */ ++#define TRIO_PUSH_DMA_EVT_CTR_INT_BIT 10 ++ ++/* The MAP_EVT_CTR wrapped. */ ++#define TRIO_MAP_EVT_CTR_INT_BIT 11 ++ ++enum trio_int_events { ++ TRIO_MAC_INT = 0, ++ TRIO_RSH_FULL_ERR_INT, ++ TRIO_MSG_Q_FULL_ERR_INT, ++ TRIO_MSG_Q_ARRIVED_INT, ++ TRIO_MMIO_ERR_INT, ++ TRIO_MAP_UNCLAIMED_INT, ++ TRIO_RSH_SIZE_ERR_INT, ++ TRIO_PIO_ECAM_ERR_INT, ++ TRIO_PIO_CPL_ERR_INT, ++ TRIO_MMIO_PROT_ERR_INT, ++ TRIO_PUSH_DMA_EVT_CTR_INT, ++ TRIO_MAP_EVT_CTR_INT, ++ TRIO_PIO_DISABLED_INT, ++ TRIO_REM_MMIO_ERR_INT, ++ TRIO_ERR_MSG_COR_INT, ++ TRIO_ERR_MSG_NONFATAL_INT, ++ TRIO_ERR_MSG_FATAL_INT, ++}; ++ ++struct trio_event_info { ++ const char *name; ++ int additional_info; ++}; ++ ++static const struct trio_event_info trio_events[TRIO_NUM_IRQS] = { ++ [TRIO_MAC_INT] = { ++ .name = "MAC Interrupt", ++ .additional_info = -1, ++ }, ++ [TRIO_RSH_FULL_ERR_INT] = { ++ .name = "RShim Full Error", ++ .additional_info = -1, ++ }, ++ [TRIO_MSG_Q_FULL_ERR_INT] = { ++ .name = "Msg Queue Full Error", ++ .additional_info = -1, ++ }, ++ [TRIO_MSG_Q_ARRIVED_INT] = { ++ .name = "Msg Arrived Interrupt", ++ .additional_info = -1, ++ }, ++ [TRIO_MMIO_ERR_INT] = { ++ .name = "MMIO Error", ++ .additional_info = TRIO_MMIO_ERROR_INFO, ++ }, ++ [TRIO_MAP_UNCLAIMED_INT] = { ++ .name = "Packet Unclaimed Error", ++ .additional_info = TRIO_MAP_ERR_STS, ++ }, ++ [TRIO_RSH_SIZE_ERR_INT] = { ++ .name = "RShim Size Error", ++ .additional_info = -1, ++ }, ++ [TRIO_PIO_ECAM_ERR_INT] = { ++ .name = "PIO ECAM Error", ++ .additional_info = -1, ++ }, ++ [TRIO_PIO_CPL_ERR_INT] = { ++ .name = "PIO Completion Error", ++ .additional_info = TRIO_TILE_PIO_CPL_ERR_STS, ++ }, ++ [TRIO_MMIO_PROT_ERR_INT] = { ++ .name = "MMIO Protection level Violation", ++ .additional_info = -1, ++ }, ++ [TRIO_PUSH_DMA_EVT_CTR_INT] = { ++ .name = "PUSH_DMA_CTR wrapped", ++ .additional_info = -1, ++ }, ++ [TRIO_MAP_EVT_CTR_INT] = { ++ .name = "MAP_EVT_CTR wrapped", ++ .additional_info = -1, ++ }, ++ [TRIO_PIO_DISABLED_INT] = { ++ .name = "Access to disabled PIO region", ++ .additional_info = -1, ++ }, ++ [TRIO_REM_MMIO_ERR_INT] = { ++ .name = "Remote Buffer MMIO Error", ++ .additional_info = -1, ++ }, ++ [TRIO_ERR_MSG_COR_INT] = { ++ .name = "Correctable error message received", ++ .additional_info = -1, ++ }, ++ [TRIO_ERR_MSG_NONFATAL_INT] = { ++ .name = "Nonfatal error message received", ++ .additional_info = -1, ++ }, ++ [TRIO_ERR_MSG_FATAL_INT] = { ++ .name = "Fatal error message received", ++ .additional_info = -1, ++ }, ++}; ++ ++enum l3_profile_type { ++ LRU_PROFILE = 0, /* 0 is the default behavior. */ ++ NVME_PROFILE, ++ L3_PROFILE_TYPE_NUM, ++}; ++ ++static const char *l3_profiles[L3_PROFILE_TYPE_NUM] = { ++ [LRU_PROFILE] = "Strict_LRU", ++ [NVME_PROFILE] = "NVMeOF_suitable" ++}; ++ ++/* ++ * The default profile each L3 profile would get. ++ * The current setting would make profile 1 the NVMe suitable profile ++ * and the rest of the profiles LRU profile. ++ * Note that profile 0 should be configured as LRU as this is the ++ * default profile. ++ */ ++static const enum l3_profile_type default_profile[L3_PROFILE_NUM] = { ++ [1] = NVME_PROFILE, ++}; ++ ++struct event_context { ++ int event_num; ++ int irq; ++ struct trio_context *trio; ++}; ++ ++struct trio_context { ++ /* The kernel structure representing the device. */ ++ struct platform_device *pdev; ++ ++ /* Argument to be passed back to the IRQ handler */ ++ struct event_context *events; ++ ++ /* ++ * Reg base addr, will be memmapped if sreg_use_smcs is false. ++ * Otherwise, this is a physical address. ++ */ ++ void __iomem *mmio_base; ++ ++ int trio_index; ++ ++ /* Name of the bus this TRIO corresponds to */ ++ const char *bus; ++ ++ /* The PCI device this TRIO corresponds to */ ++ struct pci_dev *trio_pci; ++ ++ /* Number of platform_irqs for this device */ ++ uint32_t num_irqs; ++ ++ /* Access regs with smcs if true */ ++ bool sreg_use_smcs; ++ ++ /* verification table for trio */ ++ uint32_t sreg_trio_tbl; ++}; ++ ++static int secure_writeq(struct trio_context *trio, uint64_t value, ++ void __iomem *addr) ++{ ++ struct arm_smccc_res res; ++ int status; ++ ++ arm_smccc_smc(MLNX_WRITE_REG_64, trio->sreg_trio_tbl, value, ++ (uintptr_t) addr, 0, 0, 0, 0, &res); ++ ++ status = res.a0; ++ ++ switch (status) { ++ /* ++ * Note: PSCI_RET_NOT_SUPPORTED is used here to maintain compatibility ++ * with older kernels that do not have SMCCC_RET_NOT_SUPPORTED ++ */ ++ case PSCI_RET_NOT_SUPPORTED: ++ dev_err(&trio->pdev->dev, ++ "%s: required SMC unsupported\n", ++ __func__); ++ return -1; ++ case SMCCC_ACCESS_VIOLATION: ++ dev_err(&trio->pdev->dev, ++ "%s: could not access register at %px\n", ++ __func__, ++ addr); ++ return -1; ++ default: ++ return 0; ++ } ++} ++ ++static int trio_writeq(struct trio_context *trio, uint64_t value, ++ void __iomem *addr) ++{ ++ if (trio->sreg_use_smcs) ++ return secure_writeq(trio, value, addr); ++ else { ++ writeq(value, addr); ++ return 0; ++ } ++} ++ ++static int secure_readq(struct trio_context *trio, void __iomem *addr, ++ uint64_t *result) ++{ ++ struct arm_smccc_res res; ++ int status; ++ ++ arm_smccc_smc(MLNX_READ_REG_64, trio->sreg_trio_tbl, (uintptr_t) addr, ++ 0, 0, 0, 0, 0, &res); ++ ++ status = res.a0; ++ ++ switch (status) { ++ /* ++ * Note: PSCI_RET_NOT_SUPPORTED is used here to maintain compatibility ++ * with older kernels that do not have SMCCC_RET_NOT_SUPPORTED ++ */ ++ case PSCI_RET_NOT_SUPPORTED: ++ dev_err(&trio->pdev->dev, ++ "%s: required SMC unsupported\n", __func__); ++ return -1; ++ case SMCCC_ACCESS_VIOLATION: ++ dev_err(&trio->pdev->dev, ++ "%s: could not read register %px\n", ++ __func__, ++ addr); ++ return -1; ++ default: ++ *result = (uint64_t)res.a1; ++ return 0; ++ } ++} ++ ++static int trio_readq(struct trio_context *trio, void __iomem *addr, ++ uint64_t *result) ++{ ++ if (trio->sreg_use_smcs) ++ return secure_readq(trio, addr, result); ++ else { ++ *result = readq(addr); ++ return 0; ++ } ++} ++ ++static irqreturn_t trio_irq_handler(int irq, void *arg) ++{ ++ struct event_context *ctx = (struct event_context *)arg; ++ struct trio_context *trio = ctx->trio; ++ ++ pr_debug("mlx_trio: TRIO %d received IRQ %d event %d (%s)\n", ++ trio->trio_index, irq, ctx->event_num, ++ trio_events[ctx->event_num].name); ++ ++ if (trio_events[ctx->event_num].additional_info != -1) { ++ uint64_t info; ++ trio_readq(trio, trio->mmio_base + ++ trio_events[ctx->event_num].additional_info, ++ &info); ++ pr_debug("mlx_trio: Addition IRQ info: %llx\n", info); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static ssize_t current_profile_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ int profile_num; ++ struct trio_context *trio; ++ struct platform_device *pdev; ++ ++ TRIO_DEV_CTL_t tdc; ++ ++ pdev = to_platform_device(dev); ++ trio = platform_get_drvdata(pdev); ++ ++ if (trio_readq(trio, trio->mmio_base + TRIO_DEV_CTL, &tdc.word)) { ++ return -EIO; ++ } ++ ++ if (tdc.l3_profile_ovd == 0) ++ profile_num = -1; ++ else ++ profile_num = tdc.l3_profile_val; ++ ++ return sprintf(buf, "%d\n", profile_num); ++} ++ ++static int set_l3cache_profile(struct trio_context *trio, long profile_num) ++{ ++ TRIO_DEV_CTL_t tdc; ++ ++ if (trio_readq(trio, trio->mmio_base + TRIO_DEV_CTL, &tdc.word)) { ++ return -EIO; ++ } ++ ++ if (profile_num == -1) { ++ dev_info(&trio->pdev->dev, "Unlink %s profile\n", trio->bus); ++ ++ tdc.l3_profile_ovd = 0; ++ } else if (profile_num < L3_PROFILE_NUM && profile_num >= 0) { ++ dev_info(&trio->pdev->dev, "Change %s to profile %ld\n", ++ trio->bus, profile_num); ++ ++ tdc.l3_profile_ovd = 1; ++ tdc.l3_profile_val = profile_num; ++ } else { ++ dev_err(&trio->pdev->dev, "Profile number out of range."); ++ return -EINVAL; ++ } ++ ++ if (trio_writeq(trio, tdc.word, trio->mmio_base + TRIO_DEV_CTL)) { ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static ssize_t current_profile_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int err; ++ long profile_num; ++ struct trio_context *trio; ++ struct platform_device *pdev; ++ ++ pdev = container_of(dev, struct platform_device, dev); ++ trio = platform_get_drvdata(pdev); ++ ++ err = kstrtol(buf, 10, &profile_num); ++ if (err) ++ return err; ++ ++ err = set_l3cache_profile(trio, profile_num); ++ if (err) ++ return err; ++ ++ return count; ++} ++ ++static DEVICE_ATTR_RW(current_profile); ++ ++static ssize_t available_profiles_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ int i; ++ ssize_t line_size; ++ ssize_t len = 0; ++ ++ for (i = 0; i < L3_PROFILE_NUM; i++) { ++ line_size = sprintf(buf, "%d %s\n", i, ++ l3_profiles[default_profile[i]]); ++ buf += line_size; ++ len += line_size; ++ } ++ return len; ++} ++ ++static DEVICE_ATTR_RO(available_profiles); ++ ++static int trio_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct trio_context *trio; ++ int i, j, ret, irq; ++ int trio_bus, trio_device, trio_function; ++ struct resource *res; ++ struct arm_smccc_res smc_res; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_warn(dev, "%s: failed to find reg resource 0\n", __func__); ++ return -ENODEV; ++ } ++ ++ trio = kzalloc(sizeof(struct trio_context), GFP_KERNEL); ++ if (!trio) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, trio); ++ trio->pdev = pdev; ++ ++ /* Determine whether to use SMCs or not. */ ++ if (device_property_read_u32(&pdev->dev, "sec_reg_block", ++ &trio->sreg_trio_tbl)) { ++ trio->sreg_use_smcs = false; ++ } else { ++ /* ++ * Ensure we have the UUID we expect for the Mellanox service. ++ */ ++ arm_smccc_smc(MLNX_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &smc_res); ++ if (smc_res.a0 != 0x89c036b4 || smc_res.a1 != 0x11e6e7d7 || ++ smc_res.a2 != 0x1a009787 || smc_res.a3 != 0xc4bf00ca) { ++ dev_err(&pdev->dev, ++ "Mellanox SMC service not available\n"); ++ return -EINVAL; ++ } ++ ++ /* ++ * Check service version to see if we actually do support the ++ * needed SMCs. If we have the calls we need, mark support for ++ * them in the trio struct. ++ */ ++ arm_smccc_smc(MLNX_SIP_SVC_VERSION, 0, 0, 0, 0, 0, 0, 0, ++ &smc_res); ++ if (smc_res.a0 == MLNX_TRIO_SVC_REQ_MAJOR && ++ smc_res.a1 >= MLNX_TRIO_SVC_MIN_MINOR) { ++ trio->sreg_use_smcs = true; ++ } else { ++ dev_err(&pdev->dev, ++ "Required SMCs are not supported.\n"); ++ ++ return -EINVAL; ++ } ++ } ++ ++ if (device_property_read_string(dev, "bus_number", &trio->bus)) { ++ dev_warn(dev, "%s: failed to retrieve Trio bus name\n", ++ __func__); ++ ret = -ENODEV; ++ goto err; ++ } ++ ++ if (device_property_read_u32(dev, "num_irqs", &trio->num_irqs)) ++ trio->num_irqs = TRIO_NUM_IRQS; ++ trio->events = kzalloc(sizeof(struct event_context) * trio->num_irqs, ++ GFP_KERNEL); ++ if (!trio->events) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ /* Map registers */ ++ if (!trio->sreg_use_smcs) { ++ trio->mmio_base = devm_ioremap_resource(&pdev->dev, res); ++ ++ if (IS_ERR(trio->mmio_base)) { ++ dev_warn(dev, "%s: ioremap failed for mmio_base %llx err %p\n", ++ __func__, res->start, trio->mmio_base); ++ ret = PTR_ERR(trio->mmio_base); ++ goto err; ++ } ++ } else ++ trio->mmio_base = (void __iomem *) res->start; ++ ++ for (i = 0; i < trio->num_irqs; ++i) { ++ struct event_context *ctx = &trio->events[i]; ++ int dri_ret; ++ ++ switch (i) { ++ case TRIO_PUSH_DMA_EVT_CTR_INT_BIT: ++ case TRIO_MAP_EVT_CTR_INT_BIT: ++ /* ++ * These events are not errors, they just indicate ++ * that a performance counter wrapped. We may want ++ * the performance counter driver to register for them. ++ */ ++ continue; ++ default: ++ break; ++ } ++ ++ irq = platform_get_irq(pdev, i); ++ if (irq < 0) { ++ dev_warn(dev, "%s: failed to get plat irq %d ret %d\n", ++ __func__, i, irq); ++ for (j = i - 1; j >= 0; j--) { ++ ctx = &trio->events[j]; ++ devm_free_irq(&pdev->dev, ctx->irq, ctx); ++ } ++ ret = -ENXIO; ++ goto err; ++ } ++ ctx->event_num = i; ++ ctx->trio = trio; ++ ctx->irq = irq; ++ dri_ret = devm_request_irq(&pdev->dev, irq, trio_irq_handler, 0, ++ dev_name(dev), ctx); ++ ++ dev_dbg(dev, "%s: request_irq returns %d %d->%d\n", __func__, ++ dri_ret, i, irq); ++ } ++ ++ /* Create the L3 cache profile on this device */ ++ device_create_file(dev, &dev_attr_current_profile); ++ device_create_file(dev, &dev_attr_available_profiles); ++ ++ /* ++ * Get the corresponding PCI device this trio maps to. ++ * If the bus number can't be read properly, no symlinks are created. ++ */ ++ if (sscanf(trio->bus, "%d:%d.%d", &trio_bus, &trio_device, ++ &trio_function) != 3) { ++ dev_warn(dev, "Device [%s] not valid\n", trio->bus); ++ return 0; ++ } ++ ++ /* trio_device is also the index of the TRIO */ ++ trio->trio_index = trio_device; ++ ++ /* The PCI domain/segment would always be 0 here. */ ++ trio->trio_pci = ++ pci_get_domain_bus_and_slot(0, trio_bus, ++ (trio_device << 3) + trio_function); ++ ++ /* Add the symlink from the TRIO to the PCI device */ ++ if (trio->trio_pci != NULL) { ++ if (sysfs_create_link(&dev->kobj, &trio->trio_pci->dev.kobj, ++ "pcie_slot")) { ++ pci_dev_put(trio->trio_pci); ++ trio->trio_pci = NULL; ++ dev_warn(dev, "Failed to create symblink for %s\n", ++ trio->bus); ++ } ++ } else ++ dev_warn(dev, "Device %s not found\n", trio->bus); ++ ++ dev_info(dev, "v" DRIVER_VERSION " probed\n"); ++ return 0; ++err: ++ dev_warn(dev, "Error probing trio\n"); ++ if (trio->events) ++ kfree(trio->events); ++ kfree(trio); ++ platform_set_drvdata(pdev, NULL); ++ return ret; ++} ++ ++static int trio_remove(struct platform_device *pdev) ++{ ++ struct trio_context *trio = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ int i; ++ ++ for (i = 0; i < trio->num_irqs; ++i) { ++ struct event_context *ctx = &trio->events[i]; ++ ++ if (ctx->irq) ++ devm_free_irq(&pdev->dev, ctx->irq, ctx); ++ } ++ device_remove_file(dev, &dev_attr_current_profile); ++ device_remove_file(dev, &dev_attr_available_profiles); ++ ++ /* Delete the symlink and decrement the reference count. */ ++ if (trio->trio_pci != NULL) { ++ sysfs_remove_link(&dev->kobj, "pcie_slot"); ++ pci_dev_put(trio->trio_pci); ++ } ++ platform_set_drvdata(pdev, NULL); ++ kfree(trio->events); ++ kfree(trio); ++ ++ return 0; ++} ++ ++static const struct acpi_device_id trio_acpi_ids[] = { ++ {"MLNXBF06", 0}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(acpi, trio_acpi_ids); ++static struct platform_driver mlx_trio_driver = { ++ .driver = { ++ .name = DRIVER_NAME, ++ .acpi_match_table = ACPI_PTR(trio_acpi_ids), ++ }, ++ .probe = trio_probe, ++ .remove = trio_remove, ++}; ++ ++static int __init trio_init(void) ++{ ++ int ret; ++ ++ ret = platform_driver_register(&mlx_trio_driver); ++ if (ret) ++ pr_err("Failed to register trio driver.\n"); ++ ++ return ret; ++} ++ ++static void __exit trio_exit(void) ++{ ++ platform_driver_unregister(&mlx_trio_driver); ++} ++ ++module_init(trio_init); ++module_exit(trio_exit); ++ ++MODULE_DESCRIPTION(DRIVER_DESCRIPTION); ++MODULE_AUTHOR("Shravan Kumar Ramani "); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_VERSION(DRIVER_VERSION); +diff --git a/drivers/platform/mellanox/trio_regs.h b/drivers/platform/mellanox/trio_regs.h +new file mode 100644 +index 000000000..cc2f2003d +--- /dev/null ++++ b/drivers/platform/mellanox/trio_regs.h +@@ -0,0 +1,236 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (c) 2019, Mellanox Technologies. All rights reserved. ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++#ifndef __TRIO_REGS_H__ ++#define __TRIO_REGS_H__ ++ ++#ifdef __ASSEMBLER__ ++#define _64bit(x) x ++#else /* __ASSEMBLER__ */ ++#define _64bit(x) x ## ULL ++#endif /* __ASSEMBLER */ ++ ++#include ++ ++#define L3C_PROF_RD_MISS__FIRST_WORD 0x0600 ++#define L3C_PROF_RD_MISS__LAST_WORD 0x063c ++#define L3C_PROF_RD_MISS__LENGTH 0x0040 ++#define L3C_PROF_RD_MISS__STRIDE 0x0004 ++ ++#define L3C_PROF_RD_MISS__LOW_ORDER_SHIFT 0 ++#define L3C_PROF_RD_MISS__LOW_ORDER_WIDTH 5 ++#define L3C_PROF_RD_MISS__LOW_ORDER_RESET_VAL 11 ++#define L3C_PROF_RD_MISS__LOW_ORDER_RMASK 0x1f ++#define L3C_PROF_RD_MISS__LOW_ORDER_MASK 0x1f ++ ++#define L3C_PROF_RD_MISS__HIGH_ORDER_SHIFT 5 ++#define L3C_PROF_RD_MISS__HIGH_ORDER_WIDTH 5 ++#define L3C_PROF_RD_MISS__HIGH_ORDER_RESET_VAL 0 ++#define L3C_PROF_RD_MISS__HIGH_ORDER_RMASK 0x1f ++#define L3C_PROF_RD_MISS__HIGH_ORDER_MASK 0x3e0 ++ ++#define L3C_PROF_RD_MISS__ALLOC_STATE_SHIFT 12 ++#define L3C_PROF_RD_MISS__ALLOC_STATE_WIDTH 1 ++#define L3C_PROF_RD_MISS__ALLOC_STATE_RESET_VAL 0 ++#define L3C_PROF_RD_MISS__ALLOC_STATE_RMASK 0x1 ++#define L3C_PROF_RD_MISS__ALLOC_STATE_MASK 0x1000 ++ ++#define L3C_PROF_RD_MISS__LOW_STATE_BLK_ALLOC_SHIFT 13 ++#define L3C_PROF_RD_MISS__LOW_STATE_BLK_ALLOC_WIDTH 1 ++#define L3C_PROF_RD_MISS__LOW_STATE_BLK_ALLOC_RESET_VAL 0 ++#define L3C_PROF_RD_MISS__LOW_STATE_BLK_ALLOC_RMASK 0x1 ++#define L3C_PROF_RD_MISS__LOW_STATE_BLK_ALLOC_MASK 0x2000 ++ ++#define L3C_PROF_RD_MISS__HIGH_STATE_BLK_ALLOC_SHIFT 14 ++#define L3C_PROF_RD_MISS__HIGH_STATE_BLK_ALLOC_WIDTH 1 ++#define L3C_PROF_RD_MISS__HIGH_STATE_BLK_ALLOC_RESET_VAL 0 ++#define L3C_PROF_RD_MISS__HIGH_STATE_BLK_ALLOC_RMASK 0x1 ++#define L3C_PROF_RD_MISS__HIGH_STATE_BLK_ALLOC_MASK 0x4000 ++ ++#define L3C_PROF_RD_MISS__PROB_SHIFT 16 ++#define L3C_PROF_RD_MISS__PROB_WIDTH 16 ++#define L3C_PROF_RD_MISS__PROB_RESET_VAL 0 ++#define L3C_PROF_RD_MISS__PROB_RMASK 0xffff ++#define L3C_PROF_RD_MISS__PROB_MASK 0xffff0000 ++ ++#define TRIO_DEV_CTL 0x0008 ++#define TRIO_DEV_CTL__LENGTH 0x0001 ++ ++#define TRIO_DEV_CTL__NDN_ROUTE_ORDER_SHIFT 0 ++#define TRIO_DEV_CTL__NDN_ROUTE_ORDER_WIDTH 1 ++#define TRIO_DEV_CTL__NDN_ROUTE_ORDER_RESET_VAL 0 ++#define TRIO_DEV_CTL__NDN_ROUTE_ORDER_RMASK 0x1 ++#define TRIO_DEV_CTL__NDN_ROUTE_ORDER_MASK 0x1 ++ ++#define TRIO_DEV_CTL__CDN_ROUTE_ORDER_SHIFT 1 ++#define TRIO_DEV_CTL__CDN_ROUTE_ORDER_WIDTH 1 ++#define TRIO_DEV_CTL__CDN_ROUTE_ORDER_RESET_VAL 1 ++#define TRIO_DEV_CTL__CDN_ROUTE_ORDER_RMASK 0x1 ++#define TRIO_DEV_CTL__CDN_ROUTE_ORDER_MASK 0x2 ++ ++#define TRIO_DEV_CTL__DDN_ROUTE_ORDER_SHIFT 2 ++#define TRIO_DEV_CTL__DDN_ROUTE_ORDER_WIDTH 1 ++#define TRIO_DEV_CTL__DDN_ROUTE_ORDER_RESET_VAL 1 ++#define TRIO_DEV_CTL__DDN_ROUTE_ORDER_RMASK 0x1 ++#define TRIO_DEV_CTL__DDN_ROUTE_ORDER_MASK 0x4 ++ ++#define TRIO_DEV_CTL__DMA_RD_CA_ENA_SHIFT 3 ++#define TRIO_DEV_CTL__DMA_RD_CA_ENA_WIDTH 1 ++#define TRIO_DEV_CTL__DMA_RD_CA_ENA_RESET_VAL 1 ++#define TRIO_DEV_CTL__DMA_RD_CA_ENA_RMASK 0x1 ++#define TRIO_DEV_CTL__DMA_RD_CA_ENA_MASK 0x8 ++ ++#define TRIO_DEV_CTL__L3_PROFILE_OVD_SHIFT 4 ++#define TRIO_DEV_CTL__L3_PROFILE_OVD_WIDTH 1 ++#define TRIO_DEV_CTL__L3_PROFILE_OVD_RESET_VAL 0 ++#define TRIO_DEV_CTL__L3_PROFILE_OVD_RMASK 0x1 ++#define TRIO_DEV_CTL__L3_PROFILE_OVD_MASK 0x10 ++ ++#define TRIO_DEV_CTL__L3_PROFILE_VAL_SHIFT 5 ++#define TRIO_DEV_CTL__L3_PROFILE_VAL_WIDTH 4 ++#define TRIO_DEV_CTL__L3_PROFILE_VAL_RESET_VAL 0 ++#define TRIO_DEV_CTL__L3_PROFILE_VAL_RMASK 0xf ++#define TRIO_DEV_CTL__L3_PROFILE_VAL_MASK 0x1e0 ++ ++#define TRIO_DEV_CTL__WR_SLVERR_MAP_SHIFT 9 ++#define TRIO_DEV_CTL__WR_SLVERR_MAP_WIDTH 2 ++#define TRIO_DEV_CTL__WR_SLVERR_MAP_RESET_VAL 2 ++#define TRIO_DEV_CTL__WR_SLVERR_MAP_RMASK 0x3 ++#define TRIO_DEV_CTL__WR_SLVERR_MAP_MASK 0x600 ++#define TRIO_DEV_CTL__WR_SLVERR_MAP_VAL_OKAY 0x0 ++#define TRIO_DEV_CTL__WR_SLVERR_MAP_VAL_DATAERROR 0x2 ++#define TRIO_DEV_CTL__WR_SLVERR_MAP_VAL_NONDATAERROR 0x3 ++ ++#define TRIO_DEV_CTL__WR_DECERR_MAP_SHIFT 11 ++#define TRIO_DEV_CTL__WR_DECERR_MAP_WIDTH 2 ++#define TRIO_DEV_CTL__WR_DECERR_MAP_RESET_VAL 3 ++#define TRIO_DEV_CTL__WR_DECERR_MAP_RMASK 0x3 ++#define TRIO_DEV_CTL__WR_DECERR_MAP_MASK 0x1800 ++#define TRIO_DEV_CTL__WR_DECERR_MAP_VAL_OKAY 0x0 ++#define TRIO_DEV_CTL__WR_DECERR_MAP_VAL_DATAERROR 0x2 ++#define TRIO_DEV_CTL__WR_DECERR_MAP_VAL_NONDATAERROR 0x3 ++ ++#define TRIO_DEV_CTL__RD_SLVERR_MAP_SHIFT 13 ++#define TRIO_DEV_CTL__RD_SLVERR_MAP_WIDTH 2 ++#define TRIO_DEV_CTL__RD_SLVERR_MAP_RESET_VAL 2 ++#define TRIO_DEV_CTL__RD_SLVERR_MAP_RMASK 0x3 ++#define TRIO_DEV_CTL__RD_SLVERR_MAP_MASK 0x6000 ++#define TRIO_DEV_CTL__RD_SLVERR_MAP_VAL_OKAY 0x0 ++#define TRIO_DEV_CTL__RD_SLVERR_MAP_VAL_DATAERROR 0x2 ++#define TRIO_DEV_CTL__RD_SLVERR_MAP_VAL_NONDATAERROR 0x3 ++ ++#define TRIO_DEV_CTL__RD_DECERR_MAP_SHIFT 15 ++#define TRIO_DEV_CTL__RD_DECERR_MAP_WIDTH 2 ++#define TRIO_DEV_CTL__RD_DECERR_MAP_RESET_VAL 3 ++#define TRIO_DEV_CTL__RD_DECERR_MAP_RMASK 0x3 ++#define TRIO_DEV_CTL__RD_DECERR_MAP_MASK 0x18000 ++#define TRIO_DEV_CTL__RD_DECERR_MAP_VAL_OKAY 0x0 ++#define TRIO_DEV_CTL__RD_DECERR_MAP_VAL_DATAERROR 0x2 ++#define TRIO_DEV_CTL__RD_DECERR_MAP_VAL_NONDATAERROR 0x3 ++ ++#define TRIO_DEV_CTL__CDN_REQ_BUF_ENA_SHIFT 17 ++#define TRIO_DEV_CTL__CDN_REQ_BUF_ENA_WIDTH 1 ++#define TRIO_DEV_CTL__CDN_REQ_BUF_ENA_RESET_VAL 1 ++#define TRIO_DEV_CTL__CDN_REQ_BUF_ENA_RMASK 0x1 ++#define TRIO_DEV_CTL__CDN_REQ_BUF_ENA_MASK 0x20000 ++ ++#define TRIO_DEV_CTL__DMA_WRQ_HWM_SHIFT 20 ++#define TRIO_DEV_CTL__DMA_WRQ_HWM_WIDTH 8 ++#define TRIO_DEV_CTL__DMA_WRQ_HWM_RESET_VAL 255 ++#define TRIO_DEV_CTL__DMA_WRQ_HWM_RMASK 0xff ++#define TRIO_DEV_CTL__DMA_WRQ_HWM_MASK 0xff00000 ++ ++#define TRIO_DEV_CTL__GTHR_DELAY_ADJ_SHIFT 28 ++#define TRIO_DEV_CTL__GTHR_DELAY_ADJ_WIDTH 4 ++#define TRIO_DEV_CTL__GTHR_DELAY_ADJ_RESET_VAL 0 ++#define TRIO_DEV_CTL__GTHR_DELAY_ADJ_RMASK 0xf ++#define TRIO_DEV_CTL__GTHR_DELAY_ADJ_MASK 0xf0000000 ++ ++#ifndef __ASSEMBLER__ ++__extension__ ++typedef union { ++ struct { ++ /* ++ * When 1, packets sent on the NDN will be routed x-first. ++ * When 0, packets will be routed y-first. This setting must ++ * match the setting in the Tiles. Devices may have ++ * additional interfaces with customized route-order settings ++ * used in addition to or instead of this field. ++ */ ++ u64 ndn_route_order : 1; ++ /* ++ * When 1, packets sent on the CDN will be routed x-first. ++ * When 0, packets will be routed y-first. This setting must ++ * match the setting in the Tiles. Devices may have ++ * additional interfaces with customized route-order settings ++ * used in addition to or instead of this field. ++ */ ++ u64 cdn_route_order : 1; ++ /* ++ * When 1, packets sent on the DDN will be routed x-first. ++ * When 0, packets will be routed y-first. This setting must ++ * match the setting in the Tiles. Devices may have ++ * additional interfaces with customized route-order settings ++ * used in addition to or instead of this field. ++ */ ++ u64 ddn_route_order : 1; ++ /* ++ * When 1, the ExpCompAck flow will be used on DMA reads ++ * which allows read-data-bypass for lower latency. Must only ++ * be changed if no DMA read traffic is inflight. ++ */ ++ u64 dma_rd_ca_ena : 1; ++ /* ++ * For devices with DMA. When 1, the L3 cache profile will be ++ * forced to L3_PROFILE_VAL. When 0, the L3 profile is ++ * selected by the device. ++ */ ++ u64 l3_profile_ovd : 1; ++ /* ++ * For devices with DMA. L3 cache profile to be used when ++ * L3_PROFILE_OVD is 1. ++ */ ++ u64 l3_profile_val : 4; ++ /* Write response mapping for MMIO slave errors */ ++ u64 wr_slverr_map : 2; ++ /* Write response mapping for MMIO decode errors */ ++ u64 wr_decerr_map : 2; ++ /* Read response mapping for MMIO slave errors */ ++ u64 rd_slverr_map : 2; ++ /* Read response mapping for MMIO decode errors */ ++ u64 rd_decerr_map : 2; ++ /* ++ * When 1, the CDN sync FIFO is allowed to back pressure ++ * until full to avoid retries and improve performance ++ */ ++ u64 cdn_req_buf_ena : 1; ++ /* Reserved. */ ++ u64 __reserved_0 : 2; ++ /* ++ * For diagnostics only. Block new traffic when WRQ_INFL ++ * count exceeds this threshold. This register field does not ++ * exist in the PKA or Tile or MSS. ++ */ ++ u64 dma_wrq_hwm : 8; ++ /* For diagnostics only. Adjust packet gather delay on RNF */ ++ u64 gthr_delay_adj : 4; ++ /* Reserved. */ ++ u64 __reserved_1 : 32; ++ }; ++ ++ u64 word; ++} TRIO_DEV_CTL_t; ++#endif /* !defined(__ASSEMBLER__) */ ++ ++#define TRIO_MMIO_ERROR_INFO 0x0608 ++ ++#define TRIO_MAP_ERR_STS 0x0810 ++ ++#define TRIO_TILE_PIO_CPL_ERR_STS 0x09f0 ++ ++#endif /* !defined(__TRIO_REGS_H__) */ +-- +2.20.1 + diff --git a/patch/0219-UBUNTU-SAUCE-platform-mellanox-mlxbf-tmfifo-Add-Blue.patch b/patch/0219-UBUNTU-SAUCE-platform-mellanox-mlxbf-tmfifo-Add-Blue.patch new file mode 100644 index 000000000..2ca8f8617 --- /dev/null +++ b/patch/0219-UBUNTU-SAUCE-platform-mellanox-mlxbf-tmfifo-Add-Blue.patch @@ -0,0 +1,245 @@ +From 9a21e6cf3c87954516a7933539fbcb5b373f9fa2 Mon Sep 17 00:00:00 2001 +From: Liming Sun +Date: Sun, 26 Jun 2022 01:10:07 -0400 +Subject: [PATCH backport 5.10 20/63] UBUNTU: SAUCE: platform/mellanox: + mlxbf-tmfifo: Add BlueField-3 support + +BugLink: https://launchpad.net/bugs/1980847 + +This commit adds BlueField-3 support which has different resource +mapping and is identified by the ACPI UID. + +Signed-off-by: Liming Sun +Change-Id: I104472a89741c1083168bacb4a7652c7767cceff +Signed-off-by: Ike Panhc +--- + drivers/platform/mellanox/mlxbf-tmfifo-regs.h | 10 +++ + drivers/platform/mellanox/mlxbf-tmfifo.c | 82 ++++++++++++++----- + 2 files changed, 70 insertions(+), 22 deletions(-) + +diff --git a/drivers/platform/mellanox/mlxbf-tmfifo-regs.h b/drivers/platform/mellanox/mlxbf-tmfifo-regs.h +index e4f0d2eda..1358dad0c 100644 +--- a/drivers/platform/mellanox/mlxbf-tmfifo-regs.h ++++ b/drivers/platform/mellanox/mlxbf-tmfifo-regs.h +@@ -60,4 +60,14 @@ + #define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_RMASK GENMASK_ULL(8, 0) + #define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK GENMASK_ULL(40, 32) + ++/* BF3 resource 0 register offset. */ ++#define MLXBF_TMFIFO_RX_DATA_BF3 0x0000 ++#define MLXBF_TMFIFO_TX_DATA_BF3 0x1000 ++ ++/* BF3 resource 1 register offset. */ ++#define MLXBF_TMFIFO_RX_STS_BF3 0x0000 ++#define MLXBF_TMFIFO_RX_CTL_BF3 0x0008 ++#define MLXBF_TMFIFO_TX_STS_BF3 0x0100 ++#define MLXBF_TMFIFO_TX_CTL_BF3 0x0108 ++ + #endif /* !defined(__MLXBF_TMFIFO_REGS_H__) */ +diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c +index 38800e86e..f401bbbd0 100644 +--- a/drivers/platform/mellanox/mlxbf-tmfifo.c ++++ b/drivers/platform/mellanox/mlxbf-tmfifo.c +@@ -47,6 +47,9 @@ + /* Message with data needs at least two words (for header & data). */ + #define MLXBF_TMFIFO_DATA_MIN_WORDS 2 + ++/* ACPI chip identifier for BlueField-3. */ ++#define MLXBF_TMFIFO_BF3_UID "1" ++ + struct mlxbf_tmfifo; + + /** +@@ -140,8 +143,14 @@ struct mlxbf_tmfifo_irq_info { + * mlxbf_tmfifo - Structure of the TmFifo + * @vdev: array of the virtual devices running over the TmFifo + * @lock: lock to protect the TmFifo access +- * @rx_base: mapped register base address for the Rx FIFO +- * @tx_base: mapped register base address for the Tx FIFO ++ * @res0: mapped register base for resource 0 ++ * @res1: mapped register base for resource 1 ++ * @rx_ctl: TMFIFO_RX_CTL register ++ * @rx_sts: TMFIFO_RX_STS register ++ * @rx_data: TMFIFO_RX_DATA register ++ * @tx_ctl: TMFIFO_TX_CTL register ++ * @tx_sts: TMFIFO_TX_STS register ++ * @tx_data: TMFIFO_TX_DATA register + * @rx_fifo_size: number of entries of the Rx FIFO + * @tx_fifo_size: number of entries of the Tx FIFO + * @pend_events: pending bits for deferred events +@@ -155,8 +164,14 @@ struct mlxbf_tmfifo_irq_info { + struct mlxbf_tmfifo { + struct mlxbf_tmfifo_vdev *vdev[MLXBF_TMFIFO_VDEV_MAX]; + struct mutex lock; /* TmFifo lock */ +- void __iomem *rx_base; +- void __iomem *tx_base; ++ void __iomem *res0; ++ void __iomem *res1; ++ void __iomem *rx_ctl; ++ void __iomem *rx_sts; ++ void __iomem *rx_data; ++ void __iomem *tx_ctl; ++ void __iomem *tx_sts; ++ void __iomem *tx_data; + int rx_fifo_size; + int tx_fifo_size; + unsigned long pend_events; +@@ -472,7 +487,7 @@ static int mlxbf_tmfifo_get_rx_avail(struct mlxbf_tmfifo *fifo) + { + u64 sts; + +- sts = readq(fifo->rx_base + MLXBF_TMFIFO_RX_STS); ++ sts = readq(fifo->rx_sts); + return FIELD_GET(MLXBF_TMFIFO_RX_STS__COUNT_MASK, sts); + } + +@@ -489,7 +504,7 @@ static int mlxbf_tmfifo_get_tx_avail(struct mlxbf_tmfifo *fifo, int vdev_id) + else + tx_reserve = 1; + +- sts = readq(fifo->tx_base + MLXBF_TMFIFO_TX_STS); ++ sts = readq(fifo->tx_sts); + count = FIELD_GET(MLXBF_TMFIFO_TX_STS__COUNT_MASK, sts); + return fifo->tx_fifo_size - tx_reserve - count; + } +@@ -525,7 +540,7 @@ static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail) + /* Write header. */ + hdr.type = VIRTIO_ID_CONSOLE; + hdr.len = htons(size); +- writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA); ++ writeq(*(u64 *)&hdr, fifo->tx_data); + + /* Use spin-lock to protect the 'cons->tx_buf'. */ + spin_lock_irqsave(&fifo->spin_lock[0], flags); +@@ -542,7 +557,7 @@ static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail) + memcpy((u8 *)&data + seg, cons->tx_buf.buf, + sizeof(u64) - seg); + } +- writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA); ++ writeq(data, fifo->tx_data); + + if (size >= sizeof(u64)) { + cons->tx_buf.tail = (cons->tx_buf.tail + sizeof(u64)) % +@@ -573,7 +588,7 @@ static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring, + + /* Read a word from FIFO for Rx. */ + if (is_rx) +- data = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA); ++ data = readq(fifo->rx_data); + + if (vring->cur_len + sizeof(u64) <= len) { + /* The whole word. */ +@@ -595,7 +610,7 @@ static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring, + + /* Write the word into FIFO for Tx. */ + if (!is_rx) +- writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA); ++ writeq(data, fifo->tx_data); + } + + /* +@@ -617,7 +632,7 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring, + /* Read/Write packet header. */ + if (is_rx) { + /* Drain one word from the FIFO. */ +- *(u64 *)&hdr = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA); ++ *(u64 *)&hdr = readq(fifo->rx_data); + + /* Skip the length 0 packets (keepalive). */ + if (hdr.len == 0) +@@ -661,7 +676,7 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring, + hdr.type = (vring->vdev_id == VIRTIO_ID_NET) ? + VIRTIO_ID_NET : VIRTIO_ID_CONSOLE; + hdr.len = htons(vring->pkt_len - hdr_len); +- writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA); ++ writeq(*(u64 *)&hdr, fifo->tx_data); + } + + vring->cur_len = hdr_len; +@@ -1155,7 +1170,7 @@ static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo) + u64 ctl; + + /* Get Tx FIFO size and set the low/high watermark. */ +- ctl = readq(fifo->tx_base + MLXBF_TMFIFO_TX_CTL); ++ ctl = readq(fifo->tx_ctl); + fifo->tx_fifo_size = + FIELD_GET(MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_MASK, ctl); + ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__LWM_MASK) | +@@ -1164,17 +1179,17 @@ static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo) + ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__HWM_MASK) | + FIELD_PREP(MLXBF_TMFIFO_TX_CTL__HWM_MASK, + fifo->tx_fifo_size - 1); +- writeq(ctl, fifo->tx_base + MLXBF_TMFIFO_TX_CTL); ++ writeq(ctl, fifo->tx_ctl); + + /* Get Rx FIFO size and set the low/high watermark. */ +- ctl = readq(fifo->rx_base + MLXBF_TMFIFO_RX_CTL); ++ ctl = readq(fifo->rx_ctl); + fifo->rx_fifo_size = + FIELD_GET(MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK, ctl); + ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__LWM_MASK) | + FIELD_PREP(MLXBF_TMFIFO_RX_CTL__LWM_MASK, 0); + ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__HWM_MASK) | + FIELD_PREP(MLXBF_TMFIFO_RX_CTL__HWM_MASK, 1); +- writeq(ctl, fifo->rx_base + MLXBF_TMFIFO_RX_CTL); ++ writeq(ctl, fifo->rx_ctl); + } + + static void mlxbf_tmfifo_cleanup(struct mlxbf_tmfifo *fifo) +@@ -1194,9 +1209,15 @@ static int mlxbf_tmfifo_probe(struct platform_device *pdev) + { + struct virtio_net_config net_config; + struct device *dev = &pdev->dev; ++ struct acpi_device *device; + struct mlxbf_tmfifo *fifo; ++ const char *uid; + int i, rc; + ++ device = ACPI_COMPANION(dev); ++ if (!device) ++ return -ENODEV; ++ + fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL); + if (!fifo) + return -ENOMEM; +@@ -1207,14 +1228,31 @@ static int mlxbf_tmfifo_probe(struct platform_device *pdev) + mutex_init(&fifo->lock); + + /* Get the resource of the Rx FIFO. */ +- fifo->rx_base = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(fifo->rx_base)) +- return PTR_ERR(fifo->rx_base); ++ fifo->res0 = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(fifo->res0)) ++ return PTR_ERR(fifo->res0); + + /* Get the resource of the Tx FIFO. */ +- fifo->tx_base = devm_platform_ioremap_resource(pdev, 1); +- if (IS_ERR(fifo->tx_base)) +- return PTR_ERR(fifo->tx_base); ++ fifo->res1 = devm_platform_ioremap_resource(pdev, 1); ++ if (IS_ERR(fifo->res1)) ++ return PTR_ERR(fifo->res1); ++ ++ uid = acpi_device_uid(device); ++ if (uid && !strcmp(uid, MLXBF_TMFIFO_BF3_UID)) { ++ fifo->rx_data = fifo->res0 + MLXBF_TMFIFO_RX_DATA_BF3; ++ fifo->tx_data = fifo->res0 + MLXBF_TMFIFO_TX_DATA_BF3; ++ fifo->rx_sts = fifo->res1 + MLXBF_TMFIFO_RX_STS_BF3; ++ fifo->rx_ctl = fifo->res1 + MLXBF_TMFIFO_RX_CTL_BF3; ++ fifo->tx_sts = fifo->res1 + MLXBF_TMFIFO_TX_STS_BF3; ++ fifo->tx_ctl = fifo->res1 + MLXBF_TMFIFO_TX_CTL_BF3; ++ } else { ++ fifo->rx_ctl = fifo->res0 + MLXBF_TMFIFO_RX_CTL; ++ fifo->rx_sts = fifo->res0 + MLXBF_TMFIFO_RX_STS; ++ fifo->rx_data = fifo->res0 + MLXBF_TMFIFO_RX_DATA; ++ fifo->tx_ctl = fifo->res1 + MLXBF_TMFIFO_TX_CTL; ++ fifo->tx_sts = fifo->res1 + MLXBF_TMFIFO_TX_STS; ++ fifo->tx_data = fifo->res1 + MLXBF_TMFIFO_TX_DATA; ++ } + + platform_set_drvdata(pdev, fifo); + +-- +2.20.1 + diff --git a/patch/0220-UBUNTU-SAUCE-pka-Add-pka-driver.patch b/patch/0220-UBUNTU-SAUCE-pka-Add-pka-driver.patch new file mode 100644 index 000000000..875083ea0 --- /dev/null +++ b/patch/0220-UBUNTU-SAUCE-pka-Add-pka-driver.patch @@ -0,0 +1,10216 @@ +From c1e48283efef4faeee6b601fc679ea228bd8d6ef Mon Sep 17 00:00:00 2001 +From: Mahantesh Salimath +Date: Thu, 30 Jun 2022 16:46:50 -0400 +Subject: [PATCH backport 5.10 21/63] UBUNTU: SAUCE: pka: Add pka driver. + +BugLink: https://bugs.launchpad.net/bugs/1980415 + +* This driver is picked from internal linux repo;bfdev-5.4.60 branch. + For commit history, please refer to above repo and branch. + +Signed-off-by: Mahantesh Salimath +Reviewed-by: Khalil Blaiech +Signed-off-by: Mahantesh Salimath +Signed-off-by: Ike Panhc +--- + drivers/platform/mellanox/Kconfig | 2 + + drivers/platform/mellanox/Makefile | 1 + + drivers/platform/mellanox/mlxbf_pka/Kconfig | 14 + + drivers/platform/mellanox/mlxbf_pka/Makefile | 9 + + .../mellanox/mlxbf_pka/mlxbf_pka_addrs.h | 284 + + .../mellanox/mlxbf_pka/mlxbf_pka_config.h | 226 + + .../mellanox/mlxbf_pka/mlxbf_pka_cpu.h | 72 + + .../mellanox/mlxbf_pka/mlxbf_pka_debug.h | 66 + + .../mellanox/mlxbf_pka/mlxbf_pka_dev.c | 2414 +++++++++ + .../mellanox/mlxbf_pka/mlxbf_pka_dev.h | 310 ++ + .../mellanox/mlxbf_pka/mlxbf_pka_drv.c | 1398 +++++ + .../mellanox/mlxbf_pka/mlxbf_pka_firmware.h | 4823 +++++++++++++++++ + .../mellanox/mlxbf_pka/mlxbf_pka_ioctl.h | 127 + + .../mellanox/mlxbf_pka/mlxbf_pka_mmio.h | 49 + + .../mellanox/mlxbf_pka/mlxbf_pka_ring.h | 276 + + 15 files changed, 10071 insertions(+) + create mode 100644 drivers/platform/mellanox/mlxbf_pka/Kconfig + create mode 100644 drivers/platform/mellanox/mlxbf_pka/Makefile + create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_addrs.h + create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_config.h + create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_cpu.h + create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_debug.h + create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c + create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.h + create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_drv.c + create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_firmware.h + create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_ioctl.h + create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_mmio.h + create mode 100644 drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_ring.h + +diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig +index 5d329350a..946bc2375 100644 +--- a/drivers/platform/mellanox/Kconfig ++++ b/drivers/platform/mellanox/Kconfig +@@ -97,6 +97,8 @@ config MLXBF_TRIO + This driver supports the TRIO PCIe root complex interface on + Mellanox BlueField SoCs. + ++source "drivers/platform/mellanox/mlxbf_pka/Kconfig" ++ + config NVSW_SN2201 + tristate "Nvidia SN2201 platform driver support" + depends on REGMAP +diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile +index 161fad566..046347d3a 100644 +--- a/drivers/platform/mellanox/Makefile ++++ b/drivers/platform/mellanox/Makefile +@@ -12,3 +12,4 @@ obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o + obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o + obj-$(CONFIG_MLXREG_LC) += mlxreg-lc.o + obj-$(CONFIG_NVSW_SN2201) += nvsw-sn2201.o ++obj-$(CONFIG_MLXBF_PKA) += mlxbf_pka/ +diff --git a/drivers/platform/mellanox/mlxbf_pka/Kconfig b/drivers/platform/mellanox/mlxbf_pka/Kconfig +new file mode 100644 +index 000000000..ebc038ec7 +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf_pka/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB ++# ++# Platform support for Mellanox BlueField PKA ++# ++ ++config MLXBF_PKA ++ tristate "Mellanox BlueField Public Key Accelerator driver" ++ depends on ARM64 && IOMMU_API && VFIO_IOMMU_TYPE1 && VFIO_PLATFORM ++ help ++ If you say yes to this option, support will be included for the ++ Public Key Accelerator device on Mellanox BlueField SoCs. ++ ++ This driver can also be built as a module. If so, the module will ++ be called pka-mlxbf. +diff --git a/drivers/platform/mellanox/mlxbf_pka/Makefile b/drivers/platform/mellanox/mlxbf_pka/Makefile +new file mode 100644 +index 000000000..d9f5be4d6 +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf_pka/Makefile +@@ -0,0 +1,9 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB ++# ++# Makefile for Mellanox BlueField PKA Driver ++# ++ ++obj-m += mlxbf-pka.o ++ ++mlxbf-pka-y := mlxbf_pka_drv.o ++mlxbf-pka-y += mlxbf_pka_dev.o +diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_addrs.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_addrs.h +new file mode 100644 +index 000000000..cd2a4d814 +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_addrs.h +@@ -0,0 +1,284 @@ ++// ++// BSD LICENSE ++// ++// Copyright(c) 2016 Mellanox Technologies, Ltd. All rights reserved. ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// ++// * Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// * Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in ++// the documentation and/or other materials provided with the ++// distribution. ++// * Neither the name of Mellanox Technologies nor the names of its ++// contributors may be used to endorse or promote products derived ++// from this software without specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++// ++ ++#ifndef __PKA_ADDRS_H__ ++#define __PKA_ADDRS_H__ ++ ++// Define memory size in bytes ++#define MEM_SIZE_4KB 0x1000 ++#define MEM_SIZE_8KB 0x2000 ++#define MEM_SIZE_16KB 0x4000 ++#define MEM_SIZE_32KB 0x8000 ++#define MEM_SIZE_64KB 0x10000 ++ ++// ++// COMMON SPACE ++// ++#define CRYPTO_COMMON_BASE 0x0 ++ ++// Common IO CSR addresses/offsets: These are all addressed as 8-byte registers. ++#define DEV_INFO_ADDR (0x00 | CRYPTO_COMMON_BASE) ++#define DEV_CTL_ADDR (0x08 | CRYPTO_COMMON_BASE) ++#define MMIO_INFO_ADDR (0x10 | CRYPTO_COMMON_BASE) ++#define SCRATCHPAD_ADDR (0x20 | CRYPTO_COMMON_BASE) ++#define SEMAPHORE0_ADDR (0x28 | CRYPTO_COMMON_BASE) ++#define SEMAPHORE1_ADDR (0x30 | CRYPTO_COMMON_BASE) ++#define CLOCK_COUNT_ADDR (0x38 | CRYPTO_COMMON_BASE) ++#define INT_SETUP_ADDR (0x40 | CRYPTO_COMMON_BASE) ++#define CRED_CTL_ADDR (0x50 | CRYPTO_COMMON_BASE) ++#define SAM_CTL_ADDR (0x58 | CRYPTO_COMMON_BASE) ++ ++// ++// CRYPTO SPACE ++// ++ ++// All addresses/offsets herein are BYTE addresses. ++ ++// EIP154 CSRS: ++ ++// Global Control Space CSR addresses/offsets. These are accessed from the ++// ARM as 8 byte reads/writes however only the bottom 32 bits are implemented. ++#define PKA_CLOCK_SWITCH_ADDR 0x11C68 ++#define PKA_CLK_FORCE_ADDR 0x11C80 ++#define MODE_SELECTION_ADDR 0x11C88 ++#define PKA_PROT_STATUS_ADDR 0x11C90 ++#define PKA_OPTIONS_ADDR 0x11DF0 ++#define PKA_VERSION_ADDR 0x11DF8 ++ ++// Advanced Interrupt Controller CSR addresses/offsets. These are accessed ++// from the ARM as 8 byte reads/writes however only the bottom 32 bits are ++// implemented. ++#define AIC_POL_CTRL_ADDR 0x11E00 ++#define AIC_TYPE_CTRL_ADDR 0x11E08 ++#define AIC_ENABLE_CTRL_ADDR 0x11E10 ++#define AIC_RAW_STAT_ADDR 0x11E18 ++#define AIC_ENABLE_SET_ADDR 0x11E18 ++#define AIC_ENABLED_STAT_ADDR 0x11E20 ++#define AIC_ACK_ADDR 0x11E20 ++#define AIC_ENABLE_CLR_ADDR 0x11E28 ++#define AIC_OPTIONS_ADDR 0x11E30 ++#define AIC_VERSION_ADDR 0x11E38 ++ ++// The True Random Number Generator CSR addresses/offsets. These are accessed ++// from the ARM as 8 byte reads/writes however only the bottom 32 bits are ++// implemented. ++#define TRNG_OUTPUT_0_ADDR 0x12000 ++#define TRNG_OUTPUT_1_ADDR 0x12008 ++#define TRNG_OUTPUT_2_ADDR 0x12010 ++#define TRNG_OUTPUT_3_ADDR 0x12018 ++#define TRNG_STATUS_ADDR 0x12020 ++#define TRNG_INTACK_ADDR 0x12020 ++#define TRNG_CONTROL_ADDR 0x12028 ++#define TRNG_CONFIG_ADDR 0x12030 ++#define TRNG_ALARMCNT_ADDR 0x12038 ++#define TRNG_FROENABLE_ADDR 0x12040 ++#define TRNG_FRODETUNE_ADDR 0x12048 ++#define TRNG_ALARMMASK_ADDR 0x12050 ++#define TRNG_ALARMSTOP_ADDR 0x12058 ++#define TRNG_BLOCKCNT_ADDR 0x120E8 ++#define TRNG_OPTIONS_ADDR 0x120F0 ++#define TRNG_TEST_ADDR 0x120E0 ++#define TRNG_RAW_L_ADDR 0x12060 ++#define TRNG_RAW_H_ADDR 0x12068 ++#define TRNG_RUN_CNT_ADDR 0x12080 ++#define TRNG_MONOBITCNT_ADDR 0x120B8 ++#define TRNG_POKER_3_0_ADDR 0x120C0 ++#define TRNG_POKER_7_4 0x120C8 ++#define TRNG_POKER_B_8 0x120D0 ++#define TRNG_POKER_F_C 0x120D8 ++ ++#define TRNG_PS_AI_0_ADDR 0x12080 ++#define TRNG_PS_AI_1_ADDR 0x12088 ++#define TRNG_PS_AI_2_ADDR 0x12090 ++#define TRNG_PS_AI_3_ADDR 0x12098 ++#define TRNG_PS_AI_4_ADDR 0x120A0 ++#define TRNG_PS_AI_5_ADDR 0x120A8 ++#define TRNG_PS_AI_6_ADDR 0x120B0 ++#define TRNG_PS_AI_7_ADDR 0x120B8 ++#define TRNG_PS_AI_8_ADDR 0x120C0 ++#define TRNG_PS_AI_9_ADDR 0x120C8 ++#define TRNG_PS_AI_10_ADDR 0x120D0 ++#define TRNG_PS_AI_11_ADDR 0x120D8 ++ ++// Control register address/offset. This is accessed from the ARM using 8 ++// byte reads/writes however only the bottom 32 bits are implemented. ++#define PKA_MASTER_SEQ_CTRL_ADDR 0x27F90 ++ ++// Ring CSRs: These are all accessed from the ARM using 8 byte reads/writes ++// however only the bottom 32 bits are implemented. ++ ++// Ring 0 CSRS ++#define COMMAND_COUNT_0_ADDR 0x80080 ++#define RESULT_COUNT_0_ADDR 0x80088 ++#define IRQ_THRESH_0_ADDR 0x80090 ++ ++// Ring 1 CSRS: ++#define COMMAND_COUNT_1_ADDR 0x90080 ++#define RESULT_COUNT_1_ADDR 0x90088 ++#define IRQ_THRESH_1_ADDR 0x90090 ++ ++// Ring 2 CSRS: ++#define COMMAND_COUNT_2_ADDR 0xA0080 ++#define RESULT_COUNT_2_ADDR 0xA0088 ++#define IRQ_THRESH_2_ADDR 0xA0090 ++ ++// Ring 3 CSRS: ++#define COMMAND_COUNT_3_ADDR 0xB0080 ++#define RESULT_COUNT_3_ADDR 0xB0088 ++#define IRQ_THRESH_3_ADDR 0xB0090 ++ ++// EIP154 RAM regions: Note that the FARM_PROG_RAM_X address range overlaps ++// with the FARM_DATA_RAM_X and FARM_DATA_RAM_X_EXT address ranges. This ++// conflict is resolved by using the FARM_PROG_RAM_X only when the ++// Sequencer is in SW reset, and the DATA_RAMs are picked only when the ++// engine is operation. ++// ++// Note: ++// The FARM_DATA_RAM_X_EXT RAMs may also be ++// called the LNME FIFO RAMs in some of the documentation. ++// ++// PKA_BUFFER_RAM : 1024 x 64 - 8K bytes ++// PKA_SECURE_RAM : 1536 x 64 - 12K bytes ++// PKA_MASTER_PROG_RAM : 8192 x 32 - 32K bytes ++// FARM_DATA_RAM_X : 1024 x 64 - 8K bytes ++// FARM_DATA_RAM_X_EXT : 256 x 32 - 1K bytes ++// FARM_PROG_RAM_X : 2048 x 32 - 8K bytes ++// ++// Note: ++// *TBD* Since hardware guys multiplied the address per 2, the size of ++// each memory/registers group increased and become two times larger. ++// Memory size should be adjusted accordingly: ++// PKA Buffer RAM size : 8KB --> 16KB ++// PKA Secure RAM size : 8KB --> 16KB ++// PKA Master Program RAM size : 32KB --> 64KB ++// PKA Farm Data RAM size : 4KB --> 8KB ++// PKA Farm Data RAM extension size : 4KB --> 8KB ++// PKA Farm Program RAM size : 8KB --> 16KB ++// ++#define PKA_BUFFER_RAM_BASE 0x00000 ++#define PKA_BUFFER_RAM_SIZE MEM_SIZE_16KB // 0x00000...0x03FFF ++ ++#define PKA_SECURE_RAM_BASE 0x20000 ++#define PKA_SECURE_RAM_SIZE MEM_SIZE_16KB // 0x20000...0x23FFF ++ ++#define PKA_MASTER_PROG_RAM_BASE 0x30000 ++#define PKA_MASTER_PROG_RAM_SIZE MEM_SIZE_64KB // 0x30000...0x3FFFF ++ ++#define FARM_DATA_RAM_0_BASE 0x40000 ++#define FARM_DATA_RAM_0_SIZE MEM_SIZE_8KB // 0x40000...0x41FFF ++#define FARM_DATA_RAM_0_EXT_BASE 0x42000 ++#define FARM_DATA_RAM_0_EXT_SIZE MEM_SIZE_8KB // 0x42000...0x43FFF ++#define FARM_PROG_RAM_0_BASE 0x40000 ++#define FARM_PROG_RAM_0_SIZE MEM_SIZE_16KB // 0x40000...0x43FFF ++#define FARM_DATA_RAM_1_BASE 0x44000 ++#define FARM_DATA_RAM_1_SIZE MEM_SIZE_8KB // 0x44000...0x45FFF ++#define FARM_DATA_RAM_1_EXT_BASE 0x46000 ++#define FARM_DATA_RAM_1_EXT_SIZE MEM_SIZE_8KB // 0x46000...0x47FFF ++#define FARM_PROG_RAM_1_BASE 0x44000 ++#define FARM_PROG_RAM_1_SIZE MEM_SIZE_16KB // 0x44000...0x47FFF ++#define FARM_DATA_RAM_2_BASE 0x48000 ++#define FARM_DATA_RAM_2_SIZE MEM_SIZE_8KB // 0x48000...0x49FFF ++#define FARM_DATA_RAM_2_EXT_BASE 0x4A000 ++#define FARM_DATA_RAM_2_EXT_SIZE MEM_SIZE_8KB // 0x4A000...0x4BFFF ++#define FARM_PROG_RAM_2_BASE 0x48000 ++#define FARM_PROG_RAM_2_SIZE MEM_SIZE_16KB // 0x48000...0x4BFFF ++#define FARM_DATA_RAM_3_BASE 0x4C000 ++#define FARM_DATA_RAM_3_SIZE MEM_SIZE_8KB // 0x4C000...0x4DFFF ++#define FARM_DATA_RAM_3_EXT_BASE 0x4E000 ++#define FARM_DATA_RAM_3_EXT_SIZE MEM_SIZE_8KB // 0x4E000...0x4FFFF ++#define FARM_PROG_RAM_3_BASE 0x4C000 ++#define FARM_PROG_RAM_3_SIZE MEM_SIZE_16KB // 0x4C000...0x4FFFF ++#define FARM_DATA_RAM_4_BASE 0x50000 ++#define FARM_DATA_RAM_4_SIZE MEM_SIZE_8KB // 0x50000...0x51FFF ++#define FARM_DATA_RAM_4_EXT_BASE 0x52000 ++#define FARM_DATA_RAM_4_EXT_SIZE MEM_SIZE_8KB // 0x52000...0x53FFF ++#define FARM_PROG_RAM_4_BASE 0x50000 ++#define FARM_PROG_RAM_4_SIZE MEM_SIZE_16KB // 0x50000...0x53FFF ++#define FARM_DATA_RAM_5_BASE 0x54000 ++#define FARM_DATA_RAM_5_SIZE MEM_SIZE_8KB // 0x54000...0x55FFF ++#define FARM_DATA_RAM_5_EXT_BASE 0x56000 ++#define FARM_DATA_RAM_5_EXT_SIZE MEM_SIZE_8KB // 0x56000...0x57FFF ++#define FARM_PROG_RAM_5_BASE 0x54000 ++#define FARM_PROG_RAM_5_SIZE MEM_SIZE_16KB // 0x54000...0x57FFF ++ ++// PKA Buffer RAM offsets. These are NOT real CSR's but instead are ++// specific offset/addresses within the EIP154 PKA_BUFFER_RAM. ++ ++// Ring 0: ++#define RING_CMMD_BASE_0_ADDR 0x00000 ++#define RING_RSLT_BASE_0_ADDR 0x00010 ++#define RING_SIZE_TYPE_0_ADDR 0x00020 ++#define RING_RW_PTRS_0_ADDR 0x00028 ++#define RING_RW_STAT_0_ADDR 0x00030 ++ ++// Ring 1 ++#define RING_CMMD_BASE_1_ADDR 0x00040 ++#define RING_RSLT_BASE_1_ADDR 0x00050 ++#define RING_SIZE_TYPE_1_ADDR 0x00060 ++#define RING_RW_PTRS_1_ADDR 0x00068 ++#define RING_RW_STAT_1_ADDR 0x00070 ++ ++// Ring 2 ++#define RING_CMMD_BASE_2_ADDR 0x00080 ++#define RING_RSLT_BASE_2_ADDR 0x00090 ++#define RING_SIZE_TYPE_2_ADDR 0x000A0 ++#define RING_RW_PTRS_2_ADDR 0x000A8 ++#define RING_RW_STAT_2_ADDR 0x000B0 ++ ++// Ring 3 ++#define RING_CMMD_BASE_3_ADDR 0x000C0 ++#define RING_RSLT_BASE_3_ADDR 0x000D0 ++#define RING_SIZE_TYPE_3_ADDR 0x000E0 ++#define RING_RW_PTRS_3_ADDR 0x000E8 ++#define RING_RW_STAT_3_ADDR 0x000F0 ++ ++// Ring Options ++#define PKA_RING_OPTIONS_ADDR 0x07FF8 ++ ++// Alternate Window RAM size ++#define PKA_WINDOW_RAM_REGION_SIZE MEM_SIZE_16KB ++ ++// Currently, we do not use these MiCA specific CSRs. ++ ++// The PKI (not EIP154) CSR address/offsets: These are all addressed as ++// 8-byte registers. ++#define PKA_INT_MASK_ADDR 0x00 ++#define PKA_INT_MASK_SET_ADDR 0x08 ++#define PKA_INT_MASK_RESET_ADDR 0x10 ++#define PKA_ZEROIZE_ADDR 0x40 ++#define TST_FRO_ADDR 0x50 ++#define FRO_COUNT_ADDR 0x58 ++#define PKA_PARITY_CTL_ADDR 0x60 ++#define PKA_PARITY_STAT_ADDR 0x68 ++ ++#endif // __PKA_ADDRS_H__ +diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_config.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_config.h +new file mode 100644 +index 000000000..5b69d55be +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_config.h +@@ -0,0 +1,226 @@ ++// ++// BSD LICENSE ++// ++// Copyright(c) 2016 Mellanox Technologies, Ltd. All rights reserved. ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// ++// * Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// * Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in ++// the documentation and/or other materials provided with the ++// distribution. ++// * Neither the name of Mellanox Technologies nor the names of its ++// contributors may be used to endorse or promote products derived ++// from this software without specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++// ++ ++#ifndef __PKA_CONFIG_H__ ++#define __PKA_CONFIG_H__ ++ ++#include "mlxbf_pka_addrs.h" ++ ++// The maximum number of PKA shims refered to as IO blocks. ++#define PKA_MAX_NUM_IO_BLOCKS 8 ++// The maximum number of Rings supported by IO block (shim). ++#define PKA_MAX_NUM_IO_BLOCK_RINGS 4 ++ ++#define PKA_MAX_NUM_RINGS \ ++ (PKA_MAX_NUM_IO_BLOCK_RINGS * PKA_MAX_NUM_IO_BLOCKS) ++ ++// Resources are regions which include info control/status words, ++// count registers and host window ram. ++#define PKA_MAX_NUM_RING_RESOURCES 3 ++ ++// PKA Ring resources. ++// Define Ring resources parameters including base address, size (in bytes) ++// and ring spacing. ++#define PKA_RING_WORDS_ADDR PKA_BUFFER_RAM_BASE ++#define PKA_RING_CNTRS_ADDR COMMAND_COUNT_0_ADDR ++ ++#define PKA_RING_WORDS_SIZE 0x40 // 64 bytes ++#define PKA_RING_CNTRS_SIZE 0x20 // 32 bytes (3 count registers) ++#define PKA_RING_MEM_SIZE 0x4000 // 16K bytes ++ ++#define PKA_RING_WORDS_SPACING 0x40 // 64 bytes ++#define PKA_RING_CNTRS_SPACING 0x10000 // 64K bytes ++#define PKA_RING_MEM_0_SPACING 0x4000 // 16K bytes ++#define PKA_RING_MEM_1_SPACING 0x10000 // 64K bytes ++ ++// PKA Window RAM parameters. ++// Define whether to split or not Window RAM during PKA device creation phase. ++#define SPLIT_WINDOW_RAM_MODE_ENABLED 1 ++#define SPLIT_WINDOW_RAM_MODE_DISABLED 0 ++#define PKA_SPLIT_WINDOW_RAM_MODE SPLIT_WINDOW_RAM_MODE_DISABLED ++// Defines for Window RAM partition. It is valid for 16K memory. ++#define PKA_WINDOW_RAM_RING_MEM_SIZE 0x0800 // 2KB ++#define PKA_WINDOW_RAM_DATA_MEM_SIZE 0x3800 // 14KB ++ ++// Offset mask, common to both Window and Alternate Window RAM. ++#define PKA_WINDOW_RAM_OFFSET_MASK1 0x730000 ++ ++// Macro for mapping PKA Ring address into Window RAM address. It converts the ++// ring address, either physical address or virtual address, to valid address ++// into the Window RAM. This is done assuming the Window RAM base, size and ++// mask. Here, base is the actual physical address of the Window RAM, with the ++// help of mask it is reduced to Window RAM offset within that PKA block. ++// Further, with the help of addr and size, we arrive at the Window RAM ++// offset address for a PKA Ring within the given Window RAM. ++#define PKA_RING_MEM_ADDR(base, mask, addr, size) \ ++ ((base & mask) | (((addr) & 0xffff) | \ ++ ((((addr) & ~((size) - 1)) & 0xf0000) >> 2))) ++ ++// PKA Master Sequencer Control/Status Register ++// Write '1' to bit [31] puts the Master controller Sequencer in a reset ++// reset state. Resetting the Sequencer (in order to load other firmware) ++// should only be done when the EIP-154 is not performing any operations. ++#define PKA_MASTER_SEQ_CTRL_RESET_VAL 0x80000000 ++// Write '1' to bit [30] will reset all Command and Result counters. This ++// bit is write-only and self clearing and can only be set if the ‘Reset’ ++// bit [31] is ‘1’. ++#define PKA_MASTER_SEQ_CTRL_CLEAR_COUNTERS_VAL 0x40000000 ++// Bit [8] in the PKA Master Sequencer Control/Status Register is tied to ++// the 'pka_master_irq interrupt' on the EIP-154 interrupt controller. ++#define PKA_MASTER_SEQ_CTRL_MASTER_IRQ_BIT 8 ++// Sequencer status bits are used by the Master controller Sequencer to ++// reflect status. Bit [0] is tied to the 'pka_master_irq' interrupt on ++// the EIP-154 interrupt controller. ++#define PKA_MASTER_SEQ_CTRL_STATUS_BYTE 0x01 ++// 'pka_master_irq' mask for the Master controller Sequencer Status Register. ++#define PKA_MASTER_SEQ_CTRL_MASTER_IRQ_MASK 0x100 ++ ++// Advanced Interrupt Controller (AIC) configuration ++// AIC Polarity Control Register is used to set each individual interrupt ++// signal (High Level / Rising Edge) during the initialization phase. ++// '0' = Low level or falling edge. ++// '1' = High level or rising edge. ++#define PKA_AIC_POL_CTRL_REG_VAL 0x000FFFFF ++// AIC Type Control Register is used to set each interrupt to level or edge. ++// '0' = Level. ++// '1' = Edge. ++#define PKA_AIC_TYPE_CTRL_REG_VAL 0x000FFFFF ++// AIC Enable Control Register is used to enable interrupt inputs. ++// '0' = Disabled. ++// '1' = Enabled. ++#define PKA_AIC_ENABLE_CTRL_REG_VAL 0x000F030F ++// AIC Enabled Status Register bits reflect the status of the interrupts ++// gated with the enable bits of the AIC_ENABLE_CTRL Register. ++// '0' = Inactive. ++// '1' = Pending. ++#define PKA_AIC_ENABLE_STAT_REG_VAL 0x000F030F ++ ++// 'pka_master_irq' mask for the AIC Enabled Status Register. ++#define PKA_AIC_ENABLED_STAT_MASTER_IRQ_MASK 0x100 ++ ++// PKA_RING_OPTIONS field to specify the priority in which rings are handled: ++// '00' = full rotating priority, ++// '01' = fixed priority (ring 0 lowest), ++// '10' = ring 0 has the highest priority and the remaining rings have ++// rotating priority, ++// '11' = reserved, do not use. ++#define PKA_FULL_ROTATING_PRIORITY 0x0 ++#define PKA_FIXED_PRIORITY 0x1 ++#define PKA_RING_0_HAS_THE_HIGHEST_PRIORITY 0x2 ++#define PKA_RESERVED 0x3 ++#define PKA_RING_OPTIONS_PRIORITY PKA_FULL_ROTATING_PRIORITY ++ ++// 'Signature' byte used because the ring options are transferred through RAM ++// which does not have a defined reset value. The EIP-154 master controller ++// keeps reading the PKA_RING_OPTIONS word at start-up until the ‘Signature’ ++// byte contains 0x46 and the ‘Reserved’ field contains zero. ++#define PKA_RING_OPTIONS_SIGNATURE_BYTE 0x46 ++ ++// Order of the result reporting: Two schemas are available: ++// InOrder - This means that the results will be reported in the same order ++// as the commands were provided. ++// OutOfOrder - This means that the results are reported as soon as they are ++// available ++#define PKA_RING_TYPE_IN_ORDER_BIT 1 ++#define PKA_RING_TYPE_OUT_OF_ORDER_BIT 0 ++#define PKA_RING_TYPE_IN_ORDER PKA_RING_TYPE_OUT_OF_ORDER_BIT ++ ++// Byte order of the data written/read to/from Rings. ++// Little Endian (LE) - The least significant bytes have the lowest address. ++// Big Endian (BE) - The most significant bytes come first. ++#define PKA_RING_BYTE_ORDER_LE 0 ++#define PKA_RING_BYTE_ORDER_BE 1 ++#define PKA_RING_BYTE_ORDER PKA_RING_BYTE_ORDER_LE ++ ++// 'trng_clk_on' mask for PKA Clock Switch Forcing Register. Turn on the ++// TRNG clock. When the TRNG is controlled via the Host slave interface, ++// this engine needs to be turned on by setting bit 11. ++#define PKA_CLK_FORCE_TRNG_ON 0x800 ++ ++// Number of TRNG Output registers ++#define PKA_TRNG_OUTPUT_CNT 4 ++ ++// TRNG Configuration ++#define PKA_TRNG_CONFIG_REG_VAL 0x00020008 ++// TRNG Alarm Counter Register Value ++#define PKA_TRNG_ALARMCNT_REG_VAL 0x000200FF ++// TRNG FRO Enable Register Value ++#define PKA_TRNG_FROENABLE_REG_VAL 0x00FFFFFF ++// TRNG Control Register Value; Set bit 10 to start the EIP-76 a.k.a TRNG ++// engine, gathering entropy from the FROs. ++#define PKA_TRNG_CONTROL_REG_VAL 0x00000400 ++ ++// TRNG Control bit ++#define PKA_TRNG_CONTROL_TEST_MODE 0x100 ++ ++// TRNG Control Register Value; Set bit 10 and 12 to start the EIP-76 a.k.a TRNG ++// engine with DRBG enabled, gathering entropy from the FROs. ++#define PKA_TRNG_CONTROL_DRBG_REG_VAL 0x00001400 ++ ++// DRBG enabled TRNG 'request_data' value. REQ_DATA_VAL (in accordance with ++// DATA_BLOCK_MASK) requests 256 blocks of 128-bit random output. ++// 4095 blocks is the max number that can be requested for the TRNG(with DRBG) ++// configuration on Bluefield platforms. ++#define PKA_TRNG_CONTROL_REQ_DATA_VAL 0x10010000 ++ ++// Mask for 'Data Block' in TRNG Control Register. ++#define PKA_TRNG_DRBG_DATA_BLOCK_MASK 0xfff00000 ++ ++// Set bit 12 of TRNG Control Register to enable DRBG functionality. ++#define PKA_TRNG_CONTROL_DRBG_ENABLE_VAL 0x00001000 ++ ++// Set bit 8 a.ka 'test_sp_800_90 DRBG' bit in the TRNG Test Register. ++#define PKA_TRNG_TEST_DRBG_VAL 0x00000080 ++ ++// Number of Personalization String/Additional Input Registers ++#define PKA_TRNG_PS_AI_REG_COUNT 12 ++ ++// DRBG Reseed enable ++#define PKA_TRNG_CONTROL_DRBG_RESEED 0x00008000 ++ ++// TRNG Status bits ++#define PKA_TRNG_STATUS_READY 0x1 ++#define PKA_TRNG_STATUS_SHUTDOWN_OFLO 0x2 ++#define PKA_TRNG_STATUS_TEST_READY 0x100 ++#define PKA_TRNG_STATUS_MONOBIT_FAIL 0x80 ++#define PKA_TRNG_STATUS_RUN_FAIL 0x10 ++#define PKA_TRNG_STATUS_POKER_FAIL 0x40 ++ ++// TRNG Alarm Counter bits ++#define PKA_TRNG_ALARMCNT_STALL_RUN_POKER 0x8000 ++ ++// TRNG Test bits ++#define PKA_TRNG_TEST_KNOWN_NOISE 0x20 ++#define PKA_TRNG_TEST_NOISE 0x2000 ++ ++#endif // __PKA_CONFIG_H__ +diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_cpu.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_cpu.h +new file mode 100644 +index 000000000..12a368c13 +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_cpu.h +@@ -0,0 +1,72 @@ ++// ++// BSD LICENSE ++// ++// Copyright(c) 2016 Mellanox Technologies, Ltd. All rights reserved. ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// ++// * Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// * Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in ++// the documentation and/or other materials provided with the ++// distribution. ++// * Neither the name of Mellanox Technologies nor the names of its ++// contributors may be used to endorse or promote products derived ++// from this software without specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++// ++ ++#ifndef __PKA_CPU_H__ ++#define __PKA_CPU_H__ ++ ++#include ++#include ++ ++#define PKA_AARCH_64 ++#define MAX_CPU_NUMBER 16 // BlueField specific ++ ++#define MEGA 1000000 ++#define GIGA 1000000000 ++ ++#define MS_PER_S 1000 ++#define US_PER_S 1000000 ++#define NS_PER_S 1000000000 ++ ++// Initial guess at our CPU speed. We set this to be larger than any ++// possible real speed, so that any calculated delays will be too long, ++// rather than too short. ++// ++//*Warning: use dummy value for frequency ++//#define CPU_HZ_MAX (2 * GIGA) // Cortex A72 : 2 GHz max -> 2.5 GHz max ++#define CPU_HZ_MAX (1255 * MEGA) // CPU Freq for High/Bin Chip ++ ++// YIELD hints the CPU to switch to another thread if possible ++// and executes as a NOP otherwise. ++#define pka_cpu_yield() ({ asm volatile("yield" : : : "memory"); }) ++// ISB flushes the pipeline, then restarts. This is guaranteed to ++// stall the CPU a number of cycles. ++#define pka_cpu_relax() ({ asm volatile("isb" : : : "memory"); }) ++ ++// Processor speed in hertz; used in routines which might be called very ++// early in boot. ++static inline uint64_t pka_early_cpu_speed(void) ++{ ++ return CPU_HZ_MAX; ++} ++ ++#endif // __PKA_CPU_H__ +diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_debug.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_debug.h +new file mode 100644 +index 000000000..a44af6eb1 +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_debug.h +@@ -0,0 +1,66 @@ ++// ++// BSD LICENSE ++// ++// Copyright(c) 2016 Mellanox Technologies, Ltd. All rights reserved. ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// ++// * Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// * Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in ++// the documentation and/or other materials provided with the ++// distribution. ++// * Neither the name of Mellanox Technologies nor the names of its ++// contributors may be used to endorse or promote products derived ++// from this software without specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++// ++ ++#ifndef __PKA_DEBUG_H__ ++#define __PKA_DEBUG_H__ ++ ++// PKA library bitmask. Use those bits to enable debug messages ++#define PKA_DRIVER 0x0001 ++#define PKA_DEV 0x0002 ++#define PKA_RING 0x0004 ++#define PKA_QUEUE 0x0008 ++#define PKA_MEM 0x0010 ++#define PKA_USER 0x0020 ++#define PKA_TESTS 0x0040 ++// PKA debug mask. This indicates the debug/verbosity level. ++#define PKA_DEBUG_LIB_MASK 0x0040 ++ ++#define PKA_PRINT(lib, fmt, args...) \ ++ ({ pr_info(#lib": "fmt, ##args); }) ++ ++#define PKA_ERROR(lib, fmt, args...) \ ++ ({ pr_err(#lib": %s: error: "fmt, __func__, ##args); }) ++ ++#define PKA_DEBUG(lib, fmt, args...) \ ++ ({ \ ++ if (lib & PKA_DEBUG_LIB_MASK) \ ++ pr_debug(#lib": %s: "fmt, __func__, ##args); \ ++ }) ++ ++#define PKA_PANIC(lib, msg, args...) \ ++ ({ \ ++ pr_info(#lib": %s: panic: "msg, __func__, ##args); \ ++ panic(msg, ##args); \ ++ }) ++ ++#endif // __PKA_DEBUG_H__ +diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c +new file mode 100644 +index 000000000..c90c70134 +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c +@@ -0,0 +1,2414 @@ ++// ++// BSD LICENSE ++// ++// Copyright(c) 2016 Mellanox Technologies, Ltd. All rights reserved. ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// ++// * Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// * Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in ++// the documentation and/or other materials provided with the ++// distribution. ++// * Neither the name of Mellanox Technologies nor the names of its ++// contributors may be used to endorse or promote products derived ++// from this software without specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++// ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mlxbf_pka_dev.h" ++ ++#define BYTES_PER_WORD 4 ++#define BYTES_PER_DOUBLE_WORD 8 ++ ++// Personalization string "NVIDIA-MELLANOX-BLUEFIELD-TRUE_RANDOM_NUMBER_GEN" ++uint32_t pka_trng_drbg_ps_str[] = ++{ ++ 0x4e564944, 0x49412d4d, 0x454c4c41, 0x4e4f582d, ++ 0x424c5545, 0x4649454c, 0x442d5452, 0x55455f52, ++ 0x414e444f, 0x4d5f4e55, 0x4d424552, 0x5f47454e ++}; ++ ++// Personalization string for DRBG test ++uint32_t pka_trng_drbg_test_ps_str[] = ++{ ++ 0x64299d83, 0xc34d7098, 0x5bd1f51d, 0xddccfdc1, ++ 0xdd0455b7, 0x166279e5, 0x0974cb1b, 0x2f2cd100, ++ 0x59a5060a, 0xca79940d, 0xd4e29a40, 0x56b7b779 ++}; ++ ++// First Entropy string for DRBG test ++uint32_t pka_trng_drbg_test_etpy_str1[] = ++{ ++ 0xaa6bbcab, 0xef45e339, 0x136ca1e7, 0xbce1c881, ++ 0x9fa37b09, 0x63b53667, 0xb36e0053, 0xa202ed81, ++ 0x4650d90d, 0x8eed6127, 0x666f2402, 0x0dfd3af9 ++}; ++ ++// Second Entropy string for DRBG test ++uint32_t pka_trng_drbg_test_etpy_str2[] = ++{ ++ 0x35c1b7a1, 0x0154c52b, 0xd5777390, 0x226a4fdb, ++ 0x5f16080d, 0x06b68369, 0xd0c93d00, 0x3336e27f, ++ 0x1abf2c37, 0xe6ab006c, 0xa4adc6e1, 0x8e1907a2 ++}; ++ ++// Known answer for DRBG test ++uint32_t pka_trng_drbg_test_output[] = ++{ ++ 0xb663b9f1, 0x24943e13, 0x80f7dce5, 0xaba1a16f ++}; ++ ++pka_dev_gbl_config_t pka_gbl_config; ++ ++// Global PKA shim resource info table ++static pka_dev_gbl_shim_res_info_t pka_gbl_res_tbl[PKA_MAX_NUM_IO_BLOCKS]; ++ ++// Start a PKA device timer. ++static uint64_t pka_dev_timer_start(uint32_t usec) ++{ ++ uint64_t cur_time = get_cycles(); ++ return (cur_time + (pka_early_cpu_speed() * usec) / 1000000ULL); ++} ++ ++// Test a PKA device timer for completion. ++static int pka_dev_timer_done(uint64_t timer) ++{ ++ return (get_cycles() >= timer); ++} ++ ++// Return register base address ++static uint64_t pka_dev_get_register_base(uint64_t base, uint64_t reg_addr) ++{ ++ return (base + reg_addr) & PAGE_MASK; ++} ++ ++// Return register offset ++static uint64_t pka_dev_get_register_offset(uint64_t base, uint64_t reg_addr) ++{ ++ return (base + reg_addr) & ~PAGE_MASK; ++} ++ ++// Return word offset within io memory ++static uint64_t pka_dev_get_word_offset(uint64_t mem_base, uint64_t word_addr, ++ uint64_t mem_size) ++{ ++ return (mem_base + word_addr) & (mem_size - 1); ++} ++ ++static uint64_t pka_dev_io_read(void *mem_ptr, uint64_t mem_off) ++{ ++ uint64_t data; ++ ++ data = pka_mmio_read(mem_ptr + mem_off); ++ ++ return data; ++} ++ ++static void pka_dev_io_write(void *mem_ptr, uint64_t mem_off, uint64_t value) ++{ ++ pka_mmio_write(mem_ptr + mem_off, value); ++} ++ ++// Add the resource to the global resource table ++static int pka_dev_add_resource(pka_dev_res_t *res_ptr, uint32_t shim_idx) ++{ ++ uint8_t res_cnt; ++ ++ res_cnt = pka_gbl_res_tbl[shim_idx].res_cnt; ++ ++ if (res_cnt >= PKA_DEV_SHIM_RES_CNT) ++ return -ENOMEM; ++ ++ pka_gbl_res_tbl[shim_idx].res_tbl[res_cnt] = res_ptr; ++ pka_gbl_res_tbl[shim_idx].res_cnt++; ++ ++ return 0; ++} ++ ++// Remove the resource from the global resource table ++static int pka_dev_put_resource(pka_dev_res_t *res, uint32_t shim_idx) ++{ ++ pka_dev_res_t *res_ptr; ++ uint8_t res_idx; ++ ++ for (res_idx = 0; res_idx < PKA_DEV_SHIM_RES_CNT; res_idx++) ++ { ++ res_ptr = pka_gbl_res_tbl[shim_idx].res_tbl[res_idx]; ++ if (res_ptr && strcmp(res_ptr->name, res->name) == 0) ++ { ++ pka_gbl_res_tbl[shim_idx].res_tbl[res_idx] = NULL; ++ pka_gbl_res_tbl[shim_idx].res_cnt--; ++ break; ++ } ++ } ++ ++ // Check whether the resource shares the same memory map; If so, ++ // the memory map shouldn't be released. ++ for (res_idx = 0; res_idx < PKA_DEV_SHIM_RES_CNT; res_idx++) ++ { ++ res_ptr = pka_gbl_res_tbl[shim_idx].res_tbl[res_idx]; ++ if (res_ptr && (res_ptr->base == res->base)) ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ ++static void* pka_dev_get_resource_ioaddr(uint64_t res_base, uint32_t shim_idx) ++{ ++ pka_dev_res_t *res_ptr; ++ uint8_t res_cnt, res_idx; ++ ++ res_cnt = pka_gbl_res_tbl[shim_idx].res_cnt; ++ ++ if (res_cnt == 0) ++ return NULL; ++ ++ for (res_idx = 0; res_idx < res_cnt; res_idx++) ++ { ++ res_ptr = pka_gbl_res_tbl[shim_idx].res_tbl[res_idx]; ++ if (res_ptr->base == res_base) ++ return res_ptr->ioaddr; ++ } ++ ++ return NULL; ++} ++ ++// Set PKA device resource config - - map io memory if needed. ++static int pka_dev_set_resource_config(pka_dev_shim_t *shim, ++ pka_dev_res_t *res_ptr, ++ uint64_t res_base, ++ uint64_t res_size, ++ uint64_t res_type, ++ char *res_name) ++{ ++ int ret = 0; ++ ++ if (res_ptr->status == PKA_DEV_RES_STATUS_MAPPED) ++ return -EPERM; ++ ++ if (res_type == PKA_DEV_RES_TYPE_REG) ++ res_ptr->base = res_base; ++ ++ if (res_type == PKA_DEV_RES_TYPE_MEM) ++ res_ptr->base = shim->mem_res.eip154_base + res_base; ++ ++ res_ptr->size = res_size; ++ res_ptr->type = res_type; ++ res_ptr->name = res_name; ++ res_ptr->status = PKA_DEV_RES_STATUS_UNMAPPED; ++ res_ptr->ioaddr = pka_dev_get_resource_ioaddr(res_ptr->base, ++ shim->shim_id); ++ if (!res_ptr->ioaddr) ++ { ++ if (!request_mem_region(res_ptr->base, res_ptr->size, res_ptr->name)) ++ { ++ PKA_ERROR(PKA_DEV, "failed to get io memory region\n"); ++ return -EPERM; ++ } ++ ++ res_ptr->ioaddr = ioremap(res_ptr->base, res_ptr->size); ++ } ++ ++ res_ptr->status = PKA_DEV_RES_STATUS_MAPPED; ++ ++ if (!res_ptr->ioaddr || pka_dev_add_resource(res_ptr, shim->shim_id)) ++ { ++ PKA_ERROR(PKA_DEV, "unable to map io memory\n"); ++ release_mem_region(res_ptr->base, res_ptr->size); ++ return -ENOMEM; ++ } ++ return ret; ++} ++ ++// Unset PKA device resource config - unmap io memory if needed. ++static void pka_dev_unset_resource_config(pka_dev_shim_t *shim, ++ pka_dev_res_t *res_ptr) ++{ ++ int ret = -EBUSY; ++ ++ if (res_ptr->status != PKA_DEV_RES_STATUS_MAPPED) ++ return; ++ ++ if (res_ptr->ioaddr && ++ ret != pka_dev_put_resource(res_ptr, shim->shim_id)) ++ { ++ iounmap(res_ptr->ioaddr); ++ release_mem_region(res_ptr->base, res_ptr->size); ++ } ++ ++ res_ptr->status = PKA_DEV_RES_STATUS_UNMAPPED; ++} ++ ++int pka_dev_clear_ring_counters(pka_dev_ring_t *ring) ++{ ++ pka_dev_shim_t *shim; ++ pka_dev_res_t *master_seq_ctrl_ptr; ++ void *master_reg_ptr; ++ uint64_t master_reg_base, master_reg_off; ++ ++ shim = ring->shim; ++ master_seq_ctrl_ptr = &shim->resources.master_seq_ctrl; ++ master_reg_base = master_seq_ctrl_ptr->base; ++ master_reg_ptr = master_seq_ctrl_ptr->ioaddr; ++ master_reg_off = pka_dev_get_register_offset(master_reg_base, ++ PKA_MASTER_SEQ_CTRL_ADDR); ++ ++ // push the EIP-154 master controller into reset. ++ pka_dev_io_write(master_reg_ptr, master_reg_off, ++ PKA_MASTER_SEQ_CTRL_RESET_VAL); ++ ++ // clear counters. ++ pka_dev_io_write(master_reg_ptr, master_reg_off, ++ PKA_MASTER_SEQ_CTRL_CLEAR_COUNTERS_VAL); ++ ++ // take the EIP-154 master controller out of reset. ++ pka_dev_io_write(master_reg_ptr, master_reg_off, 0); ++ ++ return 0; ++} ++ ++// Initialize ring. Set ring parameters and configure ring resources. ++// It returns 0 on success, a negative error code on failure. ++static int pka_dev_init_ring(pka_dev_ring_t *ring, uint32_t ring_id, ++ pka_dev_shim_t *shim) ++{ ++ int ret = 0; ++ ++ pka_dev_res_t *ring_info_words_ptr; ++ pka_dev_res_t *ring_counters_ptr; ++ pka_dev_res_t *ring_window_ram_ptr; ++ ++ uint32_t ring_words_off; ++ uint32_t ring_cntrs_off; ++ uint32_t ring_mem_off; ++ uint32_t ring_mem_base; ++ ++ uint32_t shim_ring_id; ++ uint8_t window_ram_split; ++ ++ if (ring->status != PKA_DEV_RING_STATUS_UNDEFINED) ++ { ++ PKA_ERROR(PKA_DEV, "PKA ring must be undefined\n"); ++ return -EPERM; ++ } ++ ++ if (ring_id > PKA_MAX_NUM_RINGS - 1) ++ { ++ PKA_ERROR(PKA_DEV, "invalid ring identifier\n"); ++ return -EINVAL; ++ } ++ ++ ring->ring_id = ring_id; ++ ring->shim = shim; ++ ring->resources_num = PKA_MAX_NUM_RING_RESOURCES; ++ ++ shim_ring_id = ring_id % PKA_MAX_NUM_IO_BLOCK_RINGS; ++ shim->rings[shim_ring_id] = ring; ++ ++ // Configure ring information control/status words resource ++ ring_info_words_ptr = &ring->resources.info_words; ++ ring_words_off = shim_ring_id * PKA_RING_WORDS_SPACING; ++ ring_info_words_ptr->base = ring_words_off + shim->mem_res.eip154_base + ++ PKA_RING_WORDS_ADDR; ++ ring_info_words_ptr->size = PKA_RING_WORDS_SIZE; ++ ring_info_words_ptr->type = PKA_DEV_RES_TYPE_MEM; ++ ring_info_words_ptr->status = PKA_DEV_RES_STATUS_UNMAPPED; ++ ring_info_words_ptr->name = "PKA_RING_INFO"; ++ ++ // Configure ring counters registers resource ++ ring_counters_ptr = &ring->resources.counters; ++ ring_cntrs_off = shim_ring_id * PKA_RING_CNTRS_SPACING; ++ ring_counters_ptr->base = ring_cntrs_off + shim->mem_res.eip154_base + ++ PKA_RING_CNTRS_ADDR; ++ ring_counters_ptr->size = PKA_RING_CNTRS_SIZE; ++ ring_counters_ptr->type = PKA_DEV_RES_TYPE_REG; ++ ring_counters_ptr->status = PKA_DEV_RES_STATUS_UNMAPPED; ++ ring_counters_ptr->name = "PKA_RING_CNTRS"; ++ ++ // Configure ring window RAM resource ++ window_ram_split = shim->window_ram_split; ++ if (window_ram_split == PKA_SHIM_WINDOW_RAM_SPLIT_ENABLED) ++ { ++ ring_mem_off = shim_ring_id * PKA_RING_MEM_1_SPACING; ++ ring_mem_base = ring_mem_off + shim->mem_res.alt_wndw_ram_0_base; ++ } ++ else ++ { ++ ring_mem_off = shim_ring_id * PKA_RING_MEM_0_SPACING; ++ ring_mem_base = ring_mem_off + shim->mem_res.wndw_ram_base; ++ } ++ ++ ring_window_ram_ptr = &ring->resources.window_ram; ++ ring_window_ram_ptr->base = ring_mem_base; ++ ring_window_ram_ptr->size = PKA_RING_MEM_SIZE; ++ ring_window_ram_ptr->type = PKA_DEV_RES_TYPE_MEM; ++ ring_window_ram_ptr->status = PKA_DEV_RES_STATUS_UNMAPPED; ++ ring_window_ram_ptr->name = "PKA_RING_WINDOW"; ++ ++ ring->ring_info = kzalloc(sizeof(pka_dev_hw_ring_info_t), GFP_KERNEL); ++ if (!ring->ring_info) ++ { ++ PKA_ERROR(PKA_DEV, "unable to kmalloc\n"); ++ kfree(ring->ring_info); ++ return -ENOMEM; ++ } ++ ++ mutex_init(&ring->mutex); ++ ring->status = PKA_DEV_RING_STATUS_INITIALIZED; ++ ++ return ret; ++} ++ ++// Release a given Ring. ++static int pka_dev_release_ring(pka_dev_ring_t *ring) ++{ ++ int ret = 0; ++ ++ pka_dev_shim_t *shim; ++ uint32_t shim_ring_id; ++ ++ if (ring->status == PKA_DEV_RING_STATUS_UNDEFINED) ++ return ret; ++ ++ if (ring->status == PKA_DEV_RING_STATUS_BUSY) ++ { ++ PKA_ERROR(PKA_DEV, "PKA ring is busy\n"); ++ return -EBUSY; ++ } ++ ++ shim = ring->shim; ++ ++ if (shim->status == PKA_SHIM_STATUS_RUNNING) ++ { ++ PKA_ERROR(PKA_DEV, "PKA shim is running\n"); ++ return -EPERM; ++ } ++ ++ pka_dev_unset_resource_config(shim, &ring->resources.info_words); ++ pka_dev_unset_resource_config(shim, &ring->resources.counters); ++ pka_dev_unset_resource_config(shim, &ring->resources.window_ram); ++ ++ kfree(ring->ring_info); ++ ++ ring->status = PKA_DEV_RING_STATUS_UNDEFINED; ++ shim_ring_id = ring->ring_id % PKA_MAX_NUM_IO_BLOCK_RINGS; ++ shim->rings[shim_ring_id] = NULL; ++ shim->rings_num--; ++ ++ return ret; ++} ++ ++// Partition the window RAM for a given PKA ring. Here we statically divide ++// the 16K memory region into three partitions: First partition is reserved ++// for command descriptor ring (1K), second partition is reserved for result ++// descriptor ring (1K), and the remaining 14K are reserved for vector data. ++// Through this memroy partition scheme, command/result descriptor rings hold ++// a total of 1KB/64B = 16 descriptors each. The adresses for the rings start ++// at offset 0x3800. Also note that it is possible to have rings full while ++// the vector data can support more data, the opposite can also happen, but ++// it is not suitable. For instance ECC point multiplication requires 8 input ++// vectors and 2 output vectors, a total of 10 vectors. If each vector has a ++// length of 24 words (24x4B = 96B), we can process 14KB/960B = 14 operations ++// which is close to 16 the total descriptors supported by rings. On the other ++// hand, using 12K vector data region, allows to process only 12 operations, ++// while rings can hold 32 descriptors (ring usage is significantly low). ++// For ECDSA verify, we have 12 vectors which require 1152B, with 14KB we can ++// handle 12 operations, against 10 operations with 12KB vector data memory. ++// We believe that the aformentionned memory partition help us to leverage ++// the trade-off between supported descriptors and required vectors. Note ++// that these examples gives approximative values and does not include buffer ++// word padding across vectors. ++// ++// The function also writes the result descriptor rings base addresses, size ++// and type, and initialize the read and write pointers and statistics. It ++// returns 0 on success, a negative error code on failure. ++// ++// This function must be called once per ring, at initialization before any ++// other fonctions are called. ++static int pka_dev_partition_mem(pka_dev_ring_t *ring) ++{ ++ int ret = 0; ++ ++ pka_dev_shim_t *shim; ++ pka_dev_hw_ring_info_t *ring_info; ++ ++ uint32_t ring_mem_base; ++ uint32_t ring_mem_size; ++ uint32_t data_mem_base; ++ uint32_t data_mem_size; ++ ++ uint64_t cmd_desc_ring_base; ++ uint32_t cmd_desc_ring_size; ++ uint64_t rslt_desc_ring_base; ++ uint32_t rslt_desc_ring_size; ++ ++ uint16_t num_cmd_desc; ++ uint16_t host_desc_size; ++ uint8_t ring_in_order; ++ ++ uint64_t window_ram_base; ++ uint64_t window_ram_size; ++ ++ shim = ring->shim; ++ ++ if (!ring->shim || ++ ring->status != PKA_DEV_RING_STATUS_INITIALIZED) ++ return -EPERM; ++ ++ ring_in_order = shim->ring_type; ++ window_ram_base = ring->resources.window_ram.base; ++ window_ram_size = ring->resources.window_ram.size; ++ // Partition ring memory. Give ring pair (cmmd descriptor ring and rslt ++ // descriptor ring) an equal portion of the memory. The cmmd descriptor ++ // ring and result descriptor ring are used as "non-overlapping" ring. ++ // Currently set aside 1/8 of the window RAM for command/result descriptor ++ // rings - giving a total of 1K/64B = 16 descriptors per ring. ++ // The remaining memory is "Data Memory" - i.e. memory to hold the command ++ // operands and results - also called input/output vectors (in all cases ++ // these vectors are just single large integers - often in the range of ++ // hundreds to thousands of bits long). ++ ring_mem_size = PKA_WINDOW_RAM_RING_MEM_SIZE / 2; ++ data_mem_size = PKA_WINDOW_RAM_DATA_MEM_SIZE; ++ data_mem_base = window_ram_base; ++ ring_mem_base = data_mem_base + data_mem_size; ++ ++ num_cmd_desc = ring_mem_size / CMD_DESC_SIZE; ++ host_desc_size = CMD_DESC_SIZE / BYTES_PER_WORD; ++ ++ cmd_desc_ring_size = num_cmd_desc * CMD_DESC_SIZE; ++ rslt_desc_ring_size = cmd_desc_ring_size; ++ ++ ring->num_cmd_desc = num_cmd_desc; ++ ++ // The command and result descriptor rings may be placed at different ++ // (non-overlapping) locations in Window RAM memory space. PKI command ++ // interface: Most of the functionality is defined by the EIP-154 master ++ // firmware on the EIP-154 master controller Sequencer. ++ cmd_desc_ring_base = ring_mem_base; ++ rslt_desc_ring_base = ring_mem_base + cmd_desc_ring_size; ++ ++ cmd_desc_ring_base = ++ PKA_RING_MEM_ADDR(window_ram_base, shim->mem_res.wndw_ram_off_mask, ++ cmd_desc_ring_base, window_ram_size); ++ rslt_desc_ring_base = ++ PKA_RING_MEM_ADDR(window_ram_base, shim->mem_res.wndw_ram_off_mask, ++ rslt_desc_ring_base, window_ram_size); ++ ++ ring_info = ring->ring_info; ++ // Fill ring information. ++ ring_info->cmmd_base = cmd_desc_ring_base; ++ ring_info->rslt_base = rslt_desc_ring_base; ++ ring_info->size = num_cmd_desc - 1; ++ ring_info->host_desc_size = host_desc_size; ++ ring_info->in_order = ring_in_order; ++ ring_info->cmmd_rd_ptr = 0x0; ++ ring_info->rslt_wr_ptr = 0x0; ++ ring_info->cmmd_rd_stats = 0x0; ++ ring_info->rslt_wr_stats = 0x0; ++ ++ return ret; ++} ++ ++// Write the ring base address, ring size and type, and initialize (clear) ++// the read and write pointers and statistics. ++static int pka_dev_write_ring_info(pka_dev_res_t *buffer_ram_ptr, ++ uint8_t ring_id, ++ uint32_t ring_cmmd_base_val, ++ uint32_t ring_rslt_base_val, ++ uint32_t ring_size_type_val) ++{ ++ uint32_t ring_spacing; ++ uint64_t word_off; ++ int ret = 0; ++ ++ if (buffer_ram_ptr->status != PKA_DEV_RES_STATUS_MAPPED || ++ buffer_ram_ptr->type != PKA_DEV_RES_TYPE_MEM) ++ return -EPERM; ++ ++ PKA_DEBUG(PKA_DEV, "Writing ring information control/status words\n"); ++ ++ ring_spacing = ring_id * PKA_RING_WORDS_SPACING; ++ ++ // Write the command ring base address that the EIP-154 ++ // master firmware uses with the command ring read pointer ++ // to get command descriptors from the Host ring. After the ++ // initialization, although the word is writeable it should ++ // be regarded as read-only. ++ word_off = pka_dev_get_word_offset(buffer_ram_ptr->base, ++ RING_CMMD_BASE_0_ADDR + ring_spacing, ++ PKA_BUFFER_RAM_SIZE); ++ pka_dev_io_write(buffer_ram_ptr->ioaddr, word_off, ring_cmmd_base_val); ++ ++ // Write the result ring base address that the EIP-154 ++ // master firmware uses with the result ring write pointer ++ // to put the result descriptors in the Host ring. After ++ // the initialization, although the word is writeable it ++ // should be regarded as read-only. ++ word_off = pka_dev_get_word_offset(buffer_ram_ptr->base, ++ RING_RSLT_BASE_0_ADDR + ring_spacing, ++ PKA_BUFFER_RAM_SIZE); ++ pka_dev_io_write(buffer_ram_ptr->ioaddr, word_off, ring_rslt_base_val); ++ ++ // Write the ring size (number of descriptors), the size of ++ // the descriptor and the result reporting scheme. After the ++ // initialization, although the word is writeable it should ++ // be regarded as read-only. ++ word_off = pka_dev_get_word_offset(buffer_ram_ptr->base, ++ RING_SIZE_TYPE_0_ADDR + ring_spacing, ++ PKA_BUFFER_RAM_SIZE); ++ pka_dev_io_write(buffer_ram_ptr->ioaddr, word_off, ring_size_type_val); ++ ++ // Write the command and result ring indices that the EIP-154 ++ // master firmware uses. This word should be written with zero ++ // when the ring information is initialized. After the ++ // initialization, although the word is writeable it should be ++ // regarded as read-only. ++ word_off = pka_dev_get_word_offset(buffer_ram_ptr->base, ++ RING_RW_PTRS_0_ADDR + ring_spacing, ++ PKA_BUFFER_RAM_SIZE); ++ pka_dev_io_write(buffer_ram_ptr->ioaddr, word_off, 0); ++ ++ // Write the ring statistics (two 16-bit counters, one for ++ // commands and one for results) from EIP-154 master firmware ++ // point of view. This word should be written with zero when ++ // the ring information is initialized. After the initializa- ++ // -tion, although the word is writeable it should be regarded ++ // as read-only. ++ word_off = pka_dev_get_word_offset(buffer_ram_ptr->base, ++ RING_RW_STAT_0_ADDR + ring_spacing, ++ PKA_BUFFER_RAM_SIZE); ++ pka_dev_io_write(buffer_ram_ptr->ioaddr, word_off, 0); ++ ++ return ret; ++} ++ ++// Set up the control/status words. Upon a PKI command the EIP-154 master ++// firmware will read and partially update the ring information. ++static int pka_dev_set_ring_info(pka_dev_ring_t *ring) ++{ ++ int ret = 0; ++ ++ pka_dev_shim_t *shim; ++ pka_dev_hw_ring_info_t *ring_info; ++ pka_dev_res_t *buffer_ram_ptr; ++ ++ uint32_t ring_cmmd_base_val; ++ uint32_t ring_rslt_base_val; ++ uint32_t ring_size_type_val; ++ ++ uint8_t ring_id; ++ ++ shim = ring->shim; ++ // Ring info configuration MUST be done when the PKA ring ++ // is initilaized. ++ if ((shim->status != PKA_SHIM_STATUS_INITIALIZED && ++ shim->status != PKA_SHIM_STATUS_RUNNING && ++ shim->status != PKA_SHIM_STATUS_STOPPED) || ++ ring->status != PKA_DEV_RING_STATUS_INITIALIZED) ++ return -EPERM; ++ ++ ring_id = ring->ring_id % PKA_MAX_NUM_IO_BLOCK_RINGS; ++ ++ // Partition ring memory. ++ ret = pka_dev_partition_mem(ring); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "failed to initialize ring memory\n"); ++ return ret; ++ } ++ ++ // Fill ring infomation. ++ ring_info = ring->ring_info; ++ ++ ring_cmmd_base_val = ring_info->cmmd_base; ++ ring_rslt_base_val = ring_info->rslt_base; ++ ++ ring_size_type_val = (ring_info->in_order & 0x0001) << 31; ++ ring_size_type_val |= (ring_info->host_desc_size & 0x03FF) << 18; ++ ring_size_type_val |= (ring->num_cmd_desc - 1) & 0xFFFF; ++ ++ buffer_ram_ptr = &shim->resources.buffer_ram; ++ // Write ring information status/control words in the PKA Buffer RAM ++ ret = pka_dev_write_ring_info(buffer_ram_ptr, ring_id, ring_cmmd_base_val, ++ ring_rslt_base_val, ring_size_type_val); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "failed to wirte ring information\n"); ++ return ret; ++ } ++ ++ ring->status = PKA_DEV_RING_STATUS_READY; ++ ++ return ret; ++} ++ ++// Create shim. Set shim parameters and configure shim resources. ++// It returns 0 on success, a negative error code on failure. ++static int pka_dev_create_shim(pka_dev_shim_t *shim, uint32_t shim_id, ++ uint8_t split, struct pka_dev_mem_res *mem_res) ++{ ++ int ret = 0; ++ ++ uint64_t reg_base; ++ uint64_t reg_size; ++ ++ if (shim->status == PKA_SHIM_STATUS_CREATED) ++ return ret; ++ ++ if (shim->status != PKA_SHIM_STATUS_UNDEFINED) ++ { ++ PKA_ERROR(PKA_DEV, "PKA device must be undefined\n"); ++ return -EPERM; ++ } ++ ++ if (shim_id > PKA_MAX_NUM_IO_BLOCKS - 1) ++ { ++ PKA_ERROR(PKA_DEV, "invalid shim identifier\n"); ++ return -EINVAL; ++ } ++ ++ shim->shim_id = shim_id; ++ shim->mem_res = *mem_res; ++ ++ if (split) ++ shim->window_ram_split = PKA_SHIM_WINDOW_RAM_SPLIT_ENABLED; ++ else ++ shim->window_ram_split = PKA_SHIM_WINDOW_RAM_SPLIT_DISABLED; ++ ++ shim->ring_type = PKA_RING_TYPE_IN_ORDER; ++ shim->ring_priority = PKA_RING_OPTIONS_PRIORITY; ++ shim->rings_num = PKA_MAX_NUM_IO_BLOCK_RINGS; ++ shim->rings = kzalloc(sizeof(pka_dev_ring_t) * shim->rings_num, ++ GFP_KERNEL); ++ if (!shim->rings) ++ { ++ PKA_ERROR(PKA_DEV, "unable to kmalloc\n"); ++ return -ENOMEM; ++ } ++ ++ // Set PKA device Buffer RAM config ++ ret = pka_dev_set_resource_config(shim, &shim->resources.buffer_ram, ++ PKA_BUFFER_RAM_BASE, ++ PKA_BUFFER_RAM_SIZE, ++ PKA_DEV_RES_TYPE_MEM, ++ "PKA_BUFFER_RAM"); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "unable to set Buffer RAM config\n"); ++ return ret; ++ } ++ ++ // Set PKA device Master Program RAM config ++ ret = pka_dev_set_resource_config(shim, &shim->resources.master_prog_ram, ++ PKA_MASTER_PROG_RAM_BASE, ++ PKA_MASTER_PROG_RAM_SIZE, ++ PKA_DEV_RES_TYPE_MEM, ++ "PKA_MASTER_PROG_RAM"); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "unable to set Master Program RAM config\n"); ++ return ret; ++ } ++ ++ // Set PKA device Master Controller register ++ reg_size = PAGE_SIZE; ++ reg_base = pka_dev_get_register_base(shim->mem_res.eip154_base, ++ PKA_MASTER_SEQ_CTRL_ADDR); ++ ret = pka_dev_set_resource_config(shim, &shim->resources.master_seq_ctrl, ++ reg_base, reg_size, ++ PKA_DEV_RES_TYPE_REG, ++ "PKA_MASTER_SEQ_CTRL"); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "unable to set Master Controller register " ++ "config\n"); ++ return ret; ++ } ++ ++ // Set PKA device AIC registers ++ reg_size = PAGE_SIZE; ++ reg_base = pka_dev_get_register_base(shim->mem_res.eip154_base, ++ AIC_POL_CTRL_ADDR); ++ ret = pka_dev_set_resource_config(shim, &shim->resources.aic_csr, ++ reg_base, reg_size, ++ PKA_DEV_RES_TYPE_REG, ++ "PKA_AIC_CSR"); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "unable to set AIC registers config\n"); ++ return ret; ++ } ++ ++ // Set PKA device TRNG registers ++ reg_size = PAGE_SIZE; ++ reg_base = pka_dev_get_register_base(shim->mem_res.eip154_base, ++ TRNG_OUTPUT_0_ADDR); ++ ret = pka_dev_set_resource_config(shim, &shim->resources.trng_csr, ++ reg_base, reg_size, ++ PKA_DEV_RES_TYPE_REG, ++ "PKA_TRNG_CSR"); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "unable to setup the TRNG\n"); ++ return ret; ++ } ++ ++ // Set PKA device 'glue' logic registers ++ reg_size = PAGE_SIZE; ++ reg_base = pka_dev_get_register_base(shim->mem_res.csr_base, ++ PKA_INT_MASK_ADDR); ++ ret = pka_dev_set_resource_config(shim, &shim->resources.ext_csr, ++ reg_base, reg_size, ++ PKA_DEV_RES_TYPE_REG, ++ "PKA_EXT_CSR"); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "unable to setup the MiCA specific registers\n"); ++ return ret; ++ } ++ ++ shim->status = PKA_SHIM_STATUS_CREATED; ++ ++ return ret; ++} ++ ++// Delete shim and unset shim resources. ++static int pka_dev_delete_shim(pka_dev_shim_t *shim) ++{ ++ int ret = 0; ++ pka_dev_res_t *res_buffer_ram, *res_master_prog_ram; ++ pka_dev_res_t *res_master_seq_ctrl, *res_aic_csr, *res_trng_csr; ++ ++ PKA_DEBUG(PKA_DEV, "PKA device delete shim\n"); ++ ++ if (shim->status == PKA_SHIM_STATUS_UNDEFINED) ++ return ret; ++ ++ if (shim->status != PKA_SHIM_STATUS_FINALIZED && ++ shim->status != PKA_SHIM_STATUS_CREATED) ++ { ++ PKA_ERROR(PKA_DEV, "PKA device status must be finalized\n"); ++ return -EPERM; ++ } ++ ++ res_buffer_ram = &shim->resources.buffer_ram; ++ res_master_prog_ram = &shim->resources.master_prog_ram; ++ res_master_seq_ctrl = &shim->resources.master_seq_ctrl; ++ res_aic_csr = &shim->resources.aic_csr; ++ res_trng_csr = &shim->resources.trng_csr; ++ ++ pka_dev_unset_resource_config(shim, res_buffer_ram); ++ pka_dev_unset_resource_config(shim, res_master_prog_ram); ++ pka_dev_unset_resource_config(shim, res_master_seq_ctrl); ++ pka_dev_unset_resource_config(shim, res_aic_csr); ++ pka_dev_unset_resource_config(shim, res_trng_csr); ++ ++ kfree(shim->rings); ++ ++ shim->status = PKA_SHIM_STATUS_UNDEFINED; ++ ++ return ret; ++} ++ ++static int pka_dev_config_aic_interrupts(pka_dev_res_t *aic_csr_ptr) ++{ ++ int ret = 0; ++ ++ uint64_t csr_reg_base, csr_reg_off; ++ void *csr_reg_ptr; ++ ++ if (aic_csr_ptr->status != PKA_DEV_RES_STATUS_MAPPED || ++ aic_csr_ptr->type != PKA_DEV_RES_TYPE_REG) ++ return -EPERM; ++ ++ PKA_DEBUG(PKA_DEV, "configure the AIC so that all interrupts " ++ "are properly recognized\n"); ++ ++ csr_reg_base = aic_csr_ptr->base; ++ csr_reg_ptr = aic_csr_ptr->ioaddr; ++ ++ // Configure the signal polarity for each interrupt. ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, AIC_POL_CTRL_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_AIC_POL_CTRL_REG_VAL); ++ ++ // Configure the signal type for each interrupt ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, AIC_TYPE_CTRL_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_AIC_TYPE_CTRL_REG_VAL); ++ ++ // Set the enable control register ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, AIC_ENABLE_CTRL_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_AIC_ENABLE_CTRL_REG_VAL); ++ ++ // Set the enabled status register ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, AIC_ENABLED_STAT_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_AIC_ENABLE_STAT_REG_VAL); ++ ++ // *TBD* Write PKA_INT_MASK_RESET with 1's for each interrupt bit ++ // to allow them to propagate out the interrupt controller. ++ // EIP-154 interrupts can still be programmed and observed via polling ++ // regardless of whether PKA_INT_MASK is masking out the interrupts or ++ // not. The mask is for system propagation, i.e. propagate to the GIC. ++ // Bit positions are as follows: ++ // Bit 10 - parity_error_irq (non EIP-154 interrupt) ++ // Bit 9 - trng_irq ++ // Bit 8 - pka_master_irq ++ // Bits 7:4 - pka_queue_*_result_irq ++ // Bits 3:0 - pka_queue_*_empty_irq ++ ++ return ret; ++} ++ ++static int pka_dev_load_image(pka_dev_res_t *res_ptr, const uint32_t *data_buf, ++ uint32_t size) ++{ ++ uint64_t data_rd; ++ int mismatches; ++ int i, j, ret = 0; ++ ++ if (res_ptr->status != PKA_DEV_RES_STATUS_MAPPED || ++ res_ptr->type != PKA_DEV_RES_TYPE_MEM) ++ return -EPERM; ++ ++ // Note that the image size is in word of 4 bytes and memory 'writes' ++ // are 8 bytes aligned, thus the memory start address and end address ++ // are shifted. ++ if (res_ptr->size < (size * BYTES_PER_WORD) << 1) ++ { ++ PKA_ERROR(PKA_DEV, "image size greater than memory size\n"); ++ return -EINVAL; ++ } ++ ++ for (i = 0, j = 0; i < size; i++, j += BYTES_PER_DOUBLE_WORD) ++ pka_dev_io_write(res_ptr->ioaddr, j, ++ (uint64_t) data_buf[i]); ++ ++ mismatches = 0; ++ PKA_DEBUG(PKA_DEV, "PKA DEV: verifying image (%u words)\n", size); ++ for (i = 0, j = 0; i < size; i++, j += BYTES_PER_DOUBLE_WORD) ++ { ++ data_rd = pka_dev_io_read(res_ptr->ioaddr, j); ++ if (data_rd != (uint64_t) data_buf[i]) ++ { ++ mismatches += 1; ++ PKA_DEBUG(PKA_DEV, "error while loading image: " ++ "addr:0x%llx expected data: 0x%x actual data: 0x%llx\n", ++ res_ptr->base + j, ++ data_buf[i], data_rd); ++ } ++ } ++ ++ if (mismatches > 0) ++ { ++ PKA_PANIC(PKA_DEV, "error while loading image: mismatches: %d\n", ++ mismatches); ++ return -EAGAIN; ++ } ++ ++ return ret; ++} ++ ++static int ++pka_dev_config_master_seq_controller(pka_dev_shim_t *shim, ++ pka_dev_res_t *master_seq_ctrl_ptr) ++{ ++ pka_dev_res_t *aic_csr_ptr, *master_prog_ram; ++ void *aic_reg_ptr, *master_reg_ptr; ++ ++ uint64_t aic_reg_base, aic_reg_off; ++ uint64_t master_reg_base, master_reg_off; ++ ++ const uint32_t *boot_img_ptr, *master_img_ptr; ++ uint32_t boot_img_size, master_img_size; ++ ++ uint32_t pka_master_irq; ++ ++ uint64_t timer; ++ uint8_t status_bits; ++ uint8_t shim_fw_id; ++ int ret = 0; ++ ++ if (master_seq_ctrl_ptr->status != PKA_DEV_RES_STATUS_MAPPED || ++ master_seq_ctrl_ptr->type != PKA_DEV_RES_TYPE_REG) ++ return -EPERM; ++ ++ master_reg_base = master_seq_ctrl_ptr->base; ++ master_reg_ptr = master_seq_ctrl_ptr->ioaddr; ++ master_reg_off = pka_dev_get_register_offset(master_reg_base, ++ PKA_MASTER_SEQ_CTRL_ADDR); ++ ++ PKA_DEBUG(PKA_DEV, "push the EIP-154 master controller into reset\n"); ++ pka_dev_io_write(master_reg_ptr, master_reg_off, ++ PKA_MASTER_SEQ_CTRL_RESET_VAL); ++ ++ shim_fw_id = pka_firmware_get_id(); ++ ++ // Load boot image into PKA_MASTER_PROG_RAM ++ boot_img_size = pka_firmware_array[shim_fw_id].boot_img_size; ++ PKA_DEBUG(PKA_DEV, "loading boot image (%d words)\n", boot_img_size); ++ ++ boot_img_ptr = pka_firmware_array[shim_fw_id].boot_img; ++ ret = pka_dev_load_image(&shim->resources.master_prog_ram, ++ boot_img_ptr, boot_img_size); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "failed to load boot image\n"); ++ return ret; ++ } ++ ++ PKA_DEBUG(PKA_DEV, "take the EIP-154 master controller out of reset\n"); ++ pka_dev_io_write(master_reg_ptr, master_reg_off, 0); ++ ++ // Poll for 'pka_master_irq' bit in AIC_ENABLED_STAT register to indicate ++ // sequencer is initialized ++ aic_csr_ptr = &shim->resources.aic_csr; ++ if (aic_csr_ptr->status != PKA_DEV_RES_STATUS_MAPPED || ++ aic_csr_ptr->type != PKA_DEV_RES_TYPE_REG) ++ return -EPERM; ++ ++ aic_reg_base = aic_csr_ptr->base; ++ aic_reg_ptr = aic_csr_ptr->ioaddr; ++ aic_reg_off = pka_dev_get_register_offset(aic_reg_base, ++ AIC_ENABLED_STAT_ADDR); ++ ++ pka_master_irq = 0; ++ PKA_DEBUG(PKA_DEV, "poll for 'pka_master_irq'\n"); ++ timer = pka_dev_timer_start(100000); // 100 msec ++ while (pka_master_irq == 0) ++ { ++ pka_master_irq |= pka_dev_io_read(aic_reg_ptr, aic_reg_off) ++ & PKA_AIC_ENABLED_STAT_MASTER_IRQ_MASK; ++ if (pka_dev_timer_done(timer)) ++ { ++ //PKA_PANIC(PKA_DEV, "failed to load firmware\n"); ++ return -EAGAIN; ++ } ++ } ++ PKA_DEBUG(PKA_DEV, "'pka_master_irq' is active\n"); ++ ++ // Verify that the EIP-154 boot firmware has finished without errors ++ status_bits = (uint8_t)((pka_dev_io_read(master_reg_ptr, ++ master_reg_off) >> PKA_MASTER_SEQ_CTRL_MASTER_IRQ_BIT) ++ & 0xff); ++ if (status_bits != PKA_MASTER_SEQ_CTRL_STATUS_BYTE) ++ { ++ // If the error indication (bit [15]) is set, ++ // the EIP-154 boot firmware encountered an error and is stopped. ++ if ((status_bits >> (PKA_MASTER_SEQ_CTRL_MASTER_IRQ_BIT - 1)) == 1) ++ { ++ PKA_ERROR(PKA_DEV, ++ "boot firmware encountered an error 0x%x and is stopped\n", ++ status_bits); ++ return -EAGAIN; ++ } ++ PKA_DEBUG(PKA_DEV, "boot firmware in progress %d", status_bits); ++ } ++ PKA_DEBUG(PKA_DEV, "boot firmware has finished successfully\n"); ++ ++ PKA_DEBUG(PKA_DEV, "push the EIP-154 master controller into reset\n"); ++ pka_dev_io_write(master_reg_ptr, master_reg_off, ++ PKA_MASTER_SEQ_CTRL_RESET_VAL); ++ ++ // Load Master image into PKA_MASTER_PROG_RAM ++ master_img_size = pka_firmware_array[shim_fw_id].master_img_size; ++ PKA_DEBUG(PKA_DEV, "loading master image (%d words)\n", ++ master_img_size); ++ master_prog_ram = &shim->resources.master_prog_ram; ++ master_img_ptr = pka_firmware_array[shim_fw_id].master_img; ++ ret = pka_dev_load_image(master_prog_ram, master_img_ptr, ++ master_img_size); ++ if (ret) ++ { ++ pr_err("PKA DEV: failed to load master image\n"); ++ return ret; ++ } ++ ++ PKA_DEBUG(PKA_DEV, "take the EIP-154 master controller out of reset\n"); ++ pka_dev_io_write(master_reg_ptr, master_reg_off, 0); ++ ++ return ret; ++} ++ ++// Configure ring options. ++static int pka_dev_config_ring_options(pka_dev_res_t *buffer_ram_ptr, ++ uint32_t rings_num, uint8_t ring_priority) ++{ ++ uint64_t control_word; ++ uint64_t word_off; ++ int ret = 0; ++ ++ if (buffer_ram_ptr->status != PKA_DEV_RES_STATUS_MAPPED || ++ buffer_ram_ptr->type != PKA_DEV_RES_TYPE_MEM) ++ return -EPERM; ++ ++ if (rings_num > PKA_MAX_NUM_RINGS || ++ rings_num < 1) ++ { ++ PKA_ERROR(PKA_DEV, "invalid rings number\n"); ++ return -EINVAL; ++ } ++ ++ PKA_DEBUG(PKA_DEV, "Configure PKA ring options control word\n"); ++ ++ // Write PKA_RING_OPTIONS control word located in the PKA_BUFFER_RAM. The ++ // value of this word is determined by the PKA I/O block (Shim). Set the ++ // number of implemented command/result ring pairs that is available in ++ // this EIP-154, encoded as binary value, which is 4. ++ control_word = (uint64_t) 0x0; ++ control_word |= ring_priority & 0xff; ++ control_word |= ((rings_num - 1) << 8) & 0xff00; ++ control_word |= (PKA_RING_OPTIONS_SIGNATURE_BYTE << 24) & 0xff000000; ++ word_off = pka_dev_get_word_offset(buffer_ram_ptr->base, ++ PKA_RING_OPTIONS_ADDR, PKA_BUFFER_RAM_SIZE); ++ pka_dev_io_write(buffer_ram_ptr->ioaddr, word_off, control_word); ++ ++ return ret; ++} ++ ++static int pka_dev_config_trng_clk(pka_dev_res_t *aic_csr_ptr) ++{ ++ int ret = 0; ++ ++ uint64_t csr_reg_base, csr_reg_off; ++ uint64_t timer; ++ uint32_t trng_clk_en = 0; ++ void *csr_reg_ptr; ++ ++ if (aic_csr_ptr->status != PKA_DEV_RES_STATUS_MAPPED || ++ aic_csr_ptr->type != PKA_DEV_RES_TYPE_REG) ++ return -EPERM; ++ ++ PKA_DEBUG(PKA_DEV, "Turn on TRNG clock\n"); ++ ++ csr_reg_base = aic_csr_ptr->base; ++ csr_reg_ptr = aic_csr_ptr->ioaddr; ++ ++ // Enable the TRNG clock in PKA_CLK_FORCE. ++ // In general, this register should be left in its default state of all ++ // zeroes! Only when the TRNG is directly controlled via the Host slave ++ // interface, the engine needs to be turned on using the ’trng_clk_on’ ++ // bit in this register. In case the TRNG is controlled via internal ++ // firmware, this is not required. ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, PKA_CLK_FORCE_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_CLK_FORCE_TRNG_ON); ++ // Check whether the system clock for TRNG engine is enabled. The clock ++ // MUST be running to provide access to the TRNG. ++ timer = pka_dev_timer_start(100000); // 100 msec ++ while (trng_clk_en == 0) ++ { ++ trng_clk_en |= pka_dev_io_read(csr_reg_ptr, csr_reg_off) ++ & PKA_CLK_FORCE_TRNG_ON; ++ if (pka_dev_timer_done(timer)) ++ { ++ PKA_DEBUG(PKA_DEV, "Failed to enable TRNG clock\n"); ++ return -EAGAIN; ++ } ++ } ++ PKA_DEBUG(PKA_DEV, "'trng_clk_on' is enabled\n"); ++ ++ return ret; ++} ++ ++static int pka_dev_trng_wait_test_ready(void *csr_reg_ptr, uint64_t csr_reg_base) ++{ ++ uint64_t csr_reg_off, timer, test_ready, csr_reg_val; ++ ++ test_ready = 0; ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_STATUS_ADDR); ++ timer = pka_dev_timer_start(1000000); // 1000 ms ++ ++ while (!test_ready) ++ { ++ csr_reg_val = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ test_ready = csr_reg_val & PKA_TRNG_STATUS_TEST_READY; ++ ++ if (pka_dev_timer_done(timer)) ++ { ++ PKA_DEBUG(PKA_DEV, "TRNG: TEST ready timer done, 0x%llx\n", csr_reg_val); ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++static int pka_dev_trng_enable_test(void *csr_reg_ptr, uint64_t csr_reg_base, ++ uint32_t test) ++{ ++ uint64_t csr_reg_val, csr_reg_off; ++ ++ // Set the ‘test_mode’ bit in the TRNG_CONTROL register and the ++ // ‘test_known_noise’ bit in the TRNG_TEST register – this will ++ // immediately set the ‘test_ready’ bit (in the TRNG_STATUS register) ++ // to indicate that data can be written. It will also reset the ++ // ‘monobit test’, ‘run test’ and ‘poker test’ circuits to their ++ // initial states. Note that the TRNG need not be enabled for this ++ // test. ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR); ++ csr_reg_val = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, ++ csr_reg_val | PKA_TRNG_CONTROL_TEST_MODE); ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_TEST_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, test); ++ ++ // Wait until the 'test_ready' bit is set ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_STATUS_ADDR); ++ do ++ { ++ csr_reg_val = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ } while((csr_reg_val & PKA_TRNG_STATUS_TEST_READY) == 0); ++ ++ // Check whether the 'monobit test', 'run test' and 'poker test' ++ // are reset. ++ if (csr_reg_val & (PKA_TRNG_STATUS_MONOBIT_FAIL ++ | PKA_TRNG_STATUS_RUN_FAIL ++ | PKA_TRNG_STATUS_POKER_FAIL)) ++ { ++ PKA_ERROR(PKA_DEV, "Test bits aren't reset, TRNG_STATUS:0x%llx\n", ++ csr_reg_val); ++ return -EAGAIN; ++ } ++ ++ // Set 'stall_run_poker' bit to allow inspecting the state of the ++ // result counters which would otherwise be reset immediately for ++ // the next 20,000 bits block to test. ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_ALARMCNT_ADDR); ++ csr_reg_val = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, ++ csr_reg_val | PKA_TRNG_ALARMCNT_STALL_RUN_POKER); ++ ++ return 0; ++} ++ ++static int pka_dev_trng_test_circuits(void *csr_reg_ptr, uint64_t csr_reg_base, ++ uint64_t datal, uint64_t datah, ++ int count, uint8_t add_half, ++ uint64_t *monobit_fail_cnt, ++ uint64_t *run_fail_cnt, ++ uint64_t *poker_fail_cnt) ++{ ++ uint64_t status, csr_reg_off; ++ int test_idx, error; ++ ++ if (monobit_fail_cnt == NULL || run_fail_cnt == NULL || poker_fail_cnt == NULL) ++ return -EINVAL; ++ ++ error = 0; ++ ++ for (test_idx = 0; test_idx < count; test_idx++) ++ { ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_RAW_L_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, datal); ++ ++ if (add_half) ++ { ++ if (test_idx < count - 1) ++ { ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_RAW_H_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, datah); ++ } ++ } ++ else ++ { ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_RAW_H_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, datah); ++ } ++ ++ // Wait until the ‘test_ready’ bit in the TRNG_STATUS register ++ // becomes ‘1’ again, signaling readiness for the next 64 bits ++ // of test data. At this point, the previous test data has ++ // been handled so the counter states can be inspected. ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_STATUS_ADDR); ++ do ++ { ++ status = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ } while((status & PKA_TRNG_STATUS_TEST_READY) == 0); ++ ++ // Check test status bits. ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_INTACK_ADDR); ++ if (status & PKA_TRNG_STATUS_MONOBIT_FAIL) ++ { ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_STATUS_MONOBIT_FAIL); ++ *monobit_fail_cnt += 1; ++ } ++ else if (status & PKA_TRNG_STATUS_RUN_FAIL) ++ { ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_STATUS_RUN_FAIL); ++ *run_fail_cnt += 1; ++ } ++ else if (status & PKA_TRNG_STATUS_POKER_FAIL) ++ { ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_STATUS_POKER_FAIL); ++ *poker_fail_cnt += 1; ++ } ++ ++ } ++ ++ error = (*monobit_fail_cnt || *poker_fail_cnt || *run_fail_cnt) ? -EIO : 0; ++ ++ return error; ++} ++ ++static void pka_dev_trng_disable_test(void *csr_reg_ptr, uint64_t csr_reg_base) ++{ ++ uint64_t status, val, csr_reg_off; ++ ++ // When done, clear the ‘test_known_noise’ bit in the TRNG_TEST ++ // register (will immediately clear the ‘test_ready’ bit in the ++ // TRNG_STATUS register and reset the ‘monobit test’, ‘run test’ ++ // and ‘poker test’ circuits) and clear the ‘test_mode’ bit in ++ // the TRNG_CONTROL register. ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_TEST_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0); ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_STATUS_ADDR); ++ status = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ ++ if (status & PKA_TRNG_STATUS_TEST_READY) ++ PKA_PRINT(PKA_DEV, "Warning: Test ready bit is still set\n"); ++ ++ if (status & (PKA_TRNG_STATUS_MONOBIT_FAIL ++ | PKA_TRNG_STATUS_RUN_FAIL ++ | PKA_TRNG_STATUS_POKER_FAIL)) ++ PKA_PRINT(PKA_DEV, ++ "Warning: Test bits are still set, TRNG_STATUS:0x%llx\n", status); ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR); ++ val = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, ++ (val & ~PKA_TRNG_STATUS_TEST_READY)); ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_ALARMCNT_ADDR); ++ val = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, ++ (val & ~PKA_TRNG_ALARMCNT_STALL_RUN_POKER)); ++ ++ return; ++} ++ ++static int pka_dev_trng_test_known_answer_basic(void *csr_reg_ptr, ++ uint64_t csr_reg_base) ++{ ++ int ret, cnt_idx, cnt_off; ++ uint64_t monobit_fail_cnt, run_fail_cnt, poker_fail_cnt, monobit_cnt; ++ uint64_t poker_cnt[4], csr_reg_off; ++ uint64_t poker_test_exp_cnt[4] = { ++ 0x20f42bf4, 0xaf415f4, 0xf4f4fff4, 0xfff4f4f4 ++ }; ++ ++ PKA_DEBUG(PKA_DEV, "Run known-answer test circuits\n"); ++ ++ monobit_fail_cnt = 0; ++ run_fail_cnt = 0; ++ poker_fail_cnt = 0; ++ ++ ret = pka_dev_trng_enable_test(csr_reg_ptr, csr_reg_base, ++ PKA_TRNG_TEST_KNOWN_NOISE); ++ if (ret) ++ return ret; ++ ++ ret = pka_dev_trng_test_circuits(csr_reg_ptr, csr_reg_base, 0x11111333, ++ 0x3555779f, 11, 0, &monobit_fail_cnt, &run_fail_cnt, ++ &poker_fail_cnt); ++ ++ ret |= pka_dev_trng_test_circuits(csr_reg_ptr, csr_reg_base, 0x01234567, ++ 0x89abcdef, 302, 1, &monobit_fail_cnt, &run_fail_cnt, ++ &poker_fail_cnt); ++ ++ PKA_DEBUG(PKA_DEV, "monobit_fail_cnt : 0x%llx\n", monobit_fail_cnt); ++ PKA_DEBUG(PKA_DEV, "poker_fail_cnt : 0x%llx\n", poker_fail_cnt); ++ PKA_DEBUG(PKA_DEV, "run_fail_cnt : 0x%llx\n", run_fail_cnt); ++ ++ for (cnt_idx = 0, cnt_off = 0; cnt_idx < 4; cnt_idx++, cnt_off += 8) ++ { ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ (TRNG_POKER_3_0_ADDR + cnt_off)); ++ poker_cnt[cnt_idx] = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ } ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_MONOBITCNT_ADDR); ++ monobit_cnt = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ ++ if (!ret) ++ { ++ if (memcmp(poker_cnt, poker_test_exp_cnt, sizeof(poker_test_exp_cnt))) ++ { ++ PKA_DEBUG(PKA_DEV, "invalid poker counters!\n"); ++ ret = -EIO; ++ } ++ ++ if (monobit_cnt != 9978) ++ { ++ PKA_DEBUG(PKA_DEV, "invalid sum of squares!\n"); ++ ret = -EIO; ++ } ++ } ++ ++ pka_dev_trng_disable_test(csr_reg_ptr, csr_reg_base); ++ ++ return ret; ++} ++ ++static int pka_dev_trng_test_known_answer_poker_fail(void *csr_reg_ptr, ++ uint64_t csr_reg_base) ++{ ++ uint64_t monobit_fail_cnt, run_fail_cnt, poker_fail_cnt; ++ int ret; ++ ++ monobit_fail_cnt = 0; ++ run_fail_cnt = 0; ++ poker_fail_cnt = 0; ++ ++ PKA_DEBUG(PKA_DEV, "Run known-answer test circuits (poker fail)\n"); ++ ++ pka_dev_trng_enable_test(csr_reg_ptr, csr_reg_base, ++ PKA_TRNG_TEST_KNOWN_NOISE); ++ ++ // Ignore the return value here as it is expected that poker test should ++ // fail. Check failure counts thereafter to assert only poker test has failed. ++ pka_dev_trng_test_circuits(csr_reg_ptr, csr_reg_base, 0xffffffff, ++ 0xffffffff, 11, 0, &monobit_fail_cnt, &run_fail_cnt, &poker_fail_cnt); ++ ++ PKA_DEBUG(PKA_DEV, "monobit_fail_cnt : 0x%llx\n", monobit_fail_cnt); ++ PKA_DEBUG(PKA_DEV, "poker_fail_cnt : 0x%llx\n", poker_fail_cnt); ++ PKA_DEBUG(PKA_DEV, "run_fail_cnt : 0x%llx\n", run_fail_cnt); ++ ++ if (poker_fail_cnt && !run_fail_cnt && !monobit_fail_cnt) ++ ret = 0; ++ else ++ ret = -EIO; ++ ++ pka_dev_trng_disable_test(csr_reg_ptr, csr_reg_base); ++ ++ return ret; ++} ++ ++static int pka_dev_trng_test_unknown_answer(void *csr_reg_ptr, ++ uint64_t csr_reg_base) ++{ ++ uint64_t datal, datah, csr_reg_off; ++ int ret, test_idx; ++ ++ datah = 0; ++ datal = 0; ++ ret = 0; ++ ++ PKA_DEBUG(PKA_DEV, "Run unknown-answer self test\n"); ++ ++ // First reset, the RAW registers. ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_RAW_L_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0); ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_RAW_H_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0); ++ ++ // There is a small probability for this test to fail, ++ // So run the test 10 times, if it succeeds once then ++ // assume that the test passed. ++ for (test_idx = 0; test_idx < 10; test_idx++) ++ { ++ pka_dev_trng_enable_test(csr_reg_ptr, csr_reg_base, PKA_TRNG_TEST_NOISE); ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_RAW_L_ADDR); ++ datal = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_RAW_H_ADDR); ++ datah = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ ++ PKA_DEBUG(PKA_DEV, "datal=0x%llx\n", datal); ++ PKA_DEBUG(PKA_DEV, "datah=0x%llx\n", datah); ++ ++ if (!datah && !datal) ++ { ++ ret = -EIO; ++ } ++ else ++ { ++ ret = 0; ++ break; ++ } ++ ++ pka_dev_trng_disable_test(csr_reg_ptr, csr_reg_base); ++ } ++ ++ return ret; ++} ++ ++// Test TRNG ++static int pka_dev_test_trng(void *csr_reg_ptr, uint64_t csr_reg_base) ++{ ++ int ret; ++ ++ ret = 0; ++ ++ ret = pka_dev_trng_test_known_answer_basic(csr_reg_ptr, csr_reg_base); ++ if (ret) ++ goto exit; ++ ++ ret = pka_dev_trng_test_known_answer_poker_fail(csr_reg_ptr, csr_reg_base); ++ if (ret) ++ goto exit; ++ ++ ret = pka_dev_trng_test_unknown_answer(csr_reg_ptr, csr_reg_base); ++ if (ret) ++ goto exit; ++ ++exit: ++ return ret; ++} ++ ++static void pka_dev_trng_write_ps_ai_str(void *csr_reg_ptr, ++ uint64_t csr_reg_base, ++ uint32_t input_str[]) ++{ ++ uint64_t csr_reg_off; ++ int i; ++ ++ for (i = 0; i < PKA_TRNG_PS_AI_REG_COUNT; i++) ++ { ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_PS_AI_0_ADDR + (i * 0x8)); ++ ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, input_str[i]); ++ } ++} ++ ++static void pka_dev_trng_drbg_generate(void *csr_reg_ptr, uint64_t csr_reg_base) ++{ ++ uint64_t csr_reg_off; ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_CONTROL_REQ_DATA_VAL); ++} ++ ++static int pka_dev_test_trng_drbg(void *csr_reg_ptr, uint64_t csr_reg_base) ++{ ++ uint64_t csr_reg_off, csr_reg_val; ++ int i, ret; ++ ++ ret = 0; ++ ++ // Make sure the engine is idle. ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0); ++ ++ // Enable DRBG, TRNG need not be enabled for this test. ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_CONTROL_DRBG_ENABLE_VAL); ++ ++ // Set 'test_sp_800_90' bit in the TRNG_TEST register ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_TEST_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_TEST_DRBG_VAL); ++ ++ // Wait for 'test_ready' bit to be set. ++ ret = pka_dev_trng_wait_test_ready(csr_reg_ptr, csr_reg_base); ++ if (ret) ++ goto exit; ++ ++ // Instantiate ++ pka_dev_trng_write_ps_ai_str(csr_reg_ptr, csr_reg_base, pka_trng_drbg_test_ps_str); ++ ret = pka_dev_trng_wait_test_ready(csr_reg_ptr, csr_reg_base); ++ if (ret) ++ goto exit; ++ ++ // Generate ++ pka_dev_trng_write_ps_ai_str(csr_reg_ptr, csr_reg_base, pka_trng_drbg_test_etpy_str1); ++ ret = pka_dev_trng_wait_test_ready(csr_reg_ptr, csr_reg_base); ++ if (ret) ++ goto exit; ++ ++ // A standard NIST SP 800-90A DRBG known-answer test discards ++ // the result of the first 'Generate' function and only checks ++ // the result of the second 'Generate' function. Hence 'Generate' ++ // is performed again. ++ ++ // Generate ++ pka_dev_trng_write_ps_ai_str(csr_reg_ptr, csr_reg_base, pka_trng_drbg_test_etpy_str2); ++ ret = pka_dev_trng_wait_test_ready(csr_reg_ptr, csr_reg_base); ++ if (ret) ++ goto exit; ++ ++ // Check output registers ++ for (i = 0; i < PKA_TRNG_OUTPUT_CNT; i++) ++ { ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_OUTPUT_0_ADDR + (i * 0x8)); ++ ++ csr_reg_val = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ ++ if ((uint32_t)csr_reg_val != pka_trng_drbg_test_output[i]) ++ { ++ PKA_DEBUG(PKA_DEV, ++ "DRBG known answer test failed for output register:%d, 0x%x\n", ++ i, (uint32_t)csr_reg_val); ++ ret = 1; ++ goto exit; ++ } ++ } ++ ++ // Clear 'test_sp_800_90' bit in the TRNG_TEST register. ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_TEST_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0); ++ ++exit: ++ return ret; ++} ++ ++// Configure the TRNG. ++static int pka_dev_config_trng_drbg(pka_dev_res_t *aic_csr_ptr, ++ pka_dev_res_t *trng_csr_ptr) ++{ ++ int ret = 0; ++ ++ uint64_t csr_reg_base, csr_reg_off; ++ void *csr_reg_ptr; ++ ++ if (trng_csr_ptr->status != PKA_DEV_RES_STATUS_MAPPED || ++ trng_csr_ptr->type != PKA_DEV_RES_TYPE_REG) ++ return -EPERM; ++ ++ PKA_DEBUG(PKA_DEV, "Starting up the TRNG\n"); ++ ++ ret = pka_dev_config_trng_clk(aic_csr_ptr); ++ if (ret) ++ return ret; ++ ++ csr_reg_base = trng_csr_ptr->base; ++ csr_reg_ptr = trng_csr_ptr->ioaddr; ++ ++ // Perform NIST known-answer tests on the complete SP 800-90A DRBG ++ // without BC_DF functionality. ++ ret = pka_dev_test_trng_drbg(csr_reg_ptr, csr_reg_base); ++ if (ret) ++ return ret; ++ ++ // Starting up the TRNG with a DRBG ++ ++ // Make sure the engine is idle. ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0); ++ ++ // Disable all FROs initially ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, TRNG_FROENABLE_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0); ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, TRNG_FRODETUNE_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0); ++ ++ // Write all configuration values in the TRNG_CONFIG and TRNG_ALARMCNT, ++ // write zeroes to the TRNG_ALARMMASK and TRNG_ALARMSTOP registers. ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, TRNG_CONFIG_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_CONFIG_REG_VAL); ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, TRNG_ALARMCNT_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_ALARMCNT_REG_VAL); ++ ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, TRNG_ALARMMASK_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0); ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, TRNG_ALARMSTOP_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0); ++ ++ // Enable all FROs in the TRNG_FROENABLE register. Note that this can ++ // only be done after clearing the TRNG_ALARMSTOP register. ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, TRNG_FROENABLE_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_FROENABLE_REG_VAL); ++ ++ // Optionally, write 'Personalization string' of upto 384 bits in ++ // TRNG_PS_AI_... registers. The contents of these registers will be ++ // XOR-ed into the output of the SHA-256 'Conditioning Function' to be ++ // used as seed value for the actual DRBG. ++ pka_dev_trng_write_ps_ai_str(csr_reg_ptr, csr_reg_base, pka_trng_drbg_ps_str); ++ ++ ++ // Run TRNG tests after configuring TRNG. ++ // NOTE: TRNG need not be enabled to carry out these tests. ++ ret = pka_dev_test_trng(csr_reg_ptr, csr_reg_base); ++ if (ret) ++ return ret; ++ ++ // Start the actual engine by setting the 'enable_trng' and 'drbg_en' bit ++ // in the TRNG_CONTROL register (also a nice point to set the interrupt mask ++ // bits). ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_CONTROL_DRBG_REG_VAL); ++ ++ // The engine is now ready to handle the first 'Generate' request using ++ // the 'request_data' bit of the TRNG_CONTROL register. The first output ++ // for these requests will take a while, as Noise Source and Conditioning ++ // Function must first generate seed entropy for the DRBG. ++ ++ ++ // Optionally, when buffer RAM is configured: Set a data available ++ // interrupt threshold using the 'load_thresh' and 'blocks_thresh' ++ // fields of the TRNG_INTACK register. This allows delaying the data ++ // available interrupt until the indicated number of 128-bit words are ++ // available in the buffer RAM. ++ ++ // Start the actual 'Generate' operation using the 'request_data' and 'data_blocks' ++ // fields of the TRNG_CONTROL register. ++ ++ pka_dev_trng_drbg_generate(csr_reg_ptr, csr_reg_base); ++ ++ mdelay(200); ++ ++ return ret; ++} ++ ++// Triggers hardaware zeorize to initialize PKA internal memories ++static int pka_dev_ram_zeroize(pka_dev_res_t *ext_csr_ptr) ++{ ++ uint64_t csr_reg_base, csr_reg_off, csr_reg_value; ++ uint64_t timer; ++ void *csr_reg_ptr; ++ ++ if (ext_csr_ptr->status != PKA_DEV_RES_STATUS_MAPPED || ++ ext_csr_ptr->type != PKA_DEV_RES_TYPE_REG) ++ return -EPERM; ++ ++ PKA_DEBUG(PKA_DEV, "Starting memory zeroize\n"); ++ ++ csr_reg_base = ext_csr_ptr->base; ++ csr_reg_ptr = ext_csr_ptr->ioaddr; ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ PKA_ZEROIZE_ADDR); ++ // When PKA_ZEROIZE register is written (with any value) ++ // sensitive data in the PKA is zeroed out. ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, 1); ++ ++ // Now wait until the zeroize completes ++ timer = pka_dev_timer_start(10000000); // 10000 ms ++ csr_reg_value = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ while (csr_reg_value != 0) ++ { ++ csr_reg_value = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ ++ if (pka_dev_timer_done(timer)) ++ { ++ PKA_DEBUG(PKA_DEV, "Timeout while PKA zeorize\n"); ++ return -EBUSY; ++ } ++ } ++ ++ return 0; ++} ++ ++// Initialize PKA IO block refered to as shim. It configures shim's ++// parameters and prepare resources by mapping corresponding memory. ++// The function also configures shim registers and load firmware to ++// shim internal rams. The pka_dev_shim_t passed as input is also an ++// output. It returns 0 on success, a negative error code on failure. ++static int pka_dev_init_shim(pka_dev_shim_t *shim) ++{ ++ const uint32_t *farm_img_ptr; ++ uint32_t farm_img_size, data[4], i; ++ uint8_t shim_fw_id; ++ ++ int ret = 0; ++ ++ if (shim->status != PKA_SHIM_STATUS_CREATED) ++ { ++ PKA_ERROR(PKA_DEV, "PKA device must be created\n"); ++ return -EPERM; ++ } ++ ++ // First of all, trigger a hardware zeroize to initialize internal ++ // RAM memories ++ ret = pka_dev_ram_zeroize(&shim->resources.ext_csr); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "failed to zeroize PKA\n"); ++ return ret; ++ } ++ ++ // Configure AIC registers ++ ret = pka_dev_config_aic_interrupts(&shim->resources.aic_csr); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "failed to configure AIC\n"); ++ return ret; ++ } ++ ++ shim_fw_id = pka_firmware_get_id(); ++ ++ // Load Farm image into PKA_BUFFER_RAM for non-High Assurance mode ++ // or into PKA_SECURE_RAM for High Assurance mode. ++ farm_img_size = pka_firmware_array[shim_fw_id].farm_img_size; ++ PKA_DEBUG(PKA_DEV, "loading farm image (%d words)\n", farm_img_size); ++ ++ farm_img_ptr = pka_firmware_array[shim_fw_id].farm_img; ++ // The IP provider suggests using the zeroize function to initialize ++ // the Buffer RAM. But a bug has been detected when writing ECC bits. ++ // Thus a workaround is used, and has already been shown to work; it ++ // consists of padding the farm image. Then all RAM locations will be ++ // written with correct ECC before the IP reads the image out. ++ ret = pka_dev_load_image(&shim->resources.buffer_ram, farm_img_ptr, ++ farm_img_size); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "failed to load farm image\n"); ++ return ret; ++ } ++ ++ // Configure EIP-154 Master controller Sequencer ++ ret = pka_dev_config_master_seq_controller(shim, ++ &shim->resources.master_seq_ctrl); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "failed to configure Master controller " ++ "Sequencer\n"); ++ return ret; ++ } ++ ++ // Configure PKA Ring options control word ++ ret = pka_dev_config_ring_options(&shim->resources.buffer_ram, ++ shim->rings_num, shim->ring_priority); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "failed to configure ring options\n"); ++ return ret; ++ } ++ ++ shim->trng_enabled = PKA_SHIM_TRNG_ENABLED; ++ shim->trng_err_cycle = 0; ++ ++ // Configure the TRNG ++ ret = pka_dev_config_trng_drbg(&shim->resources.aic_csr, ++ &shim->resources.trng_csr); ++ ++ // Pull out data from the content of the TRNG buffer RAM and ++ // start the re-generation of new numbers; read and drop 512 ++ // words. The read must be done over the 4 TRNG_OUTPUT_X registers ++ // at a time. ++ i = 0; ++ while (i < 128) ++ { ++ pka_dev_trng_read(shim, data, sizeof(data)); ++ i++; ++ } ++ ++ if (ret) ++ { ++ // Keep running without TRNG since it does not hurt, but ++ // notify users. ++ PKA_ERROR(PKA_DEV, "failed to configure TRNG\n"); ++ shim->trng_enabled = PKA_SHIM_TRNG_DISABLED; ++ } ++ ++ mutex_init(&shim->mutex); ++ shim->busy_ring_num = 0; ++ shim->status = PKA_SHIM_STATUS_INITIALIZED; ++ ++ return ret; ++} ++ ++// Release a given shim. ++static int pka_dev_release_shim(pka_dev_shim_t *shim) ++{ ++ int ret = 0; ++ ++ uint32_t ring_idx; ++ ++ if (shim->status != PKA_SHIM_STATUS_INITIALIZED && ++ shim->status != PKA_SHIM_STATUS_STOPPED) ++ { ++ PKA_ERROR(PKA_DEV, "PKA device must be initialized or stopped\n"); ++ return -EPERM; ++ } ++ ++ // Release rings which belong to the shim. The operating system might ++ // release ring devices before shim devices. The global configuration ++ // must be checked before proceeding to the release of ring devices. ++ if (pka_gbl_config.dev_rings_cnt) ++ { ++ for (ring_idx = 0; ring_idx < shim->rings_num; ring_idx++) ++ { ++ ret = pka_dev_release_ring(shim->rings[ring_idx]); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "failed to release ring %d\n", ring_idx); ++ return ret; ++ } ++ } ++ } ++ ++ shim->busy_ring_num = 0; ++ shim->status = PKA_SHIM_STATUS_FINALIZED; ++ ++ return ret; ++} ++ ++// Return the ring associated with the given identifier. ++pka_dev_ring_t *pka_dev_get_ring(uint32_t ring_id) ++{ ++ return pka_gbl_config.dev_rings[ring_id]; ++} ++ ++// Return the shim associated with the given identifier. ++pka_dev_shim_t *pka_dev_get_shim(uint32_t shim_id) ++{ ++ return pka_gbl_config.dev_shims[shim_id]; ++} ++ ++ ++static pka_dev_ring_t *__pka_dev_register_ring(uint32_t ring_id, ++ uint32_t shim_id) ++{ ++ pka_dev_shim_t *shim; ++ pka_dev_ring_t *ring; ++ ++ int ret; ++ ++ shim = pka_dev_get_shim(shim_id); ++ if (!shim) ++ return NULL; ++ ++ ring = kzalloc(sizeof(pka_dev_ring_t), GFP_KERNEL); ++ if (!ring) ++ return ring; ++ ++ ring->status = PKA_DEV_RING_STATUS_UNDEFINED; ++ ++ // Initialize ring. ++ ret = pka_dev_init_ring(ring, ring_id, shim); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "failed to initialize ring %d\n", ring_id); ++ pka_dev_release_ring(ring); ++ kfree(ring); ++ return NULL; ++ } ++ ++ return ring; ++} ++ ++pka_dev_ring_t *pka_dev_register_ring(uint32_t ring_id, uint32_t shim_id) ++{ ++ pka_dev_ring_t *ring; ++ ++ ring = __pka_dev_register_ring(ring_id, shim_id); ++ if (ring) ++ { ++ pka_gbl_config.dev_rings[ring->ring_id] = ring; ++ pka_gbl_config.dev_rings_cnt += 1; ++ } ++ ++ return ring; ++} ++ ++static int __pka_dev_unregister_ring(pka_dev_ring_t *ring) ++{ ++ int ret; ++ ++ if (!ring) ++ return -EINVAL; ++ ++ // Release ring ++ ret = pka_dev_release_ring(ring); ++ if (ret) ++ return ret; ++ ++ kfree(ring); ++ ++ return ret; ++} ++ ++int pka_dev_unregister_ring(pka_dev_ring_t *ring) ++{ ++ pka_gbl_config.dev_rings[ring->ring_id] = NULL; ++ pka_gbl_config.dev_rings_cnt -= 1; ++ ++ return __pka_dev_unregister_ring(ring); ++} ++ ++static pka_dev_shim_t *__pka_dev_register_shim(uint32_t shim_id, ++ struct pka_dev_mem_res *mem_res) ++{ ++ pka_dev_shim_t *shim; ++ ++ uint8_t split; ++ int ret = 0; ++ ++ PKA_DEBUG(PKA_DEV, "register shim id=%u\n", shim_id); ++ ++ shim = kzalloc(sizeof(pka_dev_shim_t), GFP_KERNEL); ++ if (!shim) ++ return shim; ++ ++ // Shim state MUST be set to undefined before calling 'pka_dev_create_shim' ++ // function ++ shim->status = PKA_SHIM_STATUS_UNDEFINED; ++ ++ // Set the Window RAM user mode ++ split = PKA_SPLIT_WINDOW_RAM_MODE; ++ ++ // Create PKA shim ++ ret = pka_dev_create_shim(shim, shim_id, split, mem_res); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "failed to create shim %u\n", shim_id); ++ pka_dev_delete_shim(shim); ++ kfree(shim); ++ return NULL; ++ } ++ ++ // Initialize PKA shim ++ ret = pka_dev_init_shim(shim); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "failed to init shim %u\n", shim_id); ++ pka_dev_release_shim(shim); ++ pka_dev_delete_shim(shim); ++ kfree(shim); ++ return NULL; ++ } ++ ++ return shim; ++} ++ ++pka_dev_shim_t *pka_dev_register_shim(uint32_t shim_id, uint8_t shim_fw_id, ++ struct pka_dev_mem_res *mem_res) ++{ ++ pka_dev_shim_t *shim; ++ ++ pka_firmware_set_id(shim_fw_id); ++ ++ shim = __pka_dev_register_shim(shim_id, mem_res); ++ if (shim) ++ { ++ pka_gbl_config.dev_shims[shim->shim_id] = shim; ++ pka_gbl_config.dev_shims_cnt += 1; ++ } ++ ++ return shim; ++} ++ ++static int __pka_dev_unregister_shim(pka_dev_shim_t *shim) ++{ ++ int ret = 0; ++ ++ if (!shim) ++ return -EINVAL; ++ ++ // Release shim ++ ret = pka_dev_release_shim(shim); ++ if (ret) ++ return ret; ++ ++ // Delete shim ++ ret = pka_dev_delete_shim(shim); ++ if (ret) ++ return ret; ++ ++ kfree(shim); ++ ++ return ret; ++} ++ ++int pka_dev_unregister_shim(pka_dev_shim_t *shim) ++{ ++ pka_gbl_config.dev_shims[shim->shim_id] = NULL; ++ pka_gbl_config.dev_shims_cnt -= 1; ++ ++ return __pka_dev_unregister_shim(shim); ++} ++ ++static bool pka_dev_trng_shutdown_oflo(pka_dev_res_t *trng_csr_ptr, ++ uint64_t *err_cycle) ++{ ++ uint64_t csr_reg_base, csr_reg_off, csr_reg_value; ++ uint64_t curr_cycle_cnt, fro_stopped_mask, fro_enabled_mask; ++ void *csr_reg_ptr; ++ ++ csr_reg_base = trng_csr_ptr->base; ++ csr_reg_ptr = trng_csr_ptr->ioaddr; ++ ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, TRNG_STATUS_ADDR); ++ csr_reg_value = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ ++ if (csr_reg_value & PKA_TRNG_STATUS_SHUTDOWN_OFLO) ++ { ++ curr_cycle_cnt = get_cycles(); ++ // See if any FROs were shut down. If they were, toggle bits in the ++ // FRO detune register and reenable the FROs. ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_ALARMSTOP_ADDR); ++ fro_stopped_mask = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ if (fro_stopped_mask) ++ { ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_FROENABLE_ADDR); ++ fro_enabled_mask = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_FRODETUNE_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, fro_stopped_mask); ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_FROENABLE_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, ++ fro_stopped_mask | fro_enabled_mask); ++ } ++ ++ // Reset the error ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_ALARMMASK_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0); ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_ALARMSTOP_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0); ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_INTACK_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, ++ PKA_TRNG_STATUS_SHUTDOWN_OFLO); ++ ++ // If we're seeing this error again within about a second, ++ // the hardware is malfunctioning. Disable the trng and return ++ // an error. ++ if (*err_cycle && (curr_cycle_cnt - *err_cycle < 1000000000)) ++ { ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_CONTROL_ADDR); ++ csr_reg_value = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ csr_reg_value &= ~PKA_TRNG_CONTROL_REG_VAL; ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, csr_reg_value); ++ return false; ++ } ++ ++ *err_cycle = curr_cycle_cnt; ++ } ++ ++ return true; ++} ++ ++static int pka_dev_trng_drbg_reseed(void *csr_reg_ptr, uint64_t csr_reg_base) ++{ ++ uint64_t csr_reg_off; ++ int ret; ++ ++ ret = 0; ++ ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_CONTROL_DRBG_RESEED); ++ ++ ret = pka_dev_trng_wait_test_ready(csr_reg_ptr, csr_reg_base); ++ if (ret) ++ return ret; ++ ++ // Write personalization string ++ pka_dev_trng_write_ps_ai_str(csr_reg_ptr, csr_reg_base, pka_trng_drbg_ps_str); ++ ++ return ret; ++} ++ ++// Read from DRBG enabled TRNG ++int pka_dev_trng_read(pka_dev_shim_t *shim, uint32_t *data, uint32_t cnt) ++{ ++ int ret = 0; ++ ++ pka_dev_res_t *trng_csr_ptr; ++ uint64_t csr_reg_base, csr_reg_off, csr_reg_value; ++ uint64_t timer; ++ uint32_t data_idx, word_cnt; ++ uint8_t output_idx, trng_ready = 0; ++ void *csr_reg_ptr; ++ ++ if (!shim || !data || (cnt % PKA_TRNG_OUTPUT_CNT != 0)) ++ return -EINVAL; ++ ++ if (!cnt) ++ return ret; ++ ++ mutex_lock(&shim->mutex); ++ ++ trng_csr_ptr = &shim->resources.trng_csr; ++ ++ if (trng_csr_ptr->status != PKA_DEV_RES_STATUS_MAPPED || ++ trng_csr_ptr->type != PKA_DEV_RES_TYPE_REG) ++ { ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ csr_reg_base = trng_csr_ptr->base; ++ csr_reg_ptr = trng_csr_ptr->ioaddr; ++ ++ if (!pka_dev_trng_shutdown_oflo(trng_csr_ptr, ++ &shim->trng_err_cycle)) ++ { ++ ret = -EWOULDBLOCK; ++ goto exit; ++ } ++ ++ // Determine the number of 32-bit words. ++ word_cnt = cnt >> 2; ++ ++ for (data_idx = 0; data_idx < word_cnt; data_idx++) ++ { ++ output_idx = data_idx % PKA_TRNG_OUTPUT_CNT; ++ ++ // Tell the hardware to advance ++ if (output_idx == 0) ++ { ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_INTACK_ADDR); ++ pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_STATUS_READY); ++ trng_ready = 0; ++ ++ // Check if 'data_blocks' field is zero in TRNG_CONTROL register, ++ // if it is then we have to issue a 'Reseed' and Generate' request ++ // for DRBG enabled TRNG. ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_CONTROL_ADDR); ++ csr_reg_value = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ ++ if (!((uint32_t)csr_reg_value & PKA_TRNG_DRBG_DATA_BLOCK_MASK)) ++ { ++ // Issue reseed ++ ret = pka_dev_trng_drbg_reseed(csr_reg_ptr, csr_reg_base); ++ if (ret) ++ { ++ ret = -EBUSY; ++ goto exit; ++ } ++ ++ // Issue generate request ++ pka_dev_trng_drbg_generate(csr_reg_ptr, csr_reg_base); ++ } ++ ++ } ++ ++ // Wait until a data word is available in the TRNG_OUTPUT_X ++ // registers (using the interrupt and/or 'ready' status bit in the ++ // TRNG_STATUS register. The only way this would hang if the TRNG ++ // never initialized, and we would not call this function if that ++ // happened. ++ timer = pka_dev_timer_start(1000000); // 1000 ms ++ csr_reg_off = ++ pka_dev_get_register_offset(csr_reg_base, TRNG_STATUS_ADDR); ++ while (trng_ready == 0) ++ { ++ csr_reg_value = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ trng_ready = csr_reg_value & PKA_TRNG_STATUS_READY; ++ ++ if (pka_dev_timer_done(timer)) ++ { ++ PKA_DEBUG(PKA_DEV, ++ "Shim %u got error obtaining random number\n", ++ shim->shim_id); ++ ret = -EBUSY; ++ goto exit; ++ } ++ } ++ ++ // Read the registers ++ csr_reg_off = pka_dev_get_register_offset(csr_reg_base, ++ TRNG_OUTPUT_0_ADDR + (output_idx * 0x8)); ++ csr_reg_value = pka_dev_io_read(csr_reg_ptr, csr_reg_off); ++ data[data_idx] = (uint32_t) csr_reg_value; ++ } ++ ++exit: ++ mutex_unlock(&shim->mutex); ++ return ret; ++} ++ ++bool pka_dev_has_trng(pka_dev_shim_t *shim) ++{ ++ if (!shim) ++ return false; ++ ++ return (shim->trng_enabled == PKA_SHIM_TRNG_ENABLED); ++} ++ ++// Syscall to open ring. ++int __pka_dev_open_ring(uint32_t ring_id) ++{ ++ pka_dev_shim_t *shim; ++ pka_dev_ring_t *ring; ++ ++ int ret = 0; ++ ++ if (pka_gbl_config.dev_rings_cnt == 0) ++ return -EPERM; ++ ++ ring = pka_dev_get_ring(ring_id); ++ if (!ring || !ring->shim) ++ return -ENXIO; ++ ++ shim = ring->shim; ++ ++ mutex_lock(&ring->mutex); ++ ++ if (shim->status == PKA_SHIM_STATUS_UNDEFINED || ++ shim->status == PKA_SHIM_STATUS_CREATED || ++ shim->status == PKA_SHIM_STATUS_FINALIZED) ++ { ++ ret = -EPERM; ++ goto unlock_return; ++ } ++ ++ if (ring->status == PKA_DEV_RING_STATUS_BUSY) ++ { ++ ret = -EBUSY; ++ goto unlock_return; ++ } ++ ++ if (ring->status != PKA_DEV_RING_STATUS_INITIALIZED) ++ { ++ ret = -EPERM; ++ goto unlock_return; ++ } ++ ++ // Set ring information words. ++ ret = pka_dev_set_ring_info(ring); ++ if (ret) ++ { ++ PKA_ERROR(PKA_DEV, "failed to set ring information\n"); ++ ret = -EWOULDBLOCK; ++ goto unlock_return; ++ } ++ ++ if (shim->busy_ring_num == 0) ++ shim->status = PKA_SHIM_STATUS_RUNNING; ++ ++ ring->status = PKA_DEV_RING_STATUS_BUSY; ++ shim->busy_ring_num += 1; ++ ++unlock_return: ++ mutex_unlock(&ring->mutex); ++ return ret; ++} ++ ++// Open ring. ++int pka_dev_open_ring(pka_ring_info_t *ring_info) ++{ ++ return __pka_dev_open_ring(ring_info->ring_id); ++} ++ ++// Syscall to close ring. ++int __pka_dev_close_ring(uint32_t ring_id) ++{ ++ pka_dev_shim_t *shim; ++ pka_dev_ring_t *ring; ++ ++ int ret = 0; ++ ++ if (pka_gbl_config.dev_rings_cnt == 0) ++ return -EPERM; ++ ++ ring = pka_dev_get_ring(ring_id); ++ if (!ring || !ring->shim) ++ return -ENXIO; ++ ++ shim = ring->shim; ++ ++ mutex_lock(&ring->mutex); ++ ++ if (shim->status != PKA_SHIM_STATUS_RUNNING && ++ ring->status != PKA_DEV_RING_STATUS_BUSY) ++ { ++ ret = -EPERM; ++ goto unlock_return; ++ } ++ ++ ring->status = PKA_DEV_RING_STATUS_INITIALIZED; ++ shim->busy_ring_num -= 1; ++ ++ if (shim->busy_ring_num == 0) ++ shim->status = PKA_SHIM_STATUS_STOPPED; ++ ++unlock_return: ++ mutex_unlock(&ring->mutex); ++ return ret; ++} ++ ++// Close ring. ++int pka_dev_close_ring(pka_ring_info_t *ring_info) ++{ ++ if (ring_info) ++ { ++ return __pka_dev_close_ring(ring_info->ring_id); ++ } ++ ++ return 0; ++} ++ ++// Syscall to map ring into memory (kernel-space). ++static int __pka_dev_mmap_ring(uint32_t ring_id) ++{ ++ //not implemented ++ return -1; ++} ++ ++// Map ring into memory (user-space). ++int pka_dev_mmap_ring(pka_ring_info_t *ring_info) ++{ ++ return __pka_dev_mmap_ring(ring_info->ring_id); ++} ++ ++// Syscall to unmap ring (kernel-space). ++static int __pka_dev_munmap_ring(uint32_t ring_id) ++{ ++ //not implemented ++ return -1; ++} ++ ++// Unmap ring (user-space). ++int pka_dev_munmap_ring(pka_ring_info_t *ring_info) ++{ ++ if (ring_info) ++ { ++ return __pka_dev_munmap_ring(ring_info->ring_id); ++ } ++ ++ return 0; ++} ++ +diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.h +new file mode 100644 +index 000000000..06ac28623 +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.h +@@ -0,0 +1,310 @@ ++// ++// BSD LICENSE ++// ++// Copyright(c) 2016 Mellanox Technologies, Ltd. All rights reserved. ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// ++// * Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// * Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in ++// the documentation and/or other materials provided with the ++// distribution. ++// * Neither the name of Mellanox Technologies nor the names of its ++// contributors may be used to endorse or promote products derived ++// from this software without specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++// ++ ++#ifndef __PKA_DEV_H__ ++#define __PKA_DEV_H__ ++ ++/// ++/// @file ++/// ++/// API to handle the PKA EIP-154 I/O block (shim). It provides functions ++/// and data structures to initialize and configure the PKA shim. It's the ++/// "southband interface" for communication with PKA hardware resources. ++/// ++ ++#include ++#include ++#include "mlxbf_pka_firmware.h" ++ ++#include ++ ++#include "mlxbf_pka_config.h" ++#include "mlxbf_pka_cpu.h" ++#include "mlxbf_pka_debug.h" ++#include "mlxbf_pka_ioctl.h" ++#include "mlxbf_pka_mmio.h" ++#include "mlxbf_pka_ring.h" ++ ++#define PKA_SYSFS_RING_DEVICES "/sys/bus/platform/devices" ++#define PKA_VFIO_DIR "/dev/vfio" ++#define PKA_VFIO_CONTAINER_PATH "/dev/vfio/vfio" ++#define PKA_VFIO_GROUP_FMT "/dev/vfio/%d" ++ ++#define PKA_DEVFS_RING_DEVICES "/dev/pka/%d" ++ ++// Defines specific to device-tree and Linux operating system. ++// Careful, all constants MUST be conform with both devicetree ++// (DTS) and ACPI tables (SSDT). ++// *TBD* Better to be detected automatically (or passed as arg ++// so far). ++#define PKA_DEV_RING_DT_PREFIX_0 "45000000.eip154:ring@%d" ++#define PKA_DEV_RING_DT_PREFIX_1 "47000000.eip154:ring@%d" ++#define PKA_DEV_RING_DT_PREFIX_2 "4d000000.eip154:ring@%d" ++#define PKA_DEV_RING_DT_PREFIX_3 "4f000000.eip154:ring@%d" ++#define PKA_DEV_RING_DT_PREFIX_4 "44000000.eip154:ring@%d" ++#define PKA_DEV_RING_DT_PREFIX_5 "46000000.eip154:ring@%d" ++#define PKA_DEV_RING_DT_PREFIX_6 "4c000000.eip154:ring@%d" ++#define PKA_DEV_RING_DT_PREFIX_7 "4e000000.eip154:ring@%d" ++ ++#define PKA_DEV_RING_ACPI_PREFIX "MLNXBF11:%02x" ++ ++/// Device resource structure ++typedef struct ++{ ++ void *ioaddr; ///< (iore)map-ped version of addr, for ++ /// driver internal use. ++ ++ uint64_t base; ///< base address of the device's ++ /// resource ++ ++ uint64_t size; ///< size of IO ++ ++ uint8_t type; ///< type of resource addr points to ++ int8_t status; ///< status of the resource ++ ++ char *name; ///< name of the resource ++} pka_dev_res_t; ++ ++/// defines for pka_dev_res->type ++#define PKA_DEV_RES_TYPE_MEM 1 // resource type is memory ++#define PKA_DEV_RES_TYPE_REG 2 // resource type is register ++ ++/// defines for pka_dev_res->status ++#define PKA_DEV_RES_STATUS_MAPPED 1 // the resource is (iore)-mapped ++#define PKA_DEV_RES_STATUS_UNMAPPED -1 // the resource is unmapped ++ ++/// PKA Ring resources structure ++typedef struct ++{ ++ pka_dev_res_t info_words; // ring information words ++ pka_dev_res_t counters; // ring counters ++ pka_dev_res_t window_ram; // window RAM ++} pka_dev_ring_res_t; ++ ++typedef struct pka_dev_shim_s pka_dev_shim_t; ++ ++/// PKA Ring structure ++typedef struct ++{ ++ uint32_t ring_id; ///< ring identifier. ++ ++ pka_dev_shim_t *shim; ///< pointer to the shim associated ++ /// to the ring. ++ ++ uint32_t resources_num; ///< number of ring ressources. ++ pka_dev_ring_res_t resources; ///< ring resources. ++ ++ pka_dev_hw_ring_info_t *ring_info; ///< ring information. ++ uint32_t num_cmd_desc; ///< number of command descriptors. ++ ++ int8_t status; ///< status of the ring. ++ ++ struct mutex mutex; ///< mutex lock for sharing ring device ++} pka_dev_ring_t; ++ ++/// defines for pka_dev_ring->status ++#define PKA_DEV_RING_STATUS_UNDEFINED -1 ++#define PKA_DEV_RING_STATUS_INITIALIZED 1 ++#define PKA_DEV_RING_STATUS_READY 2 ++#define PKA_DEV_RING_STATUS_BUSY 3 ++#define PKA_DEV_RING_STATUS_FINALIZED 4 ++ ++/// PKA Shim resources structure ++typedef struct ++{ ++ pka_dev_res_t buffer_ram; // buffer RAM ++ pka_dev_res_t master_prog_ram; // master controller program RAM ++ pka_dev_res_t master_seq_ctrl; // master sequencer controller CSR ++ pka_dev_res_t aic_csr; // interrupt controller CSRs ++ pka_dev_res_t trng_csr; // TRNG module CSRs ++ pka_dev_res_t ext_csr; // MiCA specific CSRs (glue logic) ++} pka_dev_shim_res_t; ++ ++#define PKA_DEV_SHIM_RES_CNT 6 // Number of PKA device resources ++ ++/// Platform global shim resource information ++typedef struct ++{ ++ pka_dev_res_t *res_tbl[PKA_DEV_SHIM_RES_CNT]; ++ uint8_t res_cnt; ++} pka_dev_gbl_shim_res_info_t; ++ ++struct pka_dev_mem_res ++{ ++ uint64_t eip154_base; ///< base address for eip154 mmio registers ++ uint64_t eip154_size; ///< eip154 mmio register region size ++ ++ uint64_t wndw_ram_off_mask; ///< common offset mask for alt window ram and window ram ++ uint64_t wndw_ram_base; ///< base address for window ram ++ uint64_t wndw_ram_size; ///< window ram region size ++ ++ uint64_t alt_wndw_ram_0_base; ///< base address for alternate window ram 0 ++ uint64_t alt_wndw_ram_1_base; ///< base address for alternate window ram 1 ++ uint64_t alt_wndw_ram_2_base; ///< base address for alternate window ram 2 ++ uint64_t alt_wndw_ram_3_base; ///< base address for alternate window ram 3 ++ uint64_t alt_wndw_ram_size; ///< alternate window ram regions size ++ ++ uint64_t csr_base; ///< base address for csr registers ++ uint64_t csr_size; ///< csr area size ++}; ++ ++ ++/// PKA Shim structure ++struct pka_dev_shim_s ++{ ++ struct pka_dev_mem_res mem_res; ++ ++ uint64_t trng_err_cycle; ///< TRNG error cycle ++ ++ uint32_t shim_id; ///< shim identifier ++ ++ uint32_t rings_num; ///< Number of supported rings (hw ++ /// specific) ++ ++ pka_dev_ring_t **rings; ///< pointer to rings which belong to ++ /// the shim. ++ ++ uint8_t ring_priority; ///< specify the priority in which ++ /// rings are handled. ++ ++ uint8_t ring_type; ///< indicates whether the result ++ /// ring delivers results strictly ++ /// in-order. ++ ++ pka_dev_shim_res_t resources; ///< shim resources ++ ++ uint8_t window_ram_split; ///< Window RAM mode. if non-zero, ++ /// the splitted window RAM scheme ++ /// is used. ++ ++ uint32_t busy_ring_num; ///< Number of active rings (rings in ++ /// busy state) ++ ++ uint8_t trng_enabled; ///< Whether the TRNG engine is ++ /// enabled. ++ ++ int8_t status; ///< status of the shim ++ ++ struct mutex mutex; ///< mutex lock for sharing shim ++}; ++ ++/// defines for pka_dev_shim->status ++#define PKA_SHIM_STATUS_UNDEFINED -1 ++#define PKA_SHIM_STATUS_CREATED 1 ++#define PKA_SHIM_STATUS_INITIALIZED 2 ++#define PKA_SHIM_STATUS_RUNNING 3 ++#define PKA_SHIM_STATUS_STOPPED 4 ++#define PKA_SHIM_STATUS_FINALIZED 5 ++ ++/// defines for pka_dev_shim->window_ram_split ++#define PKA_SHIM_WINDOW_RAM_SPLIT_ENABLED 1 // window RAM is splitted into ++ // 4 * 16KB blocks ++ ++#define PKA_SHIM_WINDOW_RAM_SPLIT_DISABLED 2 // window RAM is not splitted ++ // and occupies 64KB ++ ++/// defines for pka_dev_shim->trng_enabled ++#define PKA_SHIM_TRNG_ENABLED 1 ++#define PKA_SHIM_TRNG_DISABLED 0 ++ ++/// Platform global configuration structure ++typedef struct ++{ ++ uint32_t dev_shims_cnt; ///< number of registered PKA shims. ++ uint32_t dev_rings_cnt; ///< number of registered Rings. ++ ++ pka_dev_shim_t *dev_shims[PKA_MAX_NUM_IO_BLOCKS]; ///< table of registered ++ /// PKA shims. ++ ++ pka_dev_ring_t *dev_rings[PKA_MAX_NUM_RINGS]; ///< table of registered ++ /// Rings. ++} pka_dev_gbl_config_t; ++ ++extern pka_dev_gbl_config_t pka_gbl_config; ++ ++/// Ring getter for pka_dev_gbl_config_t structure which holds all system ++/// global configuration. This configuration is shared and common to kernel ++/// device driver associated with PKA hardware. ++pka_dev_ring_t *pka_dev_get_ring(uint32_t ring_id); ++ ++/// Shim getter for pka_dev_gbl_config_t structure which holds all system ++/// global configuration. This configuration is shared and common to kernel ++/// device driver associated with PKA hardware. ++pka_dev_shim_t *pka_dev_get_shim(uint32_t shim_id); ++ ++/// Register a Ring. This function initializes a Ring and configures its ++/// related resources, and returns a pointer to that ring. ++pka_dev_ring_t *pka_dev_register_ring(uint32_t ring_id, uint32_t shim_id); ++ ++/// Unregister a Ring ++int pka_dev_unregister_ring(pka_dev_ring_t *ring); ++ ++/// Register PKA IO block. This function initializes a shim and configures its ++/// related resources, and returns a pointer to that ring. ++pka_dev_shim_t *pka_dev_register_shim(uint32_t shim_id, uint8_t shim_fw_id, ++ struct pka_dev_mem_res *mem_res); ++ ++/// Unregister PKA IO block ++int pka_dev_unregister_shim(pka_dev_shim_t *shim); ++ ++/// Reset a Ring. ++int pka_dev_reset_ring(pka_dev_ring_t *ring); ++ ++/// Clear ring counters. This function resets the master sequencer controller ++/// to clear the command and result counters. ++int pka_dev_clear_ring_counters(pka_dev_ring_t *ring); ++ ++/// Read data from the TRNG. Drivers can fill up to 'cnt' bytes of data into ++/// the buffer 'data'. The buffer 'data' is aligned for any type and 'cnt' is ++/// a multiple of 4. ++int pka_dev_trng_read(pka_dev_shim_t *shim, uint32_t *data, uint32_t cnt); ++ ++/// Return true if the TRNG engine is enabled, false if not. ++bool pka_dev_has_trng(pka_dev_shim_t *shim); ++ ++/// Open the file descriptor associated with ring. It returns an integer value, ++/// which is used to refer to the file. If un-successful, it returns a negative ++/// error. ++int pka_dev_open_ring(pka_ring_info_t *ring_info); ++ ++/// Close the file descriptor associated with ring. The function returns 0 if ++/// successful, negative value to indicate an error. ++int pka_dev_close_ring(pka_ring_info_t *ring_info); ++ ++/// Map ring resources. ++int pka_dev_mmap_ring(pka_ring_info_t *ring_info); ++ ++/// Unmap ring resources. ++int pka_dev_munmap_ring(pka_ring_info_t *ring_info); ++ ++#endif /// __PKA_DEV_H__ +diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_drv.c b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_drv.c +new file mode 100644 +index 000000000..b8b5a465e +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_drv.c +@@ -0,0 +1,1398 @@ ++// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mlxbf_pka_dev.h" ++ ++ ++#define PKA_DRIVER_VERSION "v3.0" ++#define PKA_DRIVER_NAME "pka-mlxbf" ++ ++#define PKA_DRIVER_DESCRIPTION "BlueField PKA driver" ++ ++#define PKA_DEVICE_COMPAT "mlx,mlxbf-pka" ++#define PKA_RING_DEVICE_COMPAT "mlx,mlxbf-pka-ring" ++ ++#define PKA_DEVICE_ACPIHID_BF1 "MLNXBF10" ++#define PKA_RING_DEVICE_ACPIHID_BF1 "MLNXBF11" ++ ++#define PKA_DEVICE_ACPIHID_BF2 "MLNXBF20" ++#define PKA_RING_DEVICE_ACPIHID_BF2 "MLNXBF21" ++ ++#define PKA_DEVICE_ACCESS_MODE 0666 ++ ++#define PKA_DEVICE_RES_CNT 7 ++enum pka_mem_res_idx { ++ PKA_ACPI_EIP154_IDX = 0, ++ PKA_ACPI_WNDW_RAM_IDX, ++ PKA_ACPI_ALT_WNDW_RAM_0_IDX, ++ PKA_ACPI_ALT_WNDW_RAM_1_IDX, ++ PKA_ACPI_ALT_WNDW_RAM_2_IDX, ++ PKA_ACPI_ALT_WNDW_RAM_3_IDX, ++ PKA_ACPI_CSR_IDX ++}; ++ ++enum pka_plat_type { ++ PKA_PLAT_TYPE_BF1 = 0, /* Platform type Bluefield-1 */ ++ PKA_PLAT_TYPE_BF2 /* Platform type Bluefield-2 */ ++}; ++ ++static DEFINE_MUTEX(pka_drv_lock); ++ ++static uint32_t pka_device_cnt; ++static uint32_t pka_ring_device_cnt; ++ ++const char pka_compat[] = PKA_DEVICE_COMPAT; ++const char pka_ring_compat[] = PKA_RING_DEVICE_COMPAT; ++ ++const char pka_acpihid_bf1[] = PKA_DEVICE_ACPIHID_BF1; ++const char pka_ring_acpihid_bf1[] = PKA_RING_DEVICE_ACPIHID_BF1; ++ ++const char pka_acpihid_bf2[] = PKA_DEVICE_ACPIHID_BF2; ++const char pka_ring_acpihid_bf2[] = PKA_RING_DEVICE_ACPIHID_BF2; ++ ++struct pka_drv_plat_info { ++ enum pka_plat_type type; ++ uint8_t fw_id; ++}; ++ ++static struct pka_drv_plat_info pka_drv_plat[] = { ++ [PKA_PLAT_TYPE_BF1] = { ++ .type = PKA_PLAT_TYPE_BF1, ++ .fw_id = PKA_FIRMWARE_IMAGE_0_ID ++ }, ++ [PKA_PLAT_TYPE_BF2] = { ++ .type = PKA_PLAT_TYPE_BF2, ++ .fw_id = PKA_FIRMWARE_IMAGE_2_ID ++ } ++}; ++ ++static const struct acpi_device_id pka_drv_acpi_ids[] = { ++ { PKA_DEVICE_ACPIHID_BF1, (kernel_ulong_t)&pka_drv_plat[PKA_PLAT_TYPE_BF1] }, ++ { PKA_RING_DEVICE_ACPIHID_BF1, 0 }, ++ { PKA_DEVICE_ACPIHID_BF2, (kernel_ulong_t)&pka_drv_plat[PKA_PLAT_TYPE_BF2] }, ++ { PKA_RING_DEVICE_ACPIHID_BF2, 0 }, ++ {}, ++}; ++ ++struct pka_info { ++ struct device *dev; /* the device this info belongs to */ ++ const char *name; /* device name */ ++ const char *version; /* device driver version */ ++ const char *compat; ++ const char *acpihid; ++ uint8_t flag; ++ struct module *module; ++ void *priv; /* optional private data */ ++}; ++ ++/* defines for pka_info->flags */ ++#define PKA_DRIVER_FLAG_RING_DEVICE 1 ++#define PKA_DRIVER_FLAG_DEVICE 2 ++ ++struct pka_platdata { ++ struct platform_device *pdev; ++ struct pka_info *info; ++ spinlock_t lock; ++ unsigned long irq_flags; ++}; ++ ++/* Bits in pka_platdata.irq_flags */ ++enum { ++ PKA_IRQ_DISABLED = 0, ++}; ++ ++struct pka_ring_region { ++ u64 off; ++ u64 addr; ++ resource_size_t size; ++ u32 flags; ++ u32 type; ++ void __iomem *ioaddr; ++}; ++ ++/* defines for pka_ring_region->flags */ ++#define PKA_RING_REGION_FLAG_READ (1 << 0) /* Region supports read */ ++#define PKA_RING_REGION_FLAG_WRITE (1 << 1) /* Region supports write */ ++#define PKA_RING_REGION_FLAG_MMAP (1 << 2) /* Region supports mmap */ ++ ++/* defines for pka_ring_region->type */ ++#define PKA_RING_RES_TYPE_NONE 0 ++#define PKA_RING_RES_TYPE_WORDS 1 /* info control/status words */ ++#define PKA_RING_RES_TYPE_CNTRS 2 /* count registers */ ++#define PKA_RING_RES_TYPE_MEM 4 /* window RAM region */ ++ ++#define PKA_DRIVER_RING_DEV_MAX PKA_MAX_NUM_RINGS ++ ++struct pka_ring_device { ++ struct pka_info *info; ++ struct device *device; ++ struct iommu_group *group; ++ int32_t group_id; ++ uint32_t device_id; ++ uint32_t parent_device_id; ++ struct mutex mutex; ++ uint32_t flags; ++ struct module *parent_module; ++ pka_dev_ring_t *ring; ++ int minor; ++ uint32_t num_regions; ++ struct pka_ring_region *regions; ++}; ++ ++#define PKA_DRIVER_DEV_MAX PKA_MAX_NUM_IO_BLOCKS ++#define PKA_DRIVER_RING_NUM_REGIONS_MAX PKA_MAX_NUM_RING_RESOURCES ++ ++/* defines for region index */ ++#define PKA_RING_REGION_WORDS_IDX 0 ++#define PKA_RING_REGION_CNTRS_IDX 1 ++#define PKA_RING_REGION_MEM_IDX 2 ++ ++#define PKA_RING_REGION_OFFSET_SHIFT 40 ++#define PKA_RING_REGION_OFFSET_MASK \ ++ (((u64)(1) << PKA_RING_REGION_OFFSET_SHIFT) - 1) ++ ++#define PKA_RING_OFFSET_TO_INDEX(off) \ ++ (off >> PKA_RING_REGION_OFFSET_SHIFT) ++ ++#define PKA_RING_REGION_INDEX_TO_OFFSET(index) \ ++ ((u64)(index) << PKA_RING_REGION_OFFSET_SHIFT) ++ ++struct pka_device { ++ struct pka_info *info; ++ struct device *device; ++ uint32_t device_id; ++ uint8_t fw_id; /* firmware identifier */ ++ struct mutex mutex; ++ struct resource *resource[PKA_DEVICE_RES_CNT]; ++ pka_dev_shim_t *shim; ++ long irq; /* interrupt number */ ++ struct hwrng rng; ++}; ++ ++/* defines for pka_device->irq */ ++#define PKA_IRQ_CUSTOM -1 ++#define PKA_IRQ_NONE 0 ++ ++/* Hardware interrupt handler */ ++static irqreturn_t pka_drv_irq_handler(int irq, void *device) ++{ ++ struct pka_device *pka_dev = (struct pka_device *)device; ++ struct platform_device *pdev = to_platform_device(pka_dev->device); ++ struct pka_platdata *priv = platform_get_drvdata(pdev); ++ ++ PKA_DEBUG(PKA_DRIVER, ++ "handle irq in device %u\n", pka_dev->device_id); ++ ++ /* Just disable the interrupt in the interrupt controller */ ++ ++ spin_lock(&priv->lock); ++ if (!__test_and_set_bit(PKA_IRQ_DISABLED, &priv->irq_flags)) ++ disable_irq_nosync(irq); ++ spin_unlock(&priv->lock); ++ ++ return IRQ_HANDLED; ++} ++ ++static int pka_drv_register_irq(struct pka_device *pka_dev) ++{ ++ if (pka_dev->irq && (pka_dev->irq != PKA_IRQ_CUSTOM)) { ++ /* ++ * Allow sharing the irq among several devices (child devices ++ * so far) ++ */ ++ return request_irq(pka_dev->irq, ++ (irq_handler_t) pka_drv_irq_handler, ++ IRQF_SHARED, pka_dev->info->name, ++ pka_dev); ++ } ++ ++ return -ENXIO; ++} ++ ++static int pka_drv_ring_regions_init(struct pka_ring_device *ring_dev) ++{ ++ struct pka_ring_region *region; ++ pka_dev_ring_t *ring; ++ pka_dev_res_t *res; ++ uint32_t num_regions; ++ ++ ring = ring_dev->ring; ++ if (!ring || !ring->shim) ++ return -ENXIO; ++ ++ num_regions = ring->resources_num; ++ ring_dev->num_regions = num_regions; ++ ring_dev->regions = kcalloc(num_regions, ++ sizeof(struct pka_ring_region), ++ GFP_KERNEL); ++ if (!ring_dev->regions) ++ return -ENOMEM; ++ ++ /* Information words region */ ++ res = &ring->resources.info_words; ++ region = &ring_dev->regions[PKA_RING_REGION_WORDS_IDX]; ++ /* map offset to the physical address */ ++ region->off = ++ PKA_RING_REGION_INDEX_TO_OFFSET(PKA_RING_REGION_WORDS_IDX); ++ region->addr = res->base; ++ region->size = res->size; ++ region->type = PKA_RING_RES_TYPE_WORDS; ++ region->flags |= (PKA_RING_REGION_FLAG_MMAP | ++ PKA_RING_REGION_FLAG_READ | ++ PKA_RING_REGION_FLAG_WRITE); ++ ++ /* Count regiters region */ ++ res = &ring->resources.counters; ++ region = &ring_dev->regions[PKA_RING_REGION_CNTRS_IDX]; ++ /* map offset to the physical address */ ++ region->off = ++ PKA_RING_REGION_INDEX_TO_OFFSET(PKA_RING_REGION_CNTRS_IDX); ++ region->addr = res->base; ++ region->size = res->size; ++ region->type = PKA_RING_RES_TYPE_CNTRS; ++ region->flags |= (PKA_RING_REGION_FLAG_MMAP | ++ PKA_RING_REGION_FLAG_READ | ++ PKA_RING_REGION_FLAG_WRITE); ++ ++ /* Window ram region */ ++ res = &ring->resources.window_ram; ++ region = &ring_dev->regions[PKA_RING_REGION_MEM_IDX]; ++ /* map offset to the physical address */ ++ region->off = ++ PKA_RING_REGION_INDEX_TO_OFFSET(PKA_RING_REGION_MEM_IDX); ++ region->addr = res->base; ++ region->size = res->size; ++ region->type = PKA_RING_RES_TYPE_MEM; ++ region->flags |= (PKA_RING_REGION_FLAG_MMAP | ++ PKA_RING_REGION_FLAG_READ | ++ PKA_RING_REGION_FLAG_WRITE); ++ ++ return 0; ++} ++ ++static void pka_drv_ring_regions_cleanup(struct pka_ring_device *ring_dev) ++{ ++ /* clear vfio device regions */ ++ ring_dev->num_regions = 0; ++ kfree(ring_dev->regions); ++} ++ ++static int pka_drv_ring_open(void *device_data) ++{ ++ struct pka_ring_device *ring_dev = device_data; ++ struct pka_info *info = ring_dev->info; ++ pka_ring_info_t ring_info; ++ ++ int error; ++ ++ PKA_DEBUG(PKA_DRIVER, ++ "open ring device %u (device_data:%p)\n", ++ ring_dev->device_id, ring_dev); ++ ++ if (!try_module_get(info->module)) ++ return -ENODEV; ++ ++ ring_info.ring_id = ring_dev->device_id; ++ error = pka_dev_open_ring(&ring_info); ++ if (error) { ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to open ring %u\n", ring_dev->device_id); ++ module_put(info->module); ++ return error; ++ } ++ ++ /* Initialize regions */ ++ error = pka_drv_ring_regions_init(ring_dev); ++ if (error) { ++ PKA_DEBUG(PKA_DRIVER, "failed to initialize regions\n"); ++ pka_dev_close_ring(&ring_info); ++ module_put(info->module); ++ return error; ++ } ++ ++ return 0; ++} ++ ++static void pka_drv_ring_release(void *device_data) ++{ ++ struct pka_ring_device *ring_dev = device_data; ++ struct pka_info *info = ring_dev->info; ++ pka_ring_info_t ring_info; ++ ++ int error; ++ ++ PKA_DEBUG(PKA_DRIVER, ++ "release ring device %u (device_data:%p)\n", ++ ring_dev->device_id, ring_dev); ++ ++ pka_drv_ring_regions_cleanup(ring_dev); ++ ++ ring_info.ring_id = ring_dev->device_id; ++ error = pka_dev_close_ring(&ring_info); ++ if (error) ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to close ring %u\n", ++ ring_dev->device_id); ++ ++ module_put(info->module); ++} ++ ++static int pka_drv_ring_mmap_region(struct pka_ring_region region, ++ struct vm_area_struct *vma) ++{ ++ u64 req_len, pgoff, req_start; ++ ++ req_len = vma->vm_end - vma->vm_start; ++ pgoff = vma->vm_pgoff & ++ ((1U << (PKA_RING_REGION_OFFSET_SHIFT - PAGE_SHIFT)) - 1); ++ req_start = pgoff << PAGE_SHIFT; ++ ++ region.size = roundup(region.size, PAGE_SIZE); ++ ++ if (req_start + req_len > region.size) ++ return -EINVAL; ++ ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff; ++ ++ return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, ++ req_len, vma->vm_page_prot); ++} ++ ++static int pka_drv_ring_mmap(void *device_data, struct vm_area_struct *vma) ++{ ++ struct pka_ring_device *ring_dev = device_data; ++ struct pka_ring_region *region; ++ unsigned int index; ++ ++ PKA_DEBUG(PKA_DRIVER, "mmap device %u\n", ring_dev->device_id); ++ ++ index = vma->vm_pgoff >> (PKA_RING_REGION_OFFSET_SHIFT - PAGE_SHIFT); ++ ++ if (vma->vm_end < vma->vm_start) ++ return -EINVAL; ++ if (!(vma->vm_flags & VM_SHARED)) ++ return -EINVAL; ++ if (index >= ring_dev->num_regions) ++ return -EINVAL; ++ if (vma->vm_start & ~PAGE_MASK) ++ return -EINVAL; ++ if (vma->vm_end & ~PAGE_MASK) ++ return -EINVAL; ++ ++ region = &ring_dev->regions[index]; ++ ++ if (!(region->flags & PKA_RING_REGION_FLAG_MMAP)) ++ return -EINVAL; ++ ++ if (!(region->flags & PKA_RING_REGION_FLAG_READ) ++ && (vma->vm_flags & VM_READ)) ++ return -EINVAL; ++ ++ if (!(region->flags & PKA_RING_REGION_FLAG_WRITE) ++ && (vma->vm_flags & VM_WRITE)) ++ return -EINVAL; ++ ++ vma->vm_private_data = ring_dev; ++ ++ if (region->type & PKA_RING_RES_TYPE_CNTRS || ++ region->type & PKA_RING_RES_TYPE_MEM) ++ return pka_drv_ring_mmap_region(ring_dev->regions[index], vma); ++ ++ if (region->type & PKA_RING_RES_TYPE_WORDS) ++ /* ++ * Currently user space is not allowed to access this ++ * region. ++ */ ++ return -EINVAL; ++ ++ return -EINVAL; ++} ++ ++static long pka_drv_ring_ioctl(void *device_data, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct pka_ring_device *ring_dev = device_data; ++ ++ int error = -ENOTTY; ++ ++ if (cmd == PKA_RING_GET_REGION_INFO) { ++ pka_dev_region_info_t info; ++ ++ info.mem_index = PKA_RING_REGION_MEM_IDX; ++ info.mem_offset = ring_dev->regions[info.mem_index].off; ++ info.mem_size = ring_dev->regions[info.mem_index].size; ++ ++ info.reg_index = PKA_RING_REGION_CNTRS_IDX; ++ info.reg_offset = ring_dev->regions[info.reg_index].off; ++ info.reg_size = ring_dev->regions[info.reg_index].size; ++ ++ return copy_to_user((void __user *)arg, &info, sizeof(info)) ? ++ -EFAULT : 0; ++ ++ } else if (cmd == PKA_GET_RING_INFO) { ++ pka_dev_hw_ring_info_t *this_ring_info; ++ pka_dev_hw_ring_info_t hw_ring_info; ++ ++ this_ring_info = ring_dev->ring->ring_info; ++ ++ hw_ring_info.cmmd_base = this_ring_info->cmmd_base; ++ hw_ring_info.rslt_base = this_ring_info->rslt_base; ++ hw_ring_info.size = this_ring_info->size; ++ hw_ring_info.host_desc_size = this_ring_info->host_desc_size; ++ hw_ring_info.in_order = this_ring_info->in_order; ++ hw_ring_info.cmmd_rd_ptr = this_ring_info->cmmd_rd_ptr; ++ hw_ring_info.rslt_wr_ptr = this_ring_info->rslt_wr_ptr; ++ hw_ring_info.cmmd_rd_stats = this_ring_info->cmmd_rd_ptr; ++ hw_ring_info.rslt_wr_stats = this_ring_info->rslt_wr_stats; ++ ++ return copy_to_user((void __user *)arg, &hw_ring_info, ++ sizeof(hw_ring_info)) ? -EFAULT : 0; ++ } else if (cmd == PKA_CLEAR_RING_COUNTERS) { ++ return pka_dev_clear_ring_counters(ring_dev->ring); ++ } else if (cmd == PKA_GET_RANDOM_BYTES) { ++ pka_dev_trng_info_t *trng_data; ++ pka_dev_shim_t *shim; ++ bool trng_present; ++ uint32_t byte_cnt; ++ uint32_t *data; ++ int ret; ++ ++ ret = -ENOENT; ++ shim = ring_dev->ring->shim; ++ trng_data = (pka_dev_trng_info_t *)arg; ++ /* ++ * We need byte count which is multiple of 4 as ++ * required by pka_dev_trng_read() interface. ++ */ ++ byte_cnt = round_up(trng_data->count, 4); ++ ++ data = kzalloc(byte_cnt, GFP_KERNEL); ++ if (data == NULL) { ++ PKA_DEBUG(PKA_DRIVER, "failed to allocate memory.\n"); ++ return -ENOMEM; ++ } ++ ++ trng_present = pka_dev_has_trng(shim); ++ if (!trng_present) { ++ kfree(data); ++ return ret; ++ } ++ ++ ret = pka_dev_trng_read(shim, data, byte_cnt); ++ if (ret) { ++ PKA_DEBUG(PKA_DRIVER, "TRNG failed %d\n", ret); ++ kfree(data); ++ return ret; ++ } ++ ++ ret = copy_to_user((void __user *)(trng_data->data), data, trng_data->count); ++ kfree(data); ++ return ret ? -EFAULT : 0; ++ } ++ ++ return error; ++} ++ ++#ifdef CONFIG_PKA_VFIO_IOMMU ++static const struct vfio_device_ops pka_ring_vfio_ops = { ++ .name = PKA_DRIVER_NAME, ++ .open = pka_drv_ring_open, ++ .release = pka_drv_ring_release, ++ .ioctl = pka_drv_ring_ioctl, ++ .mmap = pka_drv_ring_mmap, ++}; ++ ++static int pka_drv_add_ring_device(struct pka_ring_device *ring_dev) ++{ ++ struct device *dev = ring_dev->device; ++ int ret; ++ ++ ring_dev->parent_module = THIS_MODULE; ++ ring_dev->flags = VFIO_DEVICE_FLAGS_PLATFORM; ++ ++ ring_dev->group = vfio_iommu_group_get(dev); ++ if (!ring_dev->group) { ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to get IOMMU group for device %d\n", ++ ring_dev->device_id); ++ return -EINVAL; ++ } ++ ++ /* ++ * Note that this call aims to add the given child device to a vfio ++ * group. This function creates a new driver data for the device ++ * different from the structure passed as a 3rd argument - i.e. ++ * pka_ring_dev. The struct newly created corresponds to 'vfio_device' ++ * structure which includes a field called 'device_data' that holds ++ * the initialized 'pka_ring_dev'. So to retrieve our private data, ++ * we must call 'dev_get_drvdata()' which returns the 'vfio_device' ++ * struct and access its 'device_data' field. Here one can use ++ * 'pka_platdata' structure instead to be consistent with the parent ++ * devices, and have a common driver data structure which will be used ++ * to manage devices - 'pka_drv_remove()' for instance. Since the VFIO ++ * framework alters the driver data and introduce an indirection, it ++ * is no more relevant to have a common driver data structure. Hence, ++ * we prefer to set the struct 'pka_vfio_dev' instead to avoid ++ * indirection when we have to retrieve this structure during the ++ * open(), mmap(), and ioctl() calls. Since, this structure is used ++ * as driver data here, it will be immediately reachable for these ++ * functions (see first argument passed (void *device_data) passed ++ * to those functions). ++ */ ++ ret = vfio_add_group_dev(dev, &pka_ring_vfio_ops, ring_dev); ++ if (ret) { ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to add group device %d\n", ++ ring_dev->device_id); ++ vfio_iommu_group_put(ring_dev->group, dev); ++ return ret; ++ } ++ ++ ring_dev->group_id = iommu_group_id(ring_dev->group); ++ ++ PKA_DEBUG(PKA_DRIVER, ++ "ring device %d bus:%p iommu_ops:%p group:%p\n", ++ ring_dev->device_id, ++ dev->bus, ++ dev->bus->iommu_ops, ++ ring_dev->group); ++ ++ return 0; ++} ++ ++static struct pka_ring_device *pka_drv_del_ring_device(struct device *dev) ++{ ++ struct pka_ring_device *ring_dev; ++ ++ ring_dev = vfio_del_group_dev(dev); ++ if (ring_dev) ++ vfio_iommu_group_put(dev->iommu_group, dev); ++ ++ return ring_dev; ++} ++ ++static int pka_drv_init_class(void) ++{ ++ return 0; ++} ++ ++static void pka_drv_destroy_class(void) ++{ ++} ++#else ++static struct pka { ++ struct class *class; ++ struct idr ring_idr; ++ struct mutex ring_lock; ++ struct cdev ring_cdev; ++ dev_t ring_devt; ++} pka; ++ ++static int pka_drv_open(struct inode *inode, struct file *filep) ++{ ++ struct pka_ring_device *ring_dev; ++ int ret; ++ ++ ring_dev = idr_find(&pka.ring_idr, iminor(inode)); ++ if (!ring_dev) { ++ PKA_ERROR(PKA_DRIVER, ++ "failed to find idr for device %d\n", ++ ring_dev->device_id); ++ return -ENODEV; ++ } ++ ++ ret = pka_drv_ring_open(ring_dev); ++ if (ret) ++ return ret; ++ ++ filep->private_data = ring_dev; ++ return 0; ++} ++ ++static int pka_drv_release(struct inode *inode, struct file *filep) ++{ ++ struct pka_ring_device *ring_dev = filep->private_data; ++ ++ filep->private_data = NULL; ++ pka_drv_ring_release(ring_dev); ++ ++ return 0; ++} ++ ++static int pka_drv_mmap(struct file *filep, struct vm_area_struct *vma) ++{ ++ return pka_drv_ring_mmap(filep->private_data, vma); ++} ++ ++static long pka_drv_unlocked_ioctl(struct file *filep, ++ unsigned int cmd, unsigned long arg) ++{ ++ return pka_drv_ring_ioctl(filep->private_data, cmd, arg); ++} ++ ++static const struct file_operations pka_ring_fops = { ++ .owner = THIS_MODULE, ++ .open = pka_drv_open, ++ .release = pka_drv_release, ++ .unlocked_ioctl = pka_drv_unlocked_ioctl, ++ .mmap = pka_drv_mmap, ++}; ++ ++static int pka_drv_add_ring_device(struct pka_ring_device *ring_dev) ++{ ++ struct device *dev = ring_dev->device; ++ ++ ring_dev->minor = idr_alloc(&pka.ring_idr, ++ ring_dev, 0, MINORMASK + 1, GFP_KERNEL); ++ if (ring_dev->minor < 0) { ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to alloc minor to device %d\n", ++ ring_dev->device_id); ++ return ring_dev->minor; ++ } ++ ++ dev = device_create(pka.class, NULL, ++ MKDEV(MAJOR(pka.ring_devt), ring_dev->minor), ++ ring_dev, "%d", ring_dev->device_id); ++ if (IS_ERR(dev)) { ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to create device %d\n", ++ ring_dev->device_id); ++ idr_remove(&pka.ring_idr, ring_dev->minor); ++ return PTR_ERR(dev); ++ } ++ ++ PKA_DEBUG(PKA_DRIVER, ++ "ring device %d minor:%d\n", ++ ring_dev->device_id, ring_dev->minor); ++ ++ return 0; ++} ++ ++static struct pka_ring_device *pka_drv_del_ring_device(struct device *dev) ++{ ++ struct platform_device *pdev = ++ container_of(dev, struct platform_device, dev); ++ struct pka_platdata *priv = platform_get_drvdata(pdev); ++ struct pka_info *info = priv->info; ++ struct pka_ring_device *ring_dev = info->priv; ++ ++ if (ring_dev) { ++ device_destroy(pka.class, MKDEV(MAJOR(pka.ring_devt), ++ ring_dev->minor)); ++ idr_remove(&pka.ring_idr, ring_dev->minor); ++ } ++ ++ return ring_dev; ++} ++ ++static char *pka_drv_devnode(struct device *dev, umode_t *mode) ++{ ++ if (mode != NULL) ++ *mode = PKA_DEVICE_ACCESS_MODE; ++ return kasprintf(GFP_KERNEL, "pka/%s", dev_name(dev)); ++} ++ ++static int pka_drv_init_class(void) ++{ ++ int ret; ++ ++ idr_init(&pka.ring_idr); ++ /* /sys/class/pka/$RING */ ++ pka.class = class_create(THIS_MODULE, "pka"); ++ if (IS_ERR(pka.class)) ++ return PTR_ERR(pka.class); ++ ++ /* /dev/pka/$RING */ ++ pka.class->devnode = pka_drv_devnode; ++ ++ ret = alloc_chrdev_region(&pka.ring_devt, 0, MINORMASK, "pka"); ++ if (ret) ++ goto err_alloc_chrdev; ++ ++ cdev_init(&pka.ring_cdev, &pka_ring_fops); ++ ret = cdev_add(&pka.ring_cdev, pka.ring_devt, MINORMASK); ++ if (ret) ++ goto err_cdev_add; ++ ++ return 0; ++ ++err_cdev_add: ++ unregister_chrdev_region(pka.ring_devt, MINORMASK); ++err_alloc_chrdev: ++ class_destroy(pka.class); ++ pka.class = NULL; ++ return ret; ++} ++ ++static void pka_drv_destroy_class(void) ++{ ++ idr_destroy(&pka.ring_idr); ++ cdev_del(&pka.ring_cdev); ++ unregister_chrdev_region(pka.ring_devt, MINORMASK); ++ class_destroy(pka.class); ++ pka.class = NULL; ++} ++#endif ++ ++static void pka_drv_get_mem_res(struct pka_device *pka_dev, ++ struct pka_dev_mem_res *mem_res, ++ uint64_t wndw_ram_off_mask) ++{ ++ enum pka_mem_res_idx acpi_mem_idx; ++ ++ acpi_mem_idx = PKA_ACPI_EIP154_IDX; ++ mem_res->wndw_ram_off_mask = wndw_ram_off_mask; ++ ++ /* PKA EIP154 MMIO base address*/ ++ mem_res->eip154_base = pka_dev->resource[acpi_mem_idx]->start; ++ mem_res->eip154_size = pka_dev->resource[acpi_mem_idx]->end - ++ mem_res->eip154_base + 1; ++ acpi_mem_idx++; ++ ++ /* PKA window ram base address*/ ++ mem_res->wndw_ram_base = pka_dev->resource[acpi_mem_idx]->start; ++ mem_res->wndw_ram_size = pka_dev->resource[acpi_mem_idx]->end - ++ mem_res->wndw_ram_base + 1; ++ acpi_mem_idx++; ++ ++ /* PKA alternate window ram base address ++ * Note: Here the size of all the alt window ram is same, depicted by ++ * 'alt_wndw_ram_size' variable. All alt window ram resources are read ++ * here even though not all of them are used currently. ++ */ ++ mem_res->alt_wndw_ram_0_base = pka_dev->resource[acpi_mem_idx]->start; ++ mem_res->alt_wndw_ram_size = pka_dev->resource[acpi_mem_idx]->end - ++ mem_res->alt_wndw_ram_0_base + 1; ++ ++ if (mem_res->alt_wndw_ram_size != PKA_WINDOW_RAM_REGION_SIZE) ++ PKA_ERROR(PKA_DRIVER, ++ "Alternate Window RAM size read from ACPI is incorrect.\n"); ++ ++ acpi_mem_idx++; ++ ++ mem_res->alt_wndw_ram_1_base = pka_dev->resource[acpi_mem_idx]->start; ++ acpi_mem_idx++; ++ ++ mem_res->alt_wndw_ram_2_base = pka_dev->resource[acpi_mem_idx]->start; ++ acpi_mem_idx++; ++ ++ mem_res->alt_wndw_ram_3_base = pka_dev->resource[acpi_mem_idx]->start; ++ acpi_mem_idx++; ++ ++ /* PKA CSR base address*/ ++ mem_res->csr_base = pka_dev->resource[acpi_mem_idx]->start; ++ mem_res->csr_size = pka_dev->resource[acpi_mem_idx]->end - ++ mem_res->csr_base + 1; ++} ++ ++/* ++ * Note that this function must be serialized because it calls ++ * 'pka_dev_register_shim' which manipulates common counters for ++ * pka devices. ++ */ ++static int pka_drv_register_device(struct pka_device *pka_dev, ++ uint64_t wndw_ram_off_mask) ++{ ++ uint32_t pka_shim_id; ++ uint8_t pka_shim_fw_id; ++ struct pka_dev_mem_res mem_res; ++ ++ /* Register Shim */ ++ pka_shim_id = pka_dev->device_id; ++ pka_shim_fw_id = pka_dev->fw_id; ++ ++ pka_drv_get_mem_res(pka_dev, &mem_res, wndw_ram_off_mask); ++ ++ pka_dev->shim = pka_dev_register_shim(pka_shim_id, pka_shim_fw_id, ++ &mem_res); ++ if (!pka_dev->shim) { ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to register shim id=%u\n", pka_shim_id); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static int pka_drv_unregister_device(struct pka_device *pka_dev) ++{ ++ if (!pka_dev) ++ return -EINVAL; ++ ++ if (pka_dev->shim) { ++ PKA_DEBUG(PKA_DRIVER, ++ "unregister device shim %u\n", ++ pka_dev->shim->shim_id); ++ return pka_dev_unregister_shim(pka_dev->shim); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Note that this function must be serialized because it calls ++ * 'pka_dev_register_ring' which manipulates common counters for ++ * vfio devices. ++ */ ++static int pka_drv_register_ring_device(struct pka_ring_device *ring_dev) ++{ ++ uint32_t ring_id; ++ uint32_t shim_id; ++ ++ ring_id = ring_dev->device_id; ++ shim_id = ring_dev->parent_device_id; ++ ++ ring_dev->ring = pka_dev_register_ring(ring_id, shim_id); ++ if (!ring_dev->ring) { ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to register ring device %u\n", ring_id); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static int pka_drv_unregister_ring_device(struct pka_ring_device *ring_dev) ++{ ++ uint32_t ring_id; ++ ++ if (!ring_dev) ++ return -EINVAL; ++ ++ ring_id = ring_dev->ring->ring_id; ++ ++ if (ring_dev->ring) { ++ PKA_DEBUG(PKA_DRIVER, "unregister ring device %u\n", ring_id); ++ return pka_dev_unregister_ring(ring_dev->ring); ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id pka_ring_match[] = { ++ { .compatible = PKA_RING_DEVICE_COMPAT }, ++ {}, ++}; ++ ++static int pka_drv_rng_read(struct hwrng *rng, void *data, size_t max, ++ bool wait) ++{ ++ int ret; ++ ++ struct pka_device *pka_dev = container_of(rng, struct pka_device, rng); ++ uint32_t *buffer = data; ++ ++ ret = pka_dev_trng_read(pka_dev->shim, buffer, max); ++ if (ret) { ++ PKA_DEBUG(PKA_DRIVER, ++ "%s: failed to read random bytes ret=%d", ++ rng->name, ret); ++ return 0; ++ } ++ ++ return max; ++} ++ ++static int pka_drv_probe_device(struct pka_info *info) ++{ ++ struct pka_device *pka_dev; ++ struct device *dev = info->dev; ++ struct device_node *of_node = dev->of_node; ++ struct platform_device *pdev = to_platform_device(dev); ++ struct hwrng *trng; ++ const struct acpi_device_id *aid; ++ struct pka_drv_plat_info *plat_info; ++ uint64_t wndw_ram_off_mask; ++ int ret; ++ enum pka_mem_res_idx acpi_mem_idx; ++ ++ if (!info) ++ return -EINVAL; ++ ++ pka_dev = kzalloc(sizeof(*pka_dev), GFP_KERNEL); ++ if (!pka_dev) ++ return -ENOMEM; ++ ++ mutex_lock(&pka_drv_lock); ++ pka_device_cnt += 1; ++ if (pka_device_cnt > PKA_DRIVER_DEV_MAX) { ++ PKA_DEBUG(PKA_DRIVER, ++ "cannot support %u devices\n", pka_device_cnt); ++ kfree(pka_dev); ++ mutex_unlock(&pka_drv_lock); ++ return -EPERM; ++ } ++ pka_dev->device_id = pka_device_cnt - 1; ++ mutex_unlock(&pka_drv_lock); ++ ++ pka_dev->info = info; ++ pka_dev->device = dev; ++ info->flag = PKA_DRIVER_FLAG_DEVICE; ++ mutex_init(&pka_dev->mutex); ++ ++ for (acpi_mem_idx = PKA_ACPI_EIP154_IDX; ++ acpi_mem_idx < PKA_DEVICE_RES_CNT; acpi_mem_idx++) { ++ pka_dev->resource[acpi_mem_idx] = ++ platform_get_resource(pdev, IORESOURCE_MEM, acpi_mem_idx); ++ } ++ ++ /* Window ram offset mask is platform dependent */ ++ aid = acpi_match_device(pka_drv_acpi_ids, dev); ++ if (!aid) ++ return -ENODEV; ++ ++ plat_info = (struct pka_drv_plat_info *)aid->driver_data; ++ if (plat_info->type <= PKA_PLAT_TYPE_BF2) { ++ wndw_ram_off_mask = PKA_WINDOW_RAM_OFFSET_MASK1; ++ } else { ++ PKA_ERROR(PKA_DRIVER, "Invalid platform type: %d\n", ++ (int)plat_info->type); ++ return -EINVAL; ++ } ++ ++ /* Set interrupts */ ++ ret = platform_get_irq(pdev, 0); ++ pka_dev->irq = ret; ++ if (ret == -ENXIO && of_node) { ++ pka_dev->irq = PKA_IRQ_NONE; ++ } else if (ret < 0) { ++ PKA_ERROR(PKA_DRIVER, ++ "failed to get device %u IRQ\n", pka_dev->device_id); ++ return ret; ++ } ++ ++ /* Register IRQ */ ++ ret = pka_drv_register_irq(pka_dev); ++ if (ret) { ++ PKA_ERROR(PKA_DRIVER, ++ "failed to register device %u IRQ\n", ++ pka_dev->device_id); ++ return ret; ++ } ++ ++ /* Firmware version */ ++ pka_dev->fw_id = plat_info->fw_id; ++ ++ mutex_lock(&pka_drv_lock); ++ ret = pka_drv_register_device(pka_dev, wndw_ram_off_mask); ++ if (ret) { ++ PKA_DEBUG(PKA_DRIVER, "failed to register shim id=%u\n", ++ pka_dev->device_id); ++ mutex_unlock(&pka_drv_lock); ++ return ret; ++ } ++ mutex_unlock(&pka_drv_lock); ++ ++ /* Setup the TRNG, if needed */ ++ if (pka_dev_has_trng(pka_dev->shim)) { ++ trng = &pka_dev->rng; ++ trng->name = pdev->name; ++ trng->read = pka_drv_rng_read; ++ ++ ret = hwrng_register(&pka_dev->rng); ++ if (ret) { ++ PKA_ERROR(PKA_DRIVER, ++ "failed to register trng\n"); ++ return ret; ++ } ++ } ++ ++ info->priv = pka_dev; ++ ++#ifdef BUG_SW_1127083_FIXED ++ /* ++ * Create platform devices (pka-ring) from current node. ++ * This code is reserverd for DT. ++ */ ++ if (of_node) { ++ ret = of_platform_populate(of_node, pka_ring_match, ++ NULL, dev); ++ if (ret) { ++ PKA_ERROR(PKA_DRIVER, ++ "failed to create platform devices\n"); ++ return ret; ++ } ++ } ++#endif ++ ++ return 0; ++} ++ ++static int pka_drv_remove_device(struct platform_device *pdev) ++{ ++ struct pka_platdata *priv = platform_get_drvdata(pdev); ++ struct pka_info *info = priv->info; ++ struct pka_device *pka_dev = (struct pka_device *)info->priv; ++ ++ if (!pka_dev) { ++ PKA_ERROR(PKA_DRIVER, "failed to unregister device\n"); ++ return -EINVAL; ++ } ++ ++ if (pka_dev_has_trng(pka_dev->shim)) ++ hwrng_unregister(&pka_dev->rng); ++ ++ if (pka_drv_unregister_device(pka_dev)) ++ PKA_ERROR(PKA_DRIVER, "failed to unregister device\n"); ++ ++ return 0; ++} ++ ++static int pka_drv_probe_ring_device(struct pka_info *info) ++{ ++ struct pka_ring_device *ring_dev; ++ struct device *dev = info->dev; ++ ++ int ret; ++ ++ if (!info) ++ return -EINVAL; ++ ++ ring_dev = kzalloc(sizeof(*ring_dev), GFP_KERNEL); ++ if (!ring_dev) ++ return -ENOMEM; ++ ++ mutex_lock(&pka_drv_lock); ++ pka_ring_device_cnt += 1; ++ if (pka_ring_device_cnt > PKA_DRIVER_RING_DEV_MAX) { ++ PKA_DEBUG(PKA_DRIVER, "cannot support %u ring devices\n", ++ pka_ring_device_cnt); ++ kfree(ring_dev); ++ mutex_unlock(&pka_drv_lock); ++ return -EPERM; ++ } ++ ring_dev->device_id = pka_ring_device_cnt - 1; ++ ring_dev->parent_device_id = pka_device_cnt - 1; ++ mutex_unlock(&pka_drv_lock); ++ ++ ring_dev->info = info; ++ ring_dev->device = dev; ++ info->flag = PKA_DRIVER_FLAG_RING_DEVICE; ++ mutex_init(&ring_dev->mutex); ++ ++ ret = pka_drv_add_ring_device(ring_dev); ++ if (ret) { ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to add ring device %u\n", ++ ring_dev->device_id); ++ kfree(ring_dev); ++ return ret; ++ } ++ ++ mutex_lock(&pka_drv_lock); ++ /* Register ring device */ ++ ret = pka_drv_register_ring_device(ring_dev); ++ if (ret) { ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to register ring device %u\n", ++ ring_dev->device_id); ++ mutex_unlock(&pka_drv_lock); ++ goto err_register_ring; ++ } ++ mutex_unlock(&pka_drv_lock); ++ ++ info->priv = ring_dev; ++ ++ return 0; ++ ++ err_register_ring: ++ pka_drv_del_ring_device(dev); ++ kfree(ring_dev); ++ return ret; ++} ++ ++static int pka_drv_remove_ring_device(struct platform_device *pdev) ++{ ++ struct pka_ring_device *ring_dev; ++ struct device *dev = &pdev->dev; ++ int ret; ++ ++ ring_dev = pka_drv_del_ring_device(dev); ++ if (ring_dev) { ++ ret = pka_drv_unregister_ring_device(ring_dev); ++ if (ret) { ++ PKA_ERROR(PKA_DRIVER, ++ "failed to unregister vfio device\n"); ++ return ret; ++ } ++ kfree(ring_dev); ++ } ++ ++ return 0; ++} ++ ++static int pka_drv_of_probe(struct platform_device *pdev, ++ struct pka_info *info) ++{ ++#ifdef BUG_SW_1127083_FIXED ++ struct device *dev = &pdev->dev; ++ ++ int error; ++ ++ error = device_property_read_string(dev, "compatible", &info->compat); ++ if (error) { ++ PKA_DEBUG(PKA_DRIVER, "cannot retrieve compat for %s\n", ++ pdev->name); ++ return -EINVAL; ++ } ++ ++ if (!strcmp(info->compat, pka_ring_compat)) { ++ PKA_PRINT(PKA_DRIVER, "probe ring device %s\n", ++ pdev->name); ++ error = pka_drv_probe_ring_device(info); ++ if (error) { ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to register ring device compat=%s\n", ++ info->compat); ++ return error; ++ } ++ ++ } else if (!strcmp(info->compat, pka_compat)) { ++ PKA_PRINT(PKA_DRIVER, "probe device %s\n", pdev->name); ++ error = pka_drv_probe_device(info); ++ if (error) { ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to register device compat=%s\n", ++ info->compat); ++ return error; ++ } ++ } ++ ++ return 0; ++#endif ++ return -EPERM; ++} ++ ++static int pka_drv_acpi_probe(struct platform_device *pdev, ++ struct pka_info *info) ++{ ++ struct acpi_device *adev; ++ struct device *dev = &pdev->dev; ++ ++ int error; ++ ++ if (acpi_disabled) ++ return -ENOENT; ++ ++ adev = ACPI_COMPANION(dev); ++ if (!adev) { ++ PKA_DEBUG(PKA_DRIVER, ++ "ACPI companion device not found for %s\n", ++ pdev->name); ++ return -ENODEV; ++ } ++ ++ info->acpihid = acpi_device_hid(adev); ++ if (WARN_ON(!info->acpihid)) ++ return -EINVAL; ++ ++ if (!strcmp(info->acpihid, pka_ring_acpihid_bf1) ++ || !strcmp(info->acpihid, pka_ring_acpihid_bf2)) { ++ error = pka_drv_probe_ring_device(info); ++ if (error) { ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to register ring device %s\n", ++ pdev->name); ++ return error; ++ } ++ PKA_DEBUG(PKA_DRIVER, "ring device %s probed\n", ++ pdev->name); ++ ++ } else if (!strcmp(info->acpihid, pka_acpihid_bf1) ++ || !strcmp(info->acpihid, pka_acpihid_bf2)) { ++ error = pka_drv_probe_device(info); ++ if (error) { ++ PKA_DEBUG(PKA_DRIVER, ++ "failed to register device %s\n", ++ pdev->name); ++ return error; ++ } ++ PKA_PRINT(PKA_DRIVER, "device %s probed\n", pdev->name); ++ } ++ ++ return 0; ++} ++ ++static int pka_drv_probe(struct platform_device *pdev) ++{ ++ struct pka_platdata *priv; ++ struct pka_info *info; ++ struct device *dev = &pdev->dev; ++ ++ int ret; ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ spin_lock_init(&priv->lock); ++ priv->pdev = pdev; ++ /* interrupt is disabled to begin with */ ++ priv->irq_flags = 0; ++ ++ info = kzalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ info->name = pdev->name; ++ info->version = PKA_DRIVER_VERSION; ++ info->module = THIS_MODULE; ++ info->dev = dev; ++ ++ priv->info = info; ++ ++ platform_set_drvdata(pdev, priv); ++ ++ /* ++ * There can be two kernel build combinations. One build where ++ * ACPI is not selected and another one with the ACPI. ++ * ++ * In the first case, 'pka_drv_acpi_probe' will return since ++ * acpi_disabled is 1. DT user will not see any kind of messages ++ * from ACPI. ++ * ++ * In the second case, both DT and ACPI is compiled in but the ++ * system is booting with any of these combinations. ++ * ++ * If the firmware is DT type, then acpi_disabled is 1. The ACPI ++ * probe routine terminates immediately without any messages. ++ * ++ * If the firmware is ACPI type, then acpi_disabled is 0. All other ++ * checks are valid checks. We cannot claim that this system is DT. ++ */ ++ ret = pka_drv_acpi_probe(pdev, info); ++ if (ret) ++ ret = pka_drv_of_probe(pdev, info); ++ ++ if (ret) { ++ PKA_DEBUG(PKA_DRIVER, "unknown device\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int pka_drv_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ ++ /* ++ * Little hack here: ++ * The issue here is that the driver data structure which holds our ++ * initialized private data cannot be used when the 'pdev' arguments ++ * points to child device -i.e. vfio device. Indeed, during the probe ++ * function we set an initialized structure called 'priv' as driver ++ * data for all platform devices including parents devices and child ++ * devices. This driver data is unique to each device - see call to ++ * 'platform_set_drvdata()'. However, when we add the child device to ++ * a vfio group through 'vfio_add_group_dev()' call, this function ++ * creates a new driver data for the device - i.e. a 'vfio_device' ++ * structure which includes a field called 'device_data' to hold the ++ * aforementionned initialized private data. So, to retrieve our ++ * private data, we must call 'dev_get_drvdata()' which returns the ++ * 'vfio_device' struct and access its 'device_data' field. However, ++ * this cannot be done before determining if the 'pdev' is associated ++ * with a child device or a parent device. ++ * In order to deal with that we propose this little hack which uses ++ * the iommu_group to distinguich between parent and child devices. ++ * For now, let's say it is a customized solution that works for our ++ * case. Indeed, in the current design, the private data holds some ++ * infos that defines the type of the device. The intuitive way to do ++ * that is as following: ++ * ++ * struct pka_platdata *priv = platform_get_drvdata(pdev); ++ * struct pka_info *info = priv->info; ++ * ++ * if (info->flag == PKA_DRIVER_FLAG_RING_DEVICE) ++ * return pka_drv_remove_ring_device(info); ++ * if (info->flag == PKA_DRIVER_FLAG_DEVICE) ++ * return pka_drv_remove_ring_device(info); ++ * ++ * Since the returned private data of child devices -i.e vfio devices ++ * corresponds to 'vfio_device' structure, we cannot use it to ++ * differentiate between parent and child devices. This alternative ++ * solution is used instead. ++ */ ++ if (dev->iommu_group) { ++ PKA_PRINT(PKA_DRIVER, "remove ring device %s\n", ++ pdev->name); ++ return pka_drv_remove_ring_device(pdev); ++ } ++ ++ PKA_PRINT(PKA_DRIVER, "remove device %s\n", pdev->name); ++ return pka_drv_remove_device(pdev); ++} ++ ++static const struct of_device_id pka_drv_match[] = { ++ { .compatible = PKA_DEVICE_COMPAT }, ++ { .compatible = PKA_RING_DEVICE_COMPAT }, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(of, pka_drv_match); ++ ++MODULE_DEVICE_TABLE(acpi, pka_drv_acpi_ids); ++ ++static struct platform_driver pka_drv = { ++ .driver = { ++ .name = PKA_DRIVER_NAME, ++ .of_match_table = of_match_ptr(pka_drv_match), ++ .acpi_match_table = ACPI_PTR(pka_drv_acpi_ids), ++ }, ++ .probe = pka_drv_probe, ++ .remove = pka_drv_remove, ++}; ++ ++/* Initialize the module - Register the pka platform driver */ ++static int __init pka_drv_register(void) ++{ ++ int ret; ++ ++ ret = pka_drv_init_class(); ++ if (ret) { ++ PKA_ERROR(PKA_DRIVER, "failed to create class\n"); ++ return ret; ++ } ++ ++ ret = platform_driver_register(&pka_drv); ++ if (ret) { ++ PKA_ERROR(PKA_DRIVER, "failed to register platform driver\n"); ++ return ret; ++ } ++ ++ PKA_PRINT(PKA_DRIVER, "version: " PKA_DRIVER_VERSION "\n"); ++ ++ return 0; ++} ++ ++/* Cleanup the module - unregister the pka platform driver */ ++static void __exit pka_drv_unregister(void) ++{ ++ platform_driver_unregister(&pka_drv); ++ pka_drv_destroy_class(); ++} ++ ++module_init(pka_drv_register); ++module_exit(pka_drv_unregister); ++ ++MODULE_DESCRIPTION(PKA_DRIVER_DESCRIPTION); ++MODULE_VERSION(PKA_DRIVER_VERSION); ++MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_firmware.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_firmware.h +new file mode 100644 +index 000000000..29ea27ce0 +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_firmware.h +@@ -0,0 +1,4823 @@ ++// ++// BSD LICENSE ++// ++// Copyright(c) 2016 Mellanox Technologies, Ltd. All rights reserved. ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// ++// * Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// * Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in ++// the documentation and/or other materials provided with the ++// distribution. ++// * Neither the name of Mellanox Technologies nor the names of its ++// contributors may be used to endorse or promote products derived ++// from this software without specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++// ++ ++#ifndef __DRIVERS_MICA_PKA_FW_H__ ++#define __DRIVERS_MICA_PKA_FW_H__ ++ ++#include ++ ++// ++// Program binaries ++// ++ ++// Align to PKA_BUFFER_RAM_SIZE. This is greater than the actual buffer ++// length so that the image is zero padded. ++static const uint32_t fw0_farm_img_data_buf[2048] = ++{ ++ 0x137001C9, 0x692040FA, 0x55502301, 0x328C0200, ++ 0x5E7000C9, 0x3D7000C8, 0x3670001D, 0x5370001F, ++ 0x746A4010, 0x046B4014, 0x3C621FF8, 0x4B631FF4, ++ 0x2A684000, 0x5A694004, 0x4F601FF6, 0x3F611FF2, ++ 0x5A6A4008, 0x2A6B400C, 0x19621FFA, 0x6D631FF0, ++ 0x0F684034, 0x7070001E, 0x5D34003F, 0x08601FFE, ++ 0x0328000B, 0x52C40047, 0x69240027, 0x04880000, ++ 0x76800047, 0x3380002E, 0x36800047, 0x7A800039, ++ 0xB6800047, 0xDF80003B, 0xD7800027, 0x9B800035, ++ 0xDC80003D, 0xB980003F, 0xB5800041, 0xF36A4018, ++ 0xDA621FFC, 0x9997017D, 0xA4300002, 0xD9D00061, ++ 0xBC30FFFE, 0xFC800056, 0xF36A4018, 0x9A621FFC, ++ 0xD59701CC, 0xA4300002, 0x99D00061, 0xFC30FFFE, ++ 0x99800062, 0xD097026C, 0xD38C0400, 0x8B614018, ++ 0xBC800056, 0xFF97039F, 0xFC800056, 0x9A97039D, ++ 0xFC800056, 0x9D9703A3, 0xBC800056, 0xF89703A1, ++ 0xBC800056, 0xDC970367, 0xFC800056, 0x9D200003, ++ 0xFC800056, 0xB7200023, 0xBC800056, 0xFD7000C8, ++ 0xD2200021, 0xBA8C5000, 0x9B80006F, 0xF5707FC8, ++ 0x84702084, 0xF670001D, 0xDB200000, 0xB6010000, ++ 0xCF220001, 0xB197007F, 0xA0684084, 0xD3340020, ++ 0xA7CC0052, 0xFC20000F, 0xF18C0100, 0xA4300002, ++ 0x99D00061, 0xED601FFC, 0xD5681FF0, 0x926A4014, ++ 0xF6010000, 0xB18C0100, 0x9260400C, 0xF197007F, ++ 0x34681FFC, 0x7C30FFFE, 0x616A1FF6, 0x336B1FF8, ++ 0x44624000, 0x3B634010, 0x076A1FF2, 0x526B1FF4, ++ 0x62624004, 0x1D634014, 0x006A1FFA, 0x7A230000, ++ 0x03624008, 0x7A8C5000, 0x5A63401C, 0x086440C9, ++ 0x5B800003, 0x3B6B1FE4, 0x118B4000, 0x7F8C0480, ++ 0x17BC004B, 0x6D61401C, 0x518B4000, 0x36010000, ++ 0x3C30FFFE, 0x66500000, 0x66500000, 0x26500000, ++ 0x66500000, 0x24300002, 0x102A0002, 0x65614000, ++ 0xAD624010, 0xF4604008, 0xEE218808, 0x93800073, ++ 0xE5631FEC, 0x8B6B4000, 0x846A1FF4, 0xF3604000, ++ 0xC3614004, 0x95634008, 0xAD624010, 0xCB624014, ++ 0xBB218001, 0xD0970073, 0xFA068000, 0x8C6B4008, ++ 0xE6691FF2, 0x92634000, 0x83614004, 0xF4604008, ++ 0xAD624010, 0xD6218200, 0xD0970073, 0xBC6B1FEC, ++ 0x918B4000, 0xE2631FE4, 0xF0681FF2, 0xB56040A0, ++ 0xE5691FF4, 0xB3604000, 0xB4604008, 0xCC614010, ++ 0x138C0400, 0x6470081C, 0x5270881D, 0x20F000A3, ++ 0x7C30FFFE, 0x33490000, 0x34310001, 0x5D200003, ++ 0x48D40071, 0x0931FFFF, 0x146540B4, 0x706B1FFE, ++ 0x216A1FF6, 0x7E33FFFF, 0x56D000BA, 0x336B1FF8, ++ 0x44624000, 0x03624008, 0x3B634010, 0x7F8C0480, ++ 0x17BC004B, 0x5E70011F, 0x6470081C, 0x1270881D, ++ 0x08F000B8, 0x538000BC, 0x7F8C0480, 0x17BC004B, ++ 0x6C6840A0, 0x30694024, 0x2F090000, 0x7FC8017A, ++ 0x23024000, 0x6E2E0001, 0x4B624014, 0x2F31FFFB, ++ 0x47684028, 0x1370001F, 0x3734001F, 0x57184000, ++ 0x592C0001, 0x17020000, 0x24240008, 0x6934FFE0, ++ 0x04300005, 0x65691FF4, 0x506040A2, 0x366040A6, ++ 0x592C0001, 0x2F090000, 0x10C400DF, 0x7A6940A0, ++ 0x0E050000, 0x722DFFFF, 0x6A31FFFE, 0x30510000, ++ 0x30510000, 0x61691FFA, 0x4E050000, 0x322DFFFF, ++ 0x6A31FFFE, 0x30510000, 0x30510000, 0x592C0001, ++ 0x8434FFFE, 0xC4601FEC, 0xF526000C, 0xB0621FEA, ++ 0xD126005F, 0xBA200060, 0xBA230000, 0xCB0B2000, ++ 0xF22DFFFF, 0x816140AA, 0x8F2D0001, 0xEA072000, ++ 0xBF6B1FEA, 0xD4004000, 0xFA30FFFD, 0xAF0AC000, ++ 0xFA230000, 0xA6631FEA, 0x8B0B2000, 0xFA20000C, ++ 0xBA230000, 0xF4290007, 0xF9C400F9, 0x95250007, ++ 0x9B8000FA, 0xED210007, 0xCD084000, 0xB61B4000, ++ 0xF9634088, 0x986940AA, 0xBA30FFFD, 0xCF2D0001, ++ 0xAA072000, 0xF22A0008, 0xD5621FE8, 0xB5008000, ++ 0xEE2E0001, 0xA934FFE0, 0x84300005, 0xD92C0001, ++ 0xF46B1FF0, 0x8B691FEC, 0xA1601FEE, 0xCD074000, ++ 0x92634000, 0xDD33FFFE, 0xC7530000, 0x87530000, ++ 0xC7530000, 0x87530000, 0x85330002, 0xD5634008, ++ 0xB9070000, 0xE52B0003, 0xE4280004, 0x8FC00130, ++ 0x992C0001, 0xDA604010, 0xFF8C0480, 0x97BC004B, ++ 0xDE70011F, 0x9570001C, 0x9270881D, 0xE3F0011F, ++ 0x07691FFE, 0x66684024, 0x4931FFFF, 0x1BD0012F, ++ 0x40691FF6, 0x02140000, 0x3ED00177, 0x4D084000, ++ 0x51694028, 0x2135001F, 0x3930FFFB, 0x57184000, ++ 0x3BC80174, 0x592C0001, 0x40601FE2, 0x1370001F, ++ 0x75008000, 0x3E3CFFFF, 0x18218000, 0x6C110000, ++ 0x1D33FFFE, 0x50340010, 0x57C8013B, 0x0B41C000, ++ 0x27270002, 0x47530000, 0x5180013D, 0x07530000, ++ 0x4B41C000, 0x38681FEE, 0x3A6940A0, 0x5A604010, ++ 0x0B6B4000, 0x7904C000, 0x592C0001, 0x0434FFFE, ++ 0x43614004, 0x34604008, 0x2268401C, 0x7F8C0480, ++ 0x57BC004B, 0x1E70011F, 0x1570001C, 0x6D70821D, ++ 0x07F0014C, 0x7E340008, 0x73C8015E, 0x07691FFE, ++ 0x66684024, 0x0931FFFF, 0x30D0015E, 0x40691FF6, ++ 0x02140000, 0x7ED00177, 0x4D084000, 0x11694028, ++ 0x3930FFFB, 0x6135001F, 0x57184000, 0x3BC80174, ++ 0x592C0001, 0x00601FE2, 0x1370001F, 0x6D691FE8, ++ 0x9F20000E, 0xF4310001, 0xC931FFFF, 0xB4D00166, ++ 0xE42CFFFF, 0x94800162, 0xBC694000, 0xC62207FA, ++ 0xCC6B4008, 0xA46140A8, 0xB26340A4, 0xE36240AC, ++ 0xB16040AE, 0xD77000B2, 0xFF8C0480, 0x97BC004B, ++ 0xF8700484, 0x9CE00171, 0xB8200001, 0xF6800071, ++ 0xBF200009, 0xD370001F, 0xF6800071, 0x9E200005, ++ 0x9370001F, 0xF6800071, 0xFB200007, 0x9370001F, ++ 0xF3C80071, 0x84631FE0, 0xBA230000, 0xE9631FFE, ++ 0x3F970099, 0x433C0001, 0x7CC80185, 0x033C0001, ++ 0x558001CA, 0x37681FFA, 0x136040A4, 0x5D8C0180, ++ 0x57BC004B, 0x1A700184, 0x39E0018A, 0x7D6940A8, ++ 0x096840A2, 0x65614000, 0x592C0001, 0x346B1FF0, ++ 0x5A604010, 0x15634008, 0x1D8C0180, 0x57BC004B, ++ 0x1570001C, 0x5270881D, 0x62691FFC, 0x322DFFFF, ++ 0x17C801AE, 0x54004000, 0x4034FFF0, 0x1A20000B, ++ 0x68CC01CA, 0x2A6A1FEC, 0x0100C000, 0x4D048000, ++ 0x936340A8, 0xF26340A4, 0xFF8C0480, 0x97BC004B, ++ 0xDA700184, 0xB4E001A5, 0xB26040A8, 0xCD048000, ++ 0xDD8C0180, 0x97BC004B, 0x99700284, 0xF0E001AB, ++ 0xB22DFFFF, 0xE8CC01A6, 0xD5681FF0, 0x8B691FEC, ++ 0xCE050000, 0xA16A1FF6, 0xB86B1FE2, 0xF26040A8, ++ 0x856140A4, 0xE36240AC, 0xF4681FFC, 0x862B0002, ++ 0xA42CFFFF, 0xD06340AE, 0xF96040B2, 0x968C5080, ++ 0xD7BC004B, 0xB8700484, 0x9CE001BE, 0xFE201FE8, ++ 0x85500001, 0xE4300002, 0xD36040A4, 0x9B200000, ++ 0xF66040A6, 0x9D8C0180, 0x97BC004B, 0xDA700184, ++ 0xD7E001C8, 0xB8200001, 0x9D6B1FE0, 0xD18B4000, ++ 0x87631FE6, 0xE6691FF2, 0xC06A1FFA, 0x83614004, ++ 0xE5691FF4, 0xB3621FDA, 0xAA614014, 0xD4004000, ++ 0x86240002, 0xC434FFFE, 0xE1601FD8, 0xBA054000, ++ 0xA26A1FF0, 0xCC614010, 0xC4624000, 0xAF060000, ++ 0xEF060000, 0xB1260002, 0x83624008, 0xD6218200, ++ 0x10970073, 0x516B1FF2, 0x6F060000, 0x39070000, ++ 0x74634004, 0x03624008, 0x10970073, 0x57020000, ++ 0x7B694008, 0x15681FF0, 0x3A098000, 0x7A068000, ++ 0x3197007F, 0x78681FD8, 0x476A1FF2, 0x00691FF6, ++ 0x736B1FF8, 0x2F060000, 0x21270001, 0x6537FFFE, ++ 0x2F05C000, 0x746B1FF0, 0x59611FF6, 0x3904C000, ++ 0x1E621FF2, 0x6E601FFA, 0x4C601FF0, 0x138C0400, ++ 0x5997017D, 0x01030000, 0x223F0001, 0x6DCC026A, ++ 0xB18C0100, 0xCF6A1FD8, 0xC3691FF0, 0x94004000, ++ 0xFA098000, 0x8D048000, 0xB197007F, 0xF6010000, ++ 0xEA684000, 0xBA098000, 0xBA068000, 0xF197007F, ++ 0xB36B1FF8, 0xC0691FF6, 0xE1270001, 0xA537FFFE, ++ 0xCE09C000, 0x996B1FD8, 0x876A1FF2, 0xD9611FF6, ++ 0xAF0AC000, 0xDE621FF2, 0xD38C0400, 0x9997017D, ++ 0xBC6B1FDA, 0xCF6A1FD8, 0xC3691FF0, 0x8F631FFA, ++ 0xFA098000, 0x9A611FF0, 0x81030000, 0xE23F0001, ++ 0x2DCC026A, 0x718C0100, 0x54004000, 0x0D048000, ++ 0x5260400C, 0x0D048000, 0x06240002, 0x66691FF2, ++ 0x446A1FF4, 0x3C30FFFE, 0x26500000, 0x66500000, ++ 0x24300002, 0x7197007F, 0x4B624014, 0x2A6B400C, ++ 0x77260001, 0x03691FF0, 0x21280001, 0x6D624010, ++ 0x34604008, 0x43614004, 0x52634000, 0x162A0001, ++ 0x1B058000, 0x6A31FFFE, 0x70510000, 0x30510000, ++ 0x6C078000, 0x1D33FFFE, 0x07530000, 0x47530000, ++ 0x3D218002, 0x50970073, 0x71260002, 0x2D624010, ++ 0x61691FFA, 0x1A6A4008, 0x03614004, 0x43624008, ++ 0x7B218001, 0x10970073, 0x30681FF2, 0x7C694000, ++ 0x04624000, 0x55604004, 0x526B1FF4, 0x22614008, ++ 0x5807C000, 0x27270002, 0x3B634010, 0x56218200, ++ 0x10970073, 0x7B694008, 0x43624008, 0x196B1FD8, ++ 0x25614000, 0x79070000, 0x73681FF4, 0x34634004, ++ 0x5A604010, 0x3B218001, 0x10970073, 0x62624004, ++ 0xA26A1FF0, 0xD8040000, 0xC4624000, 0x83624008, ++ 0xFC604014, 0xB6218018, 0x90970073, 0xE562400C, ++ 0xD38C0400, 0xB8200001, 0x9E6B1FE6, 0xD18B4000, ++ 0xA2631FE4, 0xD5681FF0, 0xD260400C, 0x84691FF8, ++ 0xF4611FDE, 0x846A1FF4, 0xB0621FDC, 0xFA0A4000, ++ 0x820E4000, 0xC5D40277, 0xE3024000, 0x92260003, ++ 0xB336FFFE, 0xC0601FE2, 0xCD048000, 0xA5601FE0, ++ 0xCD048000, 0xBA068000, 0xBB621FF0, 0xCD048000, ++ 0x25601FD6, 0x4B68400C, 0x76970077, 0x226A1FF0, ++ 0x4B68400C, 0x0D048000, 0x36970077, 0x656A1FF8, ++ 0x59681FE2, 0x346B1FF0, 0x3904C000, 0x40691FF6, ++ 0x3197007F, 0x538C0400, 0x476B4024, 0x22631FD2, ++ 0x4D378000, 0x23CC035A, 0x3C681FE0, 0x746B1FF0, ++ 0x3904C000, 0x66691FF2, 0x446A1FF4, 0x3197007F, ++ 0x19681FE2, 0x7C30FFFE, 0x45500001, 0x3C681FE0, ++ 0x66691FF2, 0x3197007F, 0x3D201FD8, 0x66500000, ++ 0xA6500000, 0xE6691FF2, 0xEA31FFFE, 0x87494000, ++ 0xF4310001, 0x80D4035D, 0x8931FFFF, 0xDB200000, ++ 0xC0601FD4, 0x99230001, 0x8F220001, 0xC100C000, ++ 0x97148000, 0xDCC802B2, 0xD9681FD4, 0x8D048000, ++ 0xC0601FD4, 0x8D074000, 0xBA054000, 0xFA068000, ++ 0xA9CC02AB, 0xD9681FE2, 0xF46B1FF0, 0xB904C000, ++ 0x8D210000, 0xCC6A1FDE, 0xDF970361, 0xBC30FFFE, ++ 0xE5480000, 0x8D388000, 0xA2300001, 0xD7D002C2, ++ 0x96250001, 0xF88002BE, 0xF63D0000, 0x94C802F4, ++ 0xD38C0400, 0x8B614018, 0x93218040, 0xD0970073, ++ 0xD9681FD4, 0x8F691FE2, 0xAA31FFFE, 0xC7494000, ++ 0xAA072000, 0xEE210001, 0xE56B4018, 0x9F3FFFFF, ++ 0xE1270001, 0x8D11C000, 0xB22DFFFF, 0xC1164000, ++ 0x996B1FD8, 0xD38C0400, 0xF0694024, 0x95611FD2, ++ 0xBAC802EC, 0xEF1F8000, 0xDEC802E5, 0x96621FD8, ++ 0xF0681FF2, 0x862107F6, 0xBC970360, 0xCF220001, ++ 0x0B624014, 0x7C681FD6, 0x74604008, 0x3B218001, ++ 0x50970073, 0x2A691FD6, 0x19681FE2, 0x446A1FF4, ++ 0x77260001, 0x1F970361, 0x31218010, 0x50970073, ++ 0x19681FE2, 0x4D210000, 0x446A1FF4, 0x37260001, ++ 0x5F970361, 0x13218040, 0x10970073, 0x798002B5, ++ 0x3C681FE0, 0x746B1FF0, 0x7904C000, 0x15604004, ++ 0x19681FE2, 0x7904C000, 0x73604000, 0x0C6A1FDE, ++ 0x7F6B1FDC, 0x1D634014, 0x2F0AC000, 0x570EC000, ++ 0x05D40302, 0x7602C000, 0x6D624010, 0x37218400, ++ 0x50970073, 0x0C691FD2, 0x2F1C4000, 0x44CC030F, ++ 0x6A31FFFE, 0x11484000, 0x033C0001, 0x492D0002, ++ 0x07494000, 0x57184000, 0x79C80350, 0x138C0400, ++ 0x40684020, 0x22300001, 0x18D0035A, 0x64300002, ++ 0x33D0031D, 0x6A684000, 0x5A694004, 0x15604004, ++ 0x25614000, 0x43684010, 0x73694014, 0x3C604014, ++ 0x4C614010, 0x0B6B4000, 0x15634008, 0x47631FD0, ++ 0xB2218020, 0xD0970073, 0xF1D00326, 0xBC681FE0, ++ 0xCF691FE2, 0xB3800328, 0x99681FE2, 0xEA691FE0, ++ 0xC46A1FF4, 0xB7260001, 0x9F970361, 0xD38C0400, ++ 0x916A4024, 0xF2218020, 0xD0970073, 0xBF681FD0, ++ 0xCE0A0000, 0xB7260001, 0xAA691FE0, 0xF46B1FF0, ++ 0xAF05C000, 0xCD1D0000, 0xE2CC033D, 0x99681FE2, ++ 0xAA691FE0, 0xE5601FE0, 0xD6611FE2, 0xBB681FDE, ++ 0xC7601FDC, 0x95621FDE, 0x99681FE2, 0xE6691FF2, ++ 0xBC970360, 0xF46A4010, 0xCD048000, 0xBC30FFFE, ++ 0xD38C0400, 0x844B0000, 0xA6500000, 0xE6500000, ++ 0xC13F0000, 0xBCC802B5, 0xB1218010, 0xD0970073, ++ 0xA22CFFFC, 0xD38C0400, 0xE6500000, 0xB98002B5, ++ 0xCF691FE2, 0xBC681FE0, 0x846A1FF4, 0xF197007F, ++ 0x8B624014, 0xF8200001, 0xCD210000, 0xAA6B400C, ++ 0xAD631FF0, 0xF6800071, 0xD2200017, 0xAD210007, ++ 0xDC800357, 0x9D200003, 0x8321001F, 0xDC800357, ++ 0x046A1FF4, 0x6D624010, 0x4B624014, 0x33604000, ++ 0x43614004, 0x34604008, 0x118B4000, 0x47631FE6, ++ 0x56681FF6, 0x04691FF8, 0x046A1FF4, 0x6E601FCC, ++ 0x3B611FCA, 0x7C621FF8, 0x52260003, 0x3336FFFE, ++ 0x7C621FCE, 0x346B1FF0, 0x2C078000, 0x6C078000, ++ 0x2E631FF6, 0x6C078000, 0x6D631FF0, 0x1097026C, ++ 0x033C0001, 0x72C8037C, 0x433C0001, 0x3980039A, ++ 0x55681FF0, 0x256A1FCE, 0x2C088000, 0x76970077, ++ 0x83691FF0, 0xE56A1FCE, 0xF5034000, 0x94004000, ++ 0xEC078000, 0x92634000, 0xAC088000, 0xEC088000, ++ 0xD4970084, 0x83691FF0, 0xA56A1FCE, 0xD4004000, ++ 0xAC088000, 0xFC30FFFE, 0xC5500001, 0xA7280002, ++ 0xE4300002, 0xAC088000, 0xAC088000, 0xCC601FF0, ++ 0x94970084, 0xE1691FCC, 0xC36A1FCA, 0x99611FF6, ++ 0xBC621FF8, 0xF8200001, 0xD38C0400, 0x9E6B1FE6, ++ 0xD18B4000, 0xAC220000, 0xBE8003A4, 0xD8224000, ++ 0x3E8003A4, 0x79228000, 0x7E8003A4, 0x0D22C000, ++ 0x7F621FFE, 0x07631FE6, 0x3F970099, 0x526B1FF4, ++ 0x44270003, 0x2537FFFE, 0x22631FBE, 0x76010000, ++ 0x033C0001, 0x718C0100, 0x67CC04E2, 0x3E6A40A2, ++ 0x6B6840A8, 0x37260001, 0x1A970658, 0x70681FF2, ++ 0x046A1FF4, 0x5A970658, 0x77260001, 0x3336FFFE, ++ 0x276240A2, 0x416240A6, 0x7D6940A8, 0x2D6A1FBE, ++ 0x70611FBC, 0x13201FC0, 0x13230010, 0x5B058000, ++ 0x2A410000, 0x5F2C0002, 0x452FFFFF, 0x2BCC03BF, ++ 0x56681FC0, 0x2E32FFFC, 0x36970077, 0x7B970638, ++ 0x4F691FD4, 0x30681FF2, 0x0F220001, 0x7197061F, ++ 0x306B1FFE, 0x7E33FFFF, 0x74D0052F, 0x3B6B1FBE, ++ 0x66691FF2, 0x0B6A1FD6, 0x2F05C000, 0x7797062A, ++ 0x00691FC0, 0x4F220001, 0x7E97063D, 0x2D691FDE, ++ 0x0A220004, 0x7E97063D, 0x6A6A1FDA, 0x21691FFA, ++ 0x7797062A, 0x2E691FD8, 0x3B6B1FBE, 0x70681FF2, ++ 0x89220002, 0xF904C000, 0xF904C000, 0xB197061F, ++ 0xD2970628, 0xB06B1FFE, 0xA1691FFA, 0xE31BC000, ++ 0xCAD403EF, 0xBB6B1FBE, 0xA26A1FC6, 0xEF05C000, ++ 0xAF05C000, 0xF797062A, 0xDF8003F2, 0x80691FC0, ++ 0xD5681FC6, 0xB0970614, 0x8B691FDA, 0xF0681FC4, ++ 0xA26A1FC6, 0xD46040AC, 0xE46140A8, 0xA46240A4, ++ 0xBA8C5000, 0xD4700384, 0xFA970605, 0x8D21889C, ++ 0xC5614092, 0xBA8C5000, 0xB1700080, 0xCF691FE2, ++ 0xB597064B, 0xE9204096, 0xC0502A27, 0xA15030A7, ++ 0xE9204096, 0xAA504A52, 0x995024A5, 0xD1970642, ++ 0xEF502E27, 0xBF502084, 0xB7970646, 0xC450292F, ++ 0x91970642, 0xE76B4080, 0xF2370020, 0xA2CC0444, ++ 0xE9503548, 0xA1501CE4, 0xB7970646, 0xF85024A9, ++ 0x91970642, 0xE150A148, 0xC55035A4, 0xB7970646, ++ 0x94502530, 0xD1970642, 0xC7502929, 0x8C5035B3, ++ 0xF7970646, 0xBF502108, 0x91970642, 0xF55025A9, ++ 0x2E502CA6, 0x77970646, 0x4A50288A, 0x11970642, ++ 0x7150B4EB, 0x0C509525, 0x37970646, 0x7B501086, ++ 0x51970642, 0x27502D67, 0x215035AD, 0x77970646, ++ 0x2350198F, 0x51970642, 0x676B4080, 0x00631FEE, ++ 0x715098C4, 0x1E509DB1, 0x37970646, 0x4A50316C, ++ 0x11970642, 0x40509148, 0x4F502CC6, 0x37970646, ++ 0x20503590, 0x51970642, 0x7A5099AB, 0x01194000, ++ 0x5CC80447, 0x3597064B, 0x2D204098, 0x615030A7, ++ 0x37970646, 0x595024A5, 0x51970642, 0x35800408, ++ 0x7A8C5000, 0x34200013, 0x398004E3, 0x7A8C5000, ++ 0x716A4080, 0x3B681FDE, 0x24360020, 0x4ECC04F2, ++ 0x2D6A1FBE, 0x76970077, 0x7B970638, 0x0F220001, ++ 0x6D691FDE, 0x3E97063D, 0x0C691FD2, 0x7B6B1FBE, ++ 0x37681FFA, 0x4F220001, 0x7904C000, 0x3197061F, ++ 0x12970628, 0x7B6B1FBE, 0x66691FF2, 0x086A1FD0, ++ 0x6F05C000, 0x2F05C000, 0x3797062A, 0x6E691FD8, ++ 0xBB6B1FBE, 0xF0681FF2, 0xCF220001, 0xB904C000, ++ 0xF904C000, 0xB197061F, 0x92970628, 0xD8700090, ++ 0xFA970605, 0xBA8C5000, 0xA9204096, 0xEA504A52, ++ 0x815029E5, 0xE9204096, 0xEA504A52, 0xBC502491, ++ 0xD1970642, 0x8150292A, 0xB95020B1, 0xF7970646, ++ 0x9D501264, 0xD1970642, 0xC0502D04, 0xBD5040B0, ++ 0xB7970646, 0xD25024E5, 0xD1970642, 0x8B50A088, ++ 0xDC504130, 0xB7970646, 0xAC502D4B, 0xD1970642, ++ 0x2A504A52, 0x45502924, 0x77970646, 0x27502CEB, ++ 0x51970642, 0x24502E0B, 0x3D5011AA, 0x77970646, ++ 0x7F502108, 0x11970642, 0x2A504A52, 0x45502E6B, ++ 0x37970646, 0x555020C8, 0x51970642, 0x3250AD0B, ++ 0x66502925, 0x11970642, 0x03501E52, 0x5550166B, ++ 0x37970646, 0x4C5019AA, 0x51970642, 0x2A504A52, ++ 0x115020C6, 0x77970646, 0x595024A5, 0x11970642, ++ 0x6A504A52, 0x01502D0F, 0x37970646, 0x4E502884, ++ 0x91970642, 0xCA50296A, 0xD3502188, 0x91970642, ++ 0xE650A509, 0xA4502944, 0x91970642, 0xEA504A52, ++ 0xD95024C9, 0x91970642, 0xAD50A549, 0xD5502144, ++ 0xB7970646, 0xD1502669, 0xD1970642, 0x95681FC6, ++ 0xFA8C5000, 0xA76B4080, 0xBC30FFFE, 0xDF370008, ++ 0x80CC04B7, 0xF320001B, 0xF98004E3, 0x85500001, ++ 0xB06B1FFE, 0xED204098, 0xE31BC000, 0x8DD404C4, ++ 0xFF5010E4, 0xAD204098, 0xB35014E5, 0xF7970646, ++ 0xAB5018E6, 0xD1970642, 0xF18C0100, 0xB180051F, ++ 0xEB5018E6, 0xB46B1FF0, 0x96681FF6, 0xC4691FF8, ++ 0xCC631FCA, 0xAE601FCC, 0x9D611FCE, 0xF0681FC4, ++ 0xA5691FF4, 0xF46B1FC6, 0xCF2D0001, 0x9D611FF8, ++ 0xED631FF0, 0x8F601FF6, 0xBA8C5000, 0xD097026C, ++ 0x956B1FCA, 0xC06A1FCC, 0xC4691FCE, 0xAD631FF0, ++ 0xB8621FF6, 0xDD611FF8, 0xD38C0400, 0x833C0001, ++ 0xE7CC04E2, 0x80691FC0, 0xBA97065F, 0xE5691FC2, ++ 0x3A97065F, 0x7180051F, 0x433C0001, 0x3423001F, ++ 0x44601FEC, 0x00631FEE, 0x2D6A1FBE, 0x47691FFE, ++ 0x55681FF0, 0x01194000, 0x14038000, 0x43D404ED, ++ 0x3A068000, 0x4E06C000, 0x76970077, 0x1D681FEC, ++ 0x596B1FEE, 0x1480052B, 0x0F6A1FEE, 0x4E6B4090, ++ 0x33320005, 0x4D1EC000, 0x6D360001, 0x12C804FB, ++ 0x1920000D, 0x5A230007, 0x598004E4, 0x2D6A1FBE, ++ 0x55681FF0, 0x07691FFE, 0x14038000, 0x7A068000, ++ 0x01194000, 0x47D40503, 0x4E06C000, 0x36970077, ++ 0x61691FFA, 0x15681FF0, 0x046A1FF4, 0x55970616, ++ 0x6D6A1FBE, 0x166B1FFA, 0x15681FF0, 0x6C078000, ++ 0x34634004, 0x4D048000, 0x74604008, 0x26691FF2, ++ 0x446A1FF4, 0x25614000, 0x0B624014, 0x72218020, ++ 0x266A1FFE, 0x50970073, 0x411A8000, 0x0FD40529, ++ 0x3B6B1FBE, 0x55681FF0, 0x5807C000, 0x3904C000, ++ 0x7C30FFFE, 0x05500001, 0x31800529, 0x6D6A1FBE, ++ 0x80691FC0, 0xD1681FFE, 0xD4038000, 0xA3180000, ++ 0xE8D40526, 0xBA068000, 0x8E06C000, 0xD5681FF0, ++ 0xD5970616, 0xBA230000, 0xB8200001, 0xD38C0400, ++ 0xBC634018, 0xDE6B1FE6, 0xD18B4000, 0xAD691FDE, ++ 0xCF220001, 0xBE97063D, 0xA16A1FC0, 0xE1691FFA, ++ 0xB797062A, 0xFB6B1FBE, 0xE1691FFA, 0x8F6A1FD8, ++ 0xAF05C000, 0xF797062A, 0xC76A1FC4, 0x80691FF6, ++ 0xF797062A, 0xBB6B1FBE, 0x80691FF6, 0xEA6A1FDA, ++ 0xAF05C000, 0xF797062A, 0xD1681FFE, 0xA3180000, ++ 0xD3D0054C, 0xAD691FDE, 0xB3681FC2, 0xF6970617, ++ 0xED691FDE, 0x95681FC6, 0xB6970617, 0xDA800558, ++ 0xBB6B1FBE, 0xE1691FFA, 0xC46A1FC2, 0xAF05C000, ++ 0xEF05C000, 0xB797062A, 0xBB6B1FBE, 0xC0691FF6, ++ 0xA26A1FC6, 0xEF05C000, 0xEF05C000, 0xB797062A, ++ 0x98700090, 0xFA970605, 0xFA8C5000, 0xB1700080, ++ 0xE9204096, 0xAA504A52, 0xB15024E4, 0xE9204096, ++ 0x2A504A52, 0x425030A6, 0x51970642, 0x1450B12C, ++ 0x515020F0, 0x37970646, 0x085028B1, 0x51970642, ++ 0x7E50A90A, 0x3E50AD8C, 0x11970642, 0x5050456B, ++ 0x2850BD4A, 0x77970646, 0x676B4080, 0x00631FEE, ++ 0x71700080, 0x0E50352B, 0x11970642, 0x596B1FEE, ++ 0x316A4080, 0x63330006, 0x6BD4057A, 0x35320006, ++ 0x35D005B1, 0x518004F8, 0x6A504A52, 0x0B502D8B, ++ 0x77970646, 0x37502531, 0x11970642, 0x7C50252B, ++ 0xB950210B, 0xF7970646, 0xED5018E5, 0x91970642, ++ 0xEA504A52, 0x99503CCF, 0xB7970646, 0xD1502669, ++ 0xD1970642, 0x8F50A52F, 0x835018CB, 0xD1970642, ++ 0xAA504A52, 0xD2503E69, 0xF7970646, 0x9250112C, ++ 0xD1970642, 0xBF50B5ED, 0x8950326C, 0xD1970642, ++ 0xAA504A52, 0xC15035AA, 0xD1970642, 0xB250B50D, ++ 0x92502533, 0xD1970642, 0xC3501E52, 0x9650166D, ++ 0xD1970642, 0xBB970638, 0xBB6B1FBE, 0xE6691FF2, ++ 0x0B6A1FD6, 0x6F05C000, 0x7797062A, 0x3B6B1FBE, ++ 0x66691FF2, 0x086A1FD0, 0x2F05C000, 0x6F05C000, ++ 0x7797062A, 0x3A970605, 0x3A8C5000, 0x69204096, ++ 0x2A504A52, 0x515020C6, 0x69204096, 0x2A504A52, ++ 0x5580049A, 0x3B970638, 0x3B6B1FBE, 0x66691FF2, ++ 0x0B6A1FD6, 0x6F05C000, 0x7797062A, 0x08691FDC, ++ 0x1D681FDA, 0x70970614, 0x4B691FDA, 0x09220002, ++ 0x7E97063D, 0x08691FDC, 0x15681FC6, 0x76970617, ++ 0x03691FC6, 0x6A220003, 0x7E97063D, 0x3A970605, ++ 0x7A8C5000, 0x31700080, 0x29204096, 0x6A504A52, ++ 0x7F502084, 0x29204096, 0x2A504A52, 0x6C503611, ++ 0x11970642, 0x6A504A52, 0x46502D07, 0x37970646, ++ 0x6C5034AD, 0x11970642, 0x2A504A52, 0x595024A5, ++ 0x37970646, 0x665029B0, 0x51970642, 0x27503144, ++ 0x1A50252F, 0x77970646, 0x4150194A, 0x11970642, ++ 0x745010C8, 0x0750318C, 0x37970646, 0x695028D1, ++ 0x91970642, 0xD2502569, 0xEC5019AD, 0xB7970646, ++ 0xDD501264, 0x91970642, 0x9F50B08C, 0xE8502D29, ++ 0xF7970646, 0xAD5019A6, 0x91970642, 0xEA504A52, ++ 0xB550166C, 0xF7970646, 0xDE502191, 0x91970642, ++ 0xF250AD0B, 0xAD502953, 0x91970642, 0xEA504A52, ++ 0xA950326B, 0xF7970646, 0xDE5011AB, 0x91970642, ++ 0x9950B585, 0xD2502533, 0xD1970642, 0xAA504A52, ++ 0xC75035A9, 0x91970642, 0xB950B54D, 0xC5502E6B, ++ 0x11970642, 0x43501E52, 0x5650166D, 0x11970642, ++ 0x7880059D, 0x2D6A1FBE, 0x00691FC0, 0x4B624014, ++ 0x4B32FFFE, 0x3A098000, 0x25614000, 0x456140A4, ++ 0x0F691FD4, 0x696A1FDC, 0x62614008, 0x25691FF4, ++ 0x62624004, 0x0F2D0001, 0x0C614010, 0x518B4000, ++ 0x046A1FF4, 0x6E2E0001, 0x6D624010, 0x25614000, ++ 0x34604008, 0x538C0400, 0x5570001C, 0x1270881D, ++ 0x5B058000, 0x0D048000, 0x118B4000, 0x73604000, ++ 0xB3681FF4, 0xE2614008, 0xDA604010, 0x938C0400, ++ 0xEA624018, 0x97020000, 0xB4218080, 0xD3800073, ++ 0xED684008, 0x99800634, 0xA5631FEC, 0xE5614000, ++ 0x83624008, 0xF5008000, 0xE9218800, 0x90970073, ++ 0xC46A1FF4, 0x9A970658, 0xAD684008, 0xFC6B1FEC, ++ 0xB26040A8, 0xFA8C5000, 0xDA700184, 0x918B4000, ++ 0x846A1FF4, 0xE9691FBC, 0xED624010, 0x856140A4, ++ 0xD18B4000, 0x94004000, 0xAA31FFFE, 0xD38C0400, ++ 0xBF424000, 0xD9800634, 0xD68C5080, 0x97BC004B, ++ 0xE9204096, 0x918B4000, 0x968C5080, 0xD7BC004B, ++ 0xE9204096, 0xAA504A52, 0x918B4000, 0xD6681FF6, ++ 0xB22DFFFF, 0xE3024000, 0xF736FFF0, 0xB0320003, ++ 0xFC30FFFE, 0xAF060000, 0x874A8000, 0xD4004000, ++ 0x9E34000F, 0xCD120000, 0xC1624090, 0x918B4000, ++ 0x8D048000, 0xFC30FFFE, 0xE6500000, 0xA6500000, ++ 0xE6500000, 0xA6500000, 0x918B4000, 0xE26A1FC6, ++ 0x246140A8, 0x646240A4, 0x718C0100, 0x1A700184, ++ 0x476A1FF2, 0x22624004, 0x046A1FF4, 0x4B624014, ++ 0x65614000, 0x22614008, 0x318C0100, 0x50694080, ++ 0x0C350001, 0x47CC066F, 0x518B4000, 0x2E2E0001, ++ 0x6D624010, 0x32218020, 0x13800073, 0x0079084F ++}; ++ ++static const uint32_t fw0_boot_img_data_buf[] = ++{ ++ 0x3F200503, 0x6E210001, 0x6A710249, 0x38200001, ++ 0x5460B41C, 0x1397008C, 0x0D210000, 0x4931FFFF, ++ 0x6D390001, 0x242CFFFF, 0x00CC0007, 0x736AB1F8, ++ 0x2361B140, 0x6F3A0000, 0x4FCC0013, 0x1F200777, ++ 0x5860B438, 0x1F60B45C, 0x14800017, 0x5D200333, ++ 0x1860B438, 0x5F60B45C, 0x7E60B43C, 0x0520FFFF, ++ 0x3660B420, 0x4D210000, 0x6F68B420, 0x0561B422, ++ 0x4934FEFE, 0x22300001, 0x3660B420, 0x4661B424, ++ 0xA361B426, 0xE761B428, 0xC261B42A, 0x8161B42C, ++ 0xE461B42E, 0xAF61B434, 0x8A61B436, 0xD397008C, ++ 0xCE21A0CA, 0xB9228000, 0xBF424000, 0xE12D0100, ++ 0xA42CFFFF, 0xE8CC002A, 0xCB710449, 0x83B80032, ++ 0xD8224000, 0x98800033, 0xAC220000, 0xC3210045, ++ 0x8661B424, 0xFA230000, 0xF663B42C, 0x9397008C, ++ 0xA9232000, 0xC662B428, 0xD863B434, 0x9269B1F8, ++ 0xCE390000, 0xABCC0040, 0x89210777, 0xF5800041, ++ 0x8B210333, 0xF38C0078, 0xD6BC0076, 0x8E61B438, ++ 0xE42CFFFF, 0x87CC0039, 0x85710649, 0xD397008C, ++ 0xEB21A0C8, 0xAC220000, 0xBF424000, 0xC92D0002, ++ 0xBF424000, 0xCC2D00FE, 0xE42CFFFF, 0x89CC004A, ++ 0xC468B1F8, 0x8D223000, 0x98380000, 0xC0CC005D, ++ 0x96711049, 0xE5B8005A, 0xEF204000, 0xBF222000, ++ 0x91230071, 0xD2800078, 0xDB200000, 0x91230071, ++ 0xD2800078, 0xB7712049, 0x82B80063, 0xF9214000, ++ 0x3A230000, 0x7F222000, 0x79800065, 0x0D210000, ++ 0x7A230000, 0x0C20B424, 0x2C500011, 0x45500001, ++ 0x6850C400, 0x05500001, 0x0161B42C, 0x5363B42E, ++ 0x0E62B434, 0x7C230333, 0x738C0078, 0x16BC0076, ++ 0x7963B438, 0x1B200000, 0x3560B140, 0x69710149, ++ 0x3C8C0000, 0x73800074, 0x7971FF49, 0x33800074, ++ 0x15320001, 0x45367FFF, 0x75C8008B, 0x322A0008, ++ 0x4DC00087, 0x26500000, 0x26500000, 0x66500000, ++ 0xA6500000, 0xE6500000, 0xE6500000, 0xA6500000, ++ 0xE6500000, 0xB5C8008B, 0x9480007B, 0xD3260008, ++ 0xE6500000, 0x932EFFFF, 0x8BCC0088, 0xD18B4000, ++ 0x8468B1F8, 0xDE34000F, 0xDBC80093, 0xA028000A, ++ 0xFAC40093, 0x8124000A, 0x918B4000, 0xF920000A, ++ 0x918B4000, 0xE0000000, 0xE0000000, 0xA0000000 ++}; ++ ++static const uint32_t fw0_master_img_data_buf[] = ++{ ++ 0x3F200503, 0x6E210001, 0x5E605FF4, 0x2D615FF6, ++ 0x5B200000, 0x3260B148, 0x0D205FE0, 0x5C215FE8, ++ 0x7D230008, 0x2F090000, 0x23C000F3, 0x78200001, ++ 0x1460B41C, 0x719700B0, 0x539700BA, 0x0E208000, ++ 0x7560B140, 0x20000000, 0x20000000, 0x60000000, ++ 0x25685FFE, 0x5269B1F8, 0x626B5FFA, 0x353C4600, ++ 0x2CCC0012, 0x793B0000, 0x48D4001D, 0x1B3700FF, ++ 0x5763B47A, 0x1D200333, 0x1860B438, 0x5F60B45C, ++ 0xBE60B43C, 0xFC230003, 0xF722B400, 0x8520FFFF, ++ 0xE9408000, 0x8D210000, 0xB0488000, 0xF1260002, ++ 0xFF418000, 0x8934FEFE, 0xA2300001, 0xD02A0002, ++ 0xA9408000, 0xFE260020, 0xC52FFFFF, 0x8CCC0023, ++ 0xDB200000, 0x9F60B406, 0xB660B416, 0xF560B426, ++ 0x9C60B436, 0xD460B446, 0xFD60B456, 0xA16B5FFC, ++ 0x80210100, 0xE2222F00, 0xF4370080, 0x9FC8003E, ++ 0xCD210000, 0x8D223000, 0x8C20B424, 0xEC500011, ++ 0x85500001, 0xE850C400, 0xC5500001, 0xAA410000, ++ 0xDF2C0002, 0xA6500000, 0x8E62B434, 0xC8205E90, ++ 0xE6220164, 0xAF970F80, 0x9269B1F8, 0xEA220333, ++ 0x9B200000, 0xF38C0078, 0xD1BC00EB, 0xAF62B438, ++ 0xD060B424, 0xB560B426, 0xB9610102, 0xC835000F, ++ 0x9C610100, 0xC568B400, 0xF969B420, 0x99605FCA, ++ 0xA9615FCE, 0xFA3400FF, 0xD6380200, 0x9A605FCC, ++ 0xF235FF00, 0xAB390002, 0x84615FD0, 0xC1970F0D, ++ 0x38200001, 0x57605EA0, 0x502001A0, 0x2B60010C, ++ 0x7A203000, 0x0E60010E, 0x38200001, 0x7260B148, ++ 0x58695EA0, 0x39228000, 0x14004000, 0x433C0001, ++ 0x26CC006F, 0x4262B140, 0x50800075, 0x14004000, ++ 0x463C0004, 0x2DCC0075, 0x2C68B140, 0x543C4000, ++ 0x3560B140, 0x4835000F, 0x4931FFFF, 0x002D0079, ++ 0x26894000, 0x528C1D78, 0x5F800098, 0x378C1D7A, ++ 0x5F800098, 0x3E8C1DF8, 0x1F800098, 0x5B8C1DFA, ++ 0x9F800098, 0xF48C1D7C, 0xDF800098, 0x918C1D7E, ++ 0xDF800098, 0x988C1DFC, 0x9F800098, 0xFD8C1DFE, ++ 0xDF800098, 0xB18C1D79, 0x9F800098, 0xD48C1D7B, ++ 0x9F800098, 0xDD8C1DF9, 0xDF800098, 0xB88C1DFB, ++ 0xDF800098, 0x978C1D7D, 0x9F800098, 0xF28C1D7F, ++ 0x9F800098, 0xFB8C1DFD, 0xDF800098, 0x9E8C1DFF, ++ 0x95B000E9, 0xC8BC0BF6, 0xFDD80CC3, 0x90A00BF7, ++ 0xEBA40C1D, 0xA5A80C38, 0x8CF80EFB, 0xD3E80CE1, ++ 0x17E00107, 0x796A5EA0, 0x7F2300A6, 0x2B360002, ++ 0x5DC800A6, 0x38AC0E86, 0x38215EA2, 0x63220014, ++ 0x44970F9D, 0x3EC80068, 0x30884000, 0x58380000, ++ 0x36C80101, 0x78215EA2, 0x63220014, 0x27800FC0, ++ 0x5B200000, 0x3360B000, 0x3460B008, 0x4F220001, ++ 0x2B2D0008, 0x6D62B010, 0x7B60B01C, 0x08228800, ++ 0x0C62B01C, 0x518B4000, 0x4468B1F8, 0x36635E96, ++ 0x5E34000F, 0x01030000, 0x012B000A, 0x45C000C1, ++ 0x3920000A, 0x41030000, 0x4D210000, 0x0931FFFF, ++ 0x6D390001, 0x242CFFFF, 0x01CC00C3, 0x6361B140, ++ 0x79228000, 0x36010000, 0x10310008, 0x4D39A0CA, ++ 0x3F424000, 0x6C220000, 0x7F424000, 0x06220020, ++ 0x7C2DFFBA, 0x3F424000, 0x2C220000, 0x582DFF7C, ++ 0x3F424000, 0x6B2D0008, 0x7F424000, 0x0F220001, ++ 0x2B2D0008, 0x7F424000, 0x6C220000, 0x0D2D000C, ++ 0x7F424000, 0x08228800, 0x3F424000, 0x43220400, ++ 0xA462B144, 0xD7020000, 0xE13A0200, 0xA462B144, ++ 0xD92C0001, 0x852FFFFF, 0x80CC00C8, 0xEF6B5E96, ++ 0xD18B4000, 0x8222008D, 0x988000FC, 0xE4220089, ++ 0x988000FC, 0xC6220083, 0xD88000FC, 0x85220085, ++ 0xD88000FC, 0xA9220005, 0x988000FC, 0xE0220087, ++ 0x988000FC, 0xCC220007, 0xD88000FC, 0xA6220011, ++ 0x988000FC, 0xC122008B, 0xD88000FC, 0xAD22000B, ++ 0xEA625FF2, 0x99635FF0, 0xB1320008, 0xC562B148, ++ 0xB3D00102, 0xD18B4000, 0xF8200001, 0xB19700B0, ++ 0xD39700BA, 0xBC8C0000, 0x95800105, 0xF9695F20, ++ 0xFE20011B, 0x8E35C000, 0x91C8010E, 0xC9685F24, ++ 0x823D4000, 0xC5CC00A1, 0xDF2300A1, 0xB96A5EA0, ++ 0xE1210080, 0xB336FFFE, 0xA0625EA0, 0xFB655F21, ++ 0x9A8000AB, 0xF9695F20, 0xC9685F24, 0x8E35C000, ++ 0x973DC000, 0xF2C8010F, 0xD18B4000, 0xA9970F20, ++ 0xFBC801BB, 0x90605F24, 0x80685FFC, 0xCD210000, ++ 0x24615F2E, 0x7F340003, 0x5F2C012D, 0x30884000, ++ 0x5B200000, 0x3160B122, 0x30800131, 0x4A6BB124, ++ 0x5C695F22, 0x1B200000, 0x3B370001, 0x4ECC0137, ++ 0x3C65B123, 0x70800131, 0x5C800124, 0x1A800127, ++ 0x7B9700FB, 0x2868B122, 0x3D69B124, 0x7734001F, ++ 0x34310001, 0x6C110000, 0x62D401B1, 0x216B5FFC, ++ 0x0E645F20, 0x4537FF00, 0x67330008, 0x180B0000, ++ 0x4EC001AE, 0x3E6A5F24, 0x3F215F26, 0x462E0040, ++ 0x29408000, 0x7930FFFB, 0x4E2C4000, 0x0F970FDD, ++ 0x7A695F26, 0x1B2C000C, 0x29350003, 0x49CC01AA, ++ 0x7F215F26, 0x1122FFFE, 0x21970FF3, 0x5F695F24, ++ 0x1C2C0004, 0x524A0000, 0x422D0042, 0x3F424000, ++ 0x6E2E0001, 0x0B420000, 0x26971027, 0x64970C53, ++ 0x2C685F26, 0x7E695F28, 0x5B60B408, 0x2861B40A, ++ 0x09685F24, 0x5221B40E, 0x7D60B40C, 0x30510000, ++ 0x52200021, 0x3A60B404, 0x10200040, 0x5360B414, ++ 0x91200164, 0xC7210152, 0xFF2300A6, 0xA9800C7A, ++ 0xEF685F20, 0xB86A5FE8, 0xBA3400FF, 0xD3605F22, ++ 0xEE2E0001, 0xA1625FE8, 0x81030000, 0xF930FFFB, ++ 0xA72C4010, 0xD24A0000, 0xDC2C0004, 0xB3490000, ++ 0xD63B0400, 0x8F2D0001, 0xBA0A4000, 0xF9C40175, ++ 0x8D210000, 0xEA410000, 0xC9685F24, 0xB563B120, ++ 0xBE2C0038, 0xE6500000, 0xE6500000, 0xA6500000, ++ 0xE6500000, 0x802CFFF6, 0x924A0000, 0xE22CFFCA, ++ 0x0A6B5F2E, 0x5B368000, 0x63CC018A, 0x393B0000, ++ 0x50C801A6, 0x392F003C, 0x1D40C000, 0x46685F30, ++ 0x50605F24, 0x158001A6, 0x32605F2E, 0x793B0000, ++ 0x26CC018F, 0x5F605F30, 0x76800191, 0x392F003C, ++ 0x5D40C000, 0x39695F20, 0x2B68B124, 0x4F220001, ++ 0x3A230000, 0x6C3500FF, 0x6C0B4000, 0x2C12C000, ++ 0x17148000, 0x4FCC019F, 0x5A9700F7, 0x11230191, ++ 0x71635F24, 0x10200040, 0x198001B4, 0x69970F20, ++ 0x9EC801B9, 0xD0605F24, 0xEF685F20, 0xBE6A5F24, ++ 0xFA3400FF, 0x9780013E, 0xBA215FDA, 0xE4970F39, ++ 0xDE2301B3, 0xB78001C0, 0xAF685F20, 0xFF9700F5, ++ 0xBA3400FF, 0xF18001AF, 0xFB9700FB, 0xB7380400, ++ 0xD460B120, 0x89685F24, 0x86970F33, 0xDB200000, ++ 0xB96A5EA0, 0xED645F21, 0xCC3A0001, 0xA0625EA0, ++ 0x988000A6, 0xD523019F, 0xDE8001BC, 0x9F23011B, ++ 0xF1635F24, 0xBC2000C0, 0xAD645F21, 0xD88000A6, ++ 0xB5695F32, 0xCE208000, 0xD4150000, 0xB7C801C5, ++ 0xD18B4000, 0xBA605F32, 0xB62001C8, 0xDA8000AB, ++ 0xCC685FD8, 0x9F215FD8, 0x98380000, 0xDAC801ED, ++ 0xA0970F5B, 0xF9605F34, 0xF6010000, 0x9F2C0034, ++ 0xE5480000, 0x9E6A5FEC, 0x81030000, 0xDE34000F, ++ 0xAE2E0001, 0xC7625FEC, 0xEC220000, 0x8A625F3A, ++ 0xBA62013E, 0xC6330004, 0xFF37000F, 0x9A2F01DD, ++ 0xD18B4000, 0xB48003B5, 0x9B80053F, 0xF08006DD, ++ 0x138006EA, 0x53800200, 0x53800200, 0x13800200, ++ 0x53800200, 0x13800200, 0x13800200, 0x53800200, ++ 0x53800200, 0x13800200, 0x13800200, 0x4B800BC6, ++ 0x13800200, 0x79605F34, 0x7A605F32, 0x188000A6, ++ 0x682200C1, 0x15800203, 0x2C2200A3, 0x55800203, ++ 0x2722008F, 0x55800203, 0x45220085, 0x15800203, ++ 0x0B2200C0, 0x55800203, 0x6A2200A0, 0x15800203, ++ 0x492200A1, 0x15800203, 0x23220081, 0x55800203, ++ 0xA0220087, 0xD5800203, 0xEC220000, 0xA3685F32, ++ 0xEF625F38, 0xB3230208, 0x8B341000, 0xE8CC02A0, ++ 0xFB97035E, 0xA0685F34, 0xB66A5F38, 0xDA230218, ++ 0xBC2C0035, 0xF3460000, 0xF6695F34, 0x9D800273, ++ 0xE860013C, 0xB5635F46, 0xBB97035E, 0xF9200215, ++ 0x9C605F36, 0xDE970393, 0xC9CC0263, 0x90970236, ++ 0x856A010C, 0xFA680110, 0xFE2A01A0, 0xB5C801C8, ++ 0xD8380000, 0x8DCC01C8, 0x94620110, 0xE7970C63, ++ 0x0D6A0110, 0x4C20B424, 0x6C500011, 0x05500001, ++ 0x6850C400, 0x05500001, 0x2D5001A0, 0x66500000, ++ 0x4E62B434, 0x0821022C, 0x172301C8, 0x6B940C7D, ++ 0x3E6B0112, 0x672201A0, 0x5C62010C, 0x1B200000, ++ 0x4D6A0110, 0x06600112, 0x23600110, 0x793B0000, ++ 0x0ACC0385, 0x588000A6, 0x79635F38, 0x201A4000, ++ 0x0262B140, 0x6F6B5EA0, 0x57020000, 0x1F3B0004, ++ 0x76635EA0, 0x0D388000, 0x3A605F32, 0x75008000, ++ 0x07300003, 0x75605F4A, 0x75008000, 0x3F30FFF8, ++ 0x4F384001, 0x36605F4C, 0x2832FFFF, 0x5D2E0D06, ++ 0x5D23024A, 0x078A4000, 0x13605F4E, 0x456A010C, ++ 0x102001A0, 0x4D210000, 0x4E0A0000, 0x26970DE4, ++ 0x6B970E02, 0x026B5F32, 0x0A685F4E, 0x7F37000F, ++ 0x343B0100, 0x576A5F34, 0x7263B144, 0x0B420000, ++ 0x1B695F46, 0x5F2C0002, 0x6A410000, 0x136A5F3A, ++ 0x5F2C0002, 0x0B420000, 0x31695F3C, 0x606B5F38, ++ 0x9F2C0002, 0xEA410000, 0xD18B4000, 0xBA20C000, ++ 0xFA605F32, 0xAE970C74, 0xA7220040, 0xCC20B424, ++ 0xEC500011, 0xA0500003, 0xA850C400, 0xC5500001, ++ 0x87500180, 0xE6500000, 0xCE62B434, 0x9E2000A6, ++ 0xC82100A6, 0xBF2300A6, 0x89800C7D, 0xD4635E9C, ++ 0xAD6B5FEE, 0xC5615E98, 0xEC2D0036, 0x91484000, ++ 0xB82F0001, 0xF4635FEE, 0xC0349FFF, 0x88404000, ++ 0xEC348000, 0xB9C80286, 0x912DFFFE, 0xE64A4000, ++ 0x2B2D0008, 0x51484000, 0x41625E9A, 0x30510000, ++ 0x58380000, 0x32C8029C, 0x10605E9E, 0x4A685E98, ++ 0x79215FDC, 0x2A970F4A, 0x21970E86, 0x49685E9E, ++ 0x0D6B5E9C, 0x58380000, 0x6BCC0290, 0x118B4000, ++ 0x586A5E9A, 0x1F215FD8, 0x1336FF00, 0x70D00297, ++ 0x2A970F4A, 0x4D6B5E9C, 0x778001C0, 0x31320008, ++ 0x3C2C0035, 0x73460000, 0x5F695E9E, 0x3D800274, ++ 0x7C9700F3, 0x3C209000, 0x3A605F32, 0x4480101D, ++ 0x8E208000, 0xFA605F32, 0xE480102C, 0xBD635F36, ++ 0xEC685F4A, 0xB9695F4C, 0x8B32FFFE, 0xCD048000, ++ 0xF0C402AB, 0x8F2D0001, 0xA0615F4C, 0xF5605F4A, ++ 0x93320002, 0xE4685F3A, 0xD88002B9, 0xBD635F36, ++ 0xD8380000, 0xBCD002B3, 0x99970354, 0xE4685F3A, ++ 0x8E390000, 0xDDC802B9, 0xE4300002, 0x88404000, ++ 0xBC30FFFE, 0xF6010000, 0xE72D01A0, 0x9F610106, ++ 0xCB32FFFE, 0x9CC80352, 0x94038000, 0xC3330001, ++ 0xAFD402C2, 0xEB2E0004, 0xD40C8000, 0xBD605F3A, ++ 0xD4038000, 0xBF37000F, 0x95C802C9, 0xF736FFF0, ++ 0xE42E0010, 0xAF6B5F40, 0xAC625F3E, 0xCD0B8000, ++ 0x94C402CE, 0xE0625F40, 0xDC6A5F42, 0x9B200000, ++ 0xE93600C0, 0xB5320006, 0x9BC802D6, 0xF12C0040, ++ 0x932EFFFF, 0xF88002D2, 0xEC600104, 0x85970CA6, ++ 0x9E2000A6, 0xE1970CAF, 0xEC970CB6, 0xA7970C63, ++ 0xE3690104, 0xB5680104, 0xAF2D0030, 0xE64A4000, ++ 0x092D0002, 0x704B4000, 0x493EFFFF, 0x0D1EC000, ++ 0x6CCC0322, 0x1A21B424, 0x18510041, 0x7160B428, ++ 0x4A2D0004, 0x30510000, 0x3851C010, 0x53510001, ++ 0x28220038, 0x4E62B434, 0x4C2102DB, 0x3F2300A6, ++ 0x6B940C7D, 0x3920003C, 0x3C60B348, 0x64970C53, ++ 0x27970C63, 0x50680106, 0x7B21B428, 0x356A5F3E, ++ 0x2A6B5FD0, 0x4251E000, 0x53510001, 0x1760B42C, ++ 0x492D0002, 0x30510000, 0x12200311, 0x5763B420, ++ 0x1060B424, 0x4E62B434, 0x6C685F4A, 0x39695F4C, ++ 0x5B60B408, 0x2861B40A, 0x226B5FCC, 0x7721B40C, ++ 0x4251E000, 0x13510001, 0x2B201061, 0x7D63B400, ++ 0x3A60B404, 0x6462B414, 0x5D200003, 0x3E605F50, ++ 0x7020031B, 0x21210325, 0x0A970C7D, 0x7F2300A6, ++ 0x0B940C7A, 0x67685F50, 0x4434FFFE, 0x3E605F50, ++ 0x18380000, 0x71C80320, 0x588000A6, 0x27685F50, ++ 0x4234FFFD, 0x3E605F50, 0x18380000, 0x65CC00A6, ++ 0xA46B5F36, 0xEE800CBD, 0xEA970C83, 0xB62301F2, ++ 0xEE800CBD, 0xBB2302DB, 0xA9800C83, 0xFD635F36, ++ 0xD8380000, 0xB3D0032B, 0x99970354, 0xE4685F3A, ++ 0x8E390000, 0xFBC80331, 0xE4300002, 0x88404000, ++ 0xFC30FFFE, 0xB6010000, 0xA72D01A0, 0xDF610106, ++ 0x8B32FFFE, 0xDCC80352, 0xEF6B5F40, 0xAC625F3E, ++ 0x8D0B8000, 0xF8C4033B, 0xE0625F40, 0x94038000, ++ 0xE6330003, 0x84D4033F, 0xAB2E0004, 0xD40C8000, ++ 0xBD605F3A, 0xE4970C53, 0xEC685F4A, 0xB9695F4C, ++ 0xDB60B408, 0xA861B40A, 0x90680106, 0xF56A5F3E, ++ 0xD221B40E, 0xB0510000, 0xBD60B40C, 0xD2200021, ++ 0xBA60B404, 0xE462B414, 0xC5685F36, 0xA6210341, ++ 0xFF2300A6, 0xA9800C7A, 0xA46B5F36, 0xF88000FB, ++ 0xB5635E90, 0xC16B5F34, 0xE00CC000, 0x844B0000, ++ 0x9F2C0002, 0xE5480000, 0xD4635F4A, 0xAC6B5E90, ++ 0xF6605F4C, 0x918B4000, 0xB96A5F40, 0xDB200000, ++ 0x17605F40, 0x6F3A0000, 0x7ECC0C95, 0x118B4000, ++ 0x4520FFFF, 0x2C2D0036, 0x264A4000, 0x772DFFFA, ++ 0x45625F42, 0x1D34003F, 0x17148000, 0x6CCC01F2, ++ 0x118B4000, 0x664A4000, 0x492D0002, 0x273607FC, ++ 0x57C801F4, 0x13320002, 0x2C088000, 0x4EC001F4, ++ 0x35008000, 0x62300001, 0x6FD40378, 0x2E2E0001, ++ 0x1F30FFFF, 0x518B4000, 0x76635E96, 0x33200102, ++ 0x7E97036D, 0x09600130, 0x06625F44, 0x73200102, ++ 0xBE97036D, 0xEF6B5E96, 0xEF600134, 0xA3625F46, ++ 0xD18B4000, 0xA469010C, 0x9768010E, 0xFD3D01A0, ++ 0xE6CC0390, 0x862E01A0, 0x9C62010C, 0xD8380000, ++ 0x90C8038F, 0xEC088000, 0xE8C001F0, 0x918B4000, ++ 0xD4620110, 0xA7630112, 0x988000A6, 0xD3680100, ++ 0xB6635E96, 0xDB6AB140, 0xEE210001, 0xBA230000, ++ 0xA1280001, 0xD80B0000, 0xCD11C000, 0x94038000, ++ 0xD7174000, 0xBEC803A1, 0xB4310001, 0xE1280001, ++ 0x3EC4039B, 0x6F6B5E96, 0x518B4000, 0x36635E96, ++ 0x6C220000, 0x05625E94, 0x0D6BB140, 0x45690100, ++ 0x78200001, 0x3602C000, 0x35160000, 0x5C6A5E94, ++ 0x02CC03AF, 0x6E2E0001, 0x45625E94, 0x1F30FFFF, ++ 0x722DFFFF, 0x01CC03A9, 0x2F6B5E96, 0x5C6A5E94, ++ 0x118B4000, 0x64625F4E, 0x512C03B8, 0x30884000, ++ 0x13800200, 0x7E8003C8, 0x5C800442, 0x3C800445, ++ 0x56800465, 0x1D800486, 0x3E8004EB, 0x7B8004EE, ++ 0x1B800509, 0x5E80050C, 0x7780052A, 0x13800200, ++ 0x53800200, 0x13800200, 0x13800200, 0x53800200, ++ 0x54230018, 0x0963013C, 0x1A970364, 0x7797037A, ++ 0x276A0130, 0x41030000, 0x4D0B8000, 0x2FC003D1, ++ 0x57020000, 0x106B013C, 0x28685F44, 0x5B695F46, ++ 0x32370020, 0x4DCC03D7, 0x6E2E0001, 0x09625F3C, ++ 0x360E0000, 0x420E4000, 0x4B32FFFE, 0x34970385, ++ 0x5797029D, 0x1B200000, 0x2A210120, 0x5F6A5F44, ++ 0x97970327, 0xDC200008, 0xCC210124, 0xBA6A5F46, ++ 0xD7970327, 0x969702A0, 0xA4685F3A, 0xE4210010, ++ 0xE4300002, 0xA7600128, 0xBA610104, 0xFB97035E, ++ 0xA6970CCB, 0xD0680130, 0xE0690134, 0x8E6A0120, ++ 0xFE6B0124, 0x9A60B010, 0xAA61B014, 0xFE680128, ++ 0x8E69012C, 0xEB2E0068, 0xC462B000, 0xBD2F0068, ++ 0xB463B004, 0xE06A0138, 0xDC2C0068, 0xB460B008, ++ 0xCA2D0068, 0x8461B00C, 0xAA62B018, 0xF168013C, ++ 0xBF2300A6, 0xCD388000, 0xFB60B01C, 0xAF940CD0, ++ 0xCA685F4E, 0x976A5F34, 0x98380000, 0xF5C8040D, ++ 0xF0884000, 0x8E208000, 0xA9408000, 0xDB200000, ++ 0xBF800419, 0xE4685F3A, 0xF069B024, 0xA02E0028, ++ 0xCE390000, 0x90D00409, 0xA4300002, 0xDC2C0068, ++ 0xAF090000, 0xEA31FFFE, 0xC768B028, 0xBF418000, ++ 0xB734001F, 0xE82E0002, 0xE9408000, 0xB5008000, ++ 0xDF2C0002, 0xA6500000, 0xA6500000, 0xC9970CD8, ++ 0x106A5F3C, 0x60685F34, 0x4B32FFFE, 0x33C80202, ++ 0x546B0104, 0x32695F3A, 0x09625F3C, 0x60625F40, ++ 0x600CC000, 0x272D01A0, 0x3A610104, 0x73490000, ++ 0x1F2C0002, 0x65480000, 0x63615F4A, 0x36605F4C, ++ 0x64970C53, 0x2C685F4A, 0x39695F4C, 0x7D60B40C, ++ 0x0E61B40E, 0x75680104, 0x4D210000, 0x2861B40A, ++ 0x1B60B408, 0x506A5F3C, 0x54200081, 0x3A60B404, ++ 0x6462B414, 0x21210430, 0x3F2300A6, 0x4B940C7A, ++ 0x11230202, 0x7880035E, 0x57230028, 0x0963013C, ++ 0x5B8003CA, 0x1A970364, 0x33200102, 0x7E97036D, ++ 0x49600130, 0x06625F44, 0x192C0001, 0x7E605F3C, ++ 0x2E32FFFC, 0x6B2E0004, 0x74970385, 0x1797029D, ++ 0x5B200000, 0x2A210120, 0x1F6A5F44, 0x57970327, ++ 0x1F6A5F44, 0x5C200008, 0x4C210124, 0x17970327, ++ 0x1F6A5F44, 0x72200010, 0x6D210128, 0x17970327, ++ 0x569702A0, 0x24685F3A, 0x23210018, 0x64300002, ++ 0x8160012C, 0xFA610104, 0xD823000A, 0x8963013C, ++ 0xD28003EB, 0x9A970364, 0xB797037A, 0xE8685F44, ++ 0xF60E0000, 0x8B32FFFE, 0xB4970385, 0xD797029D, ++ 0x9B200000, 0xEA210120, 0xDF6A5F44, 0x97970327, ++ 0xFA6A5F46, 0x9C200008, 0x8C210124, 0xD7970327, ++ 0x969702A0, 0xE4685F3A, 0xE76A0130, 0x976B0134, ++ 0xA4300002, 0xE7600128, 0xD70EC000, 0x8B32FFFE, ++ 0xC9625F3C, 0xAA208009, 0xB9970210, 0xC1970D7E, ++ 0x1F680148, 0x61970E49, 0x4D210000, 0x316A5F5C, ++ 0x72200010, 0x2F800E66, 0x03208100, 0x6860013C, ++ 0x5A970364, 0x3797037A, 0x316B0130, 0x7E695F44, ++ 0x180B0000, 0x4EC001F4, 0x4434FFFE, 0x17C801F4, ++ 0x420E4000, 0x0B32FFFE, 0x34970385, 0x5797029D, ++ 0x1B200000, 0x6A210120, 0x5F6A5F44, 0x17970327, ++ 0x3A6A5F46, 0x5C200008, 0x4C210124, 0x17970327, ++ 0x569702A0, 0x016A0134, 0x09690124, 0x532EFFFF, ++ 0x820D8000, 0xEA31FFFE, 0xE72D01A0, 0xA64A4000, ++ 0xC92D0002, 0x87494000, 0xB168013C, 0xE01A4000, ++ 0xD3C801FA, 0xB2695F3A, 0x816A0134, 0xF2310002, ++ 0xB1610128, 0xF4340100, 0xFAC804BA, 0xB16B0130, ++ 0xF5008000, 0x8D0B8000, 0xB82F0001, 0xEE2E0001, ++ 0xA2300001, 0xFBD004B7, 0xEE2E0001, 0x820D8000, ++ 0x9761012C, 0xD70EC000, 0xCB32FFFE, 0x89625F3C, ++ 0xF168013C, 0xB9970210, 0x81970D7E, 0xC669015C, ++ 0xB968014C, 0xE2350100, 0xDCC804E4, 0xA1970E49, ++ 0xD1520000, 0xAB2E0004, 0xA3690168, 0xDF680148, ++ 0xCE390000, 0x91D004CD, 0xAF090000, 0xEA31FFFE, ++ 0x918004CE, 0xD8218000, 0xC2685F52, 0x952EFFFC, ++ 0xFF418000, 0xAA381000, 0x9B605F52, 0xC797101D, ++ 0xA06A0154, 0xD068015C, 0xCD210000, 0x8B32FFFE, ++ 0xB4340100, 0xF2200010, 0xFCC804E3, 0x8F970E67, ++ 0xDF680148, 0xAF69014C, 0xB16A5F5C, 0xEF090000, ++ 0x2A31FFFE, 0x7A0A4000, 0x75200018, 0x2F800E66, ++ 0x576A5F58, 0x202E0028, 0x11520000, 0x51520000, ++ 0x51520000, 0x11520000, 0x168004C6, 0x40208200, ++ 0x2860013C, 0x59800488, 0x70200088, 0x2860013C, ++ 0x5A970364, 0x21361F00, 0x31320008, 0x79620138, ++ 0x33200102, 0x7E97036D, 0x49600130, 0x366B0138, ++ 0x06625F44, 0x793B0000, 0x506B013C, 0x29CC04FD, ++ 0x7F800500, 0x13370040, 0x02CC0500, 0x592C0001, ++ 0x3E605F3C, 0x760E0000, 0x4B32FFFE, 0x34970385, ++ 0x5B200000, 0x2A210120, 0x1F6A5F44, 0x772303E6, ++ 0x54800327, 0x17200048, 0x2860013C, 0x568004F0, ++ 0x1A970364, 0x73200102, 0x7E97036D, 0x09600130, ++ 0x46625F44, 0x0D32FFFD, 0x34970385, 0x5797029D, ++ 0x1B200000, 0x6A210120, 0x5F6A5F44, 0x17970327, ++ 0x1F6A5F44, 0x5C200008, 0x4C210124, 0x17970327, ++ 0x569702A0, 0x36200522, 0x13605F4E, 0x55230400, ++ 0x8963013C, 0xD28003EB, 0xD669B020, 0xA02E0028, ++ 0xD1520000, 0x91520000, 0x91520000, 0xFF418000, ++ 0xD1230202, 0x8A800CD8, 0x9A970364, 0xD52001FF, ++ 0xBE97036D, 0xC9600130, 0xFE605F3C, 0x97020000, ++ 0xC6625F44, 0x8B32FFFE, 0xB4970385, 0xDB200000, ++ 0xAA210120, 0xDF6A5F44, 0xD7970327, 0x9B200000, ++ 0xBD605F3A, 0xE7600128, 0xE4210010, 0xBA610104, ++ 0xCC230808, 0x8963013C, 0x928003EB, 0xC1030000, ++ 0xA637FFF8, 0xEECC0200, 0xF52C0544, 0xB0884000, ++ 0xD580054C, 0xBC800593, 0x9A800604, 0xD3800200, ++ 0xD780061D, 0xB380064E, 0x93800200, 0xD3800200, ++ 0x8320FFFC, 0xF9970365, 0xE1361F00, 0xB2C801F6, ++ 0xF1320008, 0xB9620138, 0xBF2A0011, 0xD3C401F6, ++ 0xB797037A, 0xE2300001, 0xDCD00558, 0xA82E0002, ++ 0xB2347FFF, 0xD7C801F4, 0xD7680138, 0xA3625F46, ++ 0xF6010000, 0x92290003, 0xBAC40560, 0xDD200003, ++ 0x3C2C0003, 0x63018000, 0x6A072000, 0x393B0000, ++ 0x4ECC01F8, 0x3E695F44, 0x242E0010, 0x420E4000, ++ 0x442A0800, 0x3A6A5F46, 0x17C401F8, 0x6832FFFF, ++ 0x020E4000, 0x4B32FFFE, 0x74970385, 0x1797029D, ++ 0x5B200000, 0x2A210120, 0x0A6B5F42, 0x5F6A5F44, ++ 0x03330001, 0x76D00578, 0x74230579, 0x14800327, ++ 0x319702AF, 0x4A6B5F42, 0x5C200008, 0x0C210124, ++ 0x7A6A5F46, 0x05330002, 0x36D00581, 0x51230582, ++ 0x94800327, 0xF19702AF, 0xC56B5F3A, 0xBA6A5F46, ++ 0xED210128, 0xB5635F46, 0xB2200010, 0xD7970327, ++ 0xD69702A0, 0xAC6B5F46, 0xBE680128, 0xC16A0134, ++ 0x8160012C, 0xCB32FFFE, 0xDC635F3A, 0x89625F3C, ++ 0xE920E000, 0xBE2305FD, 0xBA800210, 0xE520FFF8, ++ 0xB9970365, 0xE1361F00, 0xF2C801F6, 0xB1320008, ++ 0xB9620138, 0xFF2A0011, 0xD3C401F6, 0x92200082, ++ 0xFE97036D, 0x89600130, 0x86625F44, 0xD2200082, ++ 0x3E97036D, 0x6F600134, 0x62300001, 0x3AD005A5, ++ 0x682E0002, 0x32347FFF, 0x17C801F4, 0x57680138, ++ 0x63625F46, 0x36010000, 0x12290003, 0x5FC405AD, ++ 0x1D200003, 0x792C0006, 0x63018000, 0x2A072000, ++ 0x793B0000, 0x0ECC01F8, 0x3E695F44, 0x76680134, ++ 0x242E0010, 0x4931FFFF, 0x420E4000, 0x042A0800, ++ 0x17C401F8, 0x57020000, 0x4B32FFFE, 0x360E0000, ++ 0x420E4000, 0x082E0005, 0x0B32FFFE, 0x74970385, ++ 0x1797029D, 0x5B200000, 0x6A210120, 0x0A6B5F42, ++ 0x5F6A5F44, 0x03330001, 0x3CD005CA, 0x6832FFFF, ++ 0x7D2305CD, 0x14800327, 0x319702AF, 0x5F6A5F44, ++ 0x109702A3, 0x4A6B5F42, 0x5C200008, 0x0C210124, ++ 0x7A6A5F46, 0x05330002, 0x34D005D6, 0x6832FFFF, ++ 0x322305D9, 0x54800327, 0x719702AF, 0x3A6A5F46, ++ 0x109702A3, 0x49690124, 0x7A6A5F46, 0x2A31FFFE, ++ 0x672D01A0, 0x11484000, 0x0B32FFFE, 0x420D8000, ++ 0xB04B4000, 0xDA340001, 0xF5C801FE, 0xBB370001, ++ 0xF5C801FE, 0x816A0134, 0xB2200010, 0xCA6B5F42, ++ 0xED210128, 0xA6330003, 0xB6D005ED, 0xD12305EE, ++ 0x94800327, 0xF19702AF, 0xE4685F3A, 0x816A0134, ++ 0xD3605F4E, 0xB6200028, 0x8B21012C, 0xE832FFFF, ++ 0x97970327, 0xD69702A0, 0xCA685F4E, 0x816A0134, ++ 0xBD605F3A, 0xFC209000, 0xCD32FFFD, 0x89625F3C, ++ 0xF9970210, 0x81970D7E, 0xB968014C, 0xE1970E49, ++ 0x0D210000, 0x716A5F5C, 0x75200018, 0x2F800E66, ++ 0x5A970364, 0x3797037A, 0x096B5F44, 0x570EC000, ++ 0x4B32FFFE, 0x34970385, 0x1797029D, 0x5B200000, ++ 0x2A210120, 0x5F6A5F44, 0x57970327, 0x1C200008, ++ 0x4C210124, 0x3A6A5F46, 0x17970327, 0x569702A0, ++ 0x056B5F3A, 0x416A0134, 0x45330002, 0x2063012C, ++ 0x0B32FFFE, 0x49625F3C, 0x5B20F000, 0x3E2305FD, ++ 0x7A800210, 0x0620FFF9, 0x39970365, 0x45625F42, ++ 0x892D0002, 0xF5200018, 0xFE97036D, 0xAF600134, ++ 0xC434FFFE, 0x97C801F4, 0xA82E0002, 0xE3625F46, ++ 0xF420013C, 0xB3508000, 0x85500001, 0xF1290002, ++ 0x91484000, 0xD4038000, 0xCD32FFFD, 0x970EC000, ++ 0xFF340003, 0x90605F48, 0x8B32FFFE, 0xF4970385, ++ 0x9797029D, 0xFA6A5F46, 0xE86B5F48, 0xB5008000, ++ 0xA832FFFF, 0xFB370001, 0xDBC8063C, 0xB60E0000, ++ 0xEA210120, 0x9B200000, 0x97970327, 0xE86B5F48, ++ 0xBA6A5F46, 0xFB370001, 0xCCCC0675, 0x96230675, ++ 0xE4685F3A, 0x9701C000, 0xB12C01A0, 0xC5500001, ++ 0xCB32FFFE, 0x902A0002, 0xAF970F80, 0xC92801A0, ++ 0xBD605F3A, 0xE6894000, 0xE520FFF8, 0xB9970365, ++ 0xC5625F42, 0xB5200018, 0xBE97036D, 0xC9600130, ++ 0x86625F44, 0xF5200018, 0xFE97036D, 0xAF600134, ++ 0x8434FFFE, 0xD7C801F4, 0xE82E0002, 0xA3625F46, ++ 0xF420013C, 0x81509000, 0x85500001, 0xF1290002, ++ 0x11484000, 0x7E695F44, 0x5C340002, 0x10605F48, ++ 0x6832FFFF, 0x14038000, 0x170EC000, 0x570EC000, ++ 0x420E4000, 0x0B32FFFE, 0x34970385, 0x5797029D, ++ 0x1B200000, 0x6A210120, 0x4A6B5F42, 0x1F6A5F44, ++ 0x43330001, 0x14D00674, 0x16230675, 0x54800327, ++ 0x319702AF, 0x4A6B5F42, 0x7A6A5F46, 0x1C200008, ++ 0x05330002, 0x56D00680, 0x63018000, 0x2832FFFF, ++ 0x420E4000, 0x0C210124, 0x34230686, 0x54800327, ++ 0x8C210124, 0xF19702AF, 0xFA6A5F46, 0x909702A3, ++ 0xFA6A5F46, 0x909702A3, 0x8A6B5F42, 0xFA6A5F46, ++ 0xED210128, 0xA6330003, 0xBED006AD, 0xE86B5F48, ++ 0xB5008000, 0xE832FFFF, 0xFB370001, 0x9FC80691, ++ 0xF60E0000, 0xB2200010, 0x97970327, 0xE86B5F48, ++ 0xBA6A5F46, 0xFB370001, 0xEDCC06B6, 0xA769013C, ++ 0xA0685F34, 0xFA6A5F46, 0xD13D9000, 0x86CC06AB, ++ 0xD72C0028, 0x844B0000, 0x9F2C0002, 0xF3490000, ++ 0x1F2C0002, 0x761B4000, 0x73490000, 0x1F2C0002, ++ 0x761B4000, 0x33490000, 0x36200028, 0x761B4000, ++ 0x7EC806AB, 0x372306B6, 0x14800327, 0x772306B6, ++ 0x11800644, 0x72200010, 0x719702AF, 0x3A6A5F46, ++ 0x509702A3, 0x286B5F48, 0x3A6A5F46, 0x7B370001, ++ 0x1CC80697, 0x509702A3, 0x569702A0, 0x3E6A5F48, ++ 0x24685F3A, 0x6B360002, 0x5EC806C0, 0x3A6A5F46, ++ 0x60690134, 0x2832FFFF, 0x020E4000, 0x4B32FFFE, ++ 0x09625F3C, 0x64300002, 0x4160012C, 0x3168013C, ++ 0x79970210, 0x36695F58, 0x0A2D0032, 0x51484000, ++ 0x5C340002, 0x0CCC06D6, 0x206A0154, 0x5D20A000, ++ 0x14038000, 0x43330001, 0x4CD406D0, 0x2E2E0001, ++ 0x682E0002, 0x3E33FFFF, 0x170EC000, 0x4B32FFFE, ++ 0x28625F5C, 0x4E970D6A, 0x41970D7E, 0x3968014C, ++ 0x21970E49, 0x4D210000, 0x716A5F5C, 0x35200018, ++ 0x6F800E66, 0x01030000, 0x2637FFF8, 0x6ECC0200, ++ 0xB32C06E2, 0xF0884000, 0xF38006ED, 0x978007A7, ++ 0xE38009AE, 0xAE800A87, 0x93800200, 0xD78007A7, ++ 0xD3800200, 0xAE800A87, 0x98380000, 0xEECC0200, ++ 0x8D800BC5, 0xC320FFFC, 0xF9970365, 0x892D0002, ++ 0xF5200018, 0xBE97036D, 0x89600130, 0xEF600134, ++ 0x8434FFFE, 0xD7C801F4, 0xE82E0002, 0xB1290002, ++ 0x91484000, 0xE3625F46, 0xDA340001, 0x90605F48, ++ 0xF5008000, 0xBA30FFFD, 0xB60E0000, 0xF60E0000, ++ 0x8B32FFFE, 0xF4970385, 0xD797029D, 0x9B200000, ++ 0xEA210120, 0x8A6B5F42, 0xBA6A5F46, 0xC3330001, ++ 0xF6D0070B, 0xB723070C, 0x94800327, 0xF19702AF, ++ 0xA897097D, 0xFA6A5F46, 0xF6200028, 0x8D210000, ++ 0xD7970327, 0x969702A0, 0x8D685F46, 0xDB695F46, ++ 0xBA30FFFD, 0xF50C4000, 0xE0600120, 0xAA31FFFE, ++ 0x90610124, 0xC16A0134, 0xFC30FFFE, 0xB12C01A0, ++ 0xE832FFFF, 0x8D210000, 0x844B0000, 0xDF2C0002, ++ 0x1419C000, 0x532EFFFF, 0x61CC071E, 0x1235FFFE, ++ 0x50C801FC, 0x26970CCB, 0x20690134, 0x4E6A0120, ++ 0x7E6B0124, 0x21208400, 0x2B2E0068, 0x7D2F0068, ++ 0x0C61B010, 0x4462B000, 0x7463B004, 0x3B60B01C, ++ 0x7F2300A6, 0x2F940CD0, 0x1669B020, 0x72310002, ++ 0x14D00737, 0x49970CD8, 0x558001FC, 0x09970CD8, ++ 0x0D685F46, 0x6C220000, 0x46600124, 0x36010000, ++ 0x6A31FFFE, 0x170D0000, 0x31610128, 0x630D4000, ++ 0x170D0000, 0x5761012C, 0x49625F3C, 0x38200001, ++ 0x4D60013E, 0x3C209000, 0x39970210, 0x5D20A000, ++ 0x4E970D6A, 0x14680164, 0x286A0148, 0x58380000, ++ 0x20D00E47, 0x6F69014C, 0x630E8000, 0x17610140, ++ 0x71620148, 0x3A098000, 0x3661014C, 0x6A31FFFE, ++ 0x31610144, 0x40208200, 0x4D970D6C, 0x35680168, ++ 0x0E6A014C, 0x58380000, 0x60D00E47, 0x09690148, ++ 0x71620148, 0x3A098000, 0x17610140, 0x7A098000, ++ 0x8B32FFFE, 0xC20D8000, 0xF661014C, 0x9B20F000, ++ 0xCD970D6C, 0x9F680148, 0x8E690140, 0xEC220000, ++ 0xD0620144, 0xA060014C, 0x970D0000, 0xD7610140, ++ 0x9930FFFC, 0xC6600148, 0xED208001, 0x8D970D6C, ++ 0xE86A0148, 0xB968014C, 0xB66B0154, 0xF6620140, ++ 0xB6010000, 0xFA30FFFD, 0xE7600144, 0xA2300001, ++ 0x8E0A0000, 0xC20D8000, 0xD0610148, 0x810FC000, ++ 0xC9630150, 0xA7208010, 0x8D970D6C, 0xD4680164, ++ 0x0E690140, 0x58380000, 0x60D00E47, 0x286A0148, ++ 0x7968014C, 0x106B0150, 0x10610148, 0x76620140, ++ 0x782F0001, 0x09630150, 0x0E0A0000, 0x50620144, ++ 0x2D208001, 0x4D970D6C, 0x466A0150, 0x366B0154, ++ 0x7968014C, 0x09690148, 0x170EC000, 0x5F620150, ++ 0x096A0144, 0x57610140, 0x4E0A0000, 0x31620148, ++ 0x200F0000, 0x5D33FFFE, 0x7E635F5C, 0x3C30FFFE, ++ 0x67600144, 0x00208200, 0x0D970D6C, 0x41970D7E, ++ 0xA3690168, 0xF16A5F5C, 0xCE390000, 0xA0D00E47, ++ 0xE8970E5E, 0xB5200018, 0xAF800E66, 0xE020FFFD, ++ 0xF9970365, 0x892D0002, 0xB5200018, 0xFE97036D, ++ 0x89600130, 0xEF600134, 0xC434FFFE, 0x97C801F4, ++ 0xE82E0002, 0xB1290002, 0x91484000, 0xE3625F46, ++ 0x9C340002, 0xD0605F48, 0xF5008000, 0xA3018000, ++ 0xBC30FFFE, 0xCD32FFFD, 0xF60E0000, 0x820E4000, ++ 0xCB32FFFE, 0xB4970385, 0x9797029D, 0xE897097D, ++ 0xBA6A5F46, 0xF6200028, 0xCD210000, 0xA832FFFF, ++ 0xD7970327, 0x9B200000, 0xBA6A5F46, 0xCD210000, ++ 0xE832FFFF, 0x97970327, 0x969702A0, 0xFA6A5F46, ++ 0x92970644, 0xDB695F46, 0xCD685F46, 0xAC31FFFD, ++ 0xF6610120, 0xB4310001, 0xAF090000, 0xD0610124, ++ 0xA6970CCB, 0xE0690134, 0xCE6A0120, 0x8C61B010, ++ 0xAB2E0068, 0xC462B000, 0xC362B008, 0xB8208808, ++ 0xFB60B01C, 0xBF2300A6, 0xAF940CD0, 0xF069B024, ++ 0x0E390000, 0x62D00889, 0x49690124, 0x21208400, ++ 0x4A2D0068, 0x0361B004, 0x3B60B01C, 0x7F2300A6, ++ 0x6F940CD0, 0x1669B020, 0x32310002, 0x5AD40889, ++ 0x1B695F46, 0x4E6A0120, 0x78208808, 0x020E4000, ++ 0x57620120, 0x2B2E0068, 0x0462B000, 0x4362B008, ++ 0x3B60B01C, 0x7F2300A6, 0x6F940CD0, 0x3069B024, ++ 0x0E390000, 0x62D00889, 0x61208400, 0x3B60B01C, ++ 0x7F2300A6, 0x2F940CD0, 0x1669B020, 0x72310002, ++ 0x9AD40889, 0xC9970CD8, 0xCD685F46, 0xAF690120, ++ 0xE7600128, 0xBC30FFFE, 0x970D0000, 0xD761012C, ++ 0xDD9703A3, 0xA8615F3C, 0x9B20F000, 0xD02A0002, ++ 0xA5C4088B, 0xDF695F48, 0xCA350002, 0xBCCC088B, ++ 0xF9970210, 0x83970956, 0xA0970961, 0xE06A0154, ++ 0xB968014C, 0xF96B0140, 0xDF620150, 0x89690148, ++ 0xA7630148, 0xD80B0000, 0xC6630144, 0x9F30FFFF, ++ 0xEF090000, 0x97610140, 0xAD208001, 0xCD970D6C, ++ 0x2A970970, 0x7968014C, 0x6F6A0140, 0x09690148, ++ 0x766B0154, 0x0E0A0000, 0x1762014C, 0x5F30FFFF, ++ 0x570D0000, 0x17610140, 0x22300001, 0x570D0000, ++ 0x10610148, 0x5B200000, 0x67600144, 0x09630150, ++ 0x7C209000, 0x0E970D6A, 0x1F680148, 0x4E690140, ++ 0x0E6A014C, 0x4D084000, 0x6060014C, 0x10610148, ++ 0x36620140, 0x76010000, 0x5F30FFFF, 0x170D0000, ++ 0x7E610150, 0x3F208800, 0x0D970D6C, 0x7968014C, ++ 0x2F6A0140, 0x49690148, 0x766B0154, 0x0E0A0000, ++ 0x5762014C, 0x1F30FFFF, 0x2F090000, 0x57610140, ++ 0x7C30FFFE, 0x0E0A0000, 0x31620148, 0x49630150, ++ 0x3C209000, 0x4E970D6A, 0x7968014C, 0x09690148, ++ 0x6F6A0140, 0x06600148, 0x0D084000, 0x54038000, ++ 0x360E0000, 0x5762014C, 0x64300002, 0x200F0000, ++ 0x20630140, 0x4E208000, 0x4E970D6A, 0x1D20A000, ++ 0x4E970D6A, 0x17680154, 0x0E6A014C, 0x76010000, ++ 0xB4310001, 0xF5D40863, 0xD92C0001, 0x9F2C0002, ++ 0xE060014C, 0xB6620140, 0xB6010000, 0xDF30FFFF, ++ 0xF50C4000, 0xA7600144, 0xB6010000, 0xDF30FFFF, ++ 0x970D0000, 0xD0610148, 0xC0208200, 0x8D970D6C, ++ 0xDF680148, 0x986B014C, 0xA06A0154, 0xC1600140, ++ 0xB6010000, 0xFC30FFFE, 0xDC605F5A, 0x8E09C000, ++ 0xB1610144, 0xCB32FFFE, 0xE8625F5C, 0xA1208400, ++ 0xCD970D6C, 0x81970D7E, 0xA8970E5E, 0xC16B5F58, ++ 0x056A0160, 0x7E2F0034, 0x654BC000, 0x0B420000, ++ 0x7E370004, 0x34CC0D3E, 0x316A5F5C, 0x75200018, ++ 0x6F800E66, 0x09970CD8, 0x168001FA, 0x6860013C, ++ 0x3B97035E, 0x61230939, 0x75635F46, 0x0C200891, ++ 0x5C605F36, 0x1E970393, 0x09CC0263, 0x50970236, ++ 0x2E230897, 0x75635F46, 0x7C800213, 0x1F680148, ++ 0x0E6A014C, 0x4E690140, 0x6060014C, 0x10620144, ++ 0x760E0000, 0x1F30FFFF, 0x2F090000, 0x57610140, ++ 0xB1620148, 0xED208001, 0xCD970D6C, 0xAA970970, ++ 0xC9690148, 0xB968014C, 0xAF6A0140, 0xF66B0154, ++ 0xD7610140, 0x8E0A0000, 0x8E0A0000, 0xD762014C, ++ 0xBC30FFFE, 0xC6600148, 0xDB200000, 0xA7600144, ++ 0xC9630150, 0xBC209000, 0x8E970D6A, 0xF968014C, ++ 0x89690148, 0xEF6A0140, 0xC6600148, 0x8D084000, ++ 0xA4300002, 0xF60E0000, 0xF6620140, 0xA2300001, ++ 0xE060014C, 0xB2200010, 0x94695F52, 0xEC220000, ++ 0xB5190000, 0xCD615F52, 0xD3695F6C, 0xAF238000, ++ 0xDC635F56, 0x91484000, 0x816B5F34, 0xC92D0002, ++ 0xFF424000, 0xBA1F0000, 0xA0C80D47, 0xCB235F7A, ++ 0x9249C000, 0xFE2F0002, 0xCD1D0000, 0xBFCC08D7, ++ 0xD249C000, 0x8E390000, 0x98CC0D47, 0xF2695F56, ++ 0x8E390000, 0xFED408DA, 0xCA625F56, 0x982F0006, ++ 0xAE2E0001, 0xEA8008CC, 0xC2685F52, 0xA36B5F52, ++ 0xDE34000F, 0xBC3700F0, 0xB9CC08E2, 0xCE1C8000, ++ 0x3ACC08E4, 0x628008E6, 0x4E1C8000, 0x1FCC08E6, ++ 0x6E32FFFC, 0x018008E7, 0x0F31FFFC, 0x60198000, ++ 0x6B615F56, 0x236B5F52, 0x31310004, 0x4835000F, ++ 0x3F37000F, 0x4E1F4000, 0x6CC808FC, 0x14004000, ++ 0x63645F52, 0x2931FFF8, 0x19394001, 0x49615F6A, ++ 0x36010000, 0x51310003, 0x6C615F68, 0x1F30FFFF, ++ 0x2A2C0D06, 0x6E2308FB, 0x70884000, 0x1C605F6C, ++ 0x686A0148, 0x2F69014C, 0x18680140, 0x420D8000, ++ 0x2A31FFFE, 0x6B615F60, 0x7E6B0148, 0x0E0A0000, ++ 0x750F8000, 0x0163014C, 0x3C30FFFE, 0x58605F62, ++ 0x4B32FFFE, 0x09625F66, 0x05970C69, 0x5A200051, ++ 0x3160B444, 0x64685F56, 0x456B5F60, 0x1E34000F, ++ 0x47300003, 0x36010000, 0x2434FF00, 0x600CC000, ++ 0x1060B448, 0x6C3500FF, 0x6361B44A, 0x23685F68, ++ 0x206B5F62, 0x506A5F66, 0x76010000, 0x2434FF00, ++ 0x600CC000, 0x3660B44C, 0x2C3500FF, 0x4561B44E, ++ 0xAF62B454, 0xC8200925, 0xD321090A, 0xBF2300A6, ++ 0xEF800C80, 0xAE210001, 0xBA61015E, 0xCE208000, ++ 0xC960015C, 0x89970E08, 0xA36B5F52, 0xC5685F6C, ++ 0xBF37000F, 0xF43B0100, 0xF263B144, 0x9F21085B, ++ 0xDF2C0002, 0xAA410000, 0xA4685F56, 0xC2230D47, ++ 0x9E34000F, 0xE3645F52, 0xC7300003, 0xBA605F68, ++ 0x82800D7E, 0xC3970956, 0xE0970961, 0xB968014C, ++ 0xEF6A0140, 0x89690148, 0xB66B0154, 0xCE0A0000, ++ 0x9762014C, 0xEF6A0140, 0xC9630150, 0x97610140, ++ 0xFC30FFFE, 0x8E0A0000, 0xB1620148, 0xDB200000, ++ 0xE7600144, 0xBC209000, 0x8E970D6A, 0xCE690140, ++ 0x9F680148, 0xE86A0148, 0xD7610140, 0x8D084000, ++ 0xE060014C, 0x9F30FFFF, 0xB60E0000, 0xF1620148, ++ 0x9B200000, 0xC78008BE, 0xDF680148, 0x8E6A014C, ++ 0x8E690140, 0xE060014C, 0xD0620144, 0xAF090000, ++ 0xF60E0000, 0x97610140, 0xB1620148, 0xED208001, ++ 0x0E800D6C, 0x7968014C, 0x49690148, 0x2F6A0140, ++ 0x57610140, 0x360E0000, 0x31620148, 0x57020000, ++ 0x4B32FFFE, 0x0E0A0000, 0x17680154, 0x50620144, ++ 0x010C0000, 0x68600150, 0x40208200, 0x0E800D6C, ++ 0x6F6A0140, 0x09690148, 0x3968014C, 0x71620148, ++ 0x17610140, 0x7C30FFFE, 0x4E0A0000, 0x17680154, ++ 0x10620144, 0x410C0000, 0x68600150, 0x00208200, ++ 0x4E800D6C, 0x32635F4E, 0x0A6B5F42, 0x7A6A5F46, ++ 0x9C200008, 0xCD210000, 0xC5330002, 0xA9D0098A, ++ 0xD4038000, 0x8B32FFFE, 0xBE33FFFF, 0xD70EC000, ++ 0xC6230995, 0x94800327, 0xB19702AF, 0xFA6A5F46, ++ 0x909702A3, 0xFA6A5F46, 0xD09702A3, 0xBA6A5F46, ++ 0xD09702A3, 0xBA6A5F46, 0x909702A3, 0xFA6A5F46, ++ 0x909702A3, 0xDF695F48, 0xFA6A5F46, 0x8C350001, ++ 0xA5C809A8, 0xF6200028, 0xD9970354, 0xAC685F4A, ++ 0xF9695F4C, 0x8B32FFFE, 0x8D048000, 0xE6C409A2, ++ 0x0F2D0001, 0x60615F4C, 0x75605F4A, 0x0520FFFF, ++ 0x4D210000, 0x3A6A5F46, 0x242309A9, 0x54800327, ++ 0x52970644, 0x3A6A5F46, 0x32200010, 0x4D210000, ++ 0x2B6B5F4E, 0x54800327, 0x4320FFFC, 0x39970365, ++ 0x61361F00, 0x32C801F6, 0x31320008, 0x79620138, ++ 0x3F2A0011, 0x53C401F6, 0x7797037A, 0x316B0130, ++ 0x36010000, 0x5235FFFE, 0x57C801F4, 0x1808C000, ++ 0x56C009BE, 0x2FCC01F4, 0x096B5F44, 0x682E0002, ++ 0x23625F46, 0x7E2F0002, 0x50635F44, 0x3E33FFFF, ++ 0x4B32FFFE, 0x170EC000, 0x0B32FFFE, 0x74970385, ++ 0x57680138, 0x3E695F44, 0x01030000, 0x652B0003, ++ 0x26C409CE, 0x5D200003, 0x7C2C0003, 0x2A072000, ++ 0x793B0000, 0x0ECC01F8, 0x1B695F46, 0x642E0010, ++ 0x35034000, 0x6C31FFFD, 0x4E09C000, 0x020E4000, ++ 0x042A0800, 0x57C401F8, 0x5797029D, 0x1B200000, ++ 0x6A210120, 0x0A6B5F42, 0x3A6A5F46, 0x43330001, ++ 0xACD009E3, 0xED2309E4, 0xD4800327, 0xB19702AF, ++ 0xCC970BA4, 0xBA6A5F46, 0xB6200028, 0xCD210000, ++ 0xD7970327, 0x969702A0, 0xBE695F44, 0xCD685F46, ++ 0x8931FFFF, 0xD70D0000, 0xD0610124, 0x9F30FFFF, ++ 0xD70D0000, 0xB6610120, 0xA6970CCB, 0xE0690134, ++ 0x8E6A0120, 0xCC61B010, 0xEB2E0068, 0x8462B000, ++ 0x8362B008, 0xF8208808, 0xFB60B01C, 0xBF2300A6, ++ 0xEF940CD0, 0xB069B024, 0x8E390000, 0xC6D00A0A, ++ 0x09690124, 0x61208400, 0x4A2D0068, 0x0361B004, ++ 0x7B60B01C, 0x3F2300A6, 0x2F940CD0, 0x5669B020, ++ 0x72310002, 0x05D00A0C, 0x09970CD8, 0x558001FC, ++ 0x09970CD8, 0x4D685F46, 0x7E695F44, 0x0E6A0120, ++ 0x46600124, 0x170D0000, 0x31610128, 0x46690130, ++ 0x176B0134, 0x7C30FFFE, 0x760E0000, 0x3662012C, ++ 0x28630130, 0x79610134, 0x6C220000, 0x09625F3C, ++ 0x6920E000, 0x39970210, 0x14680164, 0x67690150, ++ 0x98380000, 0xE0D00E47, 0xF66B0154, 0x896A0144, ++ 0xF968014C, 0x98610154, 0xB82F0001, 0xC9630150, ++ 0xCE690140, 0x9762014C, 0x81600140, 0xD4004000, ++ 0x820D8000, 0xD0610148, 0xE832FFFF, 0xAC088000, ++ 0xE7600144, 0x80208200, 0x8D970D6C, 0xF5680168, ++ 0xB66B0154, 0xD8380000, 0xE0D00E47, 0x8E6A014C, ++ 0x89690148, 0xC9630150, 0xF1620148, 0xBA098000, ++ 0xD7610140, 0x820D8000, 0xA832FFFF, 0xC20D8000, ++ 0xB661014C, 0xDB20F000, 0xCD970D6C, 0x9F680148, ++ 0xEF69014C, 0xAF6A0140, 0xBA230000, 0xC6630144, ++ 0xE060014C, 0x970D0000, 0x90610148, 0xF60E0000, ++ 0xB6620140, 0xED208001, 0xCD970D6C, 0xA86A0148, ++ 0xF968014C, 0x8E690140, 0xB66B0154, 0xF6620140, ++ 0xB60E0000, 0xDF30FFFF, 0xF60E0000, 0xB1620148, ++ 0xAF090000, 0xF1610144, 0xFE33FFFF, 0x89630150, ++ 0xE7208010, 0x8D970D6C, 0x82690164, 0xF968014C, ++ 0x0E390000, 0x60D00E47, 0x4E690140, 0x286A0148, ++ 0x506B0150, 0x10610148, 0x36620140, 0x782F0001, ++ 0x49630150, 0x2F090000, 0x31610144, 0x6D208001, ++ 0x0D970D6C, 0x466A0150, 0x766B0154, 0x3968014C, ++ 0x49690148, 0x170EC000, 0x1F620150, 0x600F0000, ++ 0x1D33FFFE, 0x7E635F5C, 0x5F6B0144, 0x17610140, ++ 0x180B0000, 0x67630148, 0x7C30FFFE, 0x180B0000, ++ 0x46630144, 0x00208200, 0x0D970D6C, 0x41970D7E, ++ 0xA3690168, 0xF16A5F5C, 0xCE390000, 0xA0D00E47, ++ 0xE8970E5E, 0xB5200018, 0xAF800E66, 0xE020FFFD, ++ 0xF9970365, 0xA1361F00, 0xB2C801F6, 0xF1320008, ++ 0xB9620138, 0xFF2A0011, 0xD3C401F6, 0xB797037A, ++ 0xF16B0130, 0xB6010000, 0x9235FFFE, 0xD7C801F4, ++ 0x9808C000, 0xDBC00A97, 0xEFCC01F4, 0x896B5F44, ++ 0xA82E0002, 0xE3625F46, 0xFE2F0002, 0x90635F44, ++ 0xC100C000, 0xBE33FFFF, 0xA00F0000, 0xCB32FFFE, ++ 0x170EC000, 0x4B32FFFE, 0x74970385, 0x17680138, ++ 0x7E695F44, 0x01030000, 0x252B0003, 0x64C40AA9, ++ 0x5D200003, 0x3F2C0005, 0x2A072000, 0x793B0000, ++ 0x0ECC01F8, 0x5B695F46, 0x642E0010, 0x2A31FFFE, ++ 0x420E4000, 0x042A0800, 0x17C401F8, 0x5797029D, ++ 0x1B200000, 0x4D210000, 0x5F6A5F44, 0x17970327, ++ 0x0C970BA4, 0x7A6A5F46, 0x76200028, 0x0D210000, ++ 0x6832FFFF, 0x17970327, 0x169702A0, 0x68685F44, ++ 0x1B695F46, 0x57020000, 0x75034000, 0x1F30FFFF, ++ 0x4931FFFF, 0x140C8000, 0x06600124, 0x750C4000, ++ 0x67600128, 0x200CC000, 0x20600120, 0x66970CCB, ++ 0x20690134, 0x496A0128, 0x5F610130, 0x0C61B010, ++ 0x6B2E0068, 0x0462B000, 0x0362B008, 0x78208808, ++ 0x3B60B01C, 0x7F2300A6, 0x6F940CD0, 0x3069B024, ++ 0x0E390000, 0x73D40ADC, 0x49970CD8, 0x168001FA, ++ 0x49690124, 0x21208400, 0x0A2D0068, 0x4361B004, ++ 0xBB60B01C, 0xFF2300A6, 0xEF940CD0, 0x9669B020, ++ 0xF2310002, 0xB0D40ADA, 0x8E6A0120, 0xF8208808, ++ 0xEB2E0068, 0x8462B000, 0x8362B008, 0xFB60B01C, ++ 0xBF2300A6, 0xEF940CD0, 0xF069B024, 0x8E390000, ++ 0xC8D00ADA, 0xA1208400, 0xBB60B01C, 0xFF2300A6, ++ 0xAF940CD0, 0xD669B020, 0xF2310002, 0xB0D40ADA, ++ 0x89970CD8, 0xCD685F46, 0xEF690120, 0xA7600128, ++ 0xD70D0000, 0x9761012C, 0xAC220000, 0xC9625F3C, ++ 0x9B20F000, 0xF9970210, 0xDF680148, 0x8E6A014C, ++ 0xCE690140, 0xA060014C, 0x90620144, 0xEF090000, ++ 0xD7610140, 0xB60E0000, 0xB1620148, 0xED208001, ++ 0x8D970D6C, 0xF968014C, 0xC9690148, 0xAF6A0140, ++ 0xD7610140, 0xA3018000, 0x970D0000, 0xD0610148, ++ 0x9F30FFFF, 0xCE0A0000, 0xD7680154, 0x90620144, ++ 0x810C0000, 0xE8600150, 0xC0208200, 0x8D970D6C, ++ 0xE06A0154, 0xB968014C, 0xB96B0140, 0xDF620150, ++ 0x09690148, 0x67630148, 0x580B0000, 0x06630144, ++ 0x5F30FFFF, 0x2F090000, 0x17610140, 0x6D208001, ++ 0x4D970D6C, 0x3968014C, 0x2F6A0140, 0x49690148, ++ 0x31620148, 0x4E0A0000, 0x57680154, 0x10620144, ++ 0x57610140, 0x010C0000, 0x28600150, 0x40208200, ++ 0x0D970D6C, 0x7968014C, 0x766B0154, 0x09690148, ++ 0x2F6A0140, 0x49630150, 0x57610140, 0x36695F58, ++ 0x4E0A0000, 0x1762014C, 0x2F2D0030, 0x664A4000, ++ 0x2F2D0006, 0x47494000, 0x673607FC, 0x13320002, ++ 0x79620154, 0x14038000, 0x03330001, 0x7ED40B49, ++ 0x6E2E0001, 0x282E0002, 0x10620144, 0x6832FFFF, ++ 0x31620148, 0x40351F00, 0x50310008, 0x39610158, ++ 0x6920E000, 0x0D970D6C, 0x3E680144, 0x4E6A014C, ++ 0x0E690140, 0x506B0150, 0x760E0000, 0x1762014C, ++ 0x0100C000, 0x43330001, 0x52D40B5C, 0x192C0001, ++ 0x5F2C0002, 0x1F30FFFF, 0x170D0000, 0x57610140, ++ 0x8D210000, 0xD0610148, 0xE920E000, 0x8D970D6C, ++ 0xD06B0150, 0x97680154, 0x8E6A014C, 0xC163014C, ++ 0xE8600150, 0x8E600154, 0x81030000, 0xC3330001, ++ 0xB4D40B6E, 0xD92C0001, 0xDF2C0002, 0x90620144, ++ 0xCE0A0000, 0xB6620140, 0x9F30FFFF, 0xF60E0000, ++ 0xB1620148, 0xED208001, 0xCD970D6C, 0x89690148, ++ 0x896A0144, 0xD06B0150, 0xD7610140, 0xB1620148, ++ 0xC100C000, 0xBE33FFFF, 0x89630150, 0xCE600154, ++ 0x01030000, 0x43330001, 0x5BD40B84, 0x192C0001, ++ 0x5F2C0002, 0x27600144, 0x00208200, 0x4D970D6C, ++ 0x68690144, 0x286A0148, 0x3968014C, 0x766B0154, ++ 0x36620140, 0x49630150, 0x4E600154, 0x01030000, ++ 0x43330001, 0x12D40B93, 0x192C0001, 0x5F2C0002, ++ 0x2060014C, 0x7A0A4000, 0x71620148, 0x3C30FFFE, ++ 0x0E0A0000, 0x50620144, 0x40208200, 0x0D970D6C, ++ 0x49690148, 0x206A0154, 0x186B014C, 0x57610140, ++ 0x9F620150, 0xFE33FFFF, 0xCE09C000, 0xA3800878, ++ 0xF2635F4E, 0x8A6B5F42, 0x9C200008, 0xCD210000, ++ 0xDF6A5F44, 0x85330002, 0x86D00BB0, 0xEC6B5F46, ++ 0xA832FFFF, 0xD70EC000, 0xEF230BC0, 0x94800327, ++ 0xF19702AF, 0x9F6A5F44, 0x909702A3, 0xDF6A5F44, ++ 0xAC685F4A, 0xF9695F4C, 0xCB32FFFE, 0x8D048000, ++ 0xA5C40BBB, 0xCF2D0001, 0xE0615F4C, 0xB5605F4A, ++ 0xFA6A5F46, 0x8520FFFF, 0x8D210000, 0xF19702AF, ++ 0xBA6A5F46, 0xF2200010, 0xCD210000, 0xAB6B5F4E, ++ 0xD4800327, 0x93800200, 0x81030000, 0xC637FFFF, ++ 0xEECC0200, 0xAE2C0BCB, 0xB0884000, 0xE9800BCC, ++ 0x9A970364, 0xDF20000E, 0xFE97036D, 0xA43C000E, ++ 0xEFCC01F4, 0x952001FF, 0xBE97036D, 0xFE605F3C, ++ 0xBF340003, 0xEFCC01F4, 0xC92E000E, 0x8B32FFFE, ++ 0xB4970385, 0xD797029D, 0xE822000E, 0x9B200000, ++ 0xCD210000, 0x97970327, 0xA0685F34, 0xC92101D8, ++ 0x1F610106, 0x7D2C0008, 0x73490000, 0x1F2C0002, ++ 0x65480000, 0x23615F4A, 0x36605F4C, 0x67685F3C, ++ 0x58695F40, 0x3C30FFFE, 0x1B605F3E, 0x6F090000, ++ 0x02C40BEE, 0x57605F40, 0x502001A0, 0x2A230BF3, ++ 0x6C600104, 0x3D635F36, 0x3D8002D7, 0x72200010, ++ 0x2C600104, 0x58800420, 0x529700EB, 0x2A220003, ++ 0x2F62B438, 0x56695FCA, 0x42685EDE, 0x2C220000, ++ 0x4A61B400, 0x2862B406, 0x18380000, 0x7CC8009C, ++ 0x15340080, 0x43C80C05, 0x6F200C16, 0x27230C06, ++ 0x5A8000AB, 0x1B605EDE, 0x24685EEC, 0x5E23009C, ++ 0x6C220000, 0x0A625EEC, 0x14695EDE, 0x5B6A5EF0, ++ 0x18380000, 0x7AC800F3, 0x60198000, 0x176A5F02, ++ 0x60198000, 0x396A5EA0, 0x1CD000AB, 0x5E36FDFF, ++ 0x20625EA0, 0x5A8000AB, 0x51215EDE, 0x2F220006, ++ 0x04970F9D, 0x77215EEC, 0x70510000, 0x30510000, ++ 0x70884000, 0x2F220030, 0x2F62B438, 0x70695FCE, ++ 0xAC685EF0, 0xEC220000, 0xE061B420, 0x8262B426, ++ 0xD8380000, 0x9FC8009D, 0x95340080, 0xEDC80C2B, ++ 0xE5200C31, 0xAF230C2C, 0x9A8000AB, 0xF5605EF0, ++ 0xA8685EFE, 0xFD23009D, 0xEC220000, 0x86625EFE, ++ 0xE1800C0A, 0xBF215EF0, 0xAF220006, 0xC4970F9D, ++ 0xBB215EFE, 0xF0510000, 0xF0510000, 0xB0884000, ++ 0xAF220300, 0xEF62B438, 0xF0695FCE, 0xA0685F02, ++ 0xEC220000, 0x8161B440, 0xA362B446, 0xD8380000, ++ 0x99C8009E, 0xD5340080, 0xCEC80C46, 0xAF200C4C, ++ 0xCF230C47, 0x9A8000AB, 0xB9605F02, 0xEC685F10, ++ 0xFB23009E, 0xAC220000, 0x82625F10, 0xE1800C0A, ++ 0xB3215F02, 0xEF220006, 0xC4970F9D, 0xBF215F10, ++ 0xF0510000, 0xB0510000, 0xB0884000, 0xC2685EDE, ++ 0x91215EDE, 0xD8380000, 0xC0D00C5F, 0xA1205EEC, ++ 0xA5518000, 0xE6500000, 0xD8695EA0, 0xA6500000, ++ 0xC0390200, 0x81615EA0, 0x918B4000, 0xC100C000, ++ 0x2F220006, 0x7F2300A6, 0x67800FC0, 0x2C685EF0, ++ 0x7F215EF0, 0x18380000, 0x00D00C5F, 0x6D205EFE, ++ 0x66800C58, 0x20685F02, 0x33215F02, 0x58380000, ++ 0x00D00C5F, 0x69205F10, 0x66800C58, 0x02685EDE, ++ 0x51215EDE, 0x18380000, 0x3FD40C57, 0x588000A6, ++ 0x2C685EF0, 0x7F215EF0, 0x58380000, 0x1ED000A6, ++ 0x2D205EFE, 0x66800C58, 0x7D605EEC, 0x0E615EEE, ++ 0x518B4000, 0x31605EFE, 0x0A615F00, 0x518B4000, ++ 0xB5605F10, 0xC6615F12, 0xD18B4000, 0xAC685EF0, ++ 0xCD210000, 0x98380000, 0xA5C80C94, 0xEF61B434, ++ 0xD16A5FCE, 0xA361B426, 0x8162B420, 0xD5340080, ++ 0x85C80C93, 0xD4635E9C, 0xFF215EF0, 0xAF220006, ++ 0xC4970F9D, 0x8D6B5E9C, 0x9A8000AB, 0xE3615EF0, ++ 0x918B4000, 0xD7620116, 0xC7200C98, 0x9A8000AB, ++ 0x86970C6F, 0xCE6A0116, 0xE620B404, 0xAC500011, ++ 0xE0500003, 0xA850C400, 0x85500001, 0xC7500180, ++ 0x26500000, 0x6462B414, 0x5E2000A6, 0x082100A6, ++ 0x7F2300A6, 0x29800C7A, 0x20690102, 0x5B200000, ++ 0x45350020, 0x14C801F2, 0x18218000, 0x6F615ED4, ++ 0x3D605EDA, 0x7E605EDC, 0x518B4000, 0x36695ED4, ++ 0x58380000, 0x3AC800F3, 0x0E390000, 0x49D400EF, ++ 0x3D605EDA, 0x518B4000, 0x76695ED4, 0x18380000, ++ 0x3AC800F3, 0x4E390000, 0x49D400EF, 0x3E605EDC, ++ 0x518B4000, 0x20685ED4, 0x33215ED4, 0x58380000, ++ 0x24D400F1, 0x70510000, 0x518B4000, 0x18695ECC, ++ 0x63685ED2, 0x0E390000, 0x27D4009B, 0x58380000, ++ 0x5CC8009B, 0x3E23009B, 0x1A8000AB, 0x5D215ECC, ++ 0x25518000, 0x5B200000, 0x7A605ED2, 0x118B4000, ++ 0x58695ECC, 0x3A605ED2, 0x0E390000, 0x58695EA0, ++ 0x09D400EF, 0x49390008, 0x41615EA0, 0x118B4000, ++ 0x396A5EA0, 0x4E685ECC, 0x5D215ECC, 0x1736FFF7, ++ 0x60625EA0, 0x18380000, 0x24D400F1, 0x70510000, ++ 0x918B4000, 0xC2685F52, 0xD8218000, 0xB6144000, ++ 0xE6CC00A0, 0x8D615F52, 0xBC2300A0, 0xEC200CE9, ++ 0xDA8000AB, 0xB4200400, 0x9360B144, 0xC3210200, ++ 0x8A68B144, 0xDE34000F, 0xF5190000, 0x8561B144, ++ 0xE3645F52, 0xB6010000, 0x90310008, 0xE839A0C8, ++ 0xB04B4000, 0xE72D002C, 0xC7494000, 0x97020000, ++ 0x83330001, 0xD0377F00, 0xC963010A, 0xB0320003, ++ 0xCD625F68, 0x97020000, 0x8832FFF8, 0xF83A4001, ++ 0xA8625F6A, 0xD7020000, 0xE832FFFF, 0x9D2E0D06, ++ 0xE2230D1A, 0x878A4000, 0xAA205F7A, 0xD18B4000, ++ 0xC9205F82, 0x918B4000, 0x8E205F8A, 0xD18B4000, ++ 0xA0205F92, 0xD18B4000, 0xE7205F9A, 0x918B4000, ++ 0xE3205FA2, 0x918B4000, 0xA4205FAA, 0xD18B4000, ++ 0x8A205FB2, 0xD18B4000, 0xCD205FBA, 0x918B4000, ++ 0x82205FC2, 0xD18B4000, 0xDC605F6C, 0xB3490000, ++ 0xDF2C0002, 0x844B0000, 0x9F2C0002, 0xD24A0000, ++ 0x1F2C0002, 0x65480000, 0x6F615F58, 0x1C635F56, ++ 0x6B625F5A, 0x1F605F5C, 0x27970E26, 0x716A5F5C, ++ 0x536B010C, 0x2F3A0000, 0x0BC80D36, 0x6C213000, ++ 0x3A098000, 0x6C0B4000, 0x5861010E, 0x32C00D31, ++ 0x7ECC0E45, 0x05685F5A, 0x29230D36, 0x79635F54, ++ 0x026B5F68, 0x66800E2B, 0x6769010A, 0x056B5F56, ++ 0x10310008, 0x4AC80D67, 0x576A5F58, 0x22390080, ++ 0x4B2E0035, 0x07458000, 0x01970D7E, 0x42685F52, ++ 0x24230D43, 0x4B341000, 0x59CC102C, 0x1D2000A0, ++ 0x40645F53, 0x36695F58, 0x1E970273, 0x4169010E, ++ 0x4D223000, 0x3A0A4000, 0x2CC80D63, 0x54680108, ++ 0x32620114, 0x58380000, 0x69C80D50, 0x00970C95, ++ 0x45970C69, 0x0169010E, 0x2D20B444, 0x6C500011, ++ 0x05500001, 0x6850C400, 0x45500001, 0x3135FFFF, ++ 0x2A410000, 0x6B6A0114, 0x5F2C0002, 0x26500000, ++ 0x6F62B454, 0x0A200D61, 0x1C210D61, 0x7F2300A6, ++ 0xAF800C80, 0xFA203000, 0xCE60010E, 0x8D210000, ++ 0xDB610108, 0x8D615F52, 0x988000A6, 0xEC220000, ++ 0xDB62015E, 0x918B4000, 0xAE210001, 0xFA61015E, ++ 0x8960015C, 0xDC635F56, 0xC9970E08, 0xA36B5F52, ++ 0xC5685F6C, 0xBF37000F, 0xB43B0100, 0xF263B144, ++ 0xB2695F56, 0xDF2C0002, 0xEA410000, 0x93695F5A, ++ 0x9F2C0002, 0xEA410000, 0xD0695F5C, 0x9F2C0002, ++ 0xEA410000, 0xA5800D47, 0x82685F52, 0xFA69B140, ++ 0x3C30FFFE, 0x53D0038F, 0x79635F54, 0x24300002, ++ 0x41030000, 0x1E34000F, 0x3E3CFFFF, 0x79228000, ++ 0x4D120000, 0x181D8000, 0x2361B140, 0x796A5EA0, ++ 0x38CC0D8F, 0x7636FFFB, 0x60625EA0, 0x2A3B2000, ++ 0x63685F32, 0x3A635F52, 0x0D344000, 0x6AC80D99, ++ 0x05685F36, 0x599700AB, 0x41685F54, 0x3F2300A6, ++ 0x1A8000AB, 0x42685F52, 0x7A69B140, 0x2F238000, ++ 0x5E34000F, 0x17020000, 0x093EFFFF, 0x4E138000, ++ 0x9419C000, 0xE361B140, 0xFF30FFF8, 0x9438A084, ++ 0xCC500020, 0xBD680118, 0x97695F54, 0xC218C000, ++ 0xE4600118, 0xBA1CC000, 0xB8CC0DE3, 0xF161011E, ++ 0xA3685F68, 0xE363011C, 0xC160011A, 0x85970C69, ++ 0xF96B011A, 0xAD20B444, 0x8E500041, 0xC5500001, ++ 0x87500180, 0xE6500000, 0xF602C000, 0x9336FF00, ++ 0x8162B44C, 0xDB3700FF, 0xF263B44E, 0xBF222000, ++ 0xEF62B454, 0x9F6B011E, 0x9B200000, 0xE760011E, ++ 0xB93B0000, 0xD2CC0DC3, 0xFF2300A6, 0xAC200DC6, ++ 0xFA210DC6, 0xAF800C80, 0x9B68011C, 0xFA69B140, ++ 0xCA6A0118, 0x8D1D0000, 0xA361B140, 0xEC1E0000, ++ 0x93620118, 0xE2C80DDF, 0xDB200000, 0xAE210001, ++ 0xD4038000, 0x97174000, 0xBECC0DD6, 0xD92C0001, ++ 0x8931FFFF, 0xC0800DD0, 0xD461011C, 0x87300003, ++ 0xB5695F32, 0xC160011A, 0xDB354000, 0xAAC80DAF, ++ 0xE9200DAF, 0xA46B5F36, 0x9A8000AB, 0xE3685F32, ++ 0x13695F36, 0x4D344000, 0x5DC800A6, 0x26894000, ++ 0x6F3A0000, 0x10C8038F, 0x3D635F36, 0x4D6B5F4A, ++ 0x6C600104, 0x1F610106, 0x2C625F3E, 0x71635F48, ++ 0x27970C63, 0x75680104, 0x676A0106, 0x286B5F48, ++ 0x7160B428, 0x1E21B42A, 0x30510000, 0x4100C000, ++ 0x2434FF00, 0x541A0000, 0x6062B42C, 0x1B3700FF, ++ 0x1363B42E, 0x756A5F3E, 0x73200041, 0x1060B424, ++ 0x4E62B434, 0x32210DEC, 0x3F2300A6, 0x6B940C7D, ++ 0xA46B5F36, 0xD18B4000, 0xFD635F36, 0xBC200120, ++ 0xCD210000, 0x86220020, 0x8E6B5F4C, 0xC4800DE8, ++ 0xF9635F54, 0xA76B5F6A, 0x9D200140, 0xCD210000, ++ 0x86220020, 0xFD605F60, 0xCE615F62, 0x89625F66, ++ 0xDB635F5E, 0x85970C69, 0xA4685F60, 0xF66A5F62, ++ 0x826B5F5E, 0xD060B448, 0xFF21B44A, 0xB0510000, ++ 0x8100C000, 0xE434FF00, 0xD41A0000, 0x8162B44C, ++ 0xDB3700FF, 0xB263B44E, 0x906A5F66, 0xF3200041, ++ 0x3160B444, 0x6F62B454, 0x46200E43, 0x17210E11, ++ 0x7F2300A6, 0x2F800C80, 0x39635F54, 0x5B200000, ++ 0x4B210140, 0x2722002C, 0x276B5F6A, 0x7D605F60, ++ 0x0E615F62, 0x49625F66, 0x5B635F5E, 0x05970C69, ++ 0x546A5F5E, 0x24685F60, 0x17695F62, 0x54038000, ++ 0x0537FF00, 0x4218C000, 0x5060B448, 0x0D3600FF, ++ 0x0262B44A, 0x6061B44C, 0x5B200000, 0x1360B44E, ++ 0x506A5F66, 0x11200011, 0x3160B444, 0x6F62B454, ++ 0x10210E2F, 0x7F2300A6, 0x4D940C80, 0x206B5F54, ++ 0x518B4000, 0x25210041, 0x2F800D3A, 0x44210021, ++ 0x6F800D3A, 0x176A5F58, 0x02690164, 0x602E0028, ++ 0x0E390000, 0x4BD00E5A, 0x6F090000, 0x2A31FFFE, ++ 0x75680168, 0x3F418000, 0x3734001F, 0x682E0002, ++ 0x29408000, 0x75008000, 0x5F2C0002, 0x26500000, ++ 0x26500000, 0x518B4000, 0x4E208000, 0x29408000, ++ 0x5B200000, 0x29800E53, 0x20685F58, 0x4D210000, ++ 0x972C0028, 0xE6500000, 0xE6500000, 0xA6500000, ++ 0xEA410000, 0x918B4000, 0xAE230D3E, 0xE73607FC, ++ 0xD0C8038F, 0xB9635F54, 0x816B5F58, 0xC9625F66, ++ 0xA00CC000, 0xC44B0000, 0xDF2C0002, 0xA5480000, ++ 0xF9635F62, 0xB66B010E, 0x9B605F64, 0xF60DC000, ++ 0x9B610108, 0xE4970C53, 0xC1685F62, 0x94695F64, ++ 0xBD60B40C, 0xCE61B40E, 0xD4680108, 0x906A5F66, ++ 0xF421B40A, 0x9B60B408, 0xB0510000, 0xD4200081, ++ 0x3A60B404, 0x6462B414, 0x41685F54, 0x10210E75, ++ 0x7F2300A6, 0x29800C7A, 0x36695F6E, 0x4E208000, ++ 0x54150000, 0x25C80E8B, 0x118B4000, 0x796A5EA0, ++ 0x39605F6E, 0x6D200E91, 0x7536FFFD, 0x20625EA0, ++ 0x5A8000AB, 0x2A685FDC, 0x36695F6E, 0x58380000, ++ 0x0AC80EF4, 0x54605F70, 0x712C0040, 0x33490000, ++ 0x17655F6E, 0x5C65B112, 0x6F31FFFB, 0x312D4010, ++ 0x664A4000, 0x2F6BB110, 0x092D0002, 0x6F0AC000, ++ 0x9BC00EE8, 0xF04B4000, 0xD62DFFF6, 0xB93B0000, ++ 0xF7D40EAD, 0x8D685F70, 0xA02D0012, 0xE64A4000, ++ 0xD42C0042, 0x844B0000, 0xB82DFFEE, 0xEF1F8000, ++ 0x9FCC0EEA, 0xD4004000, 0xFB215F72, 0x8F970FDD, ++ 0xFE695F72, 0xB92C0006, 0xA9350003, 0xDACC0EEF, ++ 0xBB215F72, 0xF422FFFC, 0xE1970FF3, 0x8D685F70, ++ 0xB9215FDC, 0xE0970F5B, 0xE6971027, 0xA4970C53, ++ 0xEC6B5F70, 0xA8685F72, 0xBD695F74, 0xD522B40A, ++ 0xBA63B408, 0xD1520000, 0xFD60B40C, 0x8E61B40E, ++ 0xD4200081, 0xBA60B404, 0x90200040, 0xD360B414, ++ 0xD0210EBA, 0xBF2300A6, 0x8B940C7A, 0xE0685F6E, ++ 0xBC695FEA, 0xFA3400FF, 0xF930FFFB, 0x852C401A, ++ 0xC44B0000, 0x8F2D0001, 0xB82F0001, 0xDD430000, ++ 0x802CFFF6, 0xD24A0000, 0xF92C0006, 0x844B0000, ++ 0xA5615FEA, 0xF82F0001, 0xEF0AC000, 0xA5C40EDD, ++ 0xFA230000, 0x9D430000, 0x976A5F6E, 0xCD685F70, ++ 0x0D3600FF, 0x5D3A1000, 0x4A62B130, 0x06970F33, ++ 0x4E208000, 0x39605F6E, 0x0C230E91, 0x7C800115, ++ 0x66210088, 0x34655F6F, 0x0D685F70, 0x76695F6E, ++ 0x3E2C0038, 0x65480000, 0x4E800E93, 0x3F9700F5, ++ 0x4D685F70, 0x39215FDC, 0x21230EE3, 0x63800F5B, ++ 0x396A5EA0, 0x5E350800, 0x6F615F6E, 0x1DC800A6, ++ 0x0A3A0002, 0x60625EA0, 0x588000A6, 0x2B68B148, ++ 0x62300001, 0x20D00F04, 0x21300007, 0x62D00F09, ++ 0x06300008, 0x7E3CFFFF, 0x4A64B148, 0x3F80009F, ++ 0x7A230000, 0x1363B148, 0x3C635FF2, 0x59635FF0, ++ 0x6D800EFE, 0x07710048, 0x29710149, 0x5471804B, ++ 0x01800F0B, 0x40685FFC, 0x736AB1F8, 0x2434FF00, ++ 0x46300008, 0x192C0001, 0x21361F00, 0x71320008, ++ 0x0E0A0000, 0x41C000F9, 0x7F225E90, 0x3930FFFB, ++ 0x0E2C4000, 0x4E0A0000, 0x63C000F3, 0x37605FD2, ++ 0x43625FD4, 0x122A000F, 0x0EC000ED, 0x518B4000, ++ 0x88685FD6, 0xFB695FD4, 0xD8380000, 0x8FC80F27, ++ 0xF3490000, 0x87615FD6, 0x918B4000, 0xF9290044, ++ 0xD1C00F2F, 0xAE685FD2, 0xA2615FD4, 0xF6010000, ++ 0x812D0044, 0xE1615FD2, 0xD18B4000, 0x9B1C0000, ++ 0xF7605FD2, 0xB4605FD4, 0x918B4000, 0xDE695FD6, ++ 0x98380000, 0xFAC800F3, 0xEA410000, 0x91605FD6, ++ 0x918B4000, 0xCE390000, 0xD7C800ED, 0xA64A4000, ++ 0xD8380000, 0xBAC800F3, 0x88404000, 0xEF3A0000, ++ 0xAEC80F47, 0xDB2C003A, 0xCB420000, 0x892E0038, ++ 0xC32CFFC6, 0xA9408000, 0x918B4000, 0xD12DFFFE, ++ 0xC8404000, 0x918B4000, 0x8E390000, 0xD7C800ED, ++ 0xA64A4000, 0xD8380000, 0xFAC800F3, 0x88404000, ++ 0xEF3A0000, 0xA0C80F58, 0xBE2C0038, 0xCB420000, ++ 0xAC2E003A, 0xC72CFFC8, 0xE9408000, 0x918B4000, ++ 0x892D0002, 0xC8404000, 0xD18B4000, 0x8E390000, ++ 0xD7C800ED, 0x98380000, 0xBAC800F3, 0xF6635E96, ++ 0x1B2C003A, 0x444B0000, 0x472CFFFE, 0x124A0000, ++ 0x793B0000, 0x20C80F6E, 0x2F3A0000, 0x4CC80F7B, ++ 0x5F2F0038, 0x2A42C000, 0x2C2E003A, 0x662FFFC8, ++ 0x08438000, 0x4B800F76, 0x7F424000, 0x2F3A0000, ++ 0x6BC80F74, 0x2C2E003A, 0x08438000, 0x4B800F76, ++ 0x092D0002, 0x7F424000, 0x66500000, 0x26500000, ++ 0x2F6B5E96, 0x662CFFC4, 0x518B4000, 0x092D0002, ++ 0x7F424000, 0x1F2F0038, 0x2A42C000, 0x4B800F76, ++ 0x95320001, 0xC5367FFF, 0xC6C80F93, 0xB22A0008, ++ 0xD7C00F8F, 0xA6500000, 0xA6500000, 0xE6500000, ++ 0xE6500000, 0xA6500000, 0xA6500000, 0xE6500000, ++ 0xA6500000, 0xC6C80F93, 0xEA800F83, 0x93260008, ++ 0xE6500000, 0x932EFFFF, 0xB8CC0F90, 0xD18B4000, ++ 0x93635E94, 0xC4970F9D, 0xCA6B5E94, 0x9A8000AB, ++ 0x93635E94, 0xC4970F9D, 0xC1030000, 0xAB685E94, ++ 0xDA8000AB, 0x91484000, 0xA7615E92, 0xD4605E90, ++ 0x06300008, 0x55D40FBE, 0x76635E96, 0x1634007F, ++ 0x5F30FFFF, 0x092D0002, 0x170D0000, 0x704B4000, ++ 0x62300001, 0x192C0001, 0x1B695E90, 0x6C1E0000, ++ 0x3FCC0FAE, 0x5B200000, 0x63024000, 0x1B368000, ++ 0x4035007F, 0x0D1D0000, 0x3E695E92, 0x4BC80FBC, ++ 0x31320008, 0x541A0000, 0x4F2D0001, 0x07464000, ++ 0x0100C000, 0x6F6B5E96, 0x58380000, 0x118B4000, ++ 0x7F424000, 0x28800FB8, 0x1B1C0000, 0x518B4000, ++ 0x14605E90, 0x51484000, 0x45625E94, 0x06300008, ++ 0x71D40FDB, 0x17020000, 0x06300008, 0x5634007F, ++ 0x6136007F, 0x2C1E0000, 0x17C800ED, 0x5F30FFFF, ++ 0x3A6A5E90, 0x67615E92, 0x492D0002, 0x170D0000, ++ 0x7F424000, 0x1C6A5E94, 0x3E695E92, 0x62300001, ++ 0x192C0001, 0x6C1E0000, 0x74CC0FD8, 0x1B200000, ++ 0x34380080, 0x70444000, 0x518B4000, 0x1B200000, ++ 0x46800FCC, 0x36635E96, 0x044B0000, 0x5F2C0002, ++ 0xA9434000, 0xD24A0000, 0xC92D0002, 0xBF424000, ++ 0xD71B8000, 0x9F2C0002, 0x924A0000, 0xC92D0002, ++ 0xFF424000, 0x971B8000, 0x9F2C0002, 0xD24A0000, ++ 0x892D0002, 0xFF424000, 0xF51AC000, 0xAF6B5E96, ++ 0xDF2C0002, 0x892D0002, 0x918B4000, 0xD4605E90, ++ 0xA7615E92, 0xF6635E96, 0xF3490000, 0x940C8000, ++ 0xA5480000, 0xCE390000, 0xE1C8101A, 0xA1340FFC, ++ 0xCFC81002, 0xAA280041, 0x96C01002, 0xCB240041, ++ 0xAA072000, 0xCF801007, 0xCC31FFFA, 0xA3024000, ++ 0xF436FFC0, 0xB5034000, 0xBC37003F, 0xFE695E92, ++ 0xD1484000, 0x8D048000, 0x88404000, 0xC92D0002, ++ 0x91484000, 0xD604C400, 0xC8404000, 0x80C4101A, ++ 0xC92D0002, 0x91484000, 0xAC220000, 0xE2048400, ++ 0x88404000, 0xC0C4101A, 0xC92D0002, 0x91484000, ++ 0xA2048400, 0xC8404000, 0xEF6B5E96, 0x8D685E90, ++ 0xD18B4000, 0x8A685F14, 0x99215F14, 0xD8380000, ++ 0x05D01023, 0x65518000, 0x518B4000, 0x0100C000, ++ 0x49220002, 0x3F2300A6, 0x27800FC0, 0x4A685F14, ++ 0x5D215F1A, 0x18380000, 0x05D01023, 0x518B4000, ++ 0x0A685F14, 0x59215F14, 0x58380000, 0x24D400F1, ++ 0x55340080, 0x0FC81034, 0x09220002, 0x42800F98, ++ 0x30510000, 0x4E685F1A, 0x54635E9C, 0x18380000, ++ 0x33CC103A, 0x518B4000, 0x5D215F1A, 0x09220002, ++ 0x60970F94, 0x0D6B5E9C, 0x29801035, 0x60000000, ++ 0x20000000 ++}; ++ ++// Align to PKA_BUFFER_RAM_SIZE. This is greater than the actual buffer ++// length so that the image is zero padded. ++static const uint32_t fw1_farm_img_data_buf[2048] = ++{ ++ 0x267001C9, 0x132040FA, 0x26502421, 0x032040D0, ++ 0x295046C7, 0x0D500000, 0x258C0200, 0x0F70AAC9, ++ 0x3B7000C8, 0x2D70001D, 0x2670001F, 0x296A4010, ++ 0x086B4014, 0x39621FF8, 0x16631FF4, 0x15684000, ++ 0x34694004, 0x1E601FF6, 0x3F611FF2, 0x346A4008, ++ 0x156B400C, 0x32621FFA, 0x1B631FF0, 0x219700BB, ++ 0x1E684034, 0x2170001E, 0x3A34003F, 0x281A0000, ++ 0x3F621FFE, 0x0628000B, 0x20C4004A, 0x1124002C, ++ 0x21884000, 0x2980004A, 0x30800033, 0x22800048, ++ 0x3480003E, 0x2980004A, 0x2C800040, 0x2C80002C, ++ 0x3980003A, 0x27800042, 0x21800044, 0x2A800046, ++ 0x276A4018, 0x34621FFC, 0x339701D9, 0x09300002, ++ 0x39D00063, 0x3930FFFE, 0x36800059, 0x276A4018, ++ 0x34621FFC, 0x2A97025F, 0x09300002, 0x39D00063, ++ 0x3930FFFE, 0x34800064, 0x2E970327, 0x268C0400, ++ 0x16614018, 0x36800059, 0x2F970733, 0x36800059, ++ 0x2A9706EF, 0x36800059, 0x29970735, 0x36800059, ++ 0x319706F1, 0x36800059, 0x3D970422, 0x36800059, ++ 0x27970767, 0x36800059, 0x3B7000C8, 0x24200021, ++ 0x358C5000, 0x26800073, 0x2B707FC8, 0x08702084, ++ 0x2D70001D, 0x36200000, 0x2D010000, 0x1E220001, ++ 0x2F970085, 0x01684084, 0x26340020, 0x0ECC0055, ++ 0x3920000F, 0x238C0100, 0x09300002, 0x39D00063, ++ 0x1B601FFC, 0x2A681FF0, 0x246A4014, 0x2D010000, ++ 0x2460400C, 0x2F970085, 0x29681FFC, 0x3930FFFE, ++ 0x036A1FF6, 0x276B1FF8, 0x08624000, 0x37634010, ++ 0x0D6A1FFE, 0x3F9700C3, 0x0E6A1FF2, 0x246B1FF4, ++ 0x05624004, 0x3A634014, 0x006A1FFA, 0x35230000, ++ 0x06624008, 0x358C5000, 0x3463401C, 0x106440C9, ++ 0x3C800006, 0x376B1FE4, 0x228B4000, 0x3C6B1FE6, ++ 0x228B4000, 0x3F8C0480, 0x24BC004E, 0x1B61401C, ++ 0x228B4000, 0x2D010000, 0x3930FFFE, 0x0D500000, ++ 0x0D500000, 0x0D500000, 0x0D500000, 0x09300002, ++ 0x202A0002, 0x0B614000, 0x1B624010, 0x29604008, ++ 0x1D218808, 0x23800079, 0x0B631FEC, 0x166B4000, ++ 0x086A1FF4, 0x27604000, 0x06614004, 0x2A634008, ++ 0x1B624010, 0x16624014, 0x37218001, 0x25970079, ++ 0x35068000, 0x186B4008, 0x0D691FF2, 0x24634000, ++ 0x06614004, 0x29604008, 0x1B624010, 0x2A320001, ++ 0x262EFFFF, 0x36058000, 0x1531FFFE, 0x214B4000, ++ 0x20250002, 0x0E494000, 0x2819C000, 0x07CC00A5, ++ 0x16624014, 0x2C218200, 0x25970079, 0x396B1FEC, ++ 0x228B4000, 0x37694008, 0x268C0400, 0x0D684024, ++ 0x04140000, 0x18D400B0, 0x36200000, 0x228B4000, ++ 0x00240001, 0x1A084000, 0x228B4000, 0x13684030, ++ 0x37380001, 0x21604030, 0x228B4000, 0x13684030, ++ 0x0834FFFE, 0x21604030, 0x228B4000, 0x386A40C4, ++ 0x3F694030, 0x1B360001, 0x1732FFF9, 0x18350001, ++ 0x1831FFFA, 0x011A4000, 0x228B4000, 0x07018000, ++ 0x28310006, 0x18350001, 0x0D614030, 0x2C320007, ++ 0x1B360001, 0x0A6240C4, 0x228B4000, 0x29604008, ++ 0x06614004, 0x16624014, 0x37218001, 0x268C0400, ++ 0x1B61401C, 0x2A694010, 0x27604000, 0x36064000, ++ 0x1B624010, 0x228B4000, 0x29604008, 0x06614004, ++ 0x16624014, 0x2D218018, 0x268C0400, 0x1B61401C, ++ 0x296A4010, 0x27604000, 0x2F260001, 0x1B624010, ++ 0x228B4000, 0x29604008, 0x06614004, 0x16624014, ++ 0x2C218200, 0x268C0400, 0x1B61401C, 0x246A4014, ++ 0x27604000, 0x1B624010, 0x228B4000, 0x1C2100FF, ++ 0x288000EE, 0x1A210000, 0x05631FE4, 0x24611FEC, ++ 0x21681FF2, 0x2B6040A0, 0x0B691FF4, 0x27604000, ++ 0x29604008, 0x18614010, 0x268C0400, 0x0970081C, ++ 0x2470881D, 0x01F000F9, 0x3930FFFE, 0x27490000, ++ 0x29310001, 0x3A200003, 0x1DD40075, 0x1231FFFF, ++ 0x286540B4, 0x216B1FFE, 0x036A1FF6, 0x3D33FFFF, ++ 0x3FD00110, 0x276B1FF8, 0x08624000, 0x06624008, ++ 0x37634010, 0x3F8C0480, 0x24BC004E, 0x3C70011F, ++ 0x0970081C, 0x2470881D, 0x13F0010E, 0x38800112, ++ 0x3F8C0480, 0x24BC004E, 0x196840A0, 0x21694024, ++ 0x1F090000, 0x30C801D6, 0x07024000, 0x1D2E0001, ++ 0x16624014, 0x1F31FFFB, 0x0E684028, 0x2670001F, ++ 0x2F34001F, 0x2E184000, 0x322C0001, 0x2E020000, ++ 0x09240008, 0x1334FFE0, 0x08300005, 0x0B691FF4, ++ 0x206040A2, 0x2D6040A6, 0x322C0001, 0x1F090000, ++ 0x25C40135, 0x356940A0, 0x1C050000, 0x252DFFFF, ++ 0x1531FFFE, 0x21510000, 0x21510000, 0x03691FFA, ++ 0x1C050000, 0x252DFFFF, 0x1531FFFE, 0x21510000, ++ 0x21510000, 0x322C0001, 0x16691FEC, 0x0834FFFE, ++ 0x2B3D00FF, 0x19CC013D, 0x27681FF4, 0x0B240003, ++ 0x0834FFFE, 0x08601FEC, 0x2B26000C, 0x21621FEA, ++ 0x2226005F, 0x35200060, 0x35230000, 0x160B2000, ++ 0x252DFFFF, 0x026140AA, 0x1E2D0001, 0x15072000, ++ 0x3F6B1FEA, 0x28004000, 0x3530FFFD, 0x1F0AC000, ++ 0x35230000, 0x0D631FEA, 0x160B2000, 0x3520000C, ++ 0x35230000, 0x29290007, 0x26C40155, 0x2A250007, ++ 0x23800156, 0x1B210007, 0x1A084000, 0x2D1B4000, ++ 0x33634088, 0x306940AA, 0x3530FFFD, 0x1E2D0001, ++ 0x15072000, 0x252A0008, 0x2A621FE8, 0x2B008000, ++ 0x1D2E0001, 0x1334FFE0, 0x08300005, 0x322C0001, ++ 0x296B1FF0, 0x16691FEC, 0x03601FEE, 0x1A074000, ++ 0x24634000, 0x3A33FFFE, 0x0E530000, 0x0E530000, ++ 0x0E530000, 0x0E530000, 0x0A330002, 0x2A634008, ++ 0x33070000, 0x0B2B0003, 0x09280004, 0x02C0018C, ++ 0x322C0001, 0x34604010, 0x3F8C0480, 0x24BC004E, ++ 0x3C70011F, 0x2A70001C, 0x2470881D, 0x09F0017B, ++ 0x0E691FFE, 0x0D684024, 0x1231FFFF, 0x37D0018B, ++ 0x00691FF6, 0x04140000, 0x3CD001D3, 0x1A084000, ++ 0x22694028, 0x0335001F, 0x3330FFFB, 0x2E184000, ++ 0x36C801D0, 0x322C0001, 0x00601FE2, 0x2670001F, ++ 0x2B008000, 0x3D3CFFFF, 0x30218000, 0x19110000, ++ 0x3A33FFFE, 0x20340010, 0x21C80197, 0x1641C000, ++ 0x0F270002, 0x0E530000, 0x23800199, 0x0E530000, ++ 0x1641C000, 0x31681FEE, 0x356940A0, 0x34604010, ++ 0x166B4000, 0x3304C000, 0x322C0001, 0x0834FFFE, ++ 0x06614004, 0x29604008, 0x0568401C, 0x3F8C0480, ++ 0x24BC004E, 0x3C70011F, 0x2A70001C, 0x1B70821D, ++ 0x19F001A8, 0x3D340008, 0x30C801BA, 0x0E691FFE, ++ 0x0D684024, 0x1231FFFF, 0x36D001BA, 0x00691FF6, ++ 0x04140000, 0x3CD001D3, 0x1A084000, 0x22694028, ++ 0x3330FFFB, 0x0335001F, 0x2E184000, 0x36C801D0, ++ 0x322C0001, 0x00601FE2, 0x2670001F, 0x1B691FE8, ++ 0x3E20000E, 0x29310001, 0x1231FFFF, 0x28D001C2, ++ 0x092CFFFF, 0x378001BE, 0x39694000, 0x0C2207FA, ++ 0x186B4008, 0x096140A8, 0x256340A4, 0x076240AC, ++ 0x236040AE, 0x2E7000B2, 0x3F8C0480, 0x24BC004E, ++ 0x31700484, 0x24E001CD, 0x31200001, 0x20800075, ++ 0x3F200009, 0x2670001F, 0x20800075, 0x3C200005, ++ 0x2670001F, 0x20800075, 0x37200007, 0x2670001F, ++ 0x20800075, 0x08631FE0, 0x35230000, 0x25671FFF, ++ 0x227001C4, 0x229700ED, 0x063C0001, 0x3BC801E2, ++ 0x063C0001, 0x3180022B, 0x2F681FFA, 0x266040A4, ++ 0x3A8C0180, 0x24BC004E, 0x34700184, 0x34E001E7, ++ 0x3B6940A8, 0x126840A2, 0x0B614000, 0x322C0001, ++ 0x296B1FF0, 0x34604010, 0x2A634008, 0x3A8C0180, ++ 0x24BC004E, 0x2A70001C, 0x2470881D, 0x05691FFC, ++ 0x2D3D0000, 0x3DC8022D, 0x252DFFFF, 0x28C8020D, ++ 0x28004000, 0x0034FFF0, 0x3420000B, 0x0ACC022B, ++ 0x156A1FEC, 0x0200C000, 0x1A048000, 0x266340A8, ++ 0x256340A4, 0x3F8C0480, 0x24BC004E, 0x34700184, ++ 0x24E00204, 0x256040A8, 0x1A048000, 0x3A8C0180, ++ 0x24BC004E, 0x32700284, 0x2CE0020A, 0x252DFFFF, ++ 0x17CC0205, 0x2A681FF0, 0x16691FEC, 0x1C050000, ++ 0x036A1FF6, 0x316B1FE2, 0x256040A8, 0x0A6140A4, ++ 0x076240AC, 0x29681FFC, 0x0C2B0002, 0x092CFFFF, ++ 0x206340AE, 0x336040B2, 0x2C8C5080, 0x24BC004E, ++ 0x31700484, 0x3EE0021D, 0x06691FF0, 0x3D201FE8, ++ 0x096140A8, 0x0A500001, 0x09300002, 0x266040A4, ++ 0x36200000, 0x2D6040A6, 0x3A8C0180, 0x24BC004E, ++ 0x34700184, 0x35E00229, 0x31200001, 0x3A6B1FE0, ++ 0x228B4000, 0x06691FF0, 0x156A1FEC, 0x28004000, ++ 0x1A048000, 0x03601FEE, 0x268C0400, 0x2F970085, ++ 0x2D010000, 0x268C0400, 0x2C970259, 0x1E691FE2, ++ 0x252DFFFF, 0x37C8021E, 0x2C611FE2, 0x3297024D, ++ 0x1B360001, 0x0DCC0246, 0x28200078, 0x31681FEE, ++ 0x06691FF0, 0x2C970259, 0x2A681FF0, 0x2E230237, ++ 0x2D010000, 0x2A800259, 0x2A681FF0, 0x1D691FEE, ++ 0x2C970259, 0x31681FEE, 0x2E230237, 0x2D010000, ++ 0x2A800259, 0x2C681FF6, 0x252DFFFF, 0x07024000, ++ 0x2F36FFF0, 0x21320003, 0x3930FFFE, 0x1F060000, ++ 0x0E4A8000, 0x28004000, 0x3C34000F, 0x1A120000, ++ 0x228B4000, 0x0A6140A4, 0x256040A8, 0x3A8C0180, ++ 0x24BC004E, 0x34700184, 0x228B4000, 0x0E631FE6, ++ 0x2B9702A1, 0x239702AF, 0x39681FD6, 0x0E6A1FF2, ++ 0x00691FF6, 0x276B1FF8, 0x1F060000, 0x03270001, ++ 0x0B37FFFE, 0x1F05C000, 0x296B1FF0, 0x32611FF6, ++ 0x3304C000, 0x3C621FF2, 0x1D601FFA, 0x18601FF0, ++ 0x268C0400, 0x339701D9, 0x02030000, 0x053F0001, ++ 0x1FCC029E, 0x238C0100, 0x166A1FD6, 0x06691FF0, ++ 0x28004000, 0x35098000, 0x1A048000, 0x2F970085, ++ 0x2D010000, 0x15684000, 0x35098000, 0x35068000, ++ 0x2F970085, 0x276B1FF8, 0x00691FF6, 0x03270001, ++ 0x0B37FFFE, 0x1C09C000, 0x3A6B1FD6, 0x0E6A1FF2, ++ 0x32611FF6, 0x1F0AC000, 0x3C621FF2, 0x268C0400, ++ 0x339701D9, 0x326B1FD8, 0x166A1FD6, 0x06691FF0, ++ 0x1E631FFA, 0x35098000, 0x34611FF0, 0x02030000, ++ 0x053F0001, 0x1FCC029E, 0x238C0100, 0x1A210000, ++ 0x3C9702E6, 0x22970312, 0x2A681FF0, 0x2460400C, ++ 0x268C0400, 0x31200001, 0x2B800077, 0x37200007, ++ 0x2480029E, 0x0B631FEC, 0x0D691FF2, 0x006A1FFA, ++ 0x06614004, 0x0B691FF4, 0x2C621FD8, 0x15614014, ++ 0x2D3D0000, 0x29C8029F, 0x28004000, 0x0C240002, ++ 0x0834FFFE, 0x0B601FD6, 0x228B4000, 0x0B631FEC, ++ 0x39681FD6, 0x0D691FF2, 0x086A1FF4, 0x28004000, ++ 0x2F970085, 0x399700A9, 0x0F280002, 0x1BC0029F, ++ 0x0C240002, 0x39604014, 0x2F9700B3, 0x0B691FF4, ++ 0x39681FD6, 0x35054000, 0x056A1FF0, 0x18614010, ++ 0x08624000, 0x1F060000, 0x1F060000, 0x23260002, ++ 0x06624008, 0x0B62400C, 0x2C218200, 0x25970079, ++ 0x226B1FF2, 0x086A1FF4, 0x3304C000, 0x2D010000, ++ 0x2F970085, 0x399700A9, 0x0F280002, 0x1BC0029F, ++ 0x0C240002, 0x39604014, 0x35068000, 0x1B624010, ++ 0x39681FD6, 0x396A400C, 0x186B4008, 0x1F060000, ++ 0x2A681FF0, 0x29634004, 0x06624008, 0x27604000, ++ 0x2C218200, 0x25970079, 0x166A1FD6, 0x3A69400C, ++ 0x2A681FF0, 0x35068000, 0x2F970085, 0x229700B7, ++ 0x396B1FEC, 0x228B4000, 0x0B631FEC, 0x2A681FF0, ++ 0x1A048000, 0x2460400C, 0x1A048000, 0x0C240002, ++ 0x19044000, 0x086A1FF4, 0x0D691FF2, 0x3930FFFE, ++ 0x0D500000, 0x0D500000, 0x09300002, 0x2F970085, ++ 0x399700A9, 0x39604014, 0x1B684008, 0x156B400C, ++ 0x2F260001, 0x06691FF0, 0x03280001, 0x1B624010, ++ 0x29604008, 0x06614004, 0x24634000, 0x2C2A0001, ++ 0x36058000, 0x1531FFFE, 0x21510000, 0x21510000, ++ 0x19078000, 0x3A33FFFE, 0x0E530000, 0x0E530000, ++ 0x3B218002, 0x25970079, 0x23260002, 0x1B624010, ++ 0x246A4014, 0x03691FFA, 0x1B684008, 0x319700CB, ++ 0x396B1FEC, 0x228B4000, 0x0B631FEC, 0x2F9700B3, ++ 0x166B4000, 0x1668400C, 0x2763400C, 0x0D691FF2, ++ 0x246A4014, 0x219700E1, 0x3A6B1FD6, 0x0D691FF2, ++ 0x1668400C, 0x1F05C000, 0x086A1FF4, 0x319700CB, ++ 0x2A681FF0, 0x086A1FF4, 0x2D010000, 0x269700D6, ++ 0x229700B7, 0x396B1FEC, 0x228B4000, 0x05631FE4, ++ 0x2A681FF0, 0x2460400C, 0x08691FF8, 0x29611FDE, ++ 0x086A1FF4, 0x21621FDC, 0x350A4000, 0x040E4000, ++ 0x0CD40332, 0x07024000, 0x24260003, 0x2736FFFE, ++ 0x00601FE2, 0x1A048000, 0x0B601FE0, 0x1A048000, ++ 0x35068000, 0x37621FF0, 0x1A048000, 0x0B601FD6, ++ 0x1668400C, 0x2897007D, 0x056A1FF0, 0x1668400C, ++ 0x1A048000, 0x2897007D, 0x0B6A1FF8, 0x32681FE2, ++ 0x296B1FF0, 0x3304C000, 0x00691FF6, 0x2F970085, ++ 0x268C0400, 0x0E6B4024, 0x05631FD2, 0x1A378000, ++ 0x07CC0415, 0x39681FE0, 0x296B1FF0, 0x3304C000, ++ 0x0D691FF2, 0x086A1FF4, 0x2F970085, 0x32681FE2, ++ 0x3930FFFE, 0x0A500001, 0x39681FE0, 0x0D691FF2, ++ 0x2F970085, 0x3B201FD8, 0x0D500000, 0x0D500000, ++ 0x0D691FF2, 0x1531FFFE, 0x0E494000, 0x29310001, ++ 0x05D40418, 0x1231FFFF, 0x36200000, 0x00601FD4, ++ 0x32230001, 0x1E220001, 0x0200C000, 0x2E148000, ++ 0x31C8036D, 0x32681FD4, 0x1A048000, 0x00601FD4, ++ 0x1A074000, 0x35054000, 0x35068000, 0x02CC0366, ++ 0x32681FE2, 0x296B1FF0, 0x3304C000, 0x1A210000, ++ 0x186A1FDE, 0x3397041C, 0x3930FFFE, 0x0B480000, ++ 0x1A388000, 0x05300001, 0x24D0037D, 0x2C250001, ++ 0x25800379, 0x2D3D0000, 0x35C803AF, 0x268C0400, ++ 0x16614018, 0x26218040, 0x25970079, 0x32681FD4, ++ 0x1E691FE2, 0x1531FFFE, 0x0E494000, 0x15072000, ++ 0x1D210001, 0x0B6B4018, 0x3E3FFFFF, 0x03270001, ++ 0x1A11C000, 0x252DFFFF, 0x02164000, 0x326B1FD8, ++ 0x268C0400, 0x21694024, 0x2A611FD2, 0x3BC803A7, ++ 0x1F1F8000, 0x3AC803A0, 0x2C621FD8, 0x21681FF2, ++ 0x0C2107F6, 0x3297041B, 0x1E220001, 0x16624014, ++ 0x39681FD6, 0x29604008, 0x37218001, 0x25970079, ++ 0x15691FD6, 0x32681FE2, 0x086A1FF4, 0x2F260001, ++ 0x3397041C, 0x23218010, 0x25970079, 0x32681FE2, ++ 0x1A210000, 0x086A1FF4, 0x2F260001, 0x3397041C, ++ 0x26218040, 0x25970079, 0x2C800370, 0x39681FE0, ++ 0x296B1FF0, 0x3304C000, 0x2A604004, 0x32681FE2, ++ 0x3304C000, 0x27604000, 0x186A1FDE, 0x3F6B1FDC, ++ 0x3A634014, 0x1F0AC000, 0x2E0EC000, 0x1AD403BD, ++ 0x2D02C000, 0x1B624010, 0x2F218400, 0x25970079, ++ 0x18691FD2, 0x1F1C4000, 0x0DCC03CA, 0x1531FFFE, ++ 0x22484000, 0x063C0001, 0x122D0002, 0x0E494000, ++ 0x2E184000, 0x2DC8040B, 0x268C0400, 0x00684020, ++ 0x05300001, 0x30D00415, 0x09300002, 0x22D003D8, ++ 0x15684000, 0x34694004, 0x2A604004, 0x0B614000, ++ 0x06684010, 0x27694014, 0x39604014, 0x18614010, ++ 0x166B4000, 0x2A634008, 0x0E631FD0, 0x25218020, ++ 0x25970079, 0x2DD003E1, 0x39681FE0, 0x1E691FE2, ++ 0x2A8003E3, 0x32681FE2, 0x15691FE0, 0x086A1FF4, ++ 0x2F260001, 0x3397041C, 0x268C0400, 0x226A4024, ++ 0x25218020, 0x25970079, 0x3F681FD0, 0x1C0A0000, ++ 0x2F260001, 0x15691FE0, 0x296B1FF0, 0x1F05C000, ++ 0x1A1D0000, 0x00CC03F8, 0x32681FE2, 0x15691FE0, ++ 0x0B601FE0, 0x2C611FE2, 0x37681FDE, 0x0E601FDC, ++ 0x2A621FDE, 0x32681FE2, 0x0D691FF2, 0x3297041B, ++ 0x296A4010, 0x1A048000, 0x3930FFFE, 0x268C0400, ++ 0x084B0000, 0x0D500000, 0x0D500000, 0x023F0000, ++ 0x26C80370, 0x23218010, 0x25970079, 0x052CFFFC, ++ 0x268C0400, 0x0D500000, 0x2C800370, 0x1E691FE2, ++ 0x39681FE0, 0x086A1FF4, 0x2F970085, 0x16624014, ++ 0x31200001, 0x1A210000, 0x156B400C, 0x1B631FF0, ++ 0x20800075, 0x24200017, 0x1B210007, 0x3D800412, ++ 0x3A200003, 0x0621001F, 0x3D800412, 0x086A1FF4, ++ 0x1B624010, 0x16624014, 0x27604000, 0x06614004, ++ 0x29604008, 0x228B4000, 0x0E631FE6, 0x2C681FF6, ++ 0x08691FF8, 0x086A1FF4, 0x1D601FCC, 0x37611FCA, ++ 0x39621FF8, 0x24260003, 0x2736FFFE, 0x39621FCE, ++ 0x296B1FF0, 0x19078000, 0x19078000, 0x1D631FF6, ++ 0x19078000, 0x1B631FF0, 0x2E970327, 0x063C0001, ++ 0x28C80437, 0x063C0001, 0x2A800455, 0x2A681FF0, ++ 0x0B6A1FCE, 0x19088000, 0x2897007D, 0x06691FF0, ++ 0x0B6A1FCE, 0x2B034000, 0x28004000, 0x19078000, ++ 0x24634000, 0x19088000, 0x19088000, 0x2097008A, ++ 0x06691FF0, 0x0B6A1FCE, 0x28004000, 0x19088000, ++ 0x3930FFFE, 0x0A500001, 0x0F280002, 0x09300002, ++ 0x19088000, 0x19088000, 0x18601FF0, 0x2097008A, ++ 0x03691FCC, 0x066A1FCA, 0x32611FF6, 0x39621FF8, ++ 0x31200001, 0x268C0400, 0x2B800077, 0x0D601FD0, ++ 0x296A4010, 0x15684000, 0x2C621FD8, 0x08601FDA, ++ 0x10691FDC, 0x2A681FF0, 0x07024000, 0x36064000, ++ 0x36064000, 0x2897007D, 0x1E6A1FD8, 0x3A681FDA, ++ 0x1B624010, 0x27604000, 0x3F681FD0, 0x063C0001, ++ 0x09CC0471, 0x216B1FFE, 0x071BC000, 0x25D0046F, ++ 0x229706BB, 0x0D601FD0, 0x33800476, 0x379706AD, ++ 0x33800476, 0x0D3C0003, 0x08CC0476, 0x36970483, ++ 0x31200001, 0x0D601FD0, 0x3F681FD0, 0x35230000, ++ 0x2D010000, 0x293D000D, 0x0ACC047D, 0x34230007, ++ 0x3C800480, 0x2E3D000C, 0x36C80480, 0x2923001F, ++ 0x268C0400, 0x39634018, 0x2B800077, 0x08631FD6, ++ 0x37681FB2, 0x03691FFA, 0x086A1FF4, 0x2F970085, ++ 0x16624014, 0x2F681FFA, 0x226B1FF2, 0x136A1FDC, ++ 0x1D691FB4, 0x1A048000, 0x2A604004, 0x05614008, ++ 0x24634000, 0x25218020, 0x25970079, 0x3A681FB6, ++ 0x3930FFFE, 0x0A500001, 0x3A6B1FD6, 0x228B4000, ++ 0x1A048000, 0x3930FFFE, 0x0D500000, 0x0D500000, ++ 0x0D500000, 0x0D500000, 0x228B4000, 0x086A1FF4, ++ 0x1D2E0001, 0x1B624010, 0x0B614000, 0x29604008, ++ 0x268C0400, 0x2A70001C, 0x2470881D, 0x36058000, ++ 0x1A048000, 0x228B4000, 0x27604000, 0x27681FF4, ++ 0x05614008, 0x34604010, 0x268C0400, 0x15624018, ++ 0x2E020000, 0x29218080, 0x23800079, 0x08631FD6, ++ 0x387000C4, 0x249700EB, 0x246B1FF4, 0x08270003, ++ 0x0B37FFFE, 0x0D631FDC, 0x2D010000, 0x2A3D0001, ++ 0x238C0100, 0x1ACC0457, 0x3D6A40A2, 0x176840A8, ++ 0x2F260001, 0x27970498, 0x21681FF2, 0x086A1FF4, ++ 0x27970498, 0x2F260001, 0x2736FFFE, 0x0F6240A2, ++ 0x026240A6, 0x3A6B1FD6, 0x228B4000, 0x08631FD6, ++ 0x3A6B1FD6, 0x228B4000, 0x08631FD6, 0x136A1FDC, ++ 0x06691FF0, 0x3D201FB2, 0x2D230012, 0x35098000, ++ 0x36058000, 0x15410000, 0x3E2C0002, 0x0A2FFFFF, ++ 0x0FCC04D4, 0x37681FB2, 0x2897007D, 0x136A1FDC, ++ 0x3A681FB6, 0x1D32FFFC, 0x2897007D, 0x2E97052B, ++ 0x16691FB6, 0x21681FF2, 0x1E220001, 0x2A9704AA, ++ 0x1E220001, 0x1B691FB2, 0x3F970530, 0x3A6B1FD6, ++ 0x228B4000, 0x08631FD6, 0x3F6B1FDC, 0x0D691FF2, ++ 0x1D6A1FD4, 0x1F05C000, 0x2E97051D, 0x15691FBA, ++ 0x1E220001, 0x3F970530, 0x106A1FD0, 0x03691FFA, ++ 0x2E97051D, 0x216B1FFE, 0x03691FFA, 0x071BC000, ++ 0x1ED404FF, 0x3F6B1FDC, 0x036A1FC0, 0x1F05C000, ++ 0x1F05C000, 0x2E97051D, 0x34800502, 0x15691FBA, ++ 0x2C681FC0, 0x2697049F, 0x13691FD0, 0x34681FBE, ++ 0x036A1FC0, 0x286040AC, 0x096140A8, 0x096240A4, ++ 0x358C5000, 0x28700384, 0x3A6B1FD6, 0x228B4000, ++ 0x136A1FDC, 0x15691FBA, 0x16624014, 0x1632FFFE, ++ 0x35098000, 0x0B614000, 0x0A6140A4, 0x16691FB6, ++ 0x1D6A1FB8, 0x05614008, 0x0B691FF4, 0x05624004, ++ 0x1E2D0001, 0x18614010, 0x228B4000, 0x1B684008, ++ 0x2B800527, 0x0B631FEC, 0x0B614000, 0x06624008, ++ 0x2B008000, 0x13218800, 0x25970079, 0x086A1FF4, ++ 0x27970498, 0x1B684008, 0x396B1FEC, 0x256040A8, ++ 0x358C5000, 0x34700184, 0x228B4000, 0x086A1FF4, ++ 0x1D691FB4, 0x1B624010, 0x0A6140A4, 0x228B4000, ++ 0x28004000, 0x1531FFFE, 0x268C0400, 0x3F424000, ++ 0x2B800527, 0x2C8C5080, 0x24BC004E, 0x13204096, ++ 0x228B4000, 0x2C8C5080, 0x24BC004E, 0x13204096, ++ 0x3E500C63, 0x228B4000, 0x2C681FF6, 0x252DFFFF, ++ 0x07024000, 0x2F36FFF0, 0x21320003, 0x3930FFFE, ++ 0x1F060000, 0x0E4A8000, 0x28004000, 0x3C34000F, ++ 0x1A120000, 0x02624090, 0x228B4000, 0x036A1FC0, ++ 0x096140A8, 0x096240A4, 0x238C0100, 0x34700184, ++ 0x0E6A1FF2, 0x05624004, 0x086A1FF4, 0x16624014, ++ 0x0B614000, 0x05614008, 0x238C0100, 0x20694080, ++ 0x18350001, 0x03CC055B, 0x228B4000, 0x1D2E0001, ++ 0x1B624010, 0x25218020, 0x23800079, 0x08631FD6, ++ 0x16502DE7, 0x3F502084, 0x36970539, 0x13502931, ++ 0x35970535, 0x0F6B4080, 0x25370020, 0x0FCC071D, ++ 0x13503548, 0x03501CE4, 0x36970539, 0x315024A9, ++ 0x35970535, 0x0350A148, 0x0A5035A4, 0x36970539, ++ 0x3350252E, 0x35970535, 0x0E502929, 0x145035B0, ++ 0x36970539, 0x3F502108, 0x35970535, 0x2B5025A9, ++ 0x1D502CA6, 0x36970539, 0x1450288A, 0x35970535, ++ 0x2350B4EB, 0x18509525, 0x36970539, 0x37501086, ++ 0x35970535, 0x0F502D67, 0x035035AD, 0x36970539, ++ 0x1C501991, 0x35970535, 0x0F6B4080, 0x00631FEE, ++ 0x235098C4, 0x27509DAF, 0x36970539, 0x1450316C, ++ 0x35970535, 0x00509148, 0x1E502CC6, 0x36970539, ++ 0x1A50358E, 0x35970535, 0x355099AB, 0x3A6B1FD6, ++ 0x228B4000, 0x08631FD6, 0x30700090, 0x3A97050C, ++ 0x358C5000, 0x23700080, 0x13204096, 0x3E500C63, ++ 0x235024E4, 0x13204096, 0x3E500C63, 0x045030A6, ++ 0x35970535, 0x2850B12C, 0x395020EE, 0x36970539, ++ 0x0B5028AF, 0x35970535, 0x3D50A90A, 0x3D50AD8C, ++ 0x35970535, 0x29503D6B, 0x1850C54A, 0x36970539, ++ 0x0F6B4080, 0x00631FEE, 0x23700080, 0x1C50352B, ++ 0x35970535, 0x326B1FEE, 0x236A4080, 0x07330006, ++ 0x14D405B9, 0x2B320006, 0x27D005DE, 0x3220000D, ++ 0x21800457, 0x3E500C63, 0x16502D8B, 0x36970539, ++ 0x3450252F, 0x35970535, 0x3950252B, 0x3350210B, ++ 0x36970539, 0x1B5018E5, 0x35970535, 0x3E500C63, ++ 0x205044D1, 0x36970539, 0x3D502409, 0x35970535, ++ 0x0550A531, 0x065018CB, 0x35970535, 0x3E500C63, ++ 0x32504409, 0x36970539, 0x2450112C, 0x35970535, ++ 0x3650B62D, 0x0D50300C, 0x35970535, 0x3E500C63, ++ 0x025035AA, 0x35970535, 0x2550B50D, 0x3B502520, ++ 0x35970535, 0x1B501C63, 0x3350140D, 0x35970535, ++ 0x3A6B1FD6, 0x228B4000, 0x2E97052B, 0x3F6B1FDC, ++ 0x0D691FF2, 0x1D6A1FD4, 0x1F05C000, 0x2E97051D, ++ 0x1E691FB8, 0x3F681FD0, 0x2697049F, 0x13691FD0, ++ 0x12220002, 0x3F970530, 0x1E691FB8, 0x2C681FC0, ++ 0x249704A2, 0x00691FC0, 0x15220003, 0x3F970530, ++ 0x3A97050C, 0x358C5000, 0x23700080, 0x13204096, ++ 0x3E500C63, 0x3F502084, 0x13204096, 0x3E500C63, ++ 0x0B5035CF, 0x35970535, 0x3E500C63, 0x0C502D07, ++ 0x36970539, 0x195034AD, 0x35970535, 0x3E500C63, ++ 0x325024A5, 0x36970539, 0x165029AE, 0x35970535, ++ 0x0F503144, 0x2F502531, 0x36970539, 0x0250194A, ++ 0x35970535, 0x295010C8, 0x0E50318C, 0x36970539, ++ 0x085028CF, 0x35970535, 0x24502569, 0x195019AD, ++ 0x36970539, 0x25501004, 0x35970535, 0x3E50B08C, ++ 0x11502D29, 0x36970539, 0x1B5019A6, 0x35970535, ++ 0x3E500C63, 0x3450140C, 0x36970539, 0x2750218F, ++ 0x35970535, 0x2550AD0B, 0x04502940, 0x35970535, ++ 0x3E500C63, 0x0C50300B, 0x36970539, 0x3C5011AB, ++ 0x35970535, 0x3250B585, 0x3B502520, 0x35970535, ++ 0x3E500C63, 0x0E5035A9, 0x35970535, 0x3350B54D, ++ 0x15502C0B, 0x35970535, 0x1B501C63, 0x3350140D, ++ 0x35970535, 0x3A6B1FD6, 0x228B4000, 0x08631FD6, ++ 0x2E97052B, 0x03691FCC, 0x3F6B1FDC, 0x2F681FFA, ++ 0x1E220001, 0x3304C000, 0x2A9704AA, 0x2897051B, ++ 0x08691FCE, 0x3F6B1FDC, 0x21681FF2, 0x1E220001, ++ 0x3304C000, 0x3304C000, 0x2A9704AA, 0x2897051B, ++ 0x30700090, 0x3A97050C, 0x358C5000, 0x13204096, ++ 0x3E500C63, 0x0B502A25, 0x13204096, 0x3E500C63, ++ 0x2250248F, 0x35970535, 0x0250292A, 0x285020AF, ++ 0x36970539, 0x25501004, 0x35970535, 0x00502D04, ++ 0x295038AE, 0x36970539, 0x245024E5, 0x35970535, ++ 0x1650A088, 0x2A50392E, 0x36970539, 0x19502D4B, ++ 0x35970535, 0x3E500C63, 0x0A502924, 0x36970539, ++ 0x0F502CEB, 0x35970535, 0x00502DCB, 0x3B5011AA, ++ 0x36970539, 0x3F502108, 0x35970535, 0x3E500C63, ++ 0x15502C0B, 0x36970539, 0x2A5020C8, 0x35970535, ++ 0x2550AD0B, 0x0D502925, 0x35970535, 0x1B501C63, ++ 0x3550140B, 0x36970539, 0x185019AA, 0x35970535, ++ 0x3A6B1FD6, 0x228B4000, 0x08631FD6, 0x21681FF2, ++ 0x10691FDC, 0x086A1FF4, 0x19044000, 0x27604000, ++ 0x27970498, 0x21681FF2, 0x35054000, 0x19044000, ++ 0x27970498, 0x07024000, 0x39694000, 0x29681FCA, ++ 0x2F970085, 0x3A97050C, 0x13204096, 0x268C0400, ++ 0x3E500C63, 0x225020C6, 0x36970539, 0x325024A5, ++ 0x35970535, 0x3E500C63, 0x0E502D0C, 0x36970539, ++ 0x1C502884, 0x35970535, 0x3E500C63, 0x335021A8, ++ 0x36970539, 0x00502C2B, 0x35970535, 0x1450296A, ++ 0x30502028, 0x35970535, 0x0D50A509, 0x09502944, ++ 0x35970535, 0x3E500C63, 0x325024C9, 0x35970535, ++ 0x1B50A549, 0x2A502144, 0x36970539, 0x3D502409, ++ 0x35970535, 0x358C5000, 0x0F6B4080, 0x3E370008, ++ 0x0CCC06AB, 0x2720001B, 0x21800457, 0x3A6B1FD6, ++ 0x228B4000, 0x08631FD6, 0x2C681FC0, 0x3930FFFE, ++ 0x0A500001, 0x1B204098, 0x1A5000E4, 0x1B204098, ++ 0x025004E5, 0x36970539, 0x325008E6, 0x35970535, ++ 0x238C0100, 0x3A6B1FD6, 0x228B4000, 0x08631FD6, ++ 0x2C681FC0, 0x3930FFFE, 0x358C5000, 0x0A500001, ++ 0x1B204098, 0x175018E6, 0x296B1FF0, 0x2C681FF6, ++ 0x08691FF8, 0x10631FC4, 0x18601FC6, 0x3C611FC8, ++ 0x3F6B1FDC, 0x39681FD6, 0x18631FCA, 0x1D601FCC, ++ 0x34681FBE, 0x0B691FF4, 0x2F6B1FC0, 0x1E2D0001, ++ 0x3A611FF8, 0x1B631FF0, 0x1E601FF6, 0x358C5000, ++ 0x2E970327, 0x226B1FC4, 0x056A1FC6, 0x0E691FC8, ++ 0x1B631FF0, 0x31621FF6, 0x3A611FF8, 0x2A6B1FCA, ++ 0x006A1FCC, 0x0D631FDC, 0x24621FD6, 0x268C0400, ++ 0x02030000, 0x053F0001, 0x1CCC06ED, 0x15691FBA, ++ 0x2D97054B, 0x13691FBC, 0x2D97054B, 0x136A1FDC, ++ 0x15691FBA, 0x2A681FF0, 0x35068000, 0x2F970085, ++ 0x31200001, 0x3A6B1FD6, 0x228B4000, 0x19220000, ++ 0x3C8006F3, 0x00220080, 0x3C8006F3, 0x09661FFF, ++ 0x0E631FE6, 0x309704B3, 0x249704CE, 0x2E9704CB, ++ 0x309704E9, 0x2E97052B, 0x18691FD2, 0x14220004, ++ 0x3F970530, 0x08691FCE, 0x3F6B1FDC, 0x21681FF2, ++ 0x12220002, 0x3304C000, 0x3304C000, 0x2A9704AA, ++ 0x2897051B, 0x3A97050C, 0x1A21889C, 0x0A614092, ++ 0x358C5000, 0x23700080, 0x1E691FE2, 0x3797053E, ++ 0x13204096, 0x095029E7, 0x035030A7, 0x13204096, ++ 0x095029E7, 0x325024A5, 0x35970535, 0x3397055F, ++ 0x02194000, 0x3CC80720, 0x3797053E, 0x1B204098, ++ 0x035030A7, 0x36970539, 0x325024A5, 0x35970535, ++ 0x3C800713, 0x358C5000, 0x29200013, 0x21800457, ++ 0x358C5000, 0x236A4080, 0x09360020, 0x04CC0729, ++ 0x35970633, 0x358C5000, 0x29970676, 0x31200001, ++ 0x21800457, 0x1E6A1FEE, 0x1C6B4090, 0x27320005, ++ 0x1A1EC000, 0x1B360001, 0x28C80731, 0x3220000D, ++ 0x21800457, 0x3D200002, 0x21800457, 0x0F220040, ++ 0x24800737, 0x162200C0, 0x24800737, 0x09661FFF, ++ 0x0E631FE6, 0x309704B3, 0x249704CE, 0x2E9704CB, ++ 0x166A1FBA, 0x03691FFA, 0x2E97051D, 0x3F6B1FDC, ++ 0x03691FFA, 0x0B6A1FCE, 0x1F05C000, 0x2E97051D, ++ 0x1B6A1FBE, 0x00691FF6, 0x2E97051D, 0x3F6B1FDC, ++ 0x00691FF6, 0x106A1FD0, 0x1F05C000, 0x2E97051D, ++ 0x22681FFE, 0x07180000, 0x2CD00756, 0x1B691FB2, ++ 0x3F681FBC, 0x249704A2, 0x1B691FB2, 0x2C681FC0, ++ 0x249704A2, 0x2B800762, 0x3F6B1FDC, 0x03691FFA, ++ 0x106A1FBC, 0x1F05C000, 0x1F05C000, 0x2E97051D, ++ 0x3F6B1FDC, 0x00691FF6, 0x036A1FC0, 0x1F05C000, ++ 0x1F05C000, 0x2E97051D, 0x39970595, 0x358C5000, ++ 0x29970676, 0x31200001, 0x21800457, 0x0C220020, ++ 0x29800769, 0x09661FFF, 0x0E631FE6, 0x309704B3, ++ 0x249704CE, 0x2E9704CB, 0x309704E9, 0x2E97052B, ++ 0x18691FD2, 0x12220002, 0x3F970530, 0x32681FD4, ++ 0x18691FD2, 0x27604000, 0x06614004, 0x24681FCE, ++ 0x29604008, 0x238C0100, 0x25218020, 0x1B61401C, ++ 0x27604000, 0x29604008, 0x12220002, 0x268C0400, ++ 0x15624018, 0x26218040, 0x1B61401C, 0x3A97050C, ++ 0x1A21889C, 0x0A614092, 0x358C5000, 0x23700080, ++ 0x1E691FE2, 0x3797053E, 0x13204096, 0x358C5000, ++ 0x2A5020A4, 0x13204096, 0x1F50A4A4, 0x35970535, ++ 0x145028E6, 0x1A503108, 0x35970535, 0x358C5000, ++ 0x2150ACE6, 0x17503529, 0x0F6B4080, 0x13204096, ++ 0x25370020, 0x0FCC071D, 0x1B50C1AC, 0x31502549, ++ 0x35970535, 0x3E500C63, 0x3C502168, 0x35970535, ++ 0x04502D09, 0x3D5011AC, 0x35970535, 0x0D50A509, ++ 0x0E5029D0, 0x35970535, 0x2450214C, 0x1050196B, ++ 0x35970535, 0x3E500C63, 0x12501D29, 0x35970535, ++ 0x3E500C63, 0x14509510, 0x35970535, 0x3E500C63, ++ 0x3F509DE7, 0x35970535, 0x0F6B4080, 0x00631FEE, ++ 0x02194000, 0x38C807B8, 0x3797053E, 0x3F80078A, ++ 0x358C5000, 0x236A4080, 0x09360020, 0x16CC07C7, ++ 0x30700090, 0x02501865, 0x35970535, 0x1B501C63, ++ 0x35970535, 0x38501463, 0x35970535, 0x2C681FC0, ++ 0x268C0400, 0x31200001, 0x21800457, 0x1E6A1FEE, ++ 0x1C6B4090, 0x27320005, 0x1A1EC000, 0x1B360001, ++ 0x35C807BC, 0x3220000D, 0x21800457, 0x1E79084F ++}; ++ ++static const uint32_t fw1_boot_img_data_buf[] = ++{ ++ 0x36200000, 0x11210002, 0x15710249, 0x31200001, ++ 0x2860B41C, 0x21970074, 0x1A210000, 0x1231FFFF, ++ 0x1B390001, 0x092CFFFF, 0x00CC0007, 0x0761B140, ++ 0x3A200333, 0x3060B438, 0x3E60B45C, 0x3D60B43C, ++ 0x0A20FFFF, 0x2D60B420, 0x1A210000, 0x1F68B420, ++ 0x0A61B422, 0x1234FEFE, 0x05300001, 0x2D60B420, ++ 0x0C61B424, 0x0761B426, 0x0F61B428, 0x0461B42A, ++ 0x0261B42C, 0x0961B42E, 0x1F61B434, 0x1461B436, ++ 0x21970074, 0x1C21A0CA, 0x33228000, 0x3F424000, ++ 0x032D0100, 0x092CFFFF, 0x18CC0023, 0x16710449, ++ 0x1CB8002B, 0x30224000, 0x2C80002C, 0x19220000, ++ 0x06210045, 0x0C61B424, 0x35230000, 0x2D63B42C, ++ 0x21970074, 0x13232000, 0x0C62B428, 0x3063B434, ++ 0x16210333, 0x278C0078, 0x37BC005E, 0x1C61B438, ++ 0x092CFFFF, 0x0CCC0032, 0x0A710649, 0x21970074, ++ 0x1721A0C8, 0x19220000, 0x3F424000, 0x122D0002, ++ 0x3F424000, 0x182D00FE, 0x092CFFFF, 0x0FCC003E, ++ 0x1A223000, 0x2F712049, 0x1FB8004B, 0x33214000, ++ 0x35230000, 0x3F222000, 0x2880004D, 0x1A210000, ++ 0x35230000, 0x1820B424, 0x19500011, 0x0A500001, ++ 0x1150C400, 0x0A500001, 0x0261B42C, 0x2663B42E, ++ 0x1C62B434, 0x39230333, 0x278C0078, 0x37BC005E, ++ 0x3363B438, 0x36200000, 0x2B60B140, 0x13710149, ++ 0x398C0000, 0x3C80005C, 0x3371FF49, 0x3C80005C, ++ 0x2A320001, 0x0A367FFF, 0x2CC80073, 0x252A0008, ++ 0x0EC0006F, 0x0D500000, 0x0D500000, 0x0D500000, ++ 0x0D500000, 0x0D500000, 0x0D500000, 0x0D500000, ++ 0x0D500000, 0x2CC80073, 0x35800063, 0x26260008, ++ 0x0D500000, 0x262EFFFF, 0x11CC0070, 0x228B4000, ++ 0x0868B1F8, 0x3C34000F, 0x0128000A, 0x26C4007A, ++ 0x0224000A, 0x228B4000, 0x3320000A, 0x228B4000, ++ 0x01000000, 0x01000000, 0x01000000 ++}; ++ ++static const uint32_t fw1_master_img_data_buf[] = ++{ ++ 0x36200000, 0x11210002, 0x3C605FF4, 0x1B615FF6, ++ 0x36200000, 0x2560B148, 0x1A205FE0, 0x38215FE8, ++ 0x3B230008, 0x1F090000, 0x15C00104, 0x31200001, ++ 0x2860B41C, 0x2A9700B9, 0x329700C7, 0x1C208000, ++ 0x2B60B140, 0x01000000, 0x19220000, 0x0B685FFE, ++ 0x2469B1F8, 0x2B3C4600, 0x1ECC0013, 0x1D2E0001, ++ 0x28038000, 0x01000000, 0x0A2FFFFF, 0x1BCC0019, ++ 0x0B685FFE, 0x2469B1F8, 0x2B3C4600, 0x22C80021, ++ 0x25800013, 0x056B5FFA, 0x333B0000, 0x14D40026, ++ 0x363700FF, 0x2E63B47A, 0x3A200333, 0x3060B438, ++ 0x3E60B45C, 0x3D60B43C, 0x39230003, 0x2F22B400, ++ 0x0A20FFFF, 0x13408000, 0x1A210000, 0x21488000, ++ 0x23260002, 0x3F418000, 0x1234FEFE, 0x05300001, ++ 0x202A0002, 0x13408000, 0x3D260020, 0x0A2FFFFF, ++ 0x17CC002C, 0x36200000, 0x3E60B406, 0x2D60B416, ++ 0x2B60B426, 0x3860B436, 0x2860B446, 0x3B60B456, ++ 0x036B5FFC, 0x00210100, 0x05222F00, 0x29370080, ++ 0x27C80047, 0x1A210000, 0x1A223000, 0x1820B424, ++ 0x19500011, 0x0A500001, 0x1150C400, 0x0A500001, ++ 0x15410000, 0x3E2C0002, 0x0D500000, 0x1C62B434, ++ 0x10205E90, 0x0D220164, 0x0D970F97, 0x2469B1F8, ++ 0x15220333, 0x36200000, 0x278C0078, 0x30BC00FC, ++ 0x1F62B438, 0x2060B424, 0x2B60B426, 0x33610102, ++ 0x1035000F, 0x38610100, 0x0A68B400, 0x3369B420, ++ 0x32605FCA, 0x13615FCE, 0x353400FF, 0x2C380200, ++ 0x34605FCC, 0x2535FF00, 0x17390002, 0x08615FD0, ++ 0x1E970F24, 0x31200001, 0x2E605EA0, 0x202001A0, ++ 0x1760010C, 0x35203000, 0x1C60010E, 0x31200001, ++ 0x2560B148, 0x30695EA0, 0x33228000, 0x28004000, ++ 0x063C0001, 0x1FCC0078, 0x0462B140, 0x2280007E, ++ 0x28004000, 0x0C3C0004, 0x19CC007E, 0x1968B140, ++ 0x283C4000, 0x2B60B140, 0x1035000F, 0x1231FFFF, ++ 0x0B2D0082, 0x0D894000, 0x248C1D78, 0x318000A1, ++ 0x2F8C1D7A, 0x318000A1, 0x3D8C1DF8, 0x318000A1, ++ 0x368C1DFA, 0x318000A1, 0x298C1D7C, 0x318000A1, ++ 0x228C1D7E, 0x318000A1, 0x308C1DFC, 0x318000A1, ++ 0x3B8C1DFE, 0x318000A1, 0x238C1D79, 0x318000A1, ++ 0x288C1D7B, 0x318000A1, 0x3A8C1DF9, 0x318000A1, ++ 0x318C1DFB, 0x318000A1, 0x2E8C1D7D, 0x318000A1, ++ 0x258C1D7F, 0x318000A1, 0x378C1DFD, 0x318000A1, ++ 0x3C8C1DFF, 0x35B000FA, 0x07BC0C07, 0x29D80CD4, ++ 0x3FA00C08, 0x1DA40C2E, 0x1CA80C49, 0x11F80F12, ++ 0x39E80CF2, 0x32E00118, 0x336A5EA0, 0x362300AF, ++ 0x17360002, 0x33C800AF, 0x20AC0E9D, 0x31215EA2, ++ 0x07220014, 0x14970FB4, 0x27C80071, 0x21884000, ++ 0x30380000, 0x32C80112, 0x31215EA2, 0x07220014, ++ 0x1D800FD7, 0x36200000, 0x0D500000, 0x0D500000, ++ 0x0D500000, 0x0D500000, 0x36200000, 0x2760B000, ++ 0x2960B008, 0x1E220001, 0x1B62B010, 0x3760B01C, ++ 0x10228800, 0x1862B01C, 0x228B4000, 0x0868B1F8, ++ 0x2D635E96, 0x3C34000F, 0x02030000, 0x022B000A, ++ 0x05C000CE, 0x3320000A, 0x02030000, 0x1A210000, ++ 0x1231FFFF, 0x1B390001, 0x092CFFFF, 0x1DCC00D0, ++ 0x0761B140, 0x33228000, 0x2D010000, 0x20310008, ++ 0x1A39A0CA, 0x3F424000, 0x19220000, 0x3F424000, ++ 0x0C220020, 0x392DFFBA, 0x3F424000, 0x3860B150, ++ 0x1A22C000, 0x22520000, 0x22520000, 0x19220000, ++ 0x302DFF7C, 0x3F424000, 0x172D0008, 0x3F424000, ++ 0x1E220001, 0x172D0008, 0x3F424000, 0x19220000, ++ 0x1A2D000C, 0x3F424000, 0x10228800, 0x3F424000, ++ 0x06220400, 0x0962B144, 0x2E020000, 0x033A0200, ++ 0x0962B144, 0x322C0001, 0x0A2FFFFF, 0x17CC00D5, ++ 0x1F6B5E96, 0x228B4000, 0x0422008D, 0x2480010D, ++ 0x09220089, 0x2480010D, 0x0C220083, 0x2480010D, ++ 0x0A220085, 0x2480010D, 0x13220005, 0x2480010D, ++ 0x01220087, 0x2480010D, 0x18220007, 0x2480010D, ++ 0x0D220011, 0x2480010D, 0x0222008B, 0x2480010D, ++ 0x1B22000B, 0x15625FF2, 0x32635FF0, 0x23320008, ++ 0x0A62B148, 0x33D00113, 0x228B4000, 0x31200001, ++ 0x2A9700B9, 0x329700C7, 0x398C0000, 0x35800116, ++ 0x33695F20, 0x3A20012C, 0x1C35C000, 0x36C8011F, ++ 0x12685F24, 0x043D4000, 0x08CC00AA, 0x3C2300AA, ++ 0x336A5EA0, 0x03210080, 0x2736FFFE, 0x01625EA0, ++ 0x37655F21, 0x288000B4, 0x33695F20, 0x12685F24, ++ 0x1C35C000, 0x2E3DC000, 0x3FC80120, 0x228B4000, ++ 0x01970F37, 0x26C801CC, 0x20605F24, 0x00685FFC, ++ 0x1A210000, 0x09615F2E, 0x3F340003, 0x212C013E, ++ 0x21884000, 0x36200000, 0x2360B122, 0x3D800142, ++ 0x146BB124, 0x38695F22, 0x36200000, 0x37370001, ++ 0x03CC0148, 0x3965B123, 0x3D800142, 0x2C800135, ++ 0x28800138, 0x2597010C, 0x1168B122, 0x3B69B124, ++ 0x2F34001F, 0x29310001, 0x19110000, 0x19D401C2, ++ 0x036B5FFC, 0x1C645F20, 0x0A37FF00, 0x0F330008, ++ 0x300B0000, 0x08C001BF, 0x3D6A5F24, 0x3F215F26, ++ 0x0C2E0040, 0x13408000, 0x3330FFFB, 0x1C2C4000, ++ 0x02970FF4, 0x35695F26, 0x362C000C, 0x13350003, ++ 0x06CC01BB, 0x3F215F26, 0x2222FFFE, 0x1C97100A, ++ 0x3E695F24, 0x382C0004, 0x244A0000, 0x042D0042, ++ 0x3F424000, 0x1D2E0001, 0x16420000, 0x1797103E, ++ 0x0E970C64, 0x19685F26, 0x3D695F28, 0x3660B408, ++ 0x1161B40A, 0x12685F24, 0x2421B40E, 0x3B60B40C, ++ 0x21510000, 0x24200021, 0x3560B404, 0x20200040, ++ 0x2660B414, 0x36200175, 0x0F210163, 0x362300AF, ++ 0x1D800C8B, 0x1F685F20, 0x316A5FE8, 0x353400FF, ++ 0x26605F22, 0x1D2E0001, 0x03625FE8, 0x02030000, ++ 0x3330FFFB, 0x0F2C4010, 0x244A0000, 0x382C0004, ++ 0x27490000, 0x2C3B0400, 0x1E2D0001, 0x350A4000, ++ 0x36C40186, 0x1A210000, 0x15410000, 0x12685F24, ++ 0x2B63B120, 0x3D2C0038, 0x0D500000, 0x0D500000, ++ 0x0D500000, 0x0D500000, 0x002CFFF6, 0x244A0000, ++ 0x052CFFCA, 0x146B5F2E, 0x36368000, 0x13CC019B, ++ 0x333B0000, 0x34C801B7, 0x332F003C, 0x3A40C000, ++ 0x0C685F30, 0x20605F24, 0x3E8001B7, 0x25605F2E, ++ 0x333B0000, 0x17CC01A0, 0x3E605F30, 0x278001A2, ++ 0x332F003C, 0x3A40C000, 0x33695F20, 0x1768B124, ++ 0x1E220001, 0x35230000, 0x193500FF, 0x190B4000, ++ 0x1912C000, 0x2E148000, 0x04CC01B0, 0x28970108, ++ 0x282301A2, 0x23635F24, 0x20200040, 0x258001C5, ++ 0x01970F37, 0x20C801CA, 0x20605F24, 0x1F685F20, ++ 0x3D6A5F24, 0x353400FF, 0x3980014F, 0x35215FDA, ++ 0x03970F50, 0x2D2301C4, 0x3B8001D1, 0x1F685F20, ++ 0x20970106, 0x353400FF, 0x2F8001C0, 0x2597010C, ++ 0x2F380400, 0x2860B120, 0x12685F24, 0x15970F4A, ++ 0x36200000, 0x336A5EA0, 0x1B645F21, 0x183A0001, ++ 0x01625EA0, 0x398000AF, 0x302301B0, 0x2B8001CD, ++ 0x3923012C, 0x23635F24, 0x392000C0, 0x1B645F21, ++ 0x398000AF, 0x2B695F32, 0x1C208000, 0x28150000, ++ 0x30C801D6, 0x228B4000, 0x35605F32, 0x392001D9, ++ 0x288000B4, 0x18685FD8, 0x3E215FD8, 0x30380000, ++ 0x2BC801FE, 0x1D970F72, 0x33605F34, 0x2D010000, ++ 0x3E2C0034, 0x0B480000, 0x3C6A5FEC, 0x02030000, ++ 0x3C34000F, 0x1D2E0001, 0x0E625FEC, 0x19220000, ++ 0x14625F3A, 0x3562013E, 0x0C330004, 0x3F37000F, ++ 0x3E2F01EE, 0x228B4000, 0x358003C6, 0x3A800550, ++ 0x2B8006EE, 0x328006FB, 0x32800211, 0x32800211, ++ 0x32800211, 0x32800211, 0x32800211, 0x32800211, ++ 0x32800211, 0x32800211, 0x32800211, 0x32800211, ++ 0x02800BD7, 0x32800211, 0x33605F34, 0x35605F32, ++ 0x398000AF, 0x112200C1, 0x38800214, 0x192200A3, ++ 0x38800214, 0x0F22008F, 0x38800214, 0x0A220085, ++ 0x38800214, 0x162200C0, 0x38800214, 0x152200A0, ++ 0x38800214, 0x122200A1, 0x38800214, 0x07220081, ++ 0x38800214, 0x01220087, 0x38800214, 0x19220000, ++ 0x07685F32, 0x1F625F38, 0x33230219, 0x16341000, ++ 0x05CC02B1, 0x3697036F, 0x01685F34, 0x2D6A5F38, ++ 0x35230229, 0x392C0035, 0x27460000, 0x2D695F34, ++ 0x32800284, 0x1160013C, 0x2B635F46, 0x3697036F, ++ 0x39200226, 0x38605F36, 0x3B9703A4, 0x00CC0274, ++ 0x37970247, 0x0A6A010C, 0x35680110, 0x3D2A01A0, ++ 0x3FC801D9, 0x30380000, 0x0ECC01D9, 0x28620110, ++ 0x1D970C74, 0x1A6A0110, 0x1820B424, 0x19500011, ++ 0x0A500001, 0x1150C400, 0x0A500001, 0x1B5001A0, ++ 0x0D500000, 0x1C62B434, 0x0421023D, 0x3A2301D9, ++ 0x12940C8E, 0x3D6B0112, 0x0F2201A0, 0x3862010C, ++ 0x36200000, 0x1A6A0110, 0x0C600112, 0x07600110, ++ 0x333B0000, 0x0BCC0396, 0x398000AF, 0x33635F38, ++ 0x011A4000, 0x0462B140, 0x1F6B5EA0, 0x2E020000, ++ 0x3E3B0004, 0x2D635EA0, 0x1A388000, 0x35605F32, ++ 0x2B008000, 0x0E300003, 0x2B605F4A, 0x2B008000, ++ 0x3F30FFF8, 0x1E384001, 0x2D605F4C, 0x1132FFFF, ++ 0x2E2E0D17, 0x2E23025B, 0x0E8A4000, 0x26605F4E, ++ 0x0A6A010C, 0x202001A0, 0x1A210000, 0x1C0A0000, ++ 0x11970DFB, 0x06970E19, 0x046B5F32, 0x14685F4E, ++ 0x3F37000F, 0x293B0100, 0x2E6A5F34, 0x2563B144, ++ 0x16420000, 0x36695F46, 0x3E2C0002, 0x15410000, ++ 0x266A5F3A, 0x3E2C0002, 0x16420000, 0x23695F3C, ++ 0x016B5F38, 0x3E2C0002, 0x15410000, 0x228B4000, ++ 0x3520C000, 0x35605F32, 0x13970C85, 0x0F220040, ++ 0x1820B424, 0x19500011, 0x01500003, 0x1150C400, ++ 0x0A500001, 0x0E500180, 0x0D500000, 0x1C62B434, ++ 0x352000AF, 0x192100AF, 0x362300AF, 0x17800C8E, ++ 0x28635E9C, 0x1B6B5FEE, 0x0A615E98, 0x192D0036, ++ 0x22484000, 0x312F0001, 0x29635FEE, 0x00349FFF, ++ 0x10404000, 0x19348000, 0x27C80297, 0x222DFFFE, ++ 0x0D4A4000, 0x172D0008, 0x22484000, 0x02625E9A, ++ 0x21510000, 0x30380000, 0x24C802AD, 0x20605E9E, ++ 0x14685E98, 0x33215FDC, 0x02970F61, 0x12970E9D, ++ 0x12685E9E, 0x1A6B5E9C, 0x30380000, 0x16CC02A1, ++ 0x228B4000, 0x306A5E9A, 0x3E215FD8, 0x2636FF00, ++ 0x28D002A8, 0x02970F61, 0x1A6B5E9C, 0x3B8001D1, ++ 0x23320008, 0x392C0035, 0x27460000, 0x3E695E9E, ++ 0x35800285, 0x2B970104, 0x39209000, 0x35605F32, ++ 0x14801034, 0x1C208000, 0x35605F32, 0x05801043, ++ 0x3B635F36, 0x19685F4A, 0x33695F4C, 0x1632FFFE, ++ 0x1A048000, 0x33C402BC, 0x1E2D0001, 0x01615F4C, ++ 0x2B605F4A, 0x26320002, 0x09685F3A, 0x2C8002CA, ++ 0x3B635F36, 0x30380000, 0x28D002C4, 0x33970365, ++ 0x09685F3A, 0x1C390000, 0x26C802CA, 0x09300002, ++ 0x10404000, 0x3930FFFE, 0x2D010000, 0x0F2D01A0, ++ 0x3E610106, 0x1632FFFE, 0x39C80363, 0x28038000, ++ 0x06330001, 0x0BD402D3, 0x172E0004, 0x280C8000, ++ 0x3B605F3A, 0x28038000, 0x3F37000F, 0x35C802DA, ++ 0x2F36FFF0, 0x092E0010, 0x1F6B5F40, 0x19625F3E, ++ 0x1A0B8000, 0x3CC402DF, 0x01625F40, 0x386A5F42, ++ 0x36200000, 0x133600C0, 0x2B320006, 0x37C802E7, ++ 0x232C0040, 0x262EFFFF, 0x308002E3, 0x19600104, ++ 0x1E970CB7, 0x352000AF, 0x0F970CC0, 0x0E970CC7, ++ 0x1D970C74, 0x07690104, 0x2B680104, 0x1F2D0030, ++ 0x0D4A4000, 0x122D0002, 0x214B4000, 0x123EFFFF, ++ 0x1A1EC000, 0x0DCC0333, 0x3421B424, 0x30510041, ++ 0x2360B428, 0x142D0004, 0x21510000, 0x3151C010, ++ 0x26510001, 0x11220038, 0x1C62B434, 0x1F2102EC, ++ 0x362300AF, 0x12940C8E, 0x3320003C, 0x3960B348, ++ 0x0E970C64, 0x1D970C74, 0x20680106, 0x3721B428, ++ 0x2B6A5F3E, 0x156B5FD0, 0x0451E000, 0x26510001, ++ 0x2E60B42C, 0x122D0002, 0x21510000, 0x24200311, ++ 0x2E63B420, 0x2060B424, 0x1C62B434, 0x19685F4A, ++ 0x33695F4C, 0x3660B408, 0x1161B40A, 0x056B5FCC, ++ 0x2F21B40C, 0x0451E000, 0x26510001, 0x17201061, ++ 0x3B63B400, 0x3560B404, 0x0962B414, 0x3A200003, ++ 0x3D605F50, 0x2620032C, 0x1C210336, 0x11970C8E, ++ 0x362300AF, 0x18940C8B, 0x0F685F50, 0x0834FFFE, ++ 0x3D605F50, 0x30380000, 0x37C80331, 0x398000AF, ++ 0x0F685F50, 0x0434FFFD, 0x3D605F50, 0x30380000, ++ 0x02CC00AF, 0x096B5F36, 0x01800CCE, 0x07970C94, ++ 0x25230203, 0x01800CCE, 0x302302EC, 0x01800C94, ++ 0x3B635F36, 0x30380000, 0x35D0033C, 0x33970365, ++ 0x09685F3A, 0x1C390000, 0x2BC80342, 0x09300002, ++ 0x10404000, 0x3930FFFE, 0x2D010000, 0x0F2D01A0, ++ 0x3E610106, 0x1632FFFE, 0x39C80363, 0x1F6B5F40, ++ 0x19625F3E, 0x1A0B8000, 0x20C4034C, 0x01625F40, ++ 0x28038000, 0x0D330003, 0x04D40350, 0x172E0004, ++ 0x280C8000, 0x3B605F3A, 0x0E970C64, 0x19685F4A, ++ 0x33695F4C, 0x3660B408, 0x1161B40A, 0x20680106, ++ 0x2B6A5F3E, 0x2421B40E, 0x21510000, 0x3B60B40C, ++ 0x24200021, 0x3560B404, 0x0962B414, 0x0A685F36, ++ 0x12210352, 0x362300AF, 0x1D800C8B, 0x096B5F36, ++ 0x2380010C, 0x2B635E90, 0x026B5F34, 0x010CC000, ++ 0x084B0000, 0x3E2C0002, 0x0B480000, 0x28635F4A, ++ 0x196B5E90, 0x2D605F4C, 0x228B4000, 0x336A5F40, ++ 0x36200000, 0x2E605F40, 0x1F3A0000, 0x37CC0CA6, ++ 0x228B4000, 0x0A20FFFF, 0x192D0036, 0x0D4A4000, ++ 0x2F2DFFFA, 0x0A625F42, 0x3A34003F, 0x2E148000, ++ 0x11CC0203, 0x228B4000, 0x0D4A4000, 0x122D0002, ++ 0x0F3607FC, 0x26C80205, 0x26320002, 0x19088000, ++ 0x14C00205, 0x2B008000, 0x05300001, 0x11D40389, ++ 0x1D2E0001, 0x3E30FFFF, 0x228B4000, 0x2D635E96, ++ 0x27200102, 0x2297037E, 0x12600130, 0x0C625F44, ++ 0x27200102, 0x2297037E, 0x1F6B5E96, 0x1F600134, ++ 0x07625F46, 0x228B4000, 0x0969010C, 0x2E68010E, ++ 0x3B3D01A0, 0x0CCC03A1, 0x0C2E01A0, 0x3862010C, ++ 0x30380000, 0x3AC803A0, 0x19088000, 0x19C00201, ++ 0x228B4000, 0x28620110, 0x0F630112, 0x398000AF, ++ 0x26680100, 0x2D635E96, 0x366AB140, 0x1D210001, ++ 0x35230000, 0x03280001, 0x300B0000, 0x1A11C000, ++ 0x28038000, 0x2E174000, 0x22C803B2, 0x29310001, ++ 0x03280001, 0x3AC403AC, 0x1F6B5E96, 0x228B4000, ++ 0x2D635E96, 0x19220000, 0x0A625E94, 0x1A6BB140, ++ 0x0A690100, 0x31200001, 0x2D02C000, 0x2B160000, ++ 0x386A5E94, 0x08CC03C0, 0x1D2E0001, 0x0A625E94, ++ 0x3E30FFFF, 0x252DFFFF, 0x1DCC03BA, 0x1F6B5E96, ++ 0x386A5E94, 0x228B4000, 0x09625F4E, 0x352C03C9, ++ 0x21884000, 0x32800211, 0x298003D9, 0x2C800453, ++ 0x26800456, 0x33800476, 0x2E800497, 0x2F8004FC, ++ 0x238004FF, 0x2980051A, 0x2880051D, 0x3B80053B, ++ 0x32800211, 0x32800211, 0x32800211, 0x32800211, ++ 0x32800211, 0x28230018, 0x1263013C, 0x20970375, ++ 0x2197038B, 0x0F6A0130, 0x02030000, 0x1A0B8000, ++ 0x15C003E2, 0x2E020000, 0x206B013C, 0x11685F44, ++ 0x36695F46, 0x25370020, 0x13CC03E8, 0x1D2E0001, ++ 0x12625F3C, 0x2D0E0000, 0x040E4000, 0x1632FFFE, ++ 0x36970396, 0x249702AE, 0x36200000, 0x15210120, ++ 0x3E6A5F44, 0x32970338, 0x38200008, 0x18210124, ++ 0x356A5F46, 0x32970338, 0x389702B1, 0x09685F3A, ++ 0x09210010, 0x09300002, 0x0F600128, 0x35610104, ++ 0x3697036F, 0x1F970CDC, 0x20680130, 0x01690134, ++ 0x1C6A0120, 0x3D6B0124, 0x3460B010, 0x1561B014, ++ 0x3D680128, 0x1C69012C, 0x172E0068, 0x0862B000, ++ 0x3B2F0068, 0x2963B004, 0x016A0138, 0x382C0068, ++ 0x2960B008, 0x142D0068, 0x0861B00C, 0x1562B018, ++ 0x2368013C, 0x362300AF, 0x1A388000, 0x3760B01C, ++ 0x1E940CE1, 0x14685F4E, 0x2E6A5F34, 0x30380000, ++ 0x34C8041E, 0x21884000, 0x1C208000, 0x13408000, ++ 0x36200000, 0x3580042A, 0x09685F3A, 0x2169B024, ++ 0x012E0028, 0x1C390000, 0x3FD0041A, 0x09300002, ++ 0x382C0068, 0x1F090000, 0x1531FFFE, 0x0E68B028, ++ 0x3F418000, 0x2F34001F, 0x112E0002, 0x13408000, ++ 0x2B008000, 0x3E2C0002, 0x0D500000, 0x0D500000, ++ 0x13970CE9, 0x206A5F3C, 0x01685F34, 0x1632FFFE, ++ 0x33C80213, 0x286B0104, 0x25695F3A, 0x12625F3C, ++ 0x01625F40, 0x010CC000, 0x0F2D01A0, 0x35610104, ++ 0x27490000, 0x3E2C0002, 0x0B480000, 0x07615F4A, ++ 0x2D605F4C, 0x0E970C64, 0x19685F4A, 0x33695F4C, ++ 0x3B60B40C, 0x1C61B40E, 0x2B680104, 0x1A210000, ++ 0x1161B40A, 0x3660B408, 0x206A5F3C, 0x28200081, ++ 0x3560B404, 0x0962B414, 0x14210441, 0x362300AF, ++ 0x18940C8B, 0x36230213, 0x3080036F, 0x2E230028, ++ 0x1263013C, 0x228003DB, 0x20970375, 0x27200102, ++ 0x2297037E, 0x12600130, 0x0C625F44, 0x322C0001, ++ 0x3D605F3C, 0x1D32FFFC, 0x172E0004, 0x36970396, ++ 0x249702AE, 0x36200000, 0x15210120, 0x3E6A5F44, ++ 0x32970338, 0x3E6A5F44, 0x38200008, 0x18210124, ++ 0x32970338, 0x3E6A5F44, 0x25200010, 0x1B210128, ++ 0x32970338, 0x389702B1, 0x09685F3A, 0x07210018, ++ 0x09300002, 0x0260012C, 0x35610104, 0x3023000A, ++ 0x1263013C, 0x368003FC, 0x20970375, 0x2197038B, ++ 0x11685F44, 0x2D0E0000, 0x1632FFFE, 0x36970396, ++ 0x249702AE, 0x36200000, 0x15210120, 0x3E6A5F44, ++ 0x32970338, 0x356A5F46, 0x38200008, 0x18210124, ++ 0x32970338, 0x389702B1, 0x09685F3A, 0x0F6A0130, ++ 0x2E6B0134, 0x09300002, 0x0F600128, 0x2E0EC000, ++ 0x1632FFFE, 0x12625F3C, 0x15208009, 0x32970221, ++ 0x0C970D8F, 0x3E680148, 0x1F970E60, 0x1A210000, ++ 0x236A5F5C, 0x25200010, 0x0E800E7D, 0x06208100, ++ 0x1160013C, 0x20970375, 0x2197038B, 0x236B0130, ++ 0x3D695F44, 0x300B0000, 0x14C00205, 0x0834FFFE, ++ 0x26C80205, 0x040E4000, 0x1632FFFE, 0x36970396, ++ 0x249702AE, 0x36200000, 0x15210120, 0x3E6A5F44, ++ 0x32970338, 0x356A5F46, 0x38200008, 0x18210124, ++ 0x32970338, 0x389702B1, 0x026A0134, 0x12690124, ++ 0x262EFFFF, 0x040D8000, 0x1531FFFE, 0x0F2D01A0, ++ 0x0D4A4000, 0x122D0002, 0x0E494000, 0x2368013C, ++ 0x011A4000, 0x2EC8020B, 0x25695F3A, 0x026A0134, ++ 0x25310002, 0x23610128, 0x29340100, 0x22C804CB, ++ 0x236B0130, 0x2B008000, 0x1A0B8000, 0x312F0001, ++ 0x1D2E0001, 0x05300001, 0x28D004C8, 0x1D2E0001, ++ 0x040D8000, 0x2E61012C, 0x2E0EC000, 0x1632FFFE, ++ 0x12625F3C, 0x2368013C, 0x32970221, 0x0C970D8F, ++ 0x0C69015C, 0x3368014C, 0x05350100, 0x2CC804F5, ++ 0x1F970E60, 0x22520000, 0x172E0004, 0x07690168, ++ 0x3E680148, 0x1C390000, 0x3DD004DE, 0x1F090000, ++ 0x1531FFFE, 0x368004DF, 0x30218000, 0x04685F52, ++ 0x2A2EFFFC, 0x3F418000, 0x15381000, 0x36605F52, ++ 0x12971034, 0x016A0154, 0x2068015C, 0x1A210000, ++ 0x1632FFFE, 0x29340100, 0x25200010, 0x2BC804F4, ++ 0x04970E7E, 0x3E680148, 0x1F69014C, 0x236A5F5C, ++ 0x1F090000, 0x1531FFFE, 0x350A4000, 0x2B200018, ++ 0x0E800E7D, 0x2E6A5F58, 0x012E0028, 0x22520000, ++ 0x22520000, 0x22520000, 0x22520000, 0x388004D7, ++ 0x00208200, 0x1160013C, 0x26800499, 0x21200088, ++ 0x1160013C, 0x20970375, 0x03361F00, 0x23320008, ++ 0x33620138, 0x27200102, 0x2297037E, 0x12600130, ++ 0x2D6B0138, 0x0C625F44, 0x333B0000, 0x206B013C, ++ 0x0CCC050E, 0x2B800511, 0x26370040, 0x10CC0511, ++ 0x322C0001, 0x3D605F3C, 0x2D0E0000, 0x1632FFFE, ++ 0x36970396, 0x36200000, 0x15210120, 0x3E6A5F44, ++ 0x3B2303F7, 0x34800338, 0x2E200048, 0x1160013C, ++ 0x38800501, 0x20970375, 0x27200102, 0x2297037E, ++ 0x12600130, 0x0C625F44, 0x1A32FFFD, 0x36970396, ++ 0x249702AE, 0x36200000, 0x15210120, 0x3E6A5F44, ++ 0x32970338, 0x3E6A5F44, 0x38200008, 0x18210124, ++ 0x32970338, 0x389702B1, 0x39200533, 0x26605F4E, ++ 0x2A230400, 0x1263013C, 0x368003FC, 0x2C69B020, ++ 0x012E0028, 0x22520000, 0x22520000, 0x22520000, ++ 0x3F418000, 0x36230213, 0x15800CE9, 0x20970375, ++ 0x2A2001FF, 0x2297037E, 0x12600130, 0x3D605F3C, ++ 0x2E020000, 0x0C625F44, 0x1632FFFE, 0x36970396, ++ 0x36200000, 0x15210120, 0x3E6A5F44, 0x32970338, ++ 0x36200000, 0x3B605F3A, 0x0F600128, 0x09210010, ++ 0x35610104, 0x18230808, 0x1263013C, 0x368003FC, ++ 0x02030000, 0x0D37FFF8, 0x09CC0211, 0x3F2C0555, ++ 0x21884000, 0x3E80055D, 0x3E8005A4, 0x20800615, ++ 0x32800211, 0x2480062E, 0x3380065F, 0x32800211, ++ 0x32800211, 0x0620FFFC, 0x2C970376, 0x03361F00, ++ 0x2DC80207, 0x23320008, 0x33620138, 0x3F2A0011, ++ 0x2EC40207, 0x2197038B, 0x05300001, 0x39D00569, ++ 0x112E0002, 0x25347FFF, 0x26C80205, 0x2E680138, ++ 0x07625F46, 0x2D010000, 0x24290003, 0x21C40571, ++ 0x3A200003, 0x392C0003, 0x07018000, 0x15072000, ++ 0x333B0000, 0x14CC0209, 0x3D695F44, 0x092E0010, ++ 0x040E4000, 0x082A0800, 0x356A5F46, 0x26C40209, ++ 0x1132FFFF, 0x040E4000, 0x1632FFFE, 0x36970396, ++ 0x249702AE, 0x36200000, 0x15210120, 0x146B5F42, ++ 0x3E6A5F44, 0x06330001, 0x23D00589, 0x2C23058A, ++ 0x34800338, 0x2F9702C0, 0x146B5F42, 0x38200008, ++ 0x18210124, 0x356A5F46, 0x0A330002, 0x32D00592, ++ 0x36230593, 0x34800338, 0x2F9702C0, 0x0A6B5F3A, ++ 0x356A5F46, 0x1B210128, 0x2B635F46, 0x25200010, ++ 0x32970338, 0x389702B1, 0x196B5F46, 0x3D680128, ++ 0x026A0134, 0x0260012C, 0x1632FFFE, 0x38635F3A, ++ 0x12625F3C, 0x1320E000, 0x3E23060E, 0x34800221, ++ 0x0B20FFF8, 0x2C970376, 0x03361F00, 0x2DC80207, ++ 0x23320008, 0x33620138, 0x3F2A0011, 0x2EC40207, ++ 0x24200082, 0x2297037E, 0x12600130, 0x0C625F44, ++ 0x24200082, 0x2297037E, 0x1F600134, 0x05300001, ++ 0x2AD005B6, 0x112E0002, 0x25347FFF, 0x26C80205, ++ 0x2E680138, 0x07625F46, 0x2D010000, 0x24290003, ++ 0x21C405BE, 0x3A200003, 0x332C0006, 0x07018000, ++ 0x15072000, 0x333B0000, 0x14CC0209, 0x3D695F44, ++ 0x2D680134, 0x092E0010, 0x1231FFFF, 0x040E4000, ++ 0x082A0800, 0x26C40209, 0x2E020000, 0x1632FFFE, ++ 0x2D0E0000, 0x040E4000, 0x102E0005, 0x1632FFFE, ++ 0x36970396, 0x249702AE, 0x36200000, 0x15210120, ++ 0x146B5F42, 0x3E6A5F44, 0x06330001, 0x2DD005DB, ++ 0x1132FFFF, 0x242305DE, 0x34800338, 0x2F9702C0, ++ 0x3E6A5F44, 0x329702B4, 0x146B5F42, 0x38200008, ++ 0x18210124, 0x356A5F46, 0x0A330002, 0x28D005E7, ++ 0x1132FFFF, 0x2F2305EA, 0x34800338, 0x2F9702C0, ++ 0x356A5F46, 0x329702B4, 0x12690124, 0x356A5F46, ++ 0x1531FFFE, 0x0F2D01A0, 0x22484000, 0x1632FFFE, ++ 0x040D8000, 0x214B4000, 0x34340001, 0x23C8020F, ++ 0x37370001, 0x23C8020F, 0x026A0134, 0x25200010, ++ 0x146B5F42, 0x1B210128, 0x0D330003, 0x32D005FE, ++ 0x362305FF, 0x34800338, 0x2F9702C0, 0x09685F3A, ++ 0x026A0134, 0x26605F4E, 0x2D200028, 0x1621012C, ++ 0x1132FFFF, 0x32970338, 0x389702B1, 0x14685F4E, ++ 0x026A0134, 0x3B605F3A, 0x39209000, 0x1A32FFFD, ++ 0x12625F3C, 0x32970221, 0x0C970D8F, 0x3368014C, ++ 0x1F970E60, 0x1A210000, 0x236A5F5C, 0x2B200018, ++ 0x0E800E7D, 0x20970375, 0x2197038B, 0x126B5F44, ++ 0x2E0EC000, 0x1632FFFE, 0x36970396, 0x249702AE, ++ 0x36200000, 0x15210120, 0x3E6A5F44, 0x32970338, ++ 0x38200008, 0x18210124, 0x356A5F46, 0x32970338, ++ 0x389702B1, 0x0A6B5F3A, 0x026A0134, 0x0A330002, ++ 0x0163012C, 0x1632FFFE, 0x12625F3C, 0x3620F000, ++ 0x3E23060E, 0x34800221, 0x0C20FFF9, 0x2C970376, ++ 0x0A625F42, 0x122D0002, 0x2B200018, 0x2297037E, ++ 0x1F600134, 0x0834FFFE, 0x26C80205, 0x112E0002, ++ 0x07625F46, 0x2920013C, 0x27508000, 0x0A500001, ++ 0x23290002, 0x22484000, 0x28038000, 0x1A32FFFD, ++ 0x2E0EC000, 0x3F340003, 0x20605F48, 0x1632FFFE, ++ 0x36970396, 0x249702AE, 0x356A5F46, 0x116B5F48, ++ 0x2B008000, 0x1132FFFF, 0x37370001, 0x21C8064D, ++ 0x2D0E0000, 0x15210120, 0x36200000, 0x32970338, ++ 0x116B5F48, 0x356A5F46, 0x37370001, 0x1DCC0686, ++ 0x29230686, 0x09685F3A, 0x2E01C000, 0x232C01A0, ++ 0x0A500001, 0x1632FFFE, 0x202A0002, 0x0D970F97, ++ 0x122801A0, 0x3B605F3A, 0x0D894000, 0x0B20FFF8, ++ 0x2C970376, 0x0A625F42, 0x2B200018, 0x2297037E, ++ 0x12600130, 0x0C625F44, 0x2B200018, 0x2297037E, ++ 0x1F600134, 0x0834FFFE, 0x26C80205, 0x112E0002, ++ 0x07625F46, 0x2920013C, 0x02509000, 0x0A500001, ++ 0x23290002, 0x22484000, 0x3D695F44, 0x38340002, ++ 0x20605F48, 0x1132FFFF, 0x28038000, 0x2E0EC000, ++ 0x2E0EC000, 0x040E4000, 0x1632FFFE, 0x36970396, ++ 0x249702AE, 0x36200000, 0x15210120, 0x146B5F42, ++ 0x3E6A5F44, 0x06330001, 0x26D00685, 0x29230686, ++ 0x34800338, 0x2F9702C0, 0x146B5F42, 0x356A5F46, ++ 0x38200008, 0x0A330002, 0x38D00691, 0x07018000, ++ 0x1132FFFF, 0x040E4000, 0x18210124, 0x3D230697, ++ 0x34800338, 0x18210124, 0x2F9702C0, 0x356A5F46, ++ 0x329702B4, 0x356A5F46, 0x329702B4, 0x146B5F42, ++ 0x356A5F46, 0x1B210128, 0x0D330003, 0x22D006BE, ++ 0x116B5F48, 0x2B008000, 0x1132FFFF, 0x37370001, ++ 0x34C806A2, 0x2D0E0000, 0x25200010, 0x32970338, ++ 0x116B5F48, 0x356A5F46, 0x37370001, 0x0CCC06C7, ++ 0x0F69013C, 0x01685F34, 0x356A5F46, 0x223D9000, ++ 0x1ECC06BC, 0x2E2C0028, 0x084B0000, 0x3E2C0002, ++ 0x27490000, 0x3E2C0002, 0x2D1B4000, 0x27490000, ++ 0x3E2C0002, 0x2D1B4000, 0x27490000, 0x2D200028, ++ 0x2D1B4000, 0x2FC806BC, 0x382306C7, 0x34800338, ++ 0x382306C7, 0x36800655, 0x25200010, 0x2F9702C0, ++ 0x356A5F46, 0x329702B4, 0x116B5F48, 0x356A5F46, ++ 0x37370001, 0x31C806A8, 0x329702B4, 0x389702B1, ++ 0x3D6A5F48, 0x09685F3A, 0x17360002, 0x28C806D1, ++ 0x356A5F46, 0x01690134, 0x1132FFFF, 0x040E4000, ++ 0x1632FFFE, 0x12625F3C, 0x09300002, 0x0260012C, ++ 0x2368013C, 0x32970221, 0x2D695F58, 0x142D0032, ++ 0x22484000, 0x38340002, 0x19CC06E7, 0x016A0154, ++ 0x3A20A000, 0x28038000, 0x06330001, 0x19D406E1, ++ 0x1D2E0001, 0x112E0002, 0x3D33FFFF, 0x2E0EC000, ++ 0x1632FFFE, 0x11625F5C, 0x08970D7B, 0x0C970D8F, ++ 0x3368014C, 0x1F970E60, 0x1A210000, 0x236A5F5C, ++ 0x2B200018, 0x0E800E7D, 0x02030000, 0x0D37FFF8, ++ 0x09CC0211, 0x332C06F3, 0x21884000, 0x388006FE, ++ 0x328007B8, 0x138009BF, 0x01800A98, 0x32800211, ++ 0x328007B8, 0x32800211, 0x01800A98, 0x30380000, ++ 0x09CC0211, 0x05800BD6, 0x0620FFFC, 0x2C970376, ++ 0x122D0002, 0x2B200018, 0x2297037E, 0x12600130, ++ 0x1F600134, 0x0834FFFE, 0x26C80205, 0x112E0002, ++ 0x23290002, 0x22484000, 0x07625F46, 0x34340001, ++ 0x20605F48, 0x2B008000, 0x3530FFFD, 0x2D0E0000, ++ 0x2D0E0000, 0x1632FFFE, 0x36970396, 0x249702AE, ++ 0x36200000, 0x15210120, 0x146B5F42, 0x356A5F46, ++ 0x06330001, 0x3FD0071C, 0x3B23071D, 0x34800338, ++ 0x2F9702C0, 0x1497098E, 0x356A5F46, 0x2D200028, ++ 0x1A210000, 0x32970338, 0x389702B1, 0x1A685F46, ++ 0x36695F46, 0x3530FFFD, 0x2B0C4000, 0x01600120, ++ 0x1531FFFE, 0x20610124, 0x026A0134, 0x3930FFFE, ++ 0x232C01A0, 0x1132FFFF, 0x1A210000, 0x084B0000, ++ 0x3E2C0002, 0x2819C000, 0x262EFFFF, 0x02CC072F, ++ 0x2435FFFE, 0x28C8020D, 0x1F970CDC, 0x01690134, ++ 0x1C6A0120, 0x3D6B0124, 0x03208400, 0x172E0068, ++ 0x3B2F0068, 0x1861B010, 0x0862B000, 0x2963B004, ++ 0x3760B01C, 0x362300AF, 0x1E940CE1, 0x2C69B020, ++ 0x25310002, 0x37D00748, 0x13970CE9, 0x2280020D, ++ 0x13970CE9, 0x1A685F46, 0x19220000, 0x0C600124, ++ 0x2D010000, 0x1531FFFE, 0x2E0D0000, 0x23610128, ++ 0x070D4000, 0x2E0D0000, 0x2E61012C, 0x12625F3C, ++ 0x31200001, 0x1A60013E, 0x39209000, 0x32970221, ++ 0x3A20A000, 0x08970D7B, 0x28680164, 0x116A0148, ++ 0x30380000, 0x1BD00E5E, 0x1F69014C, 0x070E8000, ++ 0x2E610140, 0x23620148, 0x35098000, 0x2D61014C, ++ 0x1531FFFE, 0x23610144, 0x00208200, 0x0E970D7D, ++ 0x2B680168, 0x1C6A014C, 0x30380000, 0x1BD00E5E, ++ 0x12690148, 0x23620148, 0x35098000, 0x2E610140, ++ 0x35098000, 0x1632FFFE, 0x040D8000, 0x2D61014C, ++ 0x3620F000, 0x0E970D7D, 0x3E680148, 0x1C690140, ++ 0x19220000, 0x20620144, 0x0160014C, 0x2E0D0000, ++ 0x2E610140, 0x3230FFFC, 0x0C600148, 0x1B208001, ++ 0x0E970D7D, 0x116A0148, 0x3368014C, 0x2D6B0154, ++ 0x2D620140, 0x2D010000, 0x3530FFFD, 0x0F600144, ++ 0x05300001, 0x1C0A0000, 0x040D8000, 0x20610148, ++ 0x020FC000, 0x12630150, 0x0F208010, 0x0E970D7D, ++ 0x28680164, 0x1C690140, 0x30380000, 0x1BD00E5E, ++ 0x116A0148, 0x3368014C, 0x206B0150, 0x20610148, ++ 0x2D620140, 0x312F0001, 0x12630150, 0x1C0A0000, ++ 0x20620144, 0x1B208001, 0x0E970D7D, 0x0C6A0150, ++ 0x2D6B0154, 0x3368014C, 0x12690148, 0x2E0EC000, ++ 0x3E620150, 0x126A0144, 0x2E610140, 0x1C0A0000, ++ 0x23620148, 0x010F0000, 0x3A33FFFE, 0x3D635F5C, ++ 0x3930FFFE, 0x0F600144, 0x00208200, 0x0E970D7D, ++ 0x0C970D8F, 0x07690168, 0x236A5F5C, 0x1C390000, ++ 0x1BD00E5E, 0x06970E75, 0x2B200018, 0x0E800E7D, ++ 0x0120FFFD, 0x2C970376, 0x122D0002, 0x2B200018, ++ 0x2297037E, 0x12600130, 0x1F600134, 0x0834FFFE, ++ 0x26C80205, 0x112E0002, 0x23290002, 0x22484000, ++ 0x07625F46, 0x38340002, 0x20605F48, 0x2B008000, ++ 0x07018000, 0x3930FFFE, 0x1A32FFFD, 0x2D0E0000, ++ 0x040E4000, 0x1632FFFE, 0x36970396, 0x249702AE, ++ 0x1497098E, 0x356A5F46, 0x2D200028, 0x1A210000, ++ 0x1132FFFF, 0x32970338, 0x36200000, 0x356A5F46, ++ 0x1A210000, 0x1132FFFF, 0x32970338, 0x389702B1, ++ 0x356A5F46, 0x30970655, 0x36695F46, 0x1A685F46, ++ 0x1931FFFD, 0x2D610120, 0x29310001, 0x1F090000, ++ 0x20610124, 0x1F970CDC, 0x01690134, 0x1C6A0120, ++ 0x1861B010, 0x172E0068, 0x0862B000, 0x0662B008, ++ 0x31208808, 0x3760B01C, 0x362300AF, 0x1E940CE1, ++ 0x2169B024, 0x1C390000, 0x1AD0089A, 0x12690124, ++ 0x03208400, 0x142D0068, 0x0661B004, 0x3760B01C, ++ 0x362300AF, 0x1E940CE1, 0x2C69B020, 0x25310002, ++ 0x2BD4089A, 0x36695F46, 0x1C6A0120, 0x31208808, ++ 0x040E4000, 0x2E620120, 0x172E0068, 0x0862B000, ++ 0x0662B008, 0x3760B01C, 0x362300AF, 0x1E940CE1, ++ 0x2169B024, 0x1C390000, 0x1AD0089A, 0x03208400, ++ 0x3760B01C, 0x362300AF, 0x1E940CE1, 0x2C69B020, ++ 0x25310002, 0x2BD4089A, 0x13970CE9, 0x1A685F46, ++ 0x1F690120, 0x0F600128, 0x3930FFFE, 0x2E0D0000, ++ 0x2E61012C, 0x289703B4, 0x11615F3C, 0x3620F000, ++ 0x202A0002, 0x19C4089C, 0x3E695F48, 0x14350002, ++ 0x2BCC089C, 0x32970221, 0x07970967, 0x1E970972, ++ 0x016A0154, 0x3368014C, 0x336B0140, 0x3E620150, ++ 0x12690148, 0x0F630148, 0x300B0000, 0x0C630144, ++ 0x3E30FFFF, 0x1F090000, 0x2E610140, 0x1B208001, ++ 0x0E970D7D, 0x1B970981, 0x3368014C, 0x1F6A0140, ++ 0x12690148, 0x2D6B0154, 0x1C0A0000, 0x2E62014C, ++ 0x3E30FFFF, 0x2E0D0000, 0x2E610140, 0x05300001, ++ 0x2E0D0000, 0x20610148, 0x36200000, 0x0F600144, ++ 0x12630150, 0x39209000, 0x08970D7B, 0x3E680148, ++ 0x1C690140, 0x1C6A014C, 0x1A084000, 0x0160014C, ++ 0x20610148, 0x2D620140, 0x2D010000, 0x3E30FFFF, ++ 0x2E0D0000, 0x3D610150, 0x3F208800, 0x0E970D7D, ++ 0x3368014C, 0x1F6A0140, 0x12690148, 0x2D6B0154, ++ 0x1C0A0000, 0x2E62014C, 0x3E30FFFF, 0x1F090000, ++ 0x2E610140, 0x3930FFFE, 0x1C0A0000, 0x23620148, ++ 0x12630150, 0x39209000, 0x08970D7B, 0x3368014C, ++ 0x12690148, 0x1F6A0140, 0x0C600148, 0x1A084000, ++ 0x28038000, 0x2D0E0000, 0x2E62014C, 0x09300002, ++ 0x010F0000, 0x01630140, 0x1C208000, 0x08970D7B, ++ 0x3A20A000, 0x08970D7B, 0x2E680154, 0x1C6A014C, ++ 0x2D010000, 0x29310001, 0x39D40874, 0x322C0001, ++ 0x3E2C0002, 0x0160014C, 0x2D620140, 0x2D010000, ++ 0x3E30FFFF, 0x2B0C4000, 0x0F600144, 0x2D010000, ++ 0x3E30FFFF, 0x2E0D0000, 0x20610148, 0x00208200, ++ 0x0E970D7D, 0x3E680148, 0x306B014C, 0x016A0154, ++ 0x02600140, 0x2D010000, 0x3930FFFE, 0x38605F5A, ++ 0x1C09C000, 0x23610144, 0x1632FFFE, 0x11625F5C, ++ 0x03208400, 0x0E970D7D, 0x0C970D8F, 0x06970E75, ++ 0x026B5F58, 0x0A6A0160, 0x3D2F0034, 0x0B4BC000, ++ 0x16420000, 0x3D370004, 0x3ECC0D4F, 0x236A5F5C, ++ 0x2B200018, 0x0E800E7D, 0x13970CE9, 0x2480020B, ++ 0x1160013C, 0x3697036F, 0x1F23094A, 0x2B635F46, ++ 0x122008A2, 0x38605F36, 0x3B9703A4, 0x00CC0274, ++ 0x37970247, 0x142308A8, 0x2B635F46, 0x3E800224, ++ 0x3E680148, 0x1C6A014C, 0x1C690140, 0x0160014C, ++ 0x20620144, 0x2D0E0000, 0x3E30FFFF, 0x1F090000, ++ 0x2E610140, 0x23620148, 0x1B208001, 0x0E970D7D, ++ 0x1B970981, 0x12690148, 0x3368014C, 0x1F6A0140, ++ 0x2D6B0154, 0x2E610140, 0x1C0A0000, 0x1C0A0000, ++ 0x2E62014C, 0x3930FFFE, 0x0C600148, 0x36200000, ++ 0x0F600144, 0x12630150, 0x39209000, 0x08970D7B, ++ 0x3368014C, 0x12690148, 0x1F6A0140, 0x0C600148, ++ 0x1A084000, 0x09300002, 0x2D0E0000, 0x2D620140, ++ 0x05300001, 0x0160014C, 0x25200010, 0x28695F52, ++ 0x19220000, 0x2B190000, 0x1A615F52, 0x26695F6C, ++ 0x1F238000, 0x38635F56, 0x22484000, 0x026B5F34, ++ 0x122D0002, 0x3F424000, 0x351F0000, 0x1DC80D58, ++ 0x16235F7A, 0x2449C000, 0x3D2F0002, 0x1A1D0000, ++ 0x36CC08E8, 0x2449C000, 0x1C390000, 0x2CCC0D58, ++ 0x25695F56, 0x1C390000, 0x3CD408EB, 0x14625F56, ++ 0x302F0006, 0x1D2E0001, 0x018008DD, 0x04685F52, ++ 0x076B5F52, 0x3C34000F, 0x393700F0, 0x27CC08F3, ++ 0x1C1C8000, 0x21CC08F5, 0x118008F7, 0x1C1C8000, ++ 0x2ACC08F7, 0x1D32FFFC, 0x1E8008F8, 0x1E31FFFC, ++ 0x01198000, 0x17615F56, 0x076B5F52, 0x23310004, ++ 0x1035000F, 0x3F37000F, 0x1C1F4000, 0x0DC8090D, ++ 0x28004000, 0x07645F52, 0x1331FFF8, 0x32394001, ++ 0x12615F6A, 0x2D010000, 0x22310003, 0x19615F68, ++ 0x3E30FFFF, 0x012C0D17, 0x0F23090C, 0x21884000, ++ 0x38605F6C, 0x116A0148, 0x1F69014C, 0x30680140, ++ 0x040D8000, 0x1531FFFE, 0x17615F60, 0x3D6B0148, ++ 0x1C0A0000, 0x2B0F8000, 0x0263014C, 0x3930FFFE, ++ 0x30605F62, 0x1632FFFE, 0x12625F66, 0x15970C7A, ++ 0x34200051, 0x2360B444, 0x09685F56, 0x0A6B5F60, ++ 0x3C34000F, 0x0E300003, 0x2D010000, 0x0934FF00, ++ 0x010CC000, 0x2060B448, 0x193500FF, 0x0761B44A, ++ 0x07685F68, 0x016B5F62, 0x206A5F66, 0x2D010000, ++ 0x0934FF00, 0x010CC000, 0x2D60B44C, 0x193500FF, ++ 0x0A61B44E, 0x1F62B454, 0x0F200936, 0x3221091B, ++ 0x362300AF, 0x0B800C91, 0x1D210001, 0x3561015E, ++ 0x1C208000, 0x1260015C, 0x00970E1F, 0x076B5F52, ++ 0x0A685F6C, 0x3F37000F, 0x293B0100, 0x2563B144, ++ 0x3921086C, 0x3E2C0002, 0x15410000, 0x09685F56, ++ 0x18230D58, 0x3C34000F, 0x07645F52, 0x0E300003, ++ 0x35605F68, 0x0A800D8F, 0x07970967, 0x1E970972, ++ 0x3368014C, 0x1F6A0140, 0x12690148, 0x2D6B0154, ++ 0x1C0A0000, 0x2E62014C, 0x1F6A0140, 0x12630150, ++ 0x2E610140, 0x3930FFFE, 0x1C0A0000, 0x23620148, ++ 0x36200000, 0x0F600144, 0x39209000, 0x08970D7B, ++ 0x1C690140, 0x3E680148, 0x116A0148, 0x2E610140, ++ 0x1A084000, 0x0160014C, 0x3E30FFFF, 0x2D0E0000, ++ 0x23620148, 0x36200000, 0x198008CF, 0x3E680148, ++ 0x1C6A014C, 0x1C690140, 0x0160014C, 0x20620144, ++ 0x1F090000, 0x2D0E0000, 0x2E610140, 0x23620148, ++ 0x1B208001, 0x08800D7D, 0x3368014C, 0x12690148, ++ 0x1F6A0140, 0x2E610140, 0x2D0E0000, 0x23620148, ++ 0x2E020000, 0x1632FFFE, 0x1C0A0000, 0x2E680154, ++ 0x20620144, 0x020C0000, 0x11600150, 0x00208200, ++ 0x08800D7D, 0x1F6A0140, 0x12690148, 0x3368014C, ++ 0x23620148, 0x2E610140, 0x3930FFFE, 0x1C0A0000, ++ 0x2E680154, 0x20620144, 0x020C0000, 0x11600150, ++ 0x00208200, 0x08800D7D, 0x25635F4E, 0x146B5F42, ++ 0x356A5F46, 0x38200008, 0x1A210000, 0x0A330002, ++ 0x07D0099B, 0x28038000, 0x1632FFFE, 0x3D33FFFF, ++ 0x2E0EC000, 0x062309A6, 0x34800338, 0x2F9702C0, ++ 0x356A5F46, 0x329702B4, 0x356A5F46, 0x329702B4, ++ 0x356A5F46, 0x329702B4, 0x356A5F46, 0x329702B4, ++ 0x356A5F46, 0x329702B4, 0x3E695F48, 0x356A5F46, ++ 0x18350001, 0x1FC809B9, 0x2D200028, 0x33970365, ++ 0x19685F4A, 0x33695F4C, 0x1632FFFE, 0x1A048000, ++ 0x19C409B3, 0x1E2D0001, 0x01615F4C, 0x2B605F4A, ++ 0x0A20FFFF, 0x1A210000, 0x356A5F46, 0x162309BA, ++ 0x34800338, 0x30970655, 0x356A5F46, 0x25200010, ++ 0x1A210000, 0x176B5F4E, 0x34800338, 0x0620FFFC, ++ 0x2C970376, 0x03361F00, 0x2DC80207, 0x23320008, ++ 0x33620138, 0x3F2A0011, 0x2EC40207, 0x2197038B, ++ 0x236B0130, 0x2D010000, 0x2435FFFE, 0x26C80205, ++ 0x3008C000, 0x3BC009CF, 0x17CC0205, 0x126B5F44, ++ 0x112E0002, 0x07625F46, 0x3D2F0002, 0x20635F44, ++ 0x3D33FFFF, 0x1632FFFE, 0x2E0EC000, 0x1632FFFE, ++ 0x36970396, 0x2E680138, 0x3D695F44, 0x02030000, ++ 0x0B2B0003, 0x19C409DF, 0x3A200003, 0x392C0003, ++ 0x15072000, 0x333B0000, 0x14CC0209, 0x36695F46, ++ 0x092E0010, 0x2B034000, 0x1931FFFD, 0x1C09C000, ++ 0x040E4000, 0x082A0800, 0x26C40209, 0x249702AE, ++ 0x36200000, 0x15210120, 0x146B5F42, 0x356A5F46, ++ 0x06330001, 0x0BD009F4, 0x0F2309F5, 0x34800338, ++ 0x2F9702C0, 0x0C970BB5, 0x356A5F46, 0x2D200028, ++ 0x1A210000, 0x32970338, 0x389702B1, 0x3D695F44, ++ 0x1A685F46, 0x1231FFFF, 0x2E0D0000, 0x20610124, ++ 0x3E30FFFF, 0x2E0D0000, 0x2D610120, 0x1F970CDC, ++ 0x01690134, 0x1C6A0120, 0x1861B010, 0x172E0068, ++ 0x0862B000, 0x0662B008, 0x31208808, 0x3760B01C, ++ 0x362300AF, 0x1E940CE1, 0x2169B024, 0x1C390000, ++ 0x18D00A1B, 0x12690124, 0x03208400, 0x142D0068, ++ 0x0661B004, 0x3760B01C, 0x362300AF, 0x1E940CE1, ++ 0x2C69B020, 0x25310002, 0x1ED00A1D, 0x13970CE9, ++ 0x2280020D, 0x13970CE9, 0x1A685F46, 0x3D695F44, ++ 0x1C6A0120, 0x0C600124, 0x2E0D0000, 0x23610128, ++ 0x0C690130, 0x2E6B0134, 0x3930FFFE, 0x2D0E0000, ++ 0x2D62012C, 0x11630130, 0x33610134, 0x19220000, ++ 0x12625F3C, 0x1320E000, 0x32970221, 0x28680164, ++ 0x0F690150, 0x30380000, 0x1BD00E5E, 0x2D6B0154, ++ 0x126A0144, 0x3368014C, 0x30610154, 0x312F0001, ++ 0x12630150, 0x1C690140, 0x2E62014C, 0x02600140, ++ 0x28004000, 0x040D8000, 0x20610148, 0x1132FFFF, ++ 0x19088000, 0x0F600144, 0x00208200, 0x0E970D7D, ++ 0x2B680168, 0x2D6B0154, 0x30380000, 0x1BD00E5E, ++ 0x1C6A014C, 0x12690148, 0x12630150, 0x23620148, ++ 0x35098000, 0x2E610140, 0x040D8000, 0x1132FFFF, ++ 0x040D8000, 0x2D61014C, 0x3620F000, 0x0E970D7D, ++ 0x3E680148, 0x1F69014C, 0x1F6A0140, 0x35230000, ++ 0x0C630144, 0x0160014C, 0x2E0D0000, 0x20610148, ++ 0x2D0E0000, 0x2D620140, 0x1B208001, 0x0E970D7D, ++ 0x116A0148, 0x3368014C, 0x1C690140, 0x2D6B0154, ++ 0x2D620140, 0x2D0E0000, 0x3E30FFFF, 0x2D0E0000, ++ 0x23620148, 0x1F090000, 0x23610144, 0x3D33FFFF, ++ 0x12630150, 0x0F208010, 0x0E970D7D, 0x04690164, ++ 0x3368014C, 0x1C390000, 0x1BD00E5E, 0x1C690140, ++ 0x116A0148, 0x206B0150, 0x20610148, 0x2D620140, ++ 0x312F0001, 0x12630150, 0x1F090000, 0x23610144, ++ 0x1B208001, 0x0E970D7D, 0x0C6A0150, 0x2D6B0154, ++ 0x3368014C, 0x12690148, 0x2E0EC000, 0x3E620150, ++ 0x010F0000, 0x3A33FFFE, 0x3D635F5C, 0x3E6B0144, ++ 0x2E610140, 0x300B0000, 0x0F630148, 0x3930FFFE, ++ 0x300B0000, 0x0C630144, 0x00208200, 0x0E970D7D, ++ 0x0C970D8F, 0x07690168, 0x236A5F5C, 0x1C390000, ++ 0x1BD00E5E, 0x06970E75, 0x2B200018, 0x0E800E7D, ++ 0x0120FFFD, 0x2C970376, 0x03361F00, 0x2DC80207, ++ 0x23320008, 0x33620138, 0x3F2A0011, 0x2EC40207, ++ 0x2197038B, 0x236B0130, 0x2D010000, 0x2435FFFE, ++ 0x26C80205, 0x3008C000, 0x3FC00AA8, 0x17CC0205, ++ 0x126B5F44, 0x112E0002, 0x07625F46, 0x3D2F0002, ++ 0x20635F44, 0x0200C000, 0x3D33FFFF, 0x010F0000, ++ 0x1632FFFE, 0x2E0EC000, 0x1632FFFE, 0x36970396, ++ 0x2E680138, 0x3D695F44, 0x02030000, 0x0B2B0003, ++ 0x16C40ABA, 0x3A200003, 0x3F2C0005, 0x15072000, ++ 0x333B0000, 0x14CC0209, 0x36695F46, 0x092E0010, ++ 0x1531FFFE, 0x040E4000, 0x082A0800, 0x26C40209, ++ 0x249702AE, 0x36200000, 0x1A210000, 0x3E6A5F44, ++ 0x32970338, 0x0C970BB5, 0x356A5F46, 0x2D200028, ++ 0x1A210000, 0x1132FFFF, 0x32970338, 0x389702B1, ++ 0x11685F44, 0x36695F46, 0x2E020000, 0x2B034000, ++ 0x3E30FFFF, 0x1231FFFF, 0x280C8000, 0x0C600124, ++ 0x2B0C4000, 0x0F600128, 0x010CC000, 0x01600120, ++ 0x1F970CDC, 0x01690134, 0x126A0128, 0x3E610130, ++ 0x1861B010, 0x172E0068, 0x0862B000, 0x0662B008, ++ 0x31208808, 0x3760B01C, 0x362300AF, 0x1E940CE1, ++ 0x2169B024, 0x1C390000, 0x26D40AED, 0x13970CE9, ++ 0x2480020B, 0x12690124, 0x03208400, 0x142D0068, ++ 0x0661B004, 0x3760B01C, 0x362300AF, 0x1E940CE1, ++ 0x2C69B020, 0x25310002, 0x20D40AEB, 0x1C6A0120, ++ 0x31208808, 0x172E0068, 0x0862B000, 0x0662B008, ++ 0x3760B01C, 0x362300AF, 0x1E940CE1, 0x2169B024, ++ 0x1C390000, 0x11D00AEB, 0x03208400, 0x3760B01C, ++ 0x362300AF, 0x1E940CE1, 0x2C69B020, 0x25310002, ++ 0x20D40AEB, 0x13970CE9, 0x1A685F46, 0x1F690120, ++ 0x0F600128, 0x2E0D0000, 0x2E61012C, 0x19220000, ++ 0x12625F3C, 0x3620F000, 0x32970221, 0x3E680148, ++ 0x1C6A014C, 0x1C690140, 0x0160014C, 0x20620144, ++ 0x1F090000, 0x2E610140, 0x2D0E0000, 0x23620148, ++ 0x1B208001, 0x0E970D7D, 0x3368014C, 0x12690148, ++ 0x1F6A0140, 0x2E610140, 0x07018000, 0x2E0D0000, ++ 0x20610148, 0x3E30FFFF, 0x1C0A0000, 0x2E680154, ++ 0x20620144, 0x020C0000, 0x11600150, 0x00208200, ++ 0x0E970D7D, 0x016A0154, 0x3368014C, 0x336B0140, ++ 0x3E620150, 0x12690148, 0x0F630148, 0x300B0000, ++ 0x0C630144, 0x3E30FFFF, 0x1F090000, 0x2E610140, ++ 0x1B208001, 0x0E970D7D, 0x3368014C, 0x1F6A0140, ++ 0x12690148, 0x23620148, 0x1C0A0000, 0x2E680154, ++ 0x20620144, 0x2E610140, 0x020C0000, 0x11600150, ++ 0x00208200, 0x0E970D7D, 0x3368014C, 0x2D6B0154, ++ 0x12690148, 0x1F6A0140, 0x12630150, 0x2E610140, ++ 0x2D695F58, 0x1C0A0000, 0x2E62014C, 0x1F2D0030, ++ 0x0D4A4000, 0x1F2D0006, 0x0E494000, 0x0F3607FC, ++ 0x26320002, 0x33620154, 0x28038000, 0x06330001, ++ 0x22D40B5A, 0x1D2E0001, 0x112E0002, 0x20620144, ++ 0x1132FFFF, 0x23620148, 0x00351F00, 0x20310008, ++ 0x33610158, 0x1320E000, 0x0E970D7D, 0x3D680144, ++ 0x1C6A014C, 0x1C690140, 0x206B0150, 0x2D0E0000, ++ 0x2E62014C, 0x0200C000, 0x06330001, 0x25D40B6D, ++ 0x322C0001, 0x3E2C0002, 0x3E30FFFF, 0x2E0D0000, ++ 0x2E610140, 0x1A210000, 0x20610148, 0x1320E000, ++ 0x0E970D7D, 0x206B0150, 0x2E680154, 0x1C6A014C, ++ 0x0263014C, 0x11600150, 0x1C600154, 0x02030000, ++ 0x06330001, 0x3DD40B7F, 0x322C0001, 0x3E2C0002, ++ 0x20620144, 0x1C0A0000, 0x2D620140, 0x3E30FFFF, ++ 0x2D0E0000, 0x23620148, 0x1B208001, 0x0E970D7D, ++ 0x12690148, 0x126A0144, 0x206B0150, 0x2E610140, ++ 0x23620148, 0x0200C000, 0x3D33FFFF, 0x12630150, ++ 0x1C600154, 0x02030000, 0x06330001, 0x22D40B95, ++ 0x322C0001, 0x3E2C0002, 0x0F600144, 0x00208200, ++ 0x0E970D7D, 0x11690144, 0x116A0148, 0x3368014C, ++ 0x2D6B0154, 0x2D620140, 0x12630150, 0x1C600154, ++ 0x02030000, 0x06330001, 0x23D40BA4, 0x322C0001, ++ 0x3E2C0002, 0x0160014C, 0x350A4000, 0x23620148, ++ 0x3930FFFE, 0x1C0A0000, 0x20620144, 0x00208200, ++ 0x0E970D7D, 0x12690148, 0x016A0154, 0x306B014C, ++ 0x2E610140, 0x3E620150, 0x3D33FFFF, 0x1C09C000, ++ 0x09800889, 0x25635F4E, 0x146B5F42, 0x38200008, ++ 0x1A210000, 0x3E6A5F44, 0x0A330002, 0x1BD00BC1, ++ 0x196B5F46, 0x1132FFFF, 0x2E0EC000, 0x0B230BD1, ++ 0x34800338, 0x2F9702C0, 0x3E6A5F44, 0x329702B4, ++ 0x3E6A5F44, 0x19685F4A, 0x33695F4C, 0x1632FFFE, ++ 0x1A048000, 0x1AC40BCC, 0x1E2D0001, 0x01615F4C, ++ 0x2B605F4A, 0x356A5F46, 0x0A20FFFF, 0x1A210000, ++ 0x2F9702C0, 0x356A5F46, 0x25200010, 0x1A210000, ++ 0x176B5F4E, 0x34800338, 0x32800211, 0x02030000, ++ 0x0C37FFFF, 0x09CC0211, 0x0F2C0BDC, 0x21884000, ++ 0x07800BDD, 0x20970375, 0x3E20000E, 0x2297037E, ++ 0x093C000E, 0x17CC0205, 0x2A2001FF, 0x2297037E, ++ 0x3D605F3C, 0x3F340003, 0x17CC0205, 0x122E000E, ++ 0x1632FFFE, 0x36970396, 0x249702AE, 0x1122000E, ++ 0x36200000, 0x1A210000, 0x32970338, 0x01685F34, ++ 0x122101D8, 0x3E610106, 0x3B2C0008, 0x27490000, ++ 0x3E2C0002, 0x0B480000, 0x07615F4A, 0x2D605F4C, ++ 0x0F685F3C, 0x30695F40, 0x3930FFFE, 0x36605F3E, ++ 0x1F090000, 0x10C40BFF, 0x2E605F40, 0x202001A0, ++ 0x04230C04, 0x19600104, 0x3B635F36, 0x328002E8, ++ 0x25200010, 0x19600104, 0x24800431, 0x369700FC, ++ 0x15220003, 0x1F62B438, 0x2C695FCA, 0x04685EDE, ++ 0x19220000, 0x1461B400, 0x1162B406, 0x30380000, ++ 0x36C800A5, 0x2A340080, 0x19C80C16, 0x1E200C27, ++ 0x1B230C17, 0x288000B4, 0x36605EDE, 0x09685EEC, ++ 0x332300A5, 0x19220000, 0x14625EEC, 0x28695EDE, ++ 0x366A5EF0, 0x30380000, 0x27C80104, 0x01198000, ++ 0x2E6A5F02, 0x01198000, 0x336A5EA0, 0x24D000B4, ++ 0x3C36FDFF, 0x01625EA0, 0x288000B4, 0x22215EDE, ++ 0x1F220006, 0x14970FB4, 0x2F215EEC, 0x21510000, ++ 0x21510000, 0x21884000, 0x1F220030, 0x1F62B438, ++ 0x21695FCE, 0x19685EF0, 0x19220000, 0x0161B420, ++ 0x0462B426, 0x30380000, 0x3AC800A6, 0x2A340080, ++ 0x09C80C3C, 0x17200C42, 0x0B230C3D, 0x288000B4, ++ 0x2B605EF0, 0x11685EFE, 0x3F2300A6, 0x19220000, ++ 0x0C625EFE, 0x17800C1B, 0x3F215EF0, 0x1F220006, ++ 0x14970FB4, 0x37215EFE, 0x21510000, 0x21510000, ++ 0x21884000, 0x1F220300, 0x1F62B438, 0x21695FCE, ++ 0x01685F02, 0x19220000, 0x0261B440, 0x0762B446, ++ 0x30380000, 0x3DC800A7, 0x2A340080, 0x08C80C57, ++ 0x0B200C5D, 0x02230C58, 0x288000B4, 0x33605F02, ++ 0x19685F10, 0x382300A7, 0x19220000, 0x04625F10, ++ 0x17800C1B, 0x27215F02, 0x1F220006, 0x14970FB4, ++ 0x3F215F10, 0x21510000, 0x21510000, 0x21884000, ++ 0x04685EDE, 0x22215EDE, 0x30380000, 0x1AD00C70, ++ 0x03205EEC, 0x0B518000, 0x0D500000, 0x30695EA0, ++ 0x0D500000, 0x00390200, 0x02615EA0, 0x228B4000, ++ 0x0200C000, 0x1F220006, 0x362300AF, 0x1D800FD7, ++ 0x19685EF0, 0x3F215EF0, 0x30380000, 0x1AD00C70, ++ 0x1B205EFE, 0x0C800C69, 0x01685F02, 0x27215F02, ++ 0x30380000, 0x1AD00C70, 0x13205F10, 0x0C800C69, ++ 0x04685EDE, 0x22215EDE, 0x30380000, 0x36D40C68, ++ 0x398000AF, 0x19685EF0, 0x3F215EF0, 0x30380000, ++ 0x35D000AF, 0x1B205EFE, 0x0C800C69, 0x3B605EEC, ++ 0x1C615EEE, 0x228B4000, 0x23605EFE, 0x14615F00, ++ 0x228B4000, 0x2B605F10, 0x0C615F12, 0x228B4000, ++ 0x19685EF0, 0x1A210000, 0x30380000, 0x0AC80CA5, ++ 0x1F61B434, 0x226A5FCE, 0x0761B426, 0x0262B420, ++ 0x2A340080, 0x0DC80CA4, 0x28635E9C, 0x3F215EF0, ++ 0x1F220006, 0x14970FB4, 0x1A6B5E9C, 0x288000B4, ++ 0x07615EF0, 0x228B4000, 0x2E620116, 0x0F200CA9, ++ 0x288000B4, 0x19970C80, 0x1C6A0116, 0x0D20B404, ++ 0x19500011, 0x01500003, 0x1150C400, 0x0A500001, ++ 0x0E500180, 0x0D500000, 0x0962B414, 0x352000AF, ++ 0x192100AF, 0x362300AF, 0x1D800C8B, 0x01690102, ++ 0x36200000, 0x0A350020, 0x20C80203, 0x30218000, ++ 0x1F615ED4, 0x3B605EDA, 0x3D605EDC, 0x228B4000, ++ 0x2D695ED4, 0x30380000, 0x27C80104, 0x1C390000, ++ 0x1DD40100, 0x3B605EDA, 0x228B4000, 0x2D695ED4, ++ 0x30380000, 0x27C80104, 0x1C390000, 0x1DD40100, ++ 0x3D605EDC, 0x228B4000, 0x01685ED4, 0x27215ED4, ++ 0x30380000, 0x16D40102, 0x21510000, 0x228B4000, ++ 0x30695ECC, 0x07685ED2, 0x1C390000, 0x06D400A4, ++ 0x30380000, 0x31C800A4, 0x342300A4, 0x288000B4, ++ 0x3A215ECC, 0x0B518000, 0x36200000, 0x35605ED2, ++ 0x228B4000, 0x30695ECC, 0x35605ED2, 0x1C390000, ++ 0x30695EA0, 0x1DD40100, 0x12390008, 0x02615EA0, ++ 0x228B4000, 0x336A5EA0, 0x1C685ECC, 0x3A215ECC, ++ 0x2E36FFF7, 0x01625EA0, 0x30380000, 0x16D40102, ++ 0x21510000, 0x228B4000, 0x04685F52, 0x30218000, ++ 0x2D144000, 0x04CC00A9, 0x1A615F52, 0x302300A9, ++ 0x06200CFA, 0x288000B4, 0x29200400, 0x2660B144, ++ 0x06210200, 0x1468B144, 0x3C34000F, 0x2B190000, ++ 0x0A61B144, 0x07645F52, 0x2D010000, 0x20310008, ++ 0x1139A0C8, 0x214B4000, 0x0F2D002C, 0x0E494000, ++ 0x2E020000, 0x06330001, 0x20377F00, 0x1263010A, ++ 0x21320003, 0x1A625F68, 0x2E020000, 0x1032FFF8, ++ 0x313A4001, 0x11625F6A, 0x2E020000, 0x1132FFFF, ++ 0x2E2E0D17, 0x04230D2B, 0x0E8A4000, 0x15205F7A, ++ 0x228B4000, 0x12205F82, 0x228B4000, 0x1C205F8A, ++ 0x228B4000, 0x01205F92, 0x228B4000, 0x0F205F9A, ++ 0x228B4000, 0x07205FA2, 0x228B4000, 0x09205FAA, ++ 0x228B4000, 0x14205FB2, 0x228B4000, 0x1A205FBA, ++ 0x228B4000, 0x04205FC2, 0x228B4000, 0x38605F6C, ++ 0x27490000, 0x3E2C0002, 0x084B0000, 0x3E2C0002, ++ 0x244A0000, 0x3E2C0002, 0x0B480000, 0x1F615F58, ++ 0x38635F56, 0x17625F5A, 0x3E605F5C, 0x1E970E3D, ++ 0x236A5F5C, 0x266B010C, 0x1F3A0000, 0x01C80D47, ++ 0x19213000, 0x35098000, 0x190B4000, 0x3061010E, ++ 0x39C00D42, 0x27CC0E5C, 0x0A685F5A, 0x04230D47, ++ 0x33635F54, 0x046B5F68, 0x07800E42, 0x0F69010A, ++ 0x0A6B5F56, 0x20310008, 0x08C80D78, 0x2E6A5F58, ++ 0x05390080, 0x162E0035, 0x0E458000, 0x0C970D8F, ++ 0x04685F52, 0x1B230D54, 0x16341000, 0x3ECC1043, ++ 0x3A2000A0, 0x00645F53, 0x2D695F58, 0x34970284, ++ 0x0269010E, 0x1A223000, 0x350A4000, 0x0BC80D74, ++ 0x28680108, 0x25620114, 0x30380000, 0x12C80D61, ++ 0x0A970CA6, 0x15970C7A, 0x0269010E, 0x1B20B444, ++ 0x19500011, 0x0A500001, 0x1150C400, 0x0A500001, ++ 0x2335FFFF, 0x15410000, 0x176A0114, 0x3E2C0002, ++ 0x0D500000, 0x1F62B454, 0x0B200D72, 0x27210D72, ++ 0x362300AF, 0x0B800C91, 0x35203000, 0x1C60010E, ++ 0x1A210000, 0x36610108, 0x1A615F52, 0x398000AF, ++ 0x19220000, 0x3662015E, 0x228B4000, 0x1D210001, ++ 0x3561015E, 0x1260015C, 0x38635F56, 0x00970E1F, ++ 0x076B5F52, 0x0A685F6C, 0x3F37000F, 0x293B0100, ++ 0x2563B144, 0x25695F56, 0x3E2C0002, 0x15410000, ++ 0x26695F5A, 0x3E2C0002, 0x15410000, 0x20695F5C, ++ 0x3E2C0002, 0x15410000, 0x17800D58, 0x04685F52, ++ 0x3569B140, 0x3930FFFE, 0x3CD003A0, 0x33635F54, ++ 0x09300002, 0x02030000, 0x3C34000F, 0x3D3CFFFF, ++ 0x33228000, 0x1A120000, 0x301D8000, 0x0761B140, ++ 0x336A5EA0, 0x2BCC0DA0, 0x2D36FFFB, 0x01625EA0, ++ 0x3D3CFFFF, 0x3A225F7A, 0x3530FFFD, 0x1F060000, ++ 0x22520000, 0x22520000, 0x153B2000, 0x07685F32, ++ 0x35635F52, 0x1A344000, 0x09C80DB0, 0x0A685F36, ++ 0x2E9700B4, 0x02685F54, 0x362300AF, 0x288000B4, ++ 0x04685F52, 0x3569B140, 0x1F238000, 0x3C34000F, ++ 0x2E020000, 0x123EFFFF, 0x1C138000, 0x2819C000, ++ 0x0761B140, 0x3F30FFF8, 0x2838A084, 0x18500020, ++ 0x3B680118, 0x2E695F54, 0x0418C000, 0x09600118, ++ 0x351CC000, 0x2BCC0DFA, 0x2361011E, 0x07685F68, ++ 0x0763011C, 0x0260011A, 0x15970C7A, 0x336B011A, ++ 0x1B20B444, 0x1C500041, 0x0A500001, 0x0E500180, ++ 0x0D500000, 0x2D02C000, 0x2636FF00, 0x0262B44C, ++ 0x363700FF, 0x2563B44E, 0x3F222000, 0x1F62B454, ++ 0x3E6B011E, 0x36200000, 0x0F60011E, 0x333B0000, ++ 0x3ECC0DDA, 0x362300AF, 0x08200DDD, 0x24210DDD, ++ 0x0B800C91, 0x3668011C, 0x3569B140, 0x146A0118, ++ 0x1A1D0000, 0x0761B140, 0x191E0000, 0x26620118, ++ 0x19C80DF6, 0x36200000, 0x1D210001, 0x28038000, ++ 0x2E174000, 0x39CC0DED, 0x322C0001, 0x1231FFFF, ++ 0x07800DE7, 0x2861011C, 0x0E300003, 0x2B695F32, ++ 0x0260011A, 0x36354000, 0x1FC80DC6, 0x19200DC6, ++ 0x096B5F36, 0x288000B4, 0x07685F32, 0x26695F36, ++ 0x1A344000, 0x33C800AF, 0x0D894000, 0x1F3A0000, ++ 0x3AC803A0, 0x3B635F36, 0x1A6B5F4A, 0x19600104, ++ 0x3E610106, 0x19625F3E, 0x23635F48, 0x1D970C74, ++ 0x2B680104, 0x0F6A0106, 0x116B5F48, 0x2360B428, ++ 0x3C21B42A, 0x21510000, 0x0200C000, 0x0934FF00, ++ 0x281A0000, 0x0162B42C, 0x363700FF, 0x2663B42E, ++ 0x2B6A5F3E, 0x27200041, 0x2060B424, 0x1C62B434, ++ 0x36210E03, 0x362300AF, 0x12940C8E, 0x096B5F36, ++ 0x228B4000, 0x3B635F36, 0x39200120, 0x1A210000, ++ 0x0C220020, 0x1C6B5F4C, 0x1A800DFF, 0x33635F54, ++ 0x0F6B5F6A, 0x3A200140, 0x1A210000, 0x0C220020, ++ 0x3B605F60, 0x1C615F62, 0x12625F66, 0x36635F5E, ++ 0x15970C7A, 0x09685F60, 0x2D6A5F62, 0x046B5F5E, ++ 0x2060B448, 0x3F21B44A, 0x21510000, 0x0200C000, ++ 0x0934FF00, 0x281A0000, 0x0262B44C, 0x363700FF, ++ 0x2563B44E, 0x206A5F66, 0x27200041, 0x2360B444, ++ 0x1F62B454, 0x16200E5A, 0x21210E28, 0x362300AF, ++ 0x0B800C91, 0x33635F54, 0x36200000, 0x16210140, ++ 0x0F22002C, 0x0F6B5F6A, 0x3B605F60, 0x1C615F62, ++ 0x12625F66, 0x36635F5E, 0x15970C7A, 0x286A5F5E, ++ 0x09685F60, 0x2E695F62, 0x28038000, 0x0A37FF00, ++ 0x0418C000, 0x2060B448, 0x1A3600FF, 0x0462B44A, ++ 0x0161B44C, 0x36200000, 0x2660B44E, 0x206A5F66, ++ 0x22200011, 0x2360B444, 0x1F62B454, 0x2A210E46, ++ 0x362300AF, 0x0E940C91, 0x016B5F54, 0x228B4000, ++ 0x0B210041, 0x08800D4B, 0x08210021, 0x08800D4B, ++ 0x2E6A5F58, 0x04690164, 0x012E0028, 0x1C390000, ++ 0x01D00E71, 0x1F090000, 0x1531FFFE, 0x2B680168, ++ 0x3F418000, 0x2F34001F, 0x112E0002, 0x13408000, ++ 0x2B008000, 0x3E2C0002, 0x0D500000, 0x0D500000, ++ 0x228B4000, 0x1C208000, 0x13408000, 0x36200000, ++ 0x1C800E6A, 0x01685F58, 0x1A210000, 0x2E2C0028, ++ 0x0D500000, 0x0D500000, 0x0D500000, 0x15410000, ++ 0x228B4000, 0x0A230D4F, 0x0F3607FC, 0x3AC803A0, ++ 0x33635F54, 0x026B5F58, 0x12625F66, 0x010CC000, ++ 0x084B0000, 0x3E2C0002, 0x0B480000, 0x33635F62, ++ 0x2D6B010E, 0x36605F64, 0x2D0DC000, 0x36610108, ++ 0x0E970C64, 0x02685F62, 0x28695F64, 0x3B60B40C, ++ 0x1C61B40E, 0x28680108, 0x206A5F66, 0x2921B40A, ++ 0x3660B408, 0x21510000, 0x28200081, 0x3560B404, ++ 0x0962B414, 0x02685F54, 0x20210E8C, 0x362300AF, ++ 0x1D800C8B, 0x2D695F6E, 0x1C208000, 0x28150000, ++ 0x17C80EA2, 0x228B4000, 0x336A5EA0, 0x33605F6E, ++ 0x14200EA8, 0x2B36FFFD, 0x01625EA0, 0x288000B4, ++ 0x15685FDC, 0x2D695F6E, 0x30380000, 0x08C80F0B, ++ 0x28605F70, 0x232C0040, 0x27490000, 0x2E655F6E, ++ 0x3865B112, 0x1F31FFFB, 0x232D4010, 0x0D4A4000, ++ 0x1F6BB110, 0x122D0002, 0x1F0AC000, 0x24C00EFF, ++ 0x214B4000, 0x2C2DFFF6, 0x333B0000, 0x25D40EC4, ++ 0x1A685F70, 0x012D0012, 0x0D4A4000, 0x282C0042, ++ 0x084B0000, 0x312DFFEE, 0x1F1F8000, 0x3CCC0F01, ++ 0x28004000, 0x37215F72, 0x02970FF4, 0x3D695F72, ++ 0x332C0006, 0x13350003, 0x3DCC0F06, 0x37215F72, ++ 0x2922FFFC, 0x1C97100A, 0x1A685F70, 0x33215FDC, ++ 0x1D970F72, 0x1797103E, 0x0E970C64, 0x196B5F70, ++ 0x11685F72, 0x3B695F74, 0x2A22B40A, 0x3563B408, ++ 0x22520000, 0x3B60B40C, 0x1C61B40E, 0x28200081, ++ 0x3560B404, 0x20200040, 0x2660B414, 0x21210ED1, ++ 0x362300AF, 0x18940C8B, 0x01685F6E, 0x39695FEA, ++ 0x353400FF, 0x3330FFFB, 0x0A2C401A, 0x084B0000, ++ 0x1E2D0001, 0x312F0001, 0x3A430000, 0x002CFFF6, ++ 0x244A0000, 0x332C0006, 0x084B0000, 0x0B615FEA, ++ 0x312F0001, 0x1F0AC000, 0x17C40EF4, 0x35230000, ++ 0x3A430000, 0x2E6A5F6E, 0x1A685F70, 0x1A3600FF, ++ 0x3A3A1000, 0x1462B130, 0x15970F4A, 0x1C208000, ++ 0x33605F6E, 0x17230EA8, 0x33800126, 0x0D210088, ++ 0x29655F6F, 0x1A685F70, 0x2D695F6E, 0x3D2C0038, ++ 0x0B480000, 0x13800EAA, 0x20970106, 0x1A685F70, ++ 0x33215FDC, 0x19230EFA, 0x1B800F72, 0x336A5EA0, ++ 0x3C350800, 0x1F615F6E, 0x33C800AF, 0x143A0002, ++ 0x01625EA0, 0x398000AF, 0x1768B148, 0x05300001, ++ 0x1DD00F1B, 0x03300007, 0x19D00F20, 0x0C300008, ++ 0x3D3CFFFF, 0x1464B148, 0x388000A8, 0x35230000, ++ 0x2663B148, 0x39635FF2, 0x32635FF0, 0x19800F15, ++ 0x0E710048, 0x13710149, 0x2871804B, 0x1E800F22, ++ 0x00685FFC, 0x276AB1F8, 0x0934FF00, 0x0C300008, ++ 0x322C0001, 0x03361F00, 0x23320008, 0x1C0A0000, ++ 0x1DC0010A, 0x3F225E90, 0x3330FFFB, 0x1C2C4000, ++ 0x1C0A0000, 0x15C00104, 0x2F605FD2, 0x06625FD4, ++ 0x242A000F, 0x03C000FE, 0x228B4000, 0x10685FD6, ++ 0x37695FD4, 0x30380000, 0x04C80F3E, 0x27490000, ++ 0x0E615FD6, 0x228B4000, 0x33290044, 0x28C00F46, ++ 0x1D685FD2, 0x05615FD4, 0x2D010000, 0x022D0044, ++ 0x03615FD2, 0x228B4000, 0x361C0000, 0x2F605FD2, ++ 0x29605FD4, 0x228B4000, 0x3C695FD6, 0x30380000, ++ 0x27C80104, 0x15410000, 0x22605FD6, 0x228B4000, ++ 0x1C390000, 0x31C800FE, 0x0D4A4000, 0x30380000, ++ 0x27C80104, 0x10404000, 0x1F3A0000, 0x07C80F5E, ++ 0x362C003A, 0x16420000, 0x122E0038, 0x062CFFC6, ++ 0x13408000, 0x228B4000, 0x222DFFFE, 0x10404000, ++ 0x228B4000, 0x1C390000, 0x31C800FE, 0x0D4A4000, ++ 0x30380000, 0x27C80104, 0x10404000, 0x1F3A0000, ++ 0x06C80F6F, 0x3D2C0038, 0x16420000, 0x192E003A, ++ 0x0E2CFFC8, 0x13408000, 0x228B4000, 0x122D0002, ++ 0x10404000, 0x228B4000, 0x1C390000, 0x31C800FE, ++ 0x30380000, 0x27C80104, 0x2D635E96, 0x362C003A, ++ 0x084B0000, 0x0E2CFFFE, 0x244A0000, 0x333B0000, ++ 0x19C80F85, 0x1F3A0000, 0x0BC80F92, 0x3E2F0038, ++ 0x1542C000, 0x192E003A, 0x0D2FFFC8, 0x10438000, ++ 0x1D800F8D, 0x3F424000, 0x1F3A0000, 0x11C80F8B, ++ 0x192E003A, 0x10438000, 0x1D800F8D, 0x122D0002, ++ 0x3F424000, 0x0D500000, 0x0D500000, 0x1F6B5E96, ++ 0x0D2CFFC4, 0x228B4000, 0x122D0002, 0x3F424000, ++ 0x3E2F0038, 0x1542C000, 0x1D800F8D, 0x2A320001, ++ 0x0A367FFF, 0x03C80FAA, 0x252A0008, 0x32C00FA6, ++ 0x0D500000, 0x0D500000, 0x0D500000, 0x0D500000, ++ 0x0D500000, 0x0D500000, 0x0D500000, 0x0D500000, ++ 0x03C80FAA, 0x0F800F9A, 0x26260008, 0x0D500000, ++ 0x262EFFFF, 0x36CC0FA7, 0x228B4000, 0x26635E94, ++ 0x14970FB4, 0x146B5E94, 0x288000B4, 0x26635E94, ++ 0x14970FB4, 0x02030000, 0x17685E94, 0x288000B4, ++ 0x22484000, 0x0F615E92, 0x28605E90, 0x0C300008, ++ 0x2BD40FD5, 0x2D635E96, 0x2C34007F, 0x3E30FFFF, ++ 0x122D0002, 0x2E0D0000, 0x214B4000, 0x05300001, ++ 0x322C0001, 0x36695E90, 0x191E0000, 0x3ECC0FC5, ++ 0x36200000, 0x07024000, 0x36368000, 0x0035007F, ++ 0x1A1D0000, 0x3D695E92, 0x1AC80FD3, 0x23320008, ++ 0x281A0000, 0x1E2D0001, 0x0E464000, 0x0200C000, ++ 0x1F6B5E96, 0x30380000, 0x228B4000, 0x3F424000, ++ 0x00800FCF, 0x361C0000, 0x228B4000, 0x28605E90, ++ 0x22484000, 0x0A625E94, 0x0C300008, 0x3FD40FF2, ++ 0x2E020000, 0x0C300008, 0x2C34007F, 0x0336007F, ++ 0x191E0000, 0x31C800FE, 0x3E30FFFF, 0x356A5E90, ++ 0x0F615E92, 0x122D0002, 0x2E0D0000, 0x3F424000, ++ 0x386A5E94, 0x3D695E92, 0x05300001, 0x322C0001, ++ 0x191E0000, 0x2ECC0FEF, 0x36200000, 0x29380080, ++ 0x21444000, 0x228B4000, 0x36200000, 0x16800FE3, ++ 0x2D635E96, 0x084B0000, 0x3E2C0002, 0x13434000, ++ 0x244A0000, 0x122D0002, 0x3F424000, 0x2E1B8000, ++ 0x3E2C0002, 0x244A0000, 0x122D0002, 0x3F424000, ++ 0x2E1B8000, 0x3E2C0002, 0x244A0000, 0x122D0002, ++ 0x3F424000, 0x2B1AC000, 0x1F6B5E96, 0x3E2C0002, ++ 0x122D0002, 0x228B4000, 0x28605E90, 0x0F615E92, ++ 0x2D635E96, 0x27490000, 0x280C8000, 0x0B480000, ++ 0x1C390000, 0x14C81031, 0x03340FFC, 0x0FC81019, ++ 0x15280041, 0x3DC01019, 0x16240041, 0x15072000, ++ 0x0480101E, 0x1831FFFA, 0x07024000, 0x2936FFC0, ++ 0x2B034000, 0x3937003F, 0x3D695E92, 0x22484000, ++ 0x1A048000, 0x10404000, 0x122D0002, 0x22484000, ++ 0x2C04C400, 0x10404000, 0x17C41031, 0x122D0002, ++ 0x22484000, 0x19220000, 0x05048400, 0x10404000, ++ 0x17C41031, 0x122D0002, 0x22484000, 0x05048400, ++ 0x10404000, 0x1F6B5E96, 0x1A685E90, 0x228B4000, ++ 0x14685F14, 0x32215F14, 0x30380000, 0x10D0103A, ++ 0x0B518000, 0x228B4000, 0x0200C000, 0x12220002, ++ 0x362300AF, 0x1D800FD7, 0x14685F14, 0x3A215F1A, ++ 0x30380000, 0x10D0103A, 0x228B4000, 0x14685F14, ++ 0x32215F14, 0x30380000, 0x16D40102, 0x2A340080, ++ 0x01C8104B, 0x12220002, 0x03800FAF, 0x21510000, ++ 0x1C685F1A, 0x28635E9C, 0x30380000, 0x26CC1051, ++ 0x228B4000, 0x3A215F1A, 0x12220002, 0x08970FAB, ++ 0x1A6B5E9C, 0x0A80104C, 0x3DFFFFFF, 0x01000000, ++ 0x01000000, 0x01000000 ++}; ++ ++static const uint32_t fw2_farm_img_data_buf[2048] = ++{ ++ 0x132040FA, 0x29502501, 0x032040D0, 0x295046C7, ++ 0x0D500000, 0x267001C9, 0x258C0200, 0x0F70AAC9, ++ 0x176B40C8, 0x3B7000C8, 0x2D70001D, 0x2670001F, ++ 0x18631FFC, 0x3370C033, 0x296A4010, 0x086B4014, ++ 0x39621FF8, 0x16631FF4, 0x15684000, 0x34694004, ++ 0x1E601FF6, 0x3F611FF2, 0x346A4008, 0x156B400C, ++ 0x32621FFA, 0x1B631FF0, 0x3A9700C9, 0x1E684034, ++ 0x2170001E, 0x3A34003F, 0x281A0000, 0x3F621FFE, ++ 0x0628000B, 0x2AC4004F, 0x1D24002F, 0x21884000, ++ 0x2380004F, 0x3A800036, 0x2880004D, 0x2B800041, ++ 0x2380004F, 0x20800043, 0x2080002F, 0x3880003D, ++ 0x26800045, 0x2D800047, 0x25800049, 0x276A4018, ++ 0x34621FFC, 0x3E9701EB, 0x09300002, 0x31D0006D, ++ 0x3930FFFE, 0x3080005F, 0x276A4018, 0x34621FFC, ++ 0x3A970275, 0x09300002, 0x31D0006D, 0x3930FFFE, ++ 0x3180006E, 0x2097032F, 0x268C0400, 0x16614018, ++ 0x3080005F, 0x2297075B, 0x3080005F, 0x3B970714, ++ 0x3080005F, 0x2497075D, 0x3080005F, 0x30970716, ++ 0x3080005F, 0x38230004, 0x29671FFC, 0x3397042A, ++ 0x3080005F, 0x3397078F, 0x3080005F, 0x3B7000C8, ++ 0x24200021, 0x358C5000, 0x2E80007D, 0x2B707FC8, ++ 0x08702084, 0x2D70001D, 0x36200000, 0x2D010000, ++ 0x1E220001, 0x3997009F, 0x01684084, 0x26340020, ++ 0x01CC005A, 0x3920000F, 0x3080005F, 0x238C0100, ++ 0x376A4032, 0x1F36C000, 0x3EC80064, 0x2120002B, ++ 0x09300002, 0x31D0006D, 0x1B601FFC, 0x2A681FF0, ++ 0x246A4014, 0x2D010000, 0x2460400C, 0x3997009F, ++ 0x29681FFC, 0x3930FFFE, 0x036A1FF6, 0x276B1FF8, ++ 0x08624000, 0x37634010, 0x0D6A1FFE, 0x279700D1, ++ 0x0E6A1FF2, 0x246B1FF4, 0x05624004, 0x3A634014, ++ 0x006A1FFA, 0x35230000, 0x06624008, 0x358C5000, ++ 0x3463401C, 0x106440C9, 0x3C800006, 0x376B1FE4, ++ 0x228B4000, 0x3C6B1FE6, 0x228B4000, 0x2C681FF6, ++ 0x252DFFFF, 0x07024000, 0x2F36FFF0, 0x21320003, ++ 0x3930FFFE, 0x1F060000, 0x0E4A8000, 0x28004000, ++ 0x3C34000F, 0x1A120000, 0x228B4000, 0x24681FF8, ++ 0x3330FFFB, 0x00601FE2, 0x228B4000, 0x3F8C0480, ++ 0x33BC0053, 0x1B61401C, 0x228B4000, 0x2D010000, ++ 0x3930FFFE, 0x0D500000, 0x0D500000, 0x0D500000, ++ 0x0D500000, 0x09300002, 0x202A0002, 0x0B614000, ++ 0x1B624010, 0x29604008, 0x1D218808, 0x3C800093, ++ 0x0B631FEC, 0x0B614000, 0x086A1FF4, 0x2D010000, ++ 0x1668400C, 0x1B624010, 0x299700D9, 0x18684004, ++ 0x0D691FF2, 0x086A1FF4, 0x396B1FEC, 0x2F8000EF, ++ 0x37694008, 0x268C0400, 0x0D684024, 0x04140000, ++ 0x19D400B7, 0x36200000, 0x228B4000, 0x00240001, ++ 0x1A084000, 0x228B4000, 0x3930FFFE, 0x15410000, ++ 0x0C240002, 0x0D500000, 0x09300002, 0x262EFFFF, ++ 0x31800097, 0x13684030, 0x37380001, 0x21604030, ++ 0x228B4000, 0x13684030, 0x0834FFFE, 0x21604030, ++ 0x228B4000, 0x386A40C4, 0x3F694030, 0x1B360001, ++ 0x1732FFF9, 0x18350001, 0x1831FFFA, 0x011A4000, ++ 0x228B4000, 0x07018000, 0x28310006, 0x18350001, ++ 0x0D614030, 0x2C320007, 0x1B360001, 0x0A6240C4, ++ 0x228B4000, 0x29604008, 0x06614004, 0x16624014, ++ 0x37218001, 0x268C0400, 0x1B61401C, 0x2A694010, ++ 0x27604000, 0x36064000, 0x1B624010, 0x228B4000, ++ 0x29604008, 0x06614004, 0x16624014, 0x2D218018, ++ 0x268C0400, 0x1B61401C, 0x296A4010, 0x27604000, ++ 0x2F260001, 0x1B624010, 0x228B4000, 0x29604008, ++ 0x06614004, 0x16624014, 0x262EFFFF, 0x36058000, ++ 0x1531FFFE, 0x22484000, 0x20250002, 0x0E494000, ++ 0x2B190000, 0x0ACC00FB, 0x16624014, 0x1B684008, ++ 0x2C218200, 0x268C0400, 0x1B61401C, 0x246A4014, ++ 0x27604000, 0x1B624010, 0x228B4000, 0x1C2100FF, ++ 0x26800106, 0x1A210000, 0x05631FE4, 0x24611FEC, ++ 0x21681FF2, 0x2B6040A0, 0x0B691FF4, 0x27604000, ++ 0x29604008, 0x18614010, 0x268C0400, 0x0970081C, ++ 0x2470881D, 0x0FF00111, 0x3930FFFE, 0x27490000, ++ 0x29310001, 0x3A200003, 0x18D4007F, 0x1231FFFF, ++ 0x286540B4, 0x216B1FFE, 0x036A1FF6, 0x3D33FFFF, ++ 0x38D00127, 0x276B1FF8, 0x08624000, 0x06624008, ++ 0x37634010, 0x268C0400, 0x3C70011F, 0x0970081C, ++ 0x2470881D, 0x04F00125, 0x3B800128, 0x268C0400, ++ 0x196840A0, 0x21694024, 0x1F090000, 0x39C801E9, ++ 0x07024000, 0x1D2E0001, 0x16624014, 0x1F31FFFB, ++ 0x0E684028, 0x2670001F, 0x2F34001F, 0x2E184000, ++ 0x322C0001, 0x2E020000, 0x09240008, 0x1334FFE0, ++ 0x08300005, 0x0B691FF4, 0x206040A2, 0x2D6040A6, ++ 0x322C0001, 0x1F090000, 0x3DC4014B, 0x356940A0, ++ 0x1C050000, 0x252DFFFF, 0x1531FFFE, 0x21510000, ++ 0x21510000, 0x03691FFA, 0x1C050000, 0x252DFFFF, ++ 0x1531FFFE, 0x21510000, 0x21510000, 0x322C0001, ++ 0x16691FEC, 0x0834FFFE, 0x2B3D00FF, 0x12CC0153, ++ 0x27681FF4, 0x0B240003, 0x0834FFFE, 0x08601FEC, ++ 0x2B26000C, 0x21621FEA, 0x2226005F, 0x35200060, ++ 0x35230000, 0x160B2000, 0x252DFFFF, 0x026140AA, ++ 0x1E2D0001, 0x15072000, 0x3F6B1FEA, 0x28004000, ++ 0x3530FFFD, 0x1F0AC000, 0x35230000, 0x0D631FEA, ++ 0x160B2000, 0x3520000C, 0x35230000, 0x29290007, ++ 0x28C4016B, 0x2A250007, 0x2080016C, 0x1B210007, ++ 0x1A084000, 0x2D1B4000, 0x33634088, 0x306940AA, ++ 0x3530FFFD, 0x1E2D0001, 0x15072000, 0x252A0008, ++ 0x2A621FE8, 0x2B008000, 0x1D2E0001, 0x1334FFE0, ++ 0x08300005, 0x322C0001, 0x296B1FF0, 0x16691FEC, ++ 0x03601FEE, 0x1A074000, 0x24634000, 0x3A33FFFE, ++ 0x0E530000, 0x0E530000, 0x0E530000, 0x0E530000, ++ 0x0A330002, 0x2A634008, 0x33070000, 0x0B2B0003, ++ 0x09280004, 0x13C001A1, 0x322C0001, 0x34604010, ++ 0x268C0400, 0x3C70011F, 0x2A70001C, 0x2470881D, ++ 0x11F00190, 0x0E691FFE, 0x0D684024, 0x1231FFFF, ++ 0x20D001A0, 0x00691FF6, 0x04140000, 0x37D001E7, ++ 0x1A084000, 0x22694028, 0x0335001F, 0x3330FFFB, ++ 0x2E184000, 0x3DC801E4, 0x322C0001, 0x00601FE2, ++ 0x2670001F, 0x2B008000, 0x3D3CFFFF, 0x30218000, ++ 0x19110000, 0x3A33FFFE, 0x20340010, 0x25C801AC, ++ 0x1641C000, 0x0F270002, 0x0E530000, 0x248001AE, ++ 0x0E530000, 0x1641C000, 0x31681FEE, 0x356940A0, ++ 0x34604010, 0x166B4000, 0x3304C000, 0x322C0001, ++ 0x0834FFFE, 0x06614004, 0x29604008, 0x0568401C, ++ 0x268C0400, 0x3C70011F, 0x2A70001C, 0x1B70821D, ++ 0x07F001BC, 0x3D340008, 0x2DC801CE, 0x0E691FFE, ++ 0x0D684024, 0x1231FFFF, 0x2BD001CE, 0x00691FF6, ++ 0x04140000, 0x37D001E7, 0x1A084000, 0x22694028, ++ 0x3330FFFB, 0x0335001F, 0x2E184000, 0x3DC801E4, ++ 0x322C0001, 0x00601FE2, 0x2670001F, 0x1B691FE8, ++ 0x3E20000E, 0x29310001, 0x1231FFFF, 0x36D001D6, ++ 0x092CFFFF, 0x378001D2, 0x39694000, 0x0C2207FA, ++ 0x186B4008, 0x096140A8, 0x256340A4, 0x076240AC, ++ 0x236040AE, 0x2E7000B2, 0x3F8C0480, 0x33BC0053, ++ 0x31700484, 0x32E001E1, 0x31200001, 0x2580007F, ++ 0x3F200009, 0x2670001F, 0x2580007F, 0x3C200005, ++ 0x308001E5, 0x37200007, 0x308001E5, 0x08631FE0, ++ 0x35230000, 0x25671FFF, 0x227001C4, 0x2C970105, ++ 0x063C0001, 0x2EC801F4, 0x063C0001, 0x2F80023F, ++ 0x2F681FFA, 0x05691FFC, 0x266040A4, 0x3A8C0180, ++ 0x33BC0053, 0x2D3D0000, 0x3DC80241, 0x34700184, ++ 0x25E001FC, 0x3B6940A8, 0x126840A2, 0x0B614000, ++ 0x322C0001, 0x296B1FF0, 0x34604010, 0x2A634008, ++ 0x3A8C0180, 0x33BC0053, 0x2A70001C, 0x2470881D, ++ 0x05691FFC, 0x252DFFFF, 0x39C80220, 0x28004000, ++ 0x0034FFF0, 0x3420000B, 0x14CC023F, 0x156A1FEC, ++ 0x0200C000, 0x1A048000, 0x266340A8, 0x256340A4, ++ 0x3F8C0480, 0x33BC0053, 0x34700184, 0x3BE00217, ++ 0x256040A8, 0x1A048000, 0x3A8C0180, 0x33BC0053, ++ 0x32700284, 0x3EE0021D, 0x252DFFFF, 0x00CC0218, ++ 0x2A681FF0, 0x16691FEC, 0x1C050000, 0x036A1FF6, ++ 0x316B1FE2, 0x256040A8, 0x0A6140A4, 0x076240AC, ++ 0x29681FFC, 0x0C2B0002, 0x092CFFFF, 0x206340AE, ++ 0x336040B2, 0x2C8C5080, 0x33BC0053, 0x31700484, ++ 0x2FE00230, 0x06691FF0, 0x3D201FE8, 0x096140A8, ++ 0x0A500001, 0x0F280002, 0x09300002, 0x266040A4, ++ 0x36200000, 0x2D6040A6, 0x3A8C0180, 0x33BC0053, ++ 0x34700184, 0x2BE0023D, 0x31200001, 0x3A6B1FE0, ++ 0x228B4000, 0x06691FF0, 0x156A1FEC, 0x28004000, ++ 0x1A048000, 0x03601FEE, 0x2D010000, 0x1A048000, ++ 0x3D6A40A2, 0x266040A4, 0x1D2E0001, 0x3997009F, ++ 0x03691FFA, 0x31681FEE, 0x3997009F, 0x2A681FF0, ++ 0x1D210001, 0x269700BA, 0x31681FEE, 0x386940A4, ++ 0x2C97026F, 0x2A681FF0, 0x268C0400, 0x2C97026F, ++ 0x2A97008F, 0x1E691FE2, 0x2D3D0000, 0x2DC80231, ++ 0x29970083, 0x2C611FE2, 0x1B360001, 0x10CC0268, ++ 0x38200008, 0x31681FEE, 0x06691FF0, 0x2C97026F, ++ 0x2A681FF0, 0x25230259, 0x2D010000, 0x2A80026F, ++ 0x2A681FF0, 0x1D691FEE, 0x2C97026F, 0x31681FEE, ++ 0x25230259, 0x2D010000, 0x2A80026F, 0x0A6140A4, ++ 0x256040A8, 0x3A8C0180, 0x33BC0053, 0x34700184, ++ 0x228B4000, 0x0E631FE6, 0x3E9702B7, 0x259702C5, ++ 0x39681FD6, 0x0E6A1FF2, 0x00691FF6, 0x276B1FF8, ++ 0x1F060000, 0x03270001, 0x0B37FFFE, 0x1F05C000, ++ 0x296B1FF0, 0x32611FF6, 0x3304C000, 0x3C621FF2, ++ 0x1D601FFA, 0x18601FF0, 0x268C0400, 0x3E9701EB, ++ 0x02030000, 0x053F0001, 0x0FCC02B4, 0x238C0100, ++ 0x166A1FD6, 0x06691FF0, 0x28004000, 0x35098000, ++ 0x1A048000, 0x3997009F, 0x2D010000, 0x15684000, ++ 0x35098000, 0x35068000, 0x3997009F, 0x276B1FF8, ++ 0x00691FF6, 0x03270001, 0x0B37FFFE, 0x1C09C000, ++ 0x3A6B1FD6, 0x0E6A1FF2, 0x32611FF6, 0x1F0AC000, ++ 0x3C621FF2, 0x268C0400, 0x3E9701EB, 0x326B1FD8, ++ 0x166A1FD6, 0x06691FF0, 0x1E631FFA, 0x35098000, ++ 0x34611FF0, 0x02030000, 0x053F0001, 0x0FCC02B4, ++ 0x238C0100, 0x1A210000, 0x299702F0, 0x2B97031B, ++ 0x2A681FF0, 0x2460400C, 0x268C0400, 0x31200001, ++ 0x24800081, 0x37200007, 0x348002B4, 0x0B631FEC, ++ 0x0D691FF2, 0x006A1FFA, 0x06614004, 0x0B691FF4, ++ 0x2C621FD8, 0x15614014, 0x2D3D0000, 0x39C802B5, ++ 0x28004000, 0x0C240002, 0x0834FFFE, 0x0B601FD6, ++ 0x228B4000, 0x0B631FEC, 0x349700C1, 0x39681FD6, ++ 0x296B1FF0, 0x30040000, 0x33070000, 0x0F270002, ++ 0x2763400C, 0x19220000, 0x21681FF2, 0x16624014, ++ 0x1A048000, 0x2A604004, 0x086A1FF4, 0x2D010000, ++ 0x3997009F, 0x239700B0, 0x0F280002, 0x0BC002B5, ++ 0x0C240002, 0x246A4014, 0x39604014, 0x0B691FF4, ++ 0x296B1FF0, 0x35054000, 0x24634000, 0x18614010, ++ 0x156B400C, 0x2C218200, 0x19078000, 0x2A634008, ++ 0x3A970093, 0x18684004, 0x0D691FF2, 0x166A1FD6, ++ 0x1A1D0000, 0x2BC802CE, 0x3A69400C, 0x2A681FF0, ++ 0x35068000, 0x3997009F, 0x396B1FEC, 0x3F8000C5, ++ 0x0B631FEC, 0x2A681FF0, 0x1A048000, 0x2460400C, ++ 0x1A048000, 0x0C240002, 0x19044000, 0x086A1FF4, ++ 0x0D691FF2, 0x3930FFFE, 0x0D500000, 0x0D500000, ++ 0x09300002, 0x3997009F, 0x239700B0, 0x39604014, ++ 0x1B684008, 0x156B400C, 0x2F260001, 0x06691FF0, ++ 0x03280001, 0x1B624010, 0x29604008, 0x06614004, ++ 0x24634000, 0x2C2A0001, 0x36058000, 0x1531FFFE, ++ 0x21510000, 0x21510000, 0x19078000, 0x3A33FFFE, ++ 0x0E530000, 0x0E530000, 0x3B218002, 0x3A970093, ++ 0x23260002, 0x1B624010, 0x246A4014, 0x03691FFA, ++ 0x1B684008, 0x396B1FEC, 0x2F8000D9, 0x0B631FEC, ++ 0x349700C1, 0x166B4000, 0x1668400C, 0x2763400C, ++ 0x0D691FF2, 0x246A4014, 0x299700EF, 0x3A6B1FD6, ++ 0x0D691FF2, 0x1668400C, 0x1F05C000, 0x086A1FF4, ++ 0x299700D9, 0x2A681FF0, 0x086A1FF4, 0x2D010000, ++ 0x2B9700E4, 0x396B1FEC, 0x3F8000C5, 0x05631FE4, ++ 0x2A681FF0, 0x2460400C, 0x08691FF8, 0x29611FDE, ++ 0x086A1FF4, 0x21621FDC, 0x350A4000, 0x040E4000, ++ 0x02D4033A, 0x07024000, 0x24260003, 0x2736FFFE, ++ 0x00601FE2, 0x1A048000, 0x0B601FE0, 0x1A048000, ++ 0x35068000, 0x37621FF0, 0x1A048000, 0x0B601FD6, ++ 0x1668400C, 0x37970097, 0x056A1FF0, 0x1668400C, ++ 0x1A048000, 0x37970097, 0x0B6A1FF8, 0x32681FE2, ++ 0x296B1FF0, 0x3304C000, 0x00691FF6, 0x3997009F, ++ 0x268C0400, 0x0E6B4024, 0x05631FD2, 0x1A378000, ++ 0x09CC041D, 0x39681FE0, 0x296B1FF0, 0x3304C000, ++ 0x0D691FF2, 0x086A1FF4, 0x3997009F, 0x32681FE2, ++ 0x3930FFFE, 0x0A500001, 0x39681FE0, 0x0D691FF2, ++ 0x3997009F, 0x3B201FD8, 0x0D500000, 0x0D500000, ++ 0x0D691FF2, 0x1531FFFE, 0x0E494000, 0x29310001, ++ 0x0DD40420, 0x1231FFFF, 0x36200000, 0x00601FD4, ++ 0x32230001, 0x1E220001, 0x0200C000, 0x2E148000, ++ 0x2CC80375, 0x32681FD4, 0x1A048000, 0x00601FD4, ++ 0x1A074000, 0x35054000, 0x35068000, 0x0CCC036E, ++ 0x32681FE2, 0x296B1FF0, 0x3304C000, 0x1A210000, ++ 0x186A1FDE, 0x3B970424, 0x3930FFFE, 0x0B480000, ++ 0x1A388000, 0x05300001, 0x23D00385, 0x2C250001, ++ 0x22800381, 0x2D3D0000, 0x28C803B7, 0x268C0400, ++ 0x16614018, 0x26218040, 0x3A970093, 0x32681FD4, ++ 0x1E691FE2, 0x1531FFFE, 0x0E494000, 0x15072000, ++ 0x1D210001, 0x0B6B4018, 0x3E3FFFFF, 0x03270001, ++ 0x1A11C000, 0x252DFFFF, 0x02164000, 0x326B1FD8, ++ 0x268C0400, 0x21694024, 0x2A611FD2, 0x35C803AF, ++ 0x1F1F8000, 0x34C803A8, 0x2C621FD8, 0x21681FF2, ++ 0x0C2107F6, 0x3A970423, 0x1E220001, 0x16624014, ++ 0x39681FD6, 0x29604008, 0x37218001, 0x3A970093, ++ 0x15691FD6, 0x32681FE2, 0x086A1FF4, 0x2F260001, ++ 0x3B970424, 0x23218010, 0x3A970093, 0x32681FE2, ++ 0x1A210000, 0x086A1FF4, 0x2F260001, 0x3B970424, ++ 0x26218040, 0x3A970093, 0x22800378, 0x39681FE0, ++ 0x296B1FF0, 0x3304C000, 0x2A604004, 0x32681FE2, ++ 0x3304C000, 0x27604000, 0x186A1FDE, 0x3F6B1FDC, ++ 0x3A634014, 0x1F0AC000, 0x2E0EC000, 0x04D403C5, ++ 0x2D02C000, 0x1B624010, 0x2F218400, 0x3A970093, ++ 0x18691FD2, 0x1F1C4000, 0x10CC03D2, 0x1531FFFE, ++ 0x22484000, 0x063C0001, 0x122D0002, 0x0E494000, ++ 0x2E184000, 0x30C80413, 0x268C0400, 0x00684020, ++ 0x05300001, 0x3ED0041D, 0x09300002, 0x2AD003E0, ++ 0x15684000, 0x34694004, 0x2A604004, 0x0B614000, ++ 0x06684010, 0x27694014, 0x39604014, 0x18614010, ++ 0x166B4000, 0x2A634008, 0x0E631FD0, 0x25218020, ++ 0x3A970093, 0x23D003E9, 0x39681FE0, 0x1E691FE2, ++ 0x248003EB, 0x32681FE2, 0x15691FE0, 0x086A1FF4, ++ 0x2F260001, 0x3B970424, 0x268C0400, 0x226A4024, ++ 0x25218020, 0x3A970093, 0x3F681FD0, 0x1C0A0000, ++ 0x2F260001, 0x15691FE0, 0x296B1FF0, 0x1F05C000, ++ 0x1A1D0000, 0x1ECC0400, 0x32681FE2, 0x15691FE0, ++ 0x0B601FE0, 0x2C611FE2, 0x37681FDE, 0x0E601FDC, ++ 0x2A621FDE, 0x32681FE2, 0x0D691FF2, 0x3A970423, ++ 0x296A4010, 0x1A048000, 0x3930FFFE, 0x268C0400, ++ 0x084B0000, 0x0D500000, 0x0D500000, 0x023F0000, ++ 0x28C80378, 0x23218010, 0x3A970093, 0x052CFFFC, ++ 0x268C0400, 0x0D500000, 0x22800378, 0x1E691FE2, ++ 0x39681FE0, 0x086A1FF4, 0x3997009F, 0x16624014, ++ 0x31200001, 0x1A210000, 0x156B400C, 0x1B631FF0, ++ 0x2580007F, 0x24200017, 0x1B210007, 0x3380041A, ++ 0x3A200003, 0x0621001F, 0x3380041A, 0x086A1FF4, ++ 0x1B624010, 0x16624014, 0x27604000, 0x06614004, ++ 0x29604008, 0x228B4000, 0x0E631FE6, 0x2C681FF6, ++ 0x08691FF8, 0x086A1FF4, 0x1D601FCC, 0x37611FCA, ++ 0x24260003, 0x2736FFFE, 0x39621FCE, 0x2A681FF0, ++ 0x1A048000, 0x1A048000, 0x0B691FF4, 0x0E6A1FF2, ++ 0x3A9706F3, 0x063C0001, 0x2DC8043D, 0x063C0001, ++ 0x2E800458, 0x06691FF0, 0x0B6A1FCE, 0x28004000, ++ 0x1A048000, 0x2460400C, 0x19088000, 0x19088000, ++ 0x358C5000, 0x3D9700A4, 0x06691FF0, 0x0B6A1FCE, ++ 0x28004000, 0x19088000, 0x19088000, 0x18601FF0, ++ 0x3D9700A4, 0x2A681FF0, 0x0B6A1FCE, 0x1D210001, ++ 0x1A048000, 0x1A048000, 0x269700BA, 0x03691FCC, ++ 0x066A1FCA, 0x32611FF6, 0x39621FF8, 0x31200001, ++ 0x268C0400, 0x24800081, 0x0D601FD0, 0x296A4010, ++ 0x15684000, 0x2C621FD8, 0x08601FDA, 0x10691FDC, ++ 0x2A681FF0, 0x216B1FFE, 0x07024000, 0x36064000, ++ 0x071BC000, 0x1AD40467, 0x36064000, 0x37970097, ++ 0x1E6A1FD8, 0x3A681FDA, 0x1B624010, 0x27604000, ++ 0x3F681FD0, 0x063C0001, 0x0FCC0477, 0x216B1FFE, ++ 0x071BC000, 0x33D00475, 0x269706B6, 0x0D601FD0, ++ 0x3680047C, 0x389706A2, 0x3680047C, 0x0D3C0003, ++ 0x0DCC047C, 0x33970489, 0x31200001, 0x0D601FD0, ++ 0x3F681FD0, 0x35230000, 0x2D010000, 0x293D000D, ++ 0x0BCC0483, 0x34230007, 0x3A800486, 0x2E3D000C, ++ 0x30C80486, 0x2923001F, 0x268C0400, 0x39634018, ++ 0x24800081, 0x08631FD6, 0x2A681FF0, 0x03691FFA, ++ 0x086A1FF4, 0x3997009F, 0x16624014, 0x136A1FDC, ++ 0x03691FFA, 0x226B1FF2, 0x1A048000, 0x36058000, ++ 0x06614004, 0x29604008, 0x24634000, 0x25218020, ++ 0x3A970093, 0x0E691FFE, 0x1A048000, 0x02194000, ++ 0x1DD4049F, 0x3930FFFE, 0x0A500001, 0x3A6B1FD6, ++ 0x228B4000, 0x1A048000, 0x3930FFFE, 0x0D500000, ++ 0x0D500000, 0x0D500000, 0x0D500000, 0x228B4000, ++ 0x086A1FF4, 0x1D2E0001, 0x1B624010, 0x0B614000, ++ 0x29604008, 0x268C0400, 0x2A70001C, 0x2470881D, ++ 0x36058000, 0x1A048000, 0x228B4000, 0x27604000, ++ 0x27681FF4, 0x05614008, 0x34604010, 0x268C0400, ++ 0x15624018, 0x2E020000, 0x29218080, 0x3C800093, ++ 0x08631FD6, 0x387000C4, 0x30700090, 0x2A970103, ++ 0x246B1FF4, 0x08270003, 0x0B37FFFE, 0x0D631FDC, ++ 0x2D010000, 0x2A3D0001, 0x238C0100, 0x1ECC045A, ++ 0x3D6A40A2, 0x176840A8, 0x2F260001, 0x289704A1, ++ 0x21681FF2, 0x086A1FF4, 0x289704A1, 0x2F260001, ++ 0x2736FFFE, 0x0F6240A2, 0x026240A6, 0x3A6B1FD6, ++ 0x228B4000, 0x08631FD6, 0x136A1FDC, 0x06691FF0, ++ 0x3D201FB2, 0x2D230012, 0x35098000, 0x36058000, ++ 0x15410000, 0x3E2C0002, 0x0A2FFFFF, 0x00CC04DB, ++ 0x37681FB2, 0x37970097, 0x136A1FDC, 0x3A681FB6, ++ 0x1D32FFFC, 0x37970097, 0x2397052F, 0x16691FB6, ++ 0x21681FF2, 0x1E220001, 0x309704B3, 0x1E220001, ++ 0x1B691FB2, 0x3A6B1FD6, 0x34800534, 0x08631FD6, ++ 0x3F6B1FDC, 0x0D691FF2, 0x1D6A1FD4, 0x1F05C000, ++ 0x20970523, 0x15691FBA, 0x1E220001, 0x32970534, ++ 0x106A1FD0, 0x03691FFA, 0x20970523, 0x216B1FFE, ++ 0x03691FFA, 0x071BC000, 0x08D40505, 0x3F6B1FDC, ++ 0x036A1FC0, 0x1F05C000, 0x1F05C000, 0x20970523, ++ 0x31800508, 0x15691FBA, 0x2C681FC0, 0x219704A8, ++ 0x13691FD0, 0x34681FBE, 0x036A1FC0, 0x286040AC, ++ 0x096140A8, 0x096240A4, 0x358C5000, 0x28700384, ++ 0x3A6B1FD6, 0x228B4000, 0x136A1FDC, 0x15691FBA, ++ 0x16624014, 0x1632FFFE, 0x35098000, 0x0B614000, ++ 0x0A6140A4, 0x16691FB6, 0x1D6A1FB8, 0x05614008, ++ 0x0B691FF4, 0x05624004, 0x1E2D0001, 0x18614010, ++ 0x228B4000, 0x1B684008, 0x2880052B, 0x0B631FEC, ++ 0x2B008000, 0x296A4010, 0x3997009F, 0x086A1FF4, ++ 0x289704A1, 0x1B684008, 0x396B1FEC, 0x256040A8, ++ 0x358C5000, 0x34700184, 0x228B4000, 0x086A1FF4, ++ 0x1D691FB4, 0x1B624010, 0x0A6140A4, 0x228B4000, ++ 0x28004000, 0x1531FFFE, 0x268C0400, 0x3F424000, ++ 0x2880052B, 0x2C8C5080, 0x33BC0053, 0x13204096, ++ 0x228B4000, 0x2C8C5080, 0x33BC0053, 0x13204096, ++ 0x3E500C63, 0x228B4000, 0x1B6A1FBE, 0x096140A8, ++ 0x096240A4, 0x238C0100, 0x34700184, 0x0E6A1FF2, ++ 0x0B614000, 0x05624004, 0x086A1FF4, 0x05614008, ++ 0x16624014, 0x238C0100, 0x20694080, 0x18350001, ++ 0x0ACC0552, 0x228B4000, 0x1D2E0001, 0x1B624010, ++ 0x25218020, 0x3C800093, 0x08631FD6, 0x16502DE7, ++ 0x3F502084, 0x3B97053D, 0x13502931, 0x36970539, ++ 0x23700080, 0x13503548, 0x03501CE4, 0x3B97053D, ++ 0x315024A9, 0x36970539, 0x0350A148, 0x0A5035A4, ++ 0x3B97053D, 0x3350252E, 0x36970539, 0x0E502929, ++ 0x145035B0, 0x3B97053D, 0x3F502108, 0x36970539, ++ 0x2B5025A9, 0x1D502CA6, 0x3B97053D, 0x1450288A, ++ 0x36970539, 0x2350B4EB, 0x18509525, 0x3B97053D, ++ 0x37501086, 0x36970539, 0x0F502D67, 0x035035AD, ++ 0x3B97053D, 0x1C501991, 0x36970539, 0x0F6B4080, ++ 0x00631FEE, 0x235098C4, 0x27509DAF, 0x3B97053D, ++ 0x1450316C, 0x36970539, 0x00509148, 0x1E502CC6, ++ 0x3B97053D, 0x1A50358E, 0x36970539, 0x355099AB, ++ 0x3A6B1FD6, 0x228B4000, 0x08631FD6, 0x30700090, ++ 0x21970512, 0x358C5000, 0x23700080, 0x13204096, ++ 0x3E500C63, 0x235024E4, 0x13204096, 0x3E500C63, ++ 0x045030A6, 0x36970539, 0x2850B12C, 0x395020EE, ++ 0x3B97053D, 0x0B5028AF, 0x36970539, 0x3D50A90A, ++ 0x3D50AD8C, 0x36970539, 0x29503D6B, 0x1850C54A, ++ 0x3B97053D, 0x0F6B4080, 0x00631FEE, 0x23700080, ++ 0x1C50352B, 0x36970539, 0x326B1FEE, 0x236A4080, ++ 0x07330006, 0x06D405AE, 0x2B320006, 0x23D005D3, ++ 0x3220000D, 0x2580045A, 0x3E500C63, 0x16502D8B, ++ 0x3B97053D, 0x3450252F, 0x36970539, 0x3950252B, ++ 0x3350210B, 0x3B97053D, 0x1B5018E5, 0x36970539, ++ 0x3E500C63, 0x205044D1, 0x3B97053D, 0x3D502409, ++ 0x36970539, 0x0550A531, 0x065018CB, 0x36970539, ++ 0x3E500C63, 0x32504409, 0x3B97053D, 0x2450112C, ++ 0x36970539, 0x3650B62D, 0x0D50300C, 0x36970539, ++ 0x3E500C63, 0x025035AA, 0x36970539, 0x2550B50D, ++ 0x3B502520, 0x36970539, 0x1B501C63, 0x3350140D, ++ 0x36970539, 0x3A6B1FD6, 0x228B4000, 0x2397052F, ++ 0x3F6B1FDC, 0x0D691FF2, 0x1D6A1FD4, 0x1F05C000, ++ 0x20970523, 0x1E691FB8, 0x3F681FD0, 0x219704A8, ++ 0x13691FD0, 0x12220002, 0x32970534, 0x1E691FB8, ++ 0x2C681FC0, 0x2D9704AB, 0x00691FC0, 0x15220003, ++ 0x32970534, 0x21970512, 0x358C5000, 0x23700080, ++ 0x13204096, 0x3E500C63, 0x3F502084, 0x13204096, ++ 0x3E500C63, 0x0B5035CF, 0x36970539, 0x3E500C63, ++ 0x0C502D07, 0x3B97053D, 0x195034AD, 0x36970539, ++ 0x3E500C63, 0x325024A5, 0x3B97053D, 0x165029AE, ++ 0x36970539, 0x0F503144, 0x2F502531, 0x3B97053D, ++ 0x0250194A, 0x36970539, 0x295010C8, 0x0E50318C, ++ 0x3B97053D, 0x085028CF, 0x36970539, 0x24502569, ++ 0x195019AD, 0x3B97053D, 0x25501004, 0x36970539, ++ 0x3E50B08C, 0x11502D29, 0x3B97053D, 0x1B5019A6, ++ 0x36970539, 0x3E500C63, 0x3450140C, 0x3B97053D, ++ 0x2750218F, 0x36970539, 0x2550AD0B, 0x04502940, ++ 0x36970539, 0x3E500C63, 0x0C50300B, 0x3B97053D, ++ 0x3C5011AB, 0x36970539, 0x3250B585, 0x3B502520, ++ 0x36970539, 0x3E500C63, 0x0E5035A9, 0x36970539, ++ 0x3350B54D, 0x15502C0B, 0x36970539, 0x1B501C63, ++ 0x3350140D, 0x36970539, 0x3A6B1FD6, 0x228B4000, ++ 0x08631FD6, 0x2397052F, 0x03691FCC, 0x3F6B1FDC, ++ 0x2F681FFA, 0x1E220001, 0x3304C000, 0x309704B3, ++ 0x2B970521, 0x08691FCE, 0x3F6B1FDC, 0x21681FF2, ++ 0x1E220001, 0x3304C000, 0x3304C000, 0x309704B3, ++ 0x2B970521, 0x30700090, 0x21970512, 0x358C5000, ++ 0x13204096, 0x3E500C63, 0x0B502A25, 0x13204096, ++ 0x3E500C63, 0x2250248F, 0x36970539, 0x0250292A, ++ 0x285020AF, 0x3B97053D, 0x25501004, 0x36970539, ++ 0x00502D04, 0x295038AE, 0x3B97053D, 0x245024E5, ++ 0x36970539, 0x1650A088, 0x2A50392E, 0x3B97053D, ++ 0x19502D4B, 0x36970539, 0x3E500C63, 0x0A502924, ++ 0x3B97053D, 0x0F502CEB, 0x36970539, 0x00502DCB, ++ 0x3B5011AA, 0x3B97053D, 0x3F502108, 0x36970539, ++ 0x3E500C63, 0x15502C0B, 0x3B97053D, 0x2A5020C8, ++ 0x36970539, 0x2550AD0B, 0x0D502925, 0x36970539, ++ 0x1B501C63, 0x3550140B, 0x3B97053D, 0x185019AA, ++ 0x36970539, 0x3A6B1FD6, 0x228B4000, 0x08631FD6, ++ 0x21681FF2, 0x10691FDC, 0x086A1FF4, 0x19044000, ++ 0x27604000, 0x289704A1, 0x21681FF2, 0x35054000, ++ 0x19044000, 0x289704A1, 0x07024000, 0x39694000, ++ 0x29681FCA, 0x3997009F, 0x21970512, 0x13204096, ++ 0x268C0400, 0x3E500C63, 0x225020C6, 0x3B97053D, ++ 0x325024A5, 0x36970539, 0x3E500C63, 0x0E502D0C, ++ 0x3B97053D, 0x1C502884, 0x36970539, 0x3E500C63, ++ 0x335021A8, 0x3B97053D, 0x00502C2B, 0x36970539, ++ 0x1450296A, 0x30502028, 0x36970539, 0x0D50A509, ++ 0x09502944, 0x36970539, 0x3E500C63, 0x325024C9, ++ 0x36970539, 0x1B50A549, 0x2A502144, 0x3B97053D, ++ 0x3D502409, 0x36970539, 0x358C5000, 0x0F6B4080, ++ 0x3E370008, 0x0ECC06A0, 0x2720001B, 0x2580045A, ++ 0x3A6B1FD6, 0x228B4000, 0x1E631FCC, 0x2C681FC0, ++ 0x3930FFFE, 0x0A500001, 0x1B204098, 0x3F5010E4, ++ 0x01000000, 0x1B204098, 0x358C5000, 0x275014E5, ++ 0x01000000, 0x1B204098, 0x358C5000, 0x175018E6, ++ 0x136A1FDC, 0x07018000, 0x35068000, 0x36064000, ++ 0x36970539, 0x278006ED, 0x1E631FCC, 0x036A1FC0, ++ 0x1632FFFE, 0x358C5000, 0x25520001, 0x1B204098, ++ 0x175018E6, 0x296B1FF0, 0x2C681FF6, 0x08691FF8, ++ 0x10631FC4, 0x18601FC6, 0x3C611FC8, 0x3F6B1FDC, ++ 0x126840A2, 0x03691FFA, 0x18631FCA, 0x15601FC2, ++ 0x3A611FCE, 0x02684088, 0x306940AA, 0x0D601FD0, ++ 0x2A611FD2, 0x34681FBE, 0x0B691FF4, 0x0E6A1FF2, ++ 0x3A9706F3, 0x387000C4, 0x226B1FC4, 0x056A1FC6, ++ 0x0E691FC8, 0x1B631FF0, 0x31621FF6, 0x3A611FF8, ++ 0x2A6B1FCA, 0x086A1FC2, 0x08691FCE, 0x0D631FDC, ++ 0x0F6240A2, 0x026240A6, 0x1B6A1FD2, 0x31611FFA, ++ 0x016240AA, 0x358C5000, 0x13691FD0, 0x02030000, ++ 0x1C614088, 0x053F0001, 0x0CCC06F1, 0x15691FBA, ++ 0x24970542, 0x13691FBC, 0x24970542, 0x136A1FDC, ++ 0x35068000, 0x15691FBA, 0x2A681FF0, 0x3997009F, ++ 0x31200001, 0x2C6B1FCC, 0x228B4000, 0x1D601FFA, ++ 0x18601FF0, 0x39611FF4, 0x3A611FF8, 0x3C621FF2, ++ 0x18614010, 0x08624000, 0x20250002, 0x2435FFFE, ++ 0x19044000, 0x1531FFFE, 0x19044000, 0x1E601FF6, ++ 0x2A604004, 0x29604008, 0x3930FFFE, 0x1E220001, ++ 0x16624014, 0x26228020, 0x2A694010, 0x358C5000, ++ 0x06500002, 0x0D500000, 0x1862401C, 0x15614014, ++ 0x066A1FFC, 0x268C0400, 0x2B008000, 0x2D36FFFB, ++ 0x32C801EB, 0x3E340004, 0x1B601FFC, 0x388001EB, ++ 0x19220000, 0x31800717, 0x00220080, 0x09661FFF, ++ 0x0E631FE6, 0x19220000, 0x05661FFC, 0x3F9704BC, ++ 0x2A97008F, 0x359704D5, 0x369704EF, 0x2397052F, ++ 0x18691FD2, 0x14220004, 0x32970534, 0x08691FCE, ++ 0x3F6B1FDC, 0x21681FF2, 0x12220002, 0x3304C000, ++ 0x3304C000, 0x309704B3, 0x2B970521, 0x21970512, ++ 0x1A21889C, 0x0A614092, 0x358C5000, 0x23700080, ++ 0x1E691FE2, 0x29970083, 0x02624090, 0x13204096, ++ 0x095029E7, 0x035030A7, 0x13204096, 0x095029E7, ++ 0x325024A5, 0x36970539, 0x3A970556, 0x02194000, ++ 0x31C80748, 0x29970083, 0x02624090, 0x1B204098, ++ 0x035030A7, 0x3B97053D, 0x325024A5, 0x36970539, ++ 0x2080073A, 0x358C5000, 0x29200013, 0x2580045A, ++ 0x358C5000, 0x236A4080, 0x09360020, 0x1ACC0751, ++ 0x24970628, 0x358C5000, 0x3E97066B, 0x31200001, ++ 0x2580045A, 0x1E6A1FEE, 0x1C6B4090, 0x27320005, ++ 0x1A1EC000, 0x1B360001, 0x25C80759, 0x3220000D, ++ 0x2580045A, 0x3D200002, 0x2580045A, 0x0F220040, ++ 0x2E80075E, 0x162200C0, 0x09661FFF, 0x0E631FE6, ++ 0x14220004, 0x05661FFC, 0x3F9704BC, 0x359704D5, ++ 0x166A1FBA, 0x03691FFA, 0x20970523, 0x3F6B1FDC, ++ 0x03691FFA, 0x0B6A1FCE, 0x1F05C000, 0x20970523, ++ 0x1B6A1FBE, 0x00691FF6, 0x20970523, 0x3F6B1FDC, ++ 0x00691FF6, 0x106A1FD0, 0x1F05C000, 0x20970523, ++ 0x22681FFE, 0x07180000, 0x37D0077E, 0x1B691FB2, ++ 0x3F681FBC, 0x2D9704AB, 0x1B691FB2, 0x2C681FC0, ++ 0x2D9704AB, 0x3F80078A, 0x3F6B1FDC, 0x03691FFA, ++ 0x106A1FBC, 0x1F05C000, 0x1F05C000, 0x20970523, ++ 0x3F6B1FDC, 0x00691FF6, 0x036A1FC0, 0x1F05C000, ++ 0x1F05C000, 0x20970523, 0x2597058A, 0x358C5000, ++ 0x3E97066B, 0x31200001, 0x2580045A, 0x0C220020, ++ 0x2E800791, 0x09661FFF, 0x0E631FE6, 0x3F9704BC, ++ 0x359704D5, 0x369704EF, 0x2397052F, 0x18691FD2, ++ 0x12220002, 0x32970534, 0x32681FD4, 0x18691FD2, ++ 0x27604000, 0x06614004, 0x24681FCE, 0x29604008, ++ 0x238C0100, 0x25218020, 0x1B61401C, 0x27604000, ++ 0x29604008, 0x12220002, 0x268C0400, 0x15624018, ++ 0x26218040, 0x1B61401C, 0x21970512, 0x1A21889C, ++ 0x0A614092, 0x358C5000, 0x23700080, 0x1E691FE2, ++ 0x29970083, 0x02624090, 0x13204096, 0x358C5000, ++ 0x2A5020A4, 0x13204096, 0x1F50A4A4, 0x36970539, ++ 0x145028E6, 0x1A503108, 0x36970539, 0x358C5000, ++ 0x2150ACE6, 0x17503529, 0x0F6B4080, 0x13204096, ++ 0x25370020, 0x04CC0745, 0x1B50C1AC, 0x31502549, ++ 0x36970539, 0x3E500C63, 0x3C502168, 0x36970539, ++ 0x04502D09, 0x3D5011AC, 0x36970539, 0x0D50A509, ++ 0x0E5029D0, 0x36970539, 0x2450214C, 0x1050196B, ++ 0x36970539, 0x3E500C63, 0x12501D29, 0x36970539, ++ 0x3E500C63, 0x14509510, 0x36970539, 0x3E500C63, ++ 0x3F509DE7, 0x36970539, 0x0F6B4080, 0x00631FEE, ++ 0x02194000, 0x34C807E1, 0x29970083, 0x02624090, ++ 0x378007B2, 0x358C5000, 0x236A4080, 0x09360020, ++ 0x1ACC07F2, 0x30700090, 0x02501865, 0x36970539, ++ 0x1B501C63, 0x36970539, 0x38501463, 0x36970539, ++ 0x2C681FC0, 0x268C0400, 0x36200000, 0x2A641FFC, ++ 0x31200001, 0x2580045A, 0x1E6A1FEE, 0x1C6B4090, ++ 0x27320005, 0x1A1EC000, 0x1B360001, 0x39C807E5, ++ 0x3220000D, 0x2580045A, 0x01000000, 0x01000000, ++ 0x1E79084F ++}; ++ ++static const uint32_t fw2_boot_img_data_buf[] = ++{ ++ 0x36200000, 0x16210003, 0x15710249, 0x31200001, ++ 0x2860B41C, 0x2A97008F, 0x1A210000, 0x1231FFFF, ++ 0x1B390001, 0x092CFFFF, 0x00CC0007, 0x0761B140, ++ 0x3A200333, 0x3060B438, 0x3E60B45C, 0x3D60B43C, ++ 0x0A20FFFF, 0x2D60B420, 0x1A210000, 0x1F68B420, ++ 0x0A61B422, 0x1234FEFE, 0x05300001, 0x2D60B420, ++ 0x0C61B424, 0x0761B426, 0x0F61B428, 0x0461B42A, ++ 0x0261B42C, 0x0961B42E, 0x1F61B434, 0x1461B436, ++ 0x2A97008F, 0x1C21A0CA, 0x33228000, 0x3F424000, ++ 0x032D0100, 0x092CFFFF, 0x18CC0023, 0x156AA0CA, ++ 0x2C320007, 0x133600C0, 0x123A0004, 0x3C66B149, ++ 0x11B8002F, 0x30224000, 0x3C800030, 0x19220000, ++ 0x06210045, 0x0C61B424, 0x35230000, 0x2D63B42C, ++ 0x2A97008F, 0x13232000, 0x0C62B428, 0x3063B434, ++ 0x16210333, 0x278C0078, 0x2BBC0077, 0x1C61B438, ++ 0x092CFFFF, 0x01CC0036, 0x386AB148, 0x2636FF00, ++ 0x193A0300, 0x0A62B148, 0x268C0400, 0x3B69B148, ++ 0x343E0100, 0x0A62B148, 0x06350080, 0x09CC0054, ++ 0x1C21A0CA, 0x0D4A4000, 0x2A97008F, 0x0E262000, ++ 0x1ED40079, 0x3F424000, 0x032D0100, 0x092CFFFF, ++ 0x13CC004D, 0x2E60B42C, 0x2560B42E, 0x2E800027, ++ 0x2A97008F, 0x1721A0C8, 0x19220000, 0x3F424000, ++ 0x122D0002, 0x3F424000, 0x182D00FE, 0x092CFFFF, ++ 0x05CC0057, 0x1A223000, 0x2F712049, 0x05B80064, ++ 0x33214000, 0x35230000, 0x3F222000, 0x3F800066, ++ 0x1A210000, 0x35230000, 0x1820B424, 0x19500011, ++ 0x0A500001, 0x1150C400, 0x0A500001, 0x0261B42C, ++ 0x2663B42E, 0x1C62B434, 0x39230333, 0x278C0078, ++ 0x2BBC0077, 0x3363B438, 0x36200000, 0x2B60B140, ++ 0x13710149, 0x398C0000, 0x20800075, 0x3371FF49, ++ 0x20800075, 0x2F71FD49, 0x20800075, 0x2A320001, ++ 0x0A367FFF, 0x21C8008E, 0x252A0008, 0x1EC0008A, ++ 0x0D500000, 0x0D500000, 0x0D500000, 0x0D500000, ++ 0x0D500000, 0x0D500000, 0x0D500000, 0x0D500000, ++ 0x21C8008E, 0x2280007E, 0x26260008, 0x0D500000, ++ 0x262EFFFF, 0x1ACC008B, 0x228B4000, 0x0868B1F8, ++ 0x3C34000F, 0x0128000A, 0x33C40095, 0x0224000A, ++ 0x228B4000, 0x3320000A, 0x228B4000, 0x01000000, ++ 0x01000000, 0x01000000 ++}; ++ ++static const uint32_t fw2_master_img_data_buf[] = ++{ ++ 0x36200000, 0x16210003, 0x3C605FF4, 0x1B615FF6, ++ 0x36200000, 0x2560B148, 0x1A205FE0, 0x38215FE8, ++ 0x3B230008, 0x1F090000, 0x10C0010E, 0x31200001, ++ 0x2860B41C, 0x2A9700B9, 0x329700C7, 0x1C208000, ++ 0x2B60B140, 0x01000000, 0x19220000, 0x0B685FFE, ++ 0x2469B1F8, 0x2B3C4600, 0x1ECC0013, 0x1D2E0001, ++ 0x28038000, 0x01000000, 0x0A2FFFFF, 0x1BCC0019, ++ 0x0B685FFE, 0x2469B1F8, 0x2B3C4600, 0x22C80021, ++ 0x25800013, 0x056B5FFA, 0x333B0000, 0x14D40026, ++ 0x363700FF, 0x2E63B47A, 0x3A200333, 0x3060B438, ++ 0x3E60B45C, 0x3D60B43C, 0x39230003, 0x2F22B400, ++ 0x0A20FFFF, 0x13408000, 0x1A210000, 0x21488000, ++ 0x23260002, 0x3F418000, 0x1234FEFE, 0x05300001, ++ 0x202A0002, 0x13408000, 0x3D260020, 0x0A2FFFFF, ++ 0x17CC002C, 0x36200000, 0x3E60B406, 0x2D60B416, ++ 0x2B60B426, 0x3860B436, 0x2860B446, 0x3B60B456, ++ 0x036B5FFC, 0x00210100, 0x05222F00, 0x29370080, ++ 0x27C80047, 0x1A210000, 0x1A223000, 0x1820B424, ++ 0x19500011, 0x0A500001, 0x1150C400, 0x0A500001, ++ 0x15410000, 0x3E2C0002, 0x0D500000, 0x1C62B434, ++ 0x10205E90, 0x0D220164, 0x0F970FF0, 0x2469B1F8, ++ 0x15220333, 0x36200000, 0x278C0078, 0x26BC0106, ++ 0x1F62B438, 0x2060B424, 0x2B60B426, 0x33610102, ++ 0x1035000F, 0x38610100, 0x0A68B400, 0x3369B420, ++ 0x32605FCA, 0x13615FCE, 0x353400FF, 0x2C380200, ++ 0x34605FCC, 0x2535FF00, 0x17390002, 0x08615FD0, ++ 0x12970F7D, 0x31200001, 0x2E605EA0, 0x202001A0, ++ 0x1760010C, 0x35203000, 0x1C60010E, 0x31200001, ++ 0x2560B148, 0x30695EA0, 0x33228000, 0x28004000, ++ 0x063C0001, 0x1FCC0078, 0x0462B140, 0x2280007E, ++ 0x28004000, 0x0C3C0004, 0x19CC007E, 0x1968B140, ++ 0x283C4000, 0x2B60B140, 0x1035000F, 0x1231FFFF, ++ 0x0B2D0082, 0x0D894000, 0x248C1D78, 0x318000A1, ++ 0x2F8C1D7A, 0x318000A1, 0x3D8C1DF8, 0x318000A1, ++ 0x368C1DFA, 0x318000A1, 0x298C1D7C, 0x318000A1, ++ 0x228C1D7E, 0x318000A1, 0x308C1DFC, 0x318000A1, ++ 0x3B8C1DFE, 0x318000A1, 0x238C1D79, 0x318000A1, ++ 0x288C1D7B, 0x318000A1, 0x3A8C1DF9, 0x318000A1, ++ 0x318C1DFB, 0x318000A1, 0x2E8C1D7D, 0x318000A1, ++ 0x258C1D7F, 0x318000A1, 0x378C1DFD, 0x318000A1, ++ 0x3C8C1DFF, 0x2EB00104, 0x05BC0C60, 0x33D80D2D, ++ 0x35A00C61, 0x18A40C87, 0x04A80CA2, 0x08F80F6B, ++ 0x35E80D4B, 0x31E00122, 0x336A5EA0, 0x362300AF, ++ 0x17360002, 0x33C800AF, 0x21AC0EF6, 0x31215EA2, ++ 0x07220014, 0x1D97100D, 0x27C80071, 0x21884000, ++ 0x30380000, 0x3AC8011C, 0x31215EA2, 0x07220014, ++ 0x19801030, 0x36200000, 0x0D500000, 0x0D500000, ++ 0x0D500000, 0x0D500000, 0x36200000, 0x2760B000, ++ 0x2960B008, 0x1E220001, 0x1B62B010, 0x3760B01C, ++ 0x10228800, 0x1862B01C, 0x228B4000, 0x0868B1F8, ++ 0x2D635E96, 0x3C34000F, 0x02030000, 0x022B000A, ++ 0x05C000CE, 0x3320000A, 0x02030000, 0x1A210000, ++ 0x1231FFFF, 0x1B390001, 0x092CFFFF, 0x1DCC00D0, ++ 0x0761B140, 0x33228000, 0x2D010000, 0x20310008, ++ 0x1A39A0CA, 0x3F424000, 0x19220000, 0x3F424000, ++ 0x0C220020, 0x392DFFBA, 0x3F424000, 0x3860B150, ++ 0x022D0044, 0x28200014, 0x0D4A4000, 0x092CFFFF, ++ 0x2BC800E7, 0x06360100, 0x21C800E2, 0x28004000, ++ 0x0C300008, 0x3C34000F, 0x1A22C000, 0x22520000, ++ 0x22520000, 0x19220000, 0x2B2DFF38, 0x3F424000, ++ 0x172D0008, 0x3F424000, 0x1E220001, 0x172D0008, ++ 0x3F424000, 0x19220000, 0x1A2D000C, 0x3F424000, ++ 0x10228800, 0x3F424000, 0x06220400, 0x0962B144, ++ 0x2E020000, 0x033A0200, 0x0962B144, 0x322C0001, ++ 0x0A2FFFFF, 0x17CC00D5, 0x1F6B5E96, 0x228B4000, ++ 0x0422008D, 0x32800117, 0x09220089, 0x32800117, ++ 0x0C220083, 0x32800117, 0x0A220085, 0x32800117, ++ 0x13220005, 0x32800117, 0x01220087, 0x32800117, ++ 0x18220007, 0x32800117, 0x0D220011, 0x32800117, ++ 0x0222008B, 0x32800117, 0x1B22000B, 0x15625FF2, ++ 0x32635FF0, 0x23320008, 0x0A62B148, 0x3BD0011D, ++ 0x228B4000, 0x31200001, 0x2A9700B9, 0x329700C7, ++ 0x398C0000, 0x35800120, 0x33695F20, 0x2C200136, ++ 0x1C35C000, 0x36C80129, 0x12685F24, 0x043D4000, ++ 0x08CC00AA, 0x3C2300AA, 0x336A5EA0, 0x03210080, ++ 0x2736FFFE, 0x01625EA0, 0x37655F21, 0x288000B4, ++ 0x33695F20, 0x12685F24, 0x1C35C000, 0x2E3DC000, ++ 0x3AC8012A, 0x228B4000, 0x0C970F90, 0x30C801D6, ++ 0x20605F24, 0x00685FFC, 0x1A210000, 0x09615F2E, ++ 0x3F340003, 0x372C0148, 0x21884000, 0x36200000, ++ 0x2360B122, 0x3580014C, 0x146BB124, 0x38695F22, ++ 0x36200000, 0x37370001, 0x15CC0152, 0x3965B123, ++ 0x3580014C, 0x2980013F, 0x3D800142, 0x33970116, ++ 0x1168B122, 0x3B69B124, 0x2F34001F, 0x29310001, ++ 0x19110000, 0x11D401CC, 0x036B5FFC, 0x1C645F20, ++ 0x0A37FF00, 0x0F330008, 0x300B0000, 0x1EC001C9, ++ 0x3D6A5F24, 0x3F215F26, 0x0C2E0040, 0x13408000, ++ 0x3330FFFB, 0x1C2C4000, 0x0B97104D, 0x35695F26, ++ 0x362C000C, 0x13350003, 0x1ECC01C5, 0x3F215F26, ++ 0x2222FFFE, 0x16971063, 0x3E695F24, 0x382C0004, ++ 0x244A0000, 0x042D0042, 0x3F424000, 0x1D2E0001, ++ 0x16420000, 0x12971097, 0x1B970CBD, 0x19685F26, ++ 0x3D695F28, 0x3660B408, 0x1161B40A, 0x12685F24, ++ 0x2421B40E, 0x3B60B40C, 0x21510000, 0x24200021, ++ 0x3560B404, 0x20200040, 0x2660B414, 0x3320017F, ++ 0x0721016D, 0x362300AF, 0x11800CE4, 0x1F685F20, ++ 0x316A5FE8, 0x353400FF, 0x26605F22, 0x1D2E0001, ++ 0x03625FE8, 0x02030000, 0x3330FFFB, 0x0F2C4010, ++ 0x244A0000, 0x382C0004, 0x27490000, 0x2C3B0400, ++ 0x1E2D0001, 0x350A4000, 0x23C40190, 0x1A210000, ++ 0x15410000, 0x12685F24, 0x2B63B120, 0x3D2C0038, ++ 0x0D500000, 0x0D500000, 0x0D500000, 0x0D500000, ++ 0x002CFFF6, 0x244A0000, 0x052CFFCA, 0x146B5F2E, ++ 0x36368000, 0x1DCC01A5, 0x333B0000, 0x22C801C1, ++ 0x332F003C, 0x3A40C000, 0x0C685F30, 0x20605F24, ++ 0x288001C1, 0x25605F2E, 0x333B0000, 0x12CC01AA, ++ 0x3E605F30, 0x2F8001AC, 0x332F003C, 0x3A40C000, ++ 0x33695F20, 0x1768B124, 0x1E220001, 0x35230000, ++ 0x193500FF, 0x190B4000, 0x1912C000, 0x2E148000, ++ 0x01CC01BA, 0x3E970112, 0x202301AC, 0x23635F24, ++ 0x20200040, 0x208001CF, 0x0C970F90, 0x3BC801D4, ++ 0x20605F24, 0x1F685F20, 0x3D6A5F24, 0x353400FF, ++ 0x2C800159, 0x35215FDA, 0x03970FA9, 0x282301CE, ++ 0x3E8001DB, 0x1F685F20, 0x35970110, 0x353400FF, ++ 0x2A8001CA, 0x33970116, 0x2F380400, 0x2860B120, ++ 0x12685F24, 0x06970FA3, 0x36200000, 0x336A5EA0, ++ 0x1B645F21, 0x183A0001, 0x01625EA0, 0x398000AF, ++ 0x352301BA, 0x3D8001D7, 0x2F230136, 0x23635F24, ++ 0x392000C0, 0x1B645F21, 0x398000AF, 0x2B695F32, ++ 0x1C208000, 0x28150000, 0x30C801E0, 0x228B4000, ++ 0x35605F32, 0x3A2001E3, 0x288000B4, 0x18685FD8, ++ 0x3E215FD8, 0x30380000, 0x22C80208, 0x0B970FCB, ++ 0x33605F34, 0x2D010000, 0x3E2C0034, 0x0B480000, ++ 0x3C6A5FEC, 0x02030000, 0x3C34000F, 0x1D2E0001, ++ 0x0E625FEC, 0x19220000, 0x14625F3A, 0x3562013E, ++ 0x0C330004, 0x3F37000F, 0x2B2F01F8, 0x228B4000, ++ 0x2C8003D3, 0x3E80055D, 0x2A80073F, 0x3A80074F, ++ 0x3780021B, 0x3780021B, 0x3780021B, 0x3780021B, ++ 0x3780021B, 0x3780021B, 0x3780021B, 0x3780021B, ++ 0x3780021B, 0x3780021B, 0x00800C30, 0x3780021B, ++ 0x33605F34, 0x35605F32, 0x398000AF, 0x112200C1, ++ 0x3D80021E, 0x192200A3, 0x3D80021E, 0x0F22008F, ++ 0x3D80021E, 0x0A220085, 0x3D80021E, 0x162200C0, ++ 0x3D80021E, 0x152200A0, 0x3D80021E, 0x122200A1, ++ 0x3D80021E, 0x07220081, 0x3D80021E, 0x01220087, ++ 0x3D80021E, 0x19220000, 0x07685F32, 0x1F625F38, ++ 0x30230223, 0x16341000, 0x00CC02BB, 0x2997037C, ++ 0x01685F34, 0x2D6A5F38, 0x23230233, 0x392C0035, ++ 0x27460000, 0x2D695F34, 0x3780028E, 0x1160013C, ++ 0x2B635F46, 0x2997037C, 0x2C200230, 0x38605F36, ++ 0x229703B1, 0x05CC027E, 0x22970251, 0x0A6A010C, ++ 0x35680110, 0x3D2A01A0, 0x3CC801E3, 0x30380000, ++ 0x0DCC01E3, 0x28620110, 0x0B970CCD, 0x1A6A0110, ++ 0x1820B424, 0x19500011, 0x0A500001, 0x1150C400, ++ 0x0A500001, 0x1B5001A0, 0x0D500000, 0x1C62B434, ++ 0x11210247, 0x392301E3, 0x18940CE7, 0x3D6B0112, ++ 0x0F2201A0, 0x3862010C, 0x36200000, 0x1A6A0110, ++ 0x0C600112, 0x07600110, 0x333B0000, 0x07CC03A3, ++ 0x398000AF, 0x33635F38, 0x011A4000, 0x0462B140, ++ 0x1F6B5EA0, 0x2E020000, 0x3E3B0004, 0x2D635EA0, ++ 0x1A388000, 0x35605F32, 0x2B008000, 0x0E300003, ++ 0x2B605F4A, 0x2B008000, 0x3F30FFF8, 0x1E384001, ++ 0x2D605F4C, 0x1132FFFF, 0x2C2E0D70, 0x20230265, ++ 0x0E8A4000, 0x26605F4E, 0x0A6A010C, 0x202001A0, ++ 0x1A210000, 0x1C0A0000, 0x14970E54, 0x07970E72, ++ 0x046B5F32, 0x14685F4E, 0x3F37000F, 0x293B0100, ++ 0x2E6A5F34, 0x2563B144, 0x16420000, 0x36695F46, ++ 0x3E2C0002, 0x15410000, 0x266A5F3A, 0x3E2C0002, ++ 0x16420000, 0x23695F3C, 0x016B5F38, 0x3E2C0002, ++ 0x15410000, 0x228B4000, 0x3520C000, 0x35605F32, ++ 0x14970CDE, 0x0F220040, 0x1820B424, 0x19500011, ++ 0x01500003, 0x1150C400, 0x0A500001, 0x0E500180, ++ 0x0D500000, 0x1C62B434, 0x352000AF, 0x192100AF, ++ 0x362300AF, 0x1D800CE7, 0x28635E9C, 0x1B6B5FEE, ++ 0x0A615E98, 0x192D0036, 0x22484000, 0x312F0001, ++ 0x29635FEE, 0x00349FFF, 0x10404000, 0x19348000, ++ 0x27C802A1, 0x222DFFFE, 0x0D4A4000, 0x172D0008, ++ 0x22484000, 0x02625E9A, 0x21510000, 0x30380000, ++ 0x32C802B7, 0x20605E9E, 0x14685E98, 0x33215FDC, ++ 0x1C970FBA, 0x13970EF6, 0x12685E9E, 0x1A6B5E9C, ++ 0x30380000, 0x13CC02AB, 0x228B4000, 0x306A5E9A, ++ 0x3E215FD8, 0x2636FF00, 0x3ED002B2, 0x1C970FBA, ++ 0x1A6B5E9C, 0x3E8001DB, 0x23320008, 0x392C0035, ++ 0x27460000, 0x3E695E9E, 0x3080028F, 0x2E97010E, ++ 0x39209000, 0x35605F32, 0x0280108D, 0x1C208000, ++ 0x35605F32, 0x1680109C, 0x19685F4A, 0x33695F4C, ++ 0x1632FFFE, 0x1A048000, 0x19220000, 0x29058400, ++ 0x2B605F4A, 0x01615F4C, 0x228B4000, 0x3B635F36, ++ 0x0A625E94, 0x379702BE, 0x386A5E94, 0x09685F3A, ++ 0x3B8002D7, 0x3B635F36, 0x30380000, 0x31D002D1, ++ 0x21970372, 0x09685F3A, 0x1C390000, 0x31C802D7, ++ 0x09300002, 0x10404000, 0x3930FFFE, 0x2D010000, ++ 0x0F2D01A0, 0x3E610106, 0x1632FFFE, 0x26C80370, ++ 0x28038000, 0x06330001, 0x01D402E0, 0x172E0004, ++ 0x280C8000, 0x3B605F3A, 0x28038000, 0x3F37000F, ++ 0x37C802E7, 0x2F36FFF0, 0x092E0010, 0x1F6B5F40, ++ 0x19625F3E, 0x1A0B8000, 0x36C402EC, 0x01625F40, ++ 0x386A5F42, 0x36200000, 0x133600C0, 0x2B320006, ++ 0x28C802F4, 0x232C0040, 0x262EFFFF, 0x2F8002F0, ++ 0x19600104, 0x09970D10, 0x352000AF, 0x00970D19, ++ 0x0F970D20, 0x0B970CCD, 0x07690104, 0x2B680104, ++ 0x1F2D0030, 0x0D4A4000, 0x122D0002, 0x214B4000, ++ 0x123EFFFF, 0x1A1EC000, 0x11CC0340, 0x3421B424, ++ 0x30510041, 0x2360B428, 0x142D0004, 0x21510000, ++ 0x3151C010, 0x26510001, 0x11220038, 0x1C62B434, ++ 0x062102F9, 0x362300AF, 0x18940CE7, 0x3320003C, ++ 0x3960B348, 0x1B970CBD, 0x0B970CCD, 0x20680106, ++ 0x3721B428, 0x2B6A5F3E, 0x156B5FD0, 0x0451E000, ++ 0x26510001, 0x2E60B42C, 0x122D0002, 0x21510000, ++ 0x24200311, 0x2E63B420, 0x2060B424, 0x1C62B434, ++ 0x19685F4A, 0x33695F4C, 0x3660B408, 0x1161B40A, ++ 0x056B5FCC, 0x2F21B40C, 0x0451E000, 0x26510001, ++ 0x17201061, 0x3B63B400, 0x3560B404, 0x0962B414, ++ 0x3A200003, 0x3D605F50, 0x3F200339, 0x06210343, ++ 0x1B970CE7, 0x362300AF, 0x14940CE4, 0x0F685F50, ++ 0x0834FFFE, 0x3D605F50, 0x30380000, 0x38C8033E, ++ 0x398000AF, 0x0F685F50, 0x0434FFFD, 0x3D605F50, ++ 0x30380000, 0x02CC00AF, 0x096B5F36, 0x08800D27, ++ 0x1E970CED, 0x2D23020D, 0x08800D27, 0x292302F9, ++ 0x18800CED, 0x3B635F36, 0x30380000, 0x2FD00349, ++ 0x21970372, 0x09685F3A, 0x1C390000, 0x2FC8034F, ++ 0x09300002, 0x10404000, 0x3930FFFE, 0x2D010000, ++ 0x0F2D01A0, 0x3E610106, 0x1632FFFE, 0x26C80370, ++ 0x1F6B5F40, 0x19625F3E, 0x1A0B8000, 0x39C40359, ++ 0x01625F40, 0x28038000, 0x0D330003, 0x00D4035D, ++ 0x172E0004, 0x280C8000, 0x3B605F3A, 0x1B970CBD, ++ 0x19685F4A, 0x33695F4C, 0x3660B408, 0x1161B40A, ++ 0x20680106, 0x2B6A5F3E, 0x2421B40E, 0x21510000, ++ 0x3B60B40C, 0x24200021, 0x3560B404, 0x0962B414, ++ 0x0A685F36, 0x1621035F, 0x362300AF, 0x11800CE4, ++ 0x096B5F36, 0x35800116, 0x2B635E90, 0x026B5F34, ++ 0x010CC000, 0x084B0000, 0x3E2C0002, 0x0B480000, ++ 0x28635F4A, 0x196B5E90, 0x2D605F4C, 0x228B4000, ++ 0x336A5F40, 0x36200000, 0x2E605F40, 0x1F3A0000, ++ 0x3BCC0CFF, 0x228B4000, 0x0A20FFFF, 0x192D0036, ++ 0x0D4A4000, 0x2F2DFFFA, 0x0A625F42, 0x3A34003F, ++ 0x2E148000, 0x19CC020D, 0x228B4000, 0x0D4A4000, ++ 0x122D0002, 0x0F3607FC, 0x23C8020F, 0x26320002, ++ 0x19088000, 0x11C0020F, 0x2B008000, 0x05300001, ++ 0x0DD40396, 0x1D2E0001, 0x3E30FFFF, 0x228B4000, ++ 0x2D635E96, 0x27200102, 0x2197038B, 0x12600130, ++ 0x0C625F44, 0x27200102, 0x2197038B, 0x1F6B5E96, ++ 0x1F600134, 0x07625F46, 0x228B4000, 0x0969010C, ++ 0x2E68010E, 0x3B3D01A0, 0x03CC03AE, 0x0C2E01A0, ++ 0x3862010C, 0x30380000, 0x3EC803AD, 0x19088000, ++ 0x1CC0020B, 0x228B4000, 0x28620110, 0x0F630112, ++ 0x398000AF, 0x26680100, 0x2D635E96, 0x366AB140, ++ 0x1D210001, 0x35230000, 0x03280001, 0x300B0000, ++ 0x1A11C000, 0x28038000, 0x2E174000, 0x26C803BF, ++ 0x29310001, 0x03280001, 0x23C403B9, 0x1F6B5E96, ++ 0x228B4000, 0x2D635E96, 0x19220000, 0x0A625E94, ++ 0x1A6BB140, 0x0A690100, 0x31200001, 0x2D02C000, ++ 0x2B160000, 0x386A5E94, 0x0CCC03CD, 0x1D2E0001, ++ 0x0A625E94, 0x3E30FFFF, 0x252DFFFF, 0x09CC03C7, ++ 0x1F6B5E96, 0x386A5E94, 0x228B4000, 0x09625F4E, ++ 0x292C03D6, 0x21884000, 0x3780021B, 0x208003E6, ++ 0x26800460, 0x2A800463, 0x30800483, 0x248004A4, ++ 0x36800509, 0x3C80050C, 0x2B800527, 0x2F80052A, ++ 0x27800548, 0x3780021B, 0x3780021B, 0x3780021B, ++ 0x3780021B, 0x3780021B, 0x28230018, 0x1263013C, ++ 0x28970382, 0x3E970398, 0x0F6A0130, 0x02030000, ++ 0x1A0B8000, 0x11C003EF, 0x2E020000, 0x206B013C, ++ 0x11685F44, 0x36695F46, 0x25370020, 0x04CC03F5, ++ 0x1D2E0001, 0x12625F3C, 0x2D0E0000, 0x040E4000, ++ 0x1632FFFE, 0x3A9703A3, 0x319702B8, 0x36200000, ++ 0x15210120, 0x3E6A5F44, 0x26970345, 0x38200008, ++ 0x18210124, 0x356A5F46, 0x26970345, 0x3D9702BB, ++ 0x09685F3A, 0x09210010, 0x09300002, 0x0F600128, ++ 0x35610104, 0x2997037C, 0x16970D35, 0x20680130, ++ 0x01690134, 0x1C6A0120, 0x3D6B0124, 0x3460B010, ++ 0x1561B014, 0x3D680128, 0x1C69012C, 0x172E0068, ++ 0x0862B000, 0x3B2F0068, 0x2963B004, 0x016A0138, ++ 0x382C0068, 0x2960B008, 0x142D0068, 0x0861B00C, ++ 0x1562B018, 0x2368013C, 0x362300AF, 0x1A388000, ++ 0x3760B01C, 0x1A940D3A, 0x14685F4E, 0x2E6A5F34, ++ 0x30380000, 0x38C8042B, 0x21884000, 0x1C208000, ++ 0x13408000, 0x36200000, 0x22800437, 0x09685F3A, ++ 0x2169B024, 0x012E0028, 0x1C390000, 0x3DD00427, ++ 0x09300002, 0x382C0068, 0x1F090000, 0x1531FFFE, ++ 0x0E68B028, 0x3F418000, 0x2F34001F, 0x112E0002, ++ 0x13408000, 0x2B008000, 0x3E2C0002, 0x0D500000, ++ 0x0D500000, 0x07970D42, 0x206A5F3C, 0x01685F34, ++ 0x1632FFFE, 0x3BC8021D, 0x286B0104, 0x25695F3A, ++ 0x12625F3C, 0x01625F40, 0x010CC000, 0x0F2D01A0, ++ 0x35610104, 0x27490000, 0x3E2C0002, 0x0B480000, ++ 0x07615F4A, 0x2D605F4C, 0x1B970CBD, 0x19685F4A, ++ 0x33695F4C, 0x3B60B40C, 0x1C61B40E, 0x2B680104, ++ 0x1A210000, 0x1161B40A, 0x3660B408, 0x206A5F3C, ++ 0x28200081, 0x3560B404, 0x0962B414, 0x1B21044E, ++ 0x362300AF, 0x14940CE4, 0x3E23021D, 0x2F80037C, ++ 0x2E230028, 0x1263013C, 0x288003E8, 0x28970382, ++ 0x27200102, 0x2197038B, 0x12600130, 0x0C625F44, ++ 0x322C0001, 0x3D605F3C, 0x1D32FFFC, 0x172E0004, ++ 0x3A9703A3, 0x319702B8, 0x36200000, 0x15210120, ++ 0x3E6A5F44, 0x26970345, 0x3E6A5F44, 0x38200008, ++ 0x18210124, 0x26970345, 0x3E6A5F44, 0x25200010, ++ 0x1B210128, 0x26970345, 0x3D9702BB, 0x09685F3A, ++ 0x07210018, 0x09300002, 0x0260012C, 0x35610104, ++ 0x3023000A, 0x1263013C, 0x2C800409, 0x28970382, ++ 0x3E970398, 0x11685F44, 0x2D0E0000, 0x1632FFFE, ++ 0x3A9703A3, 0x319702B8, 0x36200000, 0x15210120, ++ 0x3E6A5F44, 0x26970345, 0x356A5F46, 0x38200008, ++ 0x18210124, 0x26970345, 0x3D9702BB, 0x09685F3A, ++ 0x0F6A0130, 0x2E6B0134, 0x09300002, 0x0F600128, ++ 0x2E0EC000, 0x1632FFFE, 0x12625F3C, 0x15208009, ++ 0x3797022B, 0x0E970DE8, 0x3E680148, 0x0A970EB9, ++ 0x1A210000, 0x236A5F5C, 0x25200010, 0x00800ED6, ++ 0x06208100, 0x1160013C, 0x28970382, 0x3E970398, ++ 0x236B0130, 0x3D695F44, 0x300B0000, 0x11C0020F, ++ 0x0834FFFE, 0x23C8020F, 0x040E4000, 0x1632FFFE, ++ 0x3A9703A3, 0x319702B8, 0x36200000, 0x15210120, ++ 0x3E6A5F44, 0x26970345, 0x356A5F46, 0x38200008, ++ 0x18210124, 0x26970345, 0x3D9702BB, 0x026A0134, ++ 0x12690124, 0x262EFFFF, 0x040D8000, 0x1531FFFE, ++ 0x0F2D01A0, 0x0D4A4000, 0x122D0002, 0x0E494000, ++ 0x2368013C, 0x011A4000, 0x35C80215, 0x25695F3A, ++ 0x026A0134, 0x25310002, 0x23610128, 0x29340100, ++ 0x3DC804D8, 0x236B0130, 0x2B008000, 0x1A0B8000, ++ 0x312F0001, 0x1D2E0001, 0x05300001, 0x3FD004D5, ++ 0x1D2E0001, 0x040D8000, 0x2E61012C, 0x2E0EC000, ++ 0x1632FFFE, 0x12625F3C, 0x2368013C, 0x3797022B, ++ 0x0E970DE8, 0x0C69015C, 0x3368014C, 0x05350100, ++ 0x3EC80502, 0x0A970EB9, 0x22520000, 0x172E0004, ++ 0x07690168, 0x3E680148, 0x1C390000, 0x31D004EB, ++ 0x1F090000, 0x1531FFFE, 0x3C8004EC, 0x30218000, ++ 0x04685F52, 0x2A2EFFFC, 0x3F418000, 0x15381000, ++ 0x36605F52, 0x0497108D, 0x016A0154, 0x2068015C, ++ 0x1A210000, 0x1632FFFE, 0x29340100, 0x25200010, ++ 0x32C80501, 0x01970ED7, 0x3E680148, 0x1F69014C, ++ 0x236A5F5C, 0x1F090000, 0x1531FFFE, 0x350A4000, ++ 0x2B200018, 0x00800ED6, 0x2E6A5F58, 0x012E0028, ++ 0x22520000, 0x22520000, 0x22520000, 0x22520000, ++ 0x328004E4, 0x00208200, 0x1160013C, 0x2F8004A6, ++ 0x21200088, 0x1160013C, 0x28970382, 0x03361F00, ++ 0x23320008, 0x33620138, 0x27200102, 0x2197038B, ++ 0x12600130, 0x2D6B0138, 0x0C625F44, 0x333B0000, ++ 0x206B013C, 0x15CC051B, 0x2480051E, 0x26370040, ++ 0x1FCC051E, 0x322C0001, 0x3D605F3C, 0x2D0E0000, ++ 0x1632FFFE, 0x3A9703A3, 0x36200000, 0x15210120, ++ 0x3E6A5F44, 0x27230404, 0x20800345, 0x2E200048, ++ 0x1160013C, 0x3780050E, 0x28970382, 0x27200102, ++ 0x2197038B, 0x12600130, 0x0C625F44, 0x1A32FFFD, ++ 0x3A9703A3, 0x319702B8, 0x36200000, 0x15210120, ++ 0x3E6A5F44, 0x26970345, 0x3E6A5F44, 0x38200008, ++ 0x18210124, 0x26970345, 0x3D9702BB, 0x25200540, ++ 0x26605F4E, 0x2A230400, 0x1263013C, 0x2C800409, ++ 0x2C69B020, 0x012E0028, 0x22520000, 0x22520000, ++ 0x22520000, 0x3F418000, 0x3E23021D, 0x01800D42, ++ 0x28970382, 0x2A2001FF, 0x2197038B, 0x12600130, ++ 0x3D605F3C, 0x2E020000, 0x0C625F44, 0x1632FFFE, ++ 0x3A9703A3, 0x36200000, 0x15210120, 0x3E6A5F44, ++ 0x26970345, 0x36200000, 0x3B605F3A, 0x0F600128, ++ 0x09210010, 0x35610104, 0x18230808, 0x1263013C, ++ 0x2C800409, 0x02030000, 0x0D37FFF8, 0x0CCC021B, ++ 0x382C0562, 0x21884000, 0x3980056A, 0x208005B0, ++ 0x2580061F, 0x31800638, 0x2680067F, 0x268006B0, ++ 0x3780021B, 0x3780021B, 0x0620FFFC, 0x2F970383, ++ 0x03361F00, 0x23320008, 0x33620138, 0x3F2A0011, ++ 0x3BC40211, 0x3E970398, 0x05300001, 0x29D00575, ++ 0x112E0002, 0x25347FFF, 0x23C8020F, 0x2E680138, ++ 0x07625F46, 0x322C0001, 0x08280003, 0x22C4057D, ++ 0x36200000, 0x0D240005, 0x07018000, 0x15072000, ++ 0x333B0000, 0x02CC0213, 0x3D695F44, 0x092E0010, ++ 0x040E4000, 0x082A0800, 0x356A5F46, 0x30C40213, ++ 0x1132FFFF, 0x040E4000, 0x1632FFFE, 0x3A9703A3, ++ 0x319702B8, 0x36200000, 0x15210120, 0x146B5F42, ++ 0x3E6A5F44, 0x06330001, 0x33D00595, 0x3C230596, ++ 0x20800345, 0x2B9702CD, 0x146B5F42, 0x38200008, ++ 0x18210124, 0x356A5F46, 0x0A330002, 0x31D0059E, ++ 0x3523059F, 0x20800345, 0x2B9702CD, 0x0A6B5F3A, ++ 0x356A5F46, 0x1B210128, 0x2B635F46, 0x25200010, ++ 0x26970345, 0x3D9702BB, 0x196B5F46, 0x3D680128, ++ 0x026A0134, 0x0260012C, 0x1632FFFE, 0x38635F3A, ++ 0x12625F3C, 0x1320E000, 0x2B230618, 0x3180022B, ++ 0x0B20FFF8, 0x2F970383, 0x03361F00, 0x23320008, ++ 0x33620138, 0x3F2A0011, 0x3BC40211, 0x24200082, ++ 0x2197038B, 0x12600130, 0x0C625F44, 0x24200082, ++ 0x2197038B, 0x1F600134, 0x05300001, 0x3BD005C1, ++ 0x112E0002, 0x25347FFF, 0x23C8020F, 0x2E680138, ++ 0x07625F46, 0x3E2C0002, 0x09280004, 0x30C405C9, ++ 0x36200000, 0x3C2C0009, 0x07018000, 0x15072000, ++ 0x333B0000, 0x02CC0213, 0x3D695F44, 0x2D680134, ++ 0x092E0010, 0x1231FFFF, 0x082A0800, 0x30C40213, ++ 0x2E020000, 0x1632FFFE, 0x2D0E0000, 0x040E4000, ++ 0x102E0005, 0x1632FFFE, 0x3A9703A3, 0x319702B8, ++ 0x36200000, 0x15210120, 0x146B5F42, 0x3E6A5F44, ++ 0x06330001, 0x23D005E5, 0x1132FFFF, 0x242305E8, ++ 0x20800345, 0x2B9702CD, 0x3E6A5F44, 0x2E9702C7, ++ 0x146B5F42, 0x38200008, 0x18210124, 0x356A5F46, ++ 0x0A330002, 0x3DD005F1, 0x1132FFFF, 0x342305F4, ++ 0x20800345, 0x2B9702CD, 0x356A5F46, 0x2E9702C7, ++ 0x12690124, 0x356A5F46, 0x1531FFFE, 0x0F2D01A0, ++ 0x22484000, 0x1632FFFE, 0x040D8000, 0x214B4000, ++ 0x34340001, 0x36C80219, 0x37370001, 0x36C80219, ++ 0x026A0134, 0x25200010, 0x146B5F42, 0x1B210128, ++ 0x0D330003, 0x3BD00608, 0x3F230609, 0x20800345, ++ 0x2B9702CD, 0x09685F3A, 0x026A0134, 0x26605F4E, ++ 0x2D200028, 0x1621012C, 0x1132FFFF, 0x26970345, ++ 0x3D9702BB, 0x14685F4E, 0x026A0134, 0x3B605F3A, ++ 0x39209000, 0x1A32FFFD, 0x12625F3C, 0x3797022B, ++ 0x0E970DE8, 0x3368014C, 0x0A970EB9, 0x1A210000, ++ 0x236A5F5C, 0x2B200018, 0x00800ED6, 0x28970382, ++ 0x3E970398, 0x126B5F44, 0x2E0EC000, 0x1632FFFE, ++ 0x3A9703A3, 0x319702B8, 0x36200000, 0x15210120, ++ 0x3E6A5F44, 0x26970345, 0x38200008, 0x18210124, ++ 0x356A5F46, 0x26970345, 0x3D9702BB, 0x0A6B5F3A, ++ 0x026A0134, 0x0A330002, 0x0163012C, 0x1632FFFE, ++ 0x12625F3C, 0x3620F000, 0x2B230618, 0x3180022B, ++ 0x0B20FFF8, 0x2F970383, 0x0A625F42, 0x2B200018, ++ 0x2197038B, 0x12600130, 0x0C625F44, 0x2B200018, ++ 0x2197038B, 0x1F600134, 0x0834FFFE, 0x23C8020F, ++ 0x112E0002, 0x07625F46, 0x3A20A000, 0x1160013C, ++ 0x3D695F44, 0x28038000, 0x070E8000, 0x2E0EC000, ++ 0x040E4000, 0x1632FFFE, 0x3A9703A3, 0x319702B8, ++ 0x36200000, 0x15210120, 0x146B5F42, 0x3E6A5F44, ++ 0x06330001, 0x3ED00658, 0x3A230659, 0x20800345, ++ 0x2B9702CD, 0x146B5F42, 0x356A5F46, 0x38200008, ++ 0x0A330002, 0x3DD00662, 0x1132FFFF, 0x18210124, ++ 0x33230666, 0x20800345, 0x18210124, 0x2B9702CD, ++ 0x356A5F46, 0x2E9702C7, 0x25200010, 0x1B210128, ++ 0x146B5F42, 0x356A5F46, 0x0D330003, 0x3ED0066E, ++ 0x3A23066F, 0x20800345, 0x2B9702CD, 0x3D9702BB, ++ 0x09685F3A, 0x356A5F46, 0x1632FFFE, 0x12625F3C, ++ 0x09300002, 0x0260012C, 0x2368013C, 0x3797022B, ++ 0x0E970DE8, 0x3368014C, 0x0A970EB9, 0x1A210000, ++ 0x236A5F5C, 0x2B200018, 0x00800ED6, 0x0C20FFF9, ++ 0x2F970383, 0x0A625F42, 0x122D0002, 0x2B200018, ++ 0x2197038B, 0x1F600134, 0x0834FFFE, 0x23C8020F, ++ 0x112E0002, 0x07625F46, 0x2920013C, 0x27508000, ++ 0x0A500001, 0x23290002, 0x22484000, 0x28038000, ++ 0x1A32FFFD, 0x2E0EC000, 0x3F340003, 0x20605F48, ++ 0x1632FFFE, 0x3A9703A3, 0x319702B8, 0x356A5F46, ++ 0x116B5F48, 0x2B008000, 0x1132FFFF, 0x37370001, ++ 0x31C8069E, 0x2D0E0000, 0x15210120, 0x36200000, ++ 0x26970345, 0x116B5F48, 0x356A5F46, 0x37370001, ++ 0x1FCC06D7, 0x2B2306D7, 0x09685F3A, 0x2E01C000, ++ 0x232C01A0, 0x0A500001, 0x1632FFFE, 0x202A0002, ++ 0x0F970FF0, 0x122801A0, 0x3B605F3A, 0x0D894000, ++ 0x0B20FFF8, 0x2F970383, 0x0A625F42, 0x2B200018, ++ 0x2197038B, 0x12600130, 0x0C625F44, 0x2B200018, ++ 0x2197038B, 0x1F600134, 0x0834FFFE, 0x23C8020F, ++ 0x112E0002, 0x07625F46, 0x2920013C, 0x02509000, ++ 0x0A500001, 0x23290002, 0x22484000, 0x3D695F44, ++ 0x38340002, 0x20605F48, 0x1132FFFF, 0x28038000, ++ 0x2E0EC000, 0x2E0EC000, 0x040E4000, 0x1632FFFE, ++ 0x3A9703A3, 0x319702B8, 0x36200000, 0x15210120, ++ 0x146B5F42, 0x3E6A5F44, 0x06330001, 0x2FD006D6, ++ 0x2B2306D7, 0x20800345, 0x2B9702CD, 0x146B5F42, ++ 0x356A5F46, 0x38200008, 0x0A330002, 0x24D006E2, ++ 0x07018000, 0x1132FFFF, 0x040E4000, 0x18210124, ++ 0x222306E8, 0x20800345, 0x18210124, 0x2B9702CD, ++ 0x356A5F46, 0x2E9702C7, 0x356A5F46, 0x2E9702C7, ++ 0x146B5F42, 0x356A5F46, 0x1B210128, 0x0D330003, ++ 0x20D0070F, 0x116B5F48, 0x2B008000, 0x1132FFFF, ++ 0x37370001, 0x36C806F3, 0x2D0E0000, 0x25200010, ++ 0x26970345, 0x116B5F48, 0x356A5F46, 0x37370001, ++ 0x05CC0718, 0x0F69013C, 0x01685F34, 0x356A5F46, ++ 0x223D9000, 0x1CCC070D, 0x2E2C0028, 0x084B0000, ++ 0x3E2C0002, 0x27490000, 0x3E2C0002, 0x2D1B4000, ++ 0x27490000, 0x3E2C0002, 0x2D1B4000, 0x27490000, ++ 0x2D200028, 0x2D1B4000, 0x2DC8070D, 0x31230718, ++ 0x20800345, 0x31230718, 0x338006A6, 0x25200010, ++ 0x2B9702CD, 0x356A5F46, 0x2E9702C7, 0x116B5F48, ++ 0x356A5F46, 0x37370001, 0x33C806F9, 0x2E9702C7, ++ 0x3D9702BB, 0x3D6A5F48, 0x09685F3A, 0x17360002, ++ 0x37C80722, 0x356A5F46, 0x01690134, 0x1132FFFF, ++ 0x040E4000, 0x1632FFFE, 0x12625F3C, 0x09300002, ++ 0x0260012C, 0x2368013C, 0x3797022B, 0x2D695F58, ++ 0x142D0032, 0x22484000, 0x38340002, 0x10CC0738, ++ 0x016A0154, 0x3A20A000, 0x28038000, 0x06330001, ++ 0x13D40732, 0x1D2E0001, 0x112E0002, 0x3D33FFFF, ++ 0x2E0EC000, 0x1632FFFE, 0x11625F5C, 0x0B970DD4, ++ 0x0E970DE8, 0x3368014C, 0x0A970EB9, 0x1A210000, ++ 0x236A5F5C, 0x2B200018, 0x00800ED6, 0x02030000, ++ 0x052B000B, 0x3EC4021B, 0x372C0744, 0x21884000, ++ 0x2B800754, 0x0D800811, 0x18800A18, 0x0B800AF1, ++ 0x3780021B, 0x0D800811, 0x3780021B, 0x0B800AF1, ++ 0x2D800752, 0x3780021B, 0x2A800753, 0x30380000, ++ 0x0CCC021B, 0x1C800C2F, 0x3780021B, 0x3780021B, ++ 0x0620FFFC, 0x2F970383, 0x122D0002, 0x2B200018, ++ 0x2197038B, 0x12600130, 0x1F600134, 0x0834FFFE, ++ 0x23C8020F, 0x112E0002, 0x23290002, 0x22484000, ++ 0x07625F46, 0x34340001, 0x20605F48, 0x2B008000, ++ 0x3530FFFD, 0x2D0E0000, 0x2D0E0000, 0x1632FFFE, ++ 0x3A9703A3, 0x319702B8, 0x36200000, 0x15210120, ++ 0x146B5F42, 0x356A5F46, 0x06330001, 0x34D00772, ++ 0x30230773, 0x20800345, 0x2B9702CD, 0x1E9709E7, ++ 0x356A5F46, 0x2D200028, 0x1A210000, 0x26970345, ++ 0x3D9702BB, 0x1A685F46, 0x36695F46, 0x3530FFFD, ++ 0x2B0C4000, 0x01600120, 0x1531FFFE, 0x20610124, ++ 0x026A0134, 0x3930FFFE, 0x232C01A0, 0x1132FFFF, ++ 0x1A210000, 0x084B0000, 0x3E2C0002, 0x2819C000, ++ 0x262EFFFF, 0x0BCC0785, 0x2435FFFE, 0x3EC80217, ++ 0x16970D35, 0x01690134, 0x1C6A0120, 0x3D6B0124, ++ 0x03208400, 0x172E0068, 0x3B2F0068, 0x1861B010, ++ 0x0862B000, 0x2963B004, 0x3760B01C, 0x362300AF, ++ 0x1A940D3A, 0x2C69B020, 0x25310002, 0x2DD0079E, ++ 0x07970D42, 0x34800217, 0x07970D42, 0x1A685F46, ++ 0x19220000, 0x0C600124, 0x2D010000, 0x1531FFFE, ++ 0x2E0D0000, 0x23610128, 0x070D4000, 0x2E0D0000, ++ 0x2E61012C, 0x12625F3C, 0x31200001, 0x1A60013E, ++ 0x39209000, 0x3797022B, 0x3A20A000, 0x0B970DD4, ++ 0x28680164, 0x126A0144, 0x28038000, 0x1632FFFE, ++ 0x2E0EC000, 0x30380000, 0x08D00EB7, 0x1F69014C, ++ 0x070E8000, 0x2E610140, 0x23620148, 0x35098000, ++ 0x2D61014C, 0x1531FFFE, 0x23610144, 0x00208200, ++ 0x00970DD6, 0x2B680168, 0x1C6A014C, 0x30380000, ++ 0x08D00EB7, 0x12690148, 0x23620148, 0x35098000, ++ 0x2E610140, 0x35098000, 0x1632FFFE, 0x040D8000, ++ 0x2D61014C, 0x3620F000, 0x00970DD6, 0x3E680148, ++ 0x1C690140, 0x19220000, 0x20620144, 0x0160014C, ++ 0x2E0D0000, 0x2E610140, 0x3230FFFC, 0x0C600148, ++ 0x1B208001, 0x00970DD6, 0x116A0148, 0x3368014C, ++ 0x2D6B0154, 0x2D620140, 0x2D010000, 0x3530FFFD, ++ 0x0F600144, 0x05300001, 0x1C0A0000, 0x040D8000, ++ 0x20610148, 0x020FC000, 0x12630150, 0x0F208010, ++ 0x00970DD6, 0x28680164, 0x1C690140, 0x30380000, ++ 0x08D00EB7, 0x116A0148, 0x3368014C, 0x206B0150, ++ 0x20610148, 0x2D620140, 0x312F0001, 0x12630150, ++ 0x1C0A0000, 0x20620144, 0x1B208001, 0x00970DD6, ++ 0x0C6A0150, 0x2D6B0154, 0x3368014C, 0x12690148, ++ 0x2E0EC000, 0x3E620150, 0x126A0144, 0x2E610140, ++ 0x1C0A0000, 0x23620148, 0x010F0000, 0x3A33FFFE, ++ 0x3D635F5C, 0x3930FFFE, 0x0F600144, 0x00208200, ++ 0x00970DD6, 0x0E970DE8, 0x07690168, 0x236A5F5C, ++ 0x1C390000, 0x08D00EB7, 0x1B970ECE, 0x2B200018, ++ 0x00800ED6, 0x0120FFFD, 0x2F970383, 0x122D0002, ++ 0x2B200018, 0x2197038B, 0x12600130, 0x1F600134, ++ 0x0834FFFE, 0x23C8020F, 0x112E0002, 0x23290002, ++ 0x22484000, 0x07625F46, 0x38340002, 0x20605F48, ++ 0x2B008000, 0x07018000, 0x3930FFFE, 0x1A32FFFD, ++ 0x2D0E0000, 0x040E4000, 0x1632FFFE, 0x3A9703A3, ++ 0x319702B8, 0x1E9709E7, 0x356A5F46, 0x2D200028, ++ 0x1A210000, 0x1132FFFF, 0x26970345, 0x36200000, ++ 0x356A5F46, 0x1A210000, 0x1132FFFF, 0x26970345, ++ 0x3D9702BB, 0x356A5F46, 0x359706A6, 0x36695F46, ++ 0x1A685F46, 0x1931FFFD, 0x2D610120, 0x29310001, ++ 0x1F090000, 0x20610124, 0x16970D35, 0x01690134, ++ 0x1C6A0120, 0x1861B010, 0x172E0068, 0x0862B000, ++ 0x0662B008, 0x31208808, 0x3760B01C, 0x362300AF, ++ 0x1A940D3A, 0x2169B024, 0x1C390000, 0x10D008F3, ++ 0x12690124, 0x03208400, 0x142D0068, 0x0661B004, ++ 0x3760B01C, 0x362300AF, 0x1A940D3A, 0x2C69B020, ++ 0x25310002, 0x21D408F3, 0x36695F46, 0x1C6A0120, ++ 0x31208808, 0x040E4000, 0x2E620120, 0x172E0068, ++ 0x0862B000, 0x0662B008, 0x3760B01C, 0x362300AF, ++ 0x1A940D3A, 0x2169B024, 0x1C390000, 0x10D008F3, ++ 0x03208400, 0x3760B01C, 0x362300AF, 0x1A940D3A, ++ 0x2C69B020, 0x25310002, 0x21D408F3, 0x07970D42, ++ 0x1A685F46, 0x1F690120, 0x0F600128, 0x3930FFFE, ++ 0x2E0D0000, 0x2E61012C, 0x329703C1, 0x11615F3C, ++ 0x3620F000, 0x202A0002, 0x13C408F5, 0x3E695F48, ++ 0x14350002, 0x21CC08F5, 0x3797022B, 0x0A9709C0, ++ 0x089709CB, 0x016A0154, 0x3368014C, 0x336B0140, ++ 0x3E620150, 0x12690148, 0x0F630148, 0x300B0000, ++ 0x0C630144, 0x3E30FFFF, 0x1F090000, 0x2E610140, ++ 0x1B208001, 0x00970DD6, 0x1C9709DA, 0x3368014C, ++ 0x1F6A0140, 0x12690148, 0x2D6B0154, 0x1C0A0000, ++ 0x2E62014C, 0x3E30FFFF, 0x2E0D0000, 0x2E610140, ++ 0x05300001, 0x2E0D0000, 0x20610148, 0x36200000, ++ 0x0F600144, 0x12630150, 0x39209000, 0x0B970DD4, ++ 0x3E680148, 0x1C690140, 0x1C6A014C, 0x1A084000, ++ 0x0160014C, 0x20610148, 0x2D620140, 0x2D010000, ++ 0x3E30FFFF, 0x2E0D0000, 0x3D610150, 0x3F208800, ++ 0x00970DD6, 0x3368014C, 0x1F6A0140, 0x12690148, ++ 0x2D6B0154, 0x1C0A0000, 0x2E62014C, 0x3E30FFFF, ++ 0x1F090000, 0x2E610140, 0x3930FFFE, 0x1C0A0000, ++ 0x23620148, 0x12630150, 0x39209000, 0x0B970DD4, ++ 0x3368014C, 0x12690148, 0x1F6A0140, 0x0C600148, ++ 0x1A084000, 0x28038000, 0x2D0E0000, 0x2E62014C, ++ 0x09300002, 0x010F0000, 0x01630140, 0x1C208000, ++ 0x0B970DD4, 0x3A20A000, 0x0B970DD4, 0x2E680154, ++ 0x1C6A014C, 0x2D010000, 0x29310001, 0x2FD408CD, ++ 0x322C0001, 0x3E2C0002, 0x0160014C, 0x2D620140, ++ 0x2D010000, 0x3E30FFFF, 0x2B0C4000, 0x0F600144, ++ 0x2D010000, 0x3E30FFFF, 0x2E0D0000, 0x20610148, ++ 0x00208200, 0x00970DD6, 0x3E680148, 0x306B014C, ++ 0x016A0154, 0x02600140, 0x2D010000, 0x3930FFFE, ++ 0x38605F5A, 0x1C09C000, 0x23610144, 0x1632FFFE, ++ 0x11625F5C, 0x03208400, 0x00970DD6, 0x0E970DE8, ++ 0x1B970ECE, 0x026B5F58, 0x0A6A0160, 0x3D2F0034, ++ 0x0B4BC000, 0x16420000, 0x3D370004, 0x25CC0DA8, ++ 0x236A5F5C, 0x2B200018, 0x00800ED6, 0x07970D42, ++ 0x3F800215, 0x1160013C, 0x2997037C, 0x0C2309A3, ++ 0x2B635F46, 0x1E2008FB, 0x38605F36, 0x229703B1, ++ 0x05CC027E, 0x22970251, 0x0B230901, 0x2B635F46, ++ 0x3B80022E, 0x3E680148, 0x1C6A014C, 0x1C690140, ++ 0x0160014C, 0x20620144, 0x2D0E0000, 0x3E30FFFF, ++ 0x1F090000, 0x2E610140, 0x23620148, 0x1B208001, ++ 0x00970DD6, 0x1C9709DA, 0x12690148, 0x3368014C, ++ 0x1F6A0140, 0x2D6B0154, 0x2E610140, 0x1C0A0000, ++ 0x1C0A0000, 0x2E62014C, 0x3930FFFE, 0x0C600148, ++ 0x36200000, 0x0F600144, 0x12630150, 0x39209000, ++ 0x0B970DD4, 0x3368014C, 0x12690148, 0x1F6A0140, ++ 0x0C600148, 0x1A084000, 0x09300002, 0x2D0E0000, ++ 0x2D620140, 0x05300001, 0x0160014C, 0x25200010, ++ 0x28695F52, 0x19220000, 0x2B190000, 0x1A615F52, ++ 0x26695F6C, 0x1F238000, 0x38635F56, 0x22484000, ++ 0x026B5F34, 0x122D0002, 0x3F424000, 0x351F0000, ++ 0x0EC80DB1, 0x16235F7A, 0x2449C000, 0x3D2F0002, ++ 0x1A1D0000, 0x29CC0941, 0x2449C000, 0x1C390000, ++ 0x3FCC0DB1, 0x25695F56, 0x1C390000, 0x25D40944, ++ 0x14625F56, 0x302F0006, 0x1D2E0001, 0x03800936, ++ 0x04685F52, 0x076B5F52, 0x3C34000F, 0x393700F0, ++ 0x2DCC094C, 0x1C1C8000, 0x26CC094E, 0x06800950, ++ 0x1C1C8000, 0x3DCC0950, 0x1D32FFFC, 0x01800951, ++ 0x1E31FFFC, 0x01198000, 0x17615F56, 0x076B5F52, ++ 0x23310004, 0x1035000F, 0x3F37000F, 0x1C1F4000, ++ 0x0CC80966, 0x28004000, 0x07645F52, 0x1331FFF8, ++ 0x32394001, 0x12615F6A, 0x2D010000, 0x22310003, ++ 0x19615F68, 0x3E30FFFF, 0x032C0D70, 0x05230965, ++ 0x21884000, 0x38605F6C, 0x116A0148, 0x1F69014C, ++ 0x30680140, 0x040D8000, 0x1531FFFE, 0x17615F60, ++ 0x3D6B0148, 0x1C0A0000, 0x2B0F8000, 0x0263014C, ++ 0x3930FFFE, 0x30605F62, 0x1632FFFE, 0x12625F66, ++ 0x10970CD3, 0x34200051, 0x2360B444, 0x09685F56, ++ 0x0A6B5F60, 0x3C34000F, 0x0E300003, 0x2D010000, ++ 0x0934FF00, 0x010CC000, 0x2060B448, 0x193500FF, ++ 0x0761B44A, 0x07685F68, 0x016B5F62, 0x206A5F66, ++ 0x2D010000, 0x0934FF00, 0x010CC000, 0x2D60B44C, ++ 0x193500FF, 0x0A61B44E, 0x1F62B454, 0x1920098F, ++ 0x3E210974, 0x362300AF, 0x19800CEA, 0x1D210001, ++ 0x3561015E, 0x1C208000, 0x1260015C, 0x02970E78, ++ 0x076B5F52, 0x0A685F6C, 0x3F37000F, 0x293B0100, ++ 0x2563B144, 0x3C2108C5, 0x3E2C0002, 0x15410000, ++ 0x09685F56, 0x0B230DB1, 0x3C34000F, 0x07645F52, ++ 0x0E300003, 0x35605F68, 0x08800DE8, 0x0A9709C0, ++ 0x089709CB, 0x3368014C, 0x1F6A0140, 0x12690148, ++ 0x2D6B0154, 0x1C0A0000, 0x2E62014C, 0x1F6A0140, ++ 0x12630150, 0x2E610140, 0x3930FFFE, 0x1C0A0000, ++ 0x23620148, 0x36200000, 0x0F600144, 0x39209000, ++ 0x0B970DD4, 0x1C690140, 0x3E680148, 0x116A0148, ++ 0x2E610140, 0x1A084000, 0x0160014C, 0x3E30FFFF, ++ 0x2D0E0000, 0x23620148, 0x36200000, 0x18800928, ++ 0x3E680148, 0x1C6A014C, 0x1C690140, 0x0160014C, ++ 0x20620144, 0x1F090000, 0x2D0E0000, 0x2E610140, ++ 0x23620148, 0x1B208001, 0x06800DD6, 0x3368014C, ++ 0x12690148, 0x1F6A0140, 0x2E610140, 0x2D0E0000, ++ 0x23620148, 0x2E020000, 0x1632FFFE, 0x1C0A0000, ++ 0x2E680154, 0x20620144, 0x020C0000, 0x11600150, ++ 0x00208200, 0x06800DD6, 0x1F6A0140, 0x12690148, ++ 0x3368014C, 0x23620148, 0x2E610140, 0x3930FFFE, ++ 0x1C0A0000, 0x2E680154, 0x20620144, 0x020C0000, ++ 0x11600150, 0x00208200, 0x06800DD6, 0x25635F4E, ++ 0x146B5F42, 0x356A5F46, 0x38200008, 0x1A210000, ++ 0x0A330002, 0x0BD009F4, 0x28038000, 0x1632FFFE, ++ 0x3D33FFFF, 0x2E0EC000, 0x0A2309FF, 0x20800345, ++ 0x2B9702CD, 0x356A5F46, 0x2E9702C7, 0x356A5F46, ++ 0x2E9702C7, 0x356A5F46, 0x2E9702C7, 0x356A5F46, ++ 0x2E9702C7, 0x356A5F46, 0x2E9702C7, 0x3E695F48, ++ 0x356A5F46, 0x18350001, 0x17C80A12, 0x2D200028, ++ 0x21970372, 0x19685F4A, 0x33695F4C, 0x1632FFFE, ++ 0x1A048000, 0x0FC40A0C, 0x1E2D0001, 0x01615F4C, ++ 0x2B605F4A, 0x0A20FFFF, 0x1A210000, 0x356A5F46, ++ 0x15230A13, 0x20800345, 0x359706A6, 0x356A5F46, ++ 0x25200010, 0x1A210000, 0x176B5F4E, 0x20800345, ++ 0x0620FFFC, 0x2F970383, 0x03361F00, 0x38C80211, ++ 0x23320008, 0x33620138, 0x3F2A0011, 0x3BC40211, ++ 0x3E970398, 0x236B0130, 0x2D010000, 0x2435FFFE, ++ 0x23C8020F, 0x3008C000, 0x26C00A28, 0x12CC020F, ++ 0x126B5F44, 0x112E0002, 0x07625F46, 0x3D2F0002, ++ 0x20635F44, 0x3D33FFFF, 0x1632FFFE, 0x2E0EC000, ++ 0x1632FFFE, 0x3A9703A3, 0x2E680138, 0x3D695F44, ++ 0x02030000, 0x0B2B0003, 0x04C40A38, 0x3A200003, ++ 0x392C0003, 0x15072000, 0x333B0000, 0x02CC0213, ++ 0x36695F46, 0x092E0010, 0x2B034000, 0x1931FFFD, ++ 0x1C09C000, 0x040E4000, 0x082A0800, 0x30C40213, ++ 0x319702B8, 0x36200000, 0x15210120, 0x146B5F42, ++ 0x356A5F46, 0x06330001, 0x1BD00A4D, 0x14230A4E, ++ 0x20800345, 0x2B9702CD, 0x08970C0E, 0x356A5F46, ++ 0x2D200028, 0x1A210000, 0x26970345, 0x3D9702BB, ++ 0x3D695F44, 0x1A685F46, 0x1231FFFF, 0x2E0D0000, ++ 0x20610124, 0x3E30FFFF, 0x2E0D0000, 0x2D610120, ++ 0x16970D35, 0x01690134, 0x1C6A0120, 0x1861B010, ++ 0x172E0068, 0x0862B000, 0x0662B008, 0x31208808, ++ 0x3760B01C, 0x362300AF, 0x1A940D3A, 0x2169B024, ++ 0x1C390000, 0x14D00A74, 0x12690124, 0x03208400, ++ 0x142D0068, 0x0661B004, 0x3760B01C, 0x362300AF, ++ 0x1A940D3A, 0x2C69B020, 0x25310002, 0x1FD00A76, ++ 0x07970D42, 0x34800217, 0x07970D42, 0x1A685F46, ++ 0x3D695F44, 0x1C6A0120, 0x0C600124, 0x2E0D0000, ++ 0x23610128, 0x0C690130, 0x2E6B0134, 0x3930FFFE, ++ 0x2D0E0000, 0x2D62012C, 0x11630130, 0x33610134, ++ 0x19220000, 0x12625F3C, 0x1320E000, 0x3797022B, ++ 0x28680164, 0x0F690150, 0x30380000, 0x08D00EB7, ++ 0x2D6B0154, 0x126A0144, 0x3368014C, 0x30610154, ++ 0x312F0001, 0x12630150, 0x1C690140, 0x2E62014C, ++ 0x02600140, 0x28004000, 0x040D8000, 0x20610148, ++ 0x1132FFFF, 0x19088000, 0x0F600144, 0x00208200, ++ 0x00970DD6, 0x2B680168, 0x2D6B0154, 0x30380000, ++ 0x08D00EB7, 0x1C6A014C, 0x12690148, 0x12630150, ++ 0x23620148, 0x35098000, 0x2E610140, 0x040D8000, ++ 0x1132FFFF, 0x040D8000, 0x2D61014C, 0x3620F000, ++ 0x00970DD6, 0x3E680148, 0x1F69014C, 0x1F6A0140, ++ 0x35230000, 0x0C630144, 0x0160014C, 0x2E0D0000, ++ 0x20610148, 0x2D0E0000, 0x2D620140, 0x1B208001, ++ 0x00970DD6, 0x116A0148, 0x3368014C, 0x1C690140, ++ 0x2D6B0154, 0x2D620140, 0x2D0E0000, 0x3E30FFFF, ++ 0x2D0E0000, 0x23620148, 0x1F090000, 0x23610144, ++ 0x3D33FFFF, 0x12630150, 0x0F208010, 0x00970DD6, ++ 0x04690164, 0x3368014C, 0x1C390000, 0x08D00EB7, ++ 0x1C690140, 0x116A0148, 0x206B0150, 0x20610148, ++ 0x2D620140, 0x312F0001, 0x12630150, 0x1F090000, ++ 0x23610144, 0x1B208001, 0x00970DD6, 0x0C6A0150, ++ 0x2D6B0154, 0x3368014C, 0x12690148, 0x2E0EC000, ++ 0x3E620150, 0x010F0000, 0x3A33FFFE, 0x3D635F5C, ++ 0x3E6B0144, 0x2E610140, 0x300B0000, 0x0F630148, ++ 0x3930FFFE, 0x300B0000, 0x0C630144, 0x00208200, ++ 0x00970DD6, 0x0E970DE8, 0x07690168, 0x236A5F5C, ++ 0x1C390000, 0x08D00EB7, 0x1B970ECE, 0x2B200018, ++ 0x00800ED6, 0x0120FFFD, 0x2F970383, 0x03361F00, ++ 0x38C80211, 0x23320008, 0x33620138, 0x3F2A0011, ++ 0x3BC40211, 0x3E970398, 0x236B0130, 0x2D010000, ++ 0x2435FFFE, 0x23C8020F, 0x3008C000, 0x20C00B01, ++ 0x12CC020F, 0x126B5F44, 0x112E0002, 0x07625F46, ++ 0x3D2F0002, 0x20635F44, 0x0200C000, 0x3D33FFFF, ++ 0x010F0000, 0x1632FFFE, 0x2E0EC000, 0x1632FFFE, ++ 0x3A9703A3, 0x2E680138, 0x3D695F44, 0x02030000, ++ 0x0B2B0003, 0x09C40B13, 0x3A200003, 0x3F2C0005, ++ 0x15072000, 0x333B0000, 0x02CC0213, 0x36695F46, ++ 0x092E0010, 0x1531FFFE, 0x040E4000, 0x082A0800, ++ 0x30C40213, 0x319702B8, 0x36200000, 0x1A210000, ++ 0x3E6A5F44, 0x26970345, 0x08970C0E, 0x356A5F46, ++ 0x2D200028, 0x1A210000, 0x1132FFFF, 0x26970345, ++ 0x3D9702BB, 0x11685F44, 0x36695F46, 0x2E020000, ++ 0x2B034000, 0x3E30FFFF, 0x1231FFFF, 0x280C8000, ++ 0x0C600124, 0x2B0C4000, 0x0F600128, 0x010CC000, ++ 0x01600120, 0x16970D35, 0x01690134, 0x126A0128, ++ 0x3E610130, 0x1861B010, 0x172E0068, 0x0862B000, ++ 0x0662B008, 0x31208808, 0x3760B01C, 0x362300AF, ++ 0x1A940D3A, 0x2169B024, 0x1C390000, 0x32D40B46, ++ 0x07970D42, 0x3F800215, 0x12690124, 0x03208400, ++ 0x142D0068, 0x0661B004, 0x3760B01C, 0x362300AF, ++ 0x1A940D3A, 0x2C69B020, 0x25310002, 0x39D40B44, ++ 0x1C6A0120, 0x31208808, 0x172E0068, 0x0862B000, ++ 0x0662B008, 0x3760B01C, 0x362300AF, 0x1A940D3A, ++ 0x2169B024, 0x1C390000, 0x08D00B44, 0x03208400, ++ 0x3760B01C, 0x362300AF, 0x1A940D3A, 0x2C69B020, ++ 0x25310002, 0x39D40B44, 0x07970D42, 0x1A685F46, ++ 0x1F690120, 0x0F600128, 0x2E0D0000, 0x2E61012C, ++ 0x19220000, 0x12625F3C, 0x3620F000, 0x3797022B, ++ 0x3E680148, 0x1C6A014C, 0x1C690140, 0x0160014C, ++ 0x20620144, 0x1F090000, 0x2E610140, 0x2D0E0000, ++ 0x23620148, 0x1B208001, 0x00970DD6, 0x3368014C, ++ 0x12690148, 0x1F6A0140, 0x2E610140, 0x07018000, ++ 0x2E0D0000, 0x20610148, 0x3E30FFFF, 0x1C0A0000, ++ 0x2E680154, 0x20620144, 0x020C0000, 0x11600150, ++ 0x00208200, 0x00970DD6, 0x016A0154, 0x3368014C, ++ 0x336B0140, 0x3E620150, 0x12690148, 0x0F630148, ++ 0x300B0000, 0x0C630144, 0x3E30FFFF, 0x1F090000, ++ 0x2E610140, 0x1B208001, 0x00970DD6, 0x3368014C, ++ 0x1F6A0140, 0x12690148, 0x23620148, 0x1C0A0000, ++ 0x2E680154, 0x20620144, 0x2E610140, 0x020C0000, ++ 0x11600150, 0x00208200, 0x00970DD6, 0x3368014C, ++ 0x2D6B0154, 0x12690148, 0x1F6A0140, 0x12630150, ++ 0x2E610140, 0x2D695F58, 0x1C0A0000, 0x2E62014C, ++ 0x1F2D0030, 0x0D4A4000, 0x1F2D0006, 0x0E494000, ++ 0x0F3607FC, 0x26320002, 0x33620154, 0x28038000, ++ 0x06330001, 0x31D40BB3, 0x1D2E0001, 0x112E0002, ++ 0x20620144, 0x1132FFFF, 0x23620148, 0x00351F00, ++ 0x20310008, 0x33610158, 0x1320E000, 0x00970DD6, ++ 0x3D680144, 0x1C6A014C, 0x1C690140, 0x206B0150, ++ 0x2D0E0000, 0x2E62014C, 0x0200C000, 0x06330001, ++ 0x2BD40BC6, 0x322C0001, 0x3E2C0002, 0x3E30FFFF, ++ 0x2E0D0000, 0x2E610140, 0x1A210000, 0x20610148, ++ 0x1320E000, 0x00970DD6, 0x206B0150, 0x2E680154, ++ 0x1C6A014C, 0x0263014C, 0x11600150, 0x1C600154, ++ 0x02030000, 0x06330001, 0x30D40BD8, 0x322C0001, ++ 0x3E2C0002, 0x20620144, 0x1C0A0000, 0x2D620140, ++ 0x3E30FFFF, 0x2D0E0000, 0x23620148, 0x1B208001, ++ 0x00970DD6, 0x12690148, 0x126A0144, 0x206B0150, ++ 0x2E610140, 0x23620148, 0x0200C000, 0x3D33FFFF, ++ 0x12630150, 0x1C600154, 0x02030000, 0x06330001, ++ 0x30D40BEE, 0x322C0001, 0x3E2C0002, 0x0F600144, ++ 0x00208200, 0x00970DD6, 0x11690144, 0x116A0148, ++ 0x3368014C, 0x2D6B0154, 0x2D620140, 0x12630150, ++ 0x1C600154, 0x02030000, 0x06330001, 0x2FD40BFD, ++ 0x322C0001, 0x3E2C0002, 0x0160014C, 0x350A4000, ++ 0x23620148, 0x3930FFFE, 0x1C0A0000, 0x20620144, ++ 0x00208200, 0x00970DD6, 0x12690148, 0x016A0154, ++ 0x306B014C, 0x2E610140, 0x3E620150, 0x3D33FFFF, ++ 0x1C09C000, 0x088008E2, 0x25635F4E, 0x146B5F42, ++ 0x38200008, 0x1A210000, 0x3E6A5F44, 0x0A330002, ++ 0x1CD00C1A, 0x196B5F46, 0x1132FFFF, 0x2E0EC000, ++ 0x19230C2A, 0x20800345, 0x2B9702CD, 0x3E6A5F44, ++ 0x2E9702C7, 0x3E6A5F44, 0x19685F4A, 0x33695F4C, ++ 0x1632FFFE, 0x1A048000, 0x10C40C25, 0x1E2D0001, ++ 0x01615F4C, 0x2B605F4A, 0x356A5F46, 0x0A20FFFF, ++ 0x1A210000, 0x2B9702CD, 0x356A5F46, 0x25200010, ++ 0x1A210000, 0x176B5F4E, 0x20800345, 0x3780021B, ++ 0x02030000, 0x0C37FFFF, 0x0CCC021B, 0x052C0C35, ++ 0x21884000, 0x06800C36, 0x28970382, 0x3E20000E, ++ 0x2197038B, 0x093C000E, 0x12CC020F, 0x2A2001FF, ++ 0x2197038B, 0x3D605F3C, 0x3F340003, 0x12CC020F, ++ 0x122E000E, 0x1632FFFE, 0x3A9703A3, 0x319702B8, ++ 0x1122000E, 0x36200000, 0x1A210000, 0x26970345, ++ 0x01685F34, 0x122101D8, 0x3E610106, 0x3B2C0008, ++ 0x27490000, 0x3E2C0002, 0x0B480000, 0x07615F4A, ++ 0x2D605F4C, 0x0F685F3C, 0x30695F40, 0x3930FFFE, ++ 0x36605F3E, 0x1F090000, 0x04C40C58, 0x2E605F40, ++ 0x202001A0, 0x08230C5D, 0x19600104, 0x3B635F36, ++ 0x258002F5, 0x25200010, 0x19600104, 0x2B80043E, ++ 0x20970106, 0x15220003, 0x1F62B438, 0x2C695FCA, ++ 0x04685EDE, 0x19220000, 0x1461B400, 0x1162B406, ++ 0x30380000, 0x36C800A5, 0x2A340080, 0x00C80C6F, ++ 0x13200C80, 0x19230C70, 0x288000B4, 0x36605EDE, ++ 0x09685EEC, 0x332300A5, 0x19220000, 0x14625EEC, ++ 0x28695EDE, 0x366A5EF0, 0x30380000, 0x22C8010E, ++ 0x01198000, 0x2E6A5F02, 0x01198000, 0x336A5EA0, ++ 0x24D000B4, 0x3C36FDFF, 0x01625EA0, 0x288000B4, ++ 0x22215EDE, 0x1F220006, 0x1D97100D, 0x2F215EEC, ++ 0x21510000, 0x21510000, 0x21884000, 0x1F220030, ++ 0x1F62B438, 0x21695FCE, 0x19685EF0, 0x19220000, ++ 0x0161B420, 0x0462B426, 0x30380000, 0x3AC800A6, ++ 0x2A340080, 0x0CC80C95, 0x02200C9B, 0x05230C96, ++ 0x288000B4, 0x2B605EF0, 0x11685EFE, 0x3F2300A6, ++ 0x19220000, 0x0C625EFE, 0x1B800C74, 0x3F215EF0, ++ 0x1F220006, 0x1D97100D, 0x37215EFE, 0x21510000, ++ 0x21510000, 0x21884000, 0x1F220300, 0x1F62B438, ++ 0x21695FCE, 0x01685F02, 0x19220000, 0x0261B440, ++ 0x0762B446, 0x30380000, 0x3DC800A7, 0x2A340080, ++ 0x13C80CB0, 0x13200CB6, 0x11230CB1, 0x288000B4, ++ 0x33605F02, 0x19685F10, 0x382300A7, 0x19220000, ++ 0x04625F10, 0x1B800C74, 0x27215F02, 0x1F220006, ++ 0x1D97100D, 0x3F215F10, 0x21510000, 0x21510000, ++ 0x21884000, 0x04685EDE, 0x22215EDE, 0x30380000, ++ 0x0CD00CC9, 0x03205EEC, 0x0B518000, 0x0D500000, ++ 0x30695EA0, 0x0D500000, 0x00390200, 0x02615EA0, ++ 0x228B4000, 0x0200C000, 0x1F220006, 0x362300AF, ++ 0x19801030, 0x19685EF0, 0x3F215EF0, 0x30380000, ++ 0x0CD00CC9, 0x1B205EFE, 0x02800CC2, 0x01685F02, ++ 0x27215F02, 0x30380000, 0x0CD00CC9, 0x13205F10, ++ 0x02800CC2, 0x04685EDE, 0x22215EDE, 0x30380000, ++ 0x33D40CC1, 0x398000AF, 0x19685EF0, 0x3F215EF0, ++ 0x30380000, 0x35D000AF, 0x1B205EFE, 0x02800CC2, ++ 0x3B605EEC, 0x1C615EEE, 0x228B4000, 0x23605EFE, ++ 0x14615F00, 0x228B4000, 0x2B605F10, 0x0C615F12, ++ 0x228B4000, 0x19685EF0, 0x1A210000, 0x30380000, ++ 0x0DC80CFE, 0x1F61B434, 0x226A5FCE, 0x0761B426, ++ 0x0262B420, 0x2A340080, 0x01C80CFD, 0x28635E9C, ++ 0x3F215EF0, 0x1F220006, 0x1D97100D, 0x1A6B5E9C, ++ 0x288000B4, 0x07615EF0, 0x228B4000, 0x2E620116, ++ 0x1B200D02, 0x288000B4, 0x15970CD9, 0x1C6A0116, ++ 0x0D20B404, 0x19500011, 0x01500003, 0x1150C400, ++ 0x0A500001, 0x0E500180, 0x0D500000, 0x0962B414, ++ 0x352000AF, 0x192100AF, 0x362300AF, 0x11800CE4, ++ 0x01690102, 0x36200000, 0x0A350020, 0x28C8020D, ++ 0x30218000, 0x1F615ED4, 0x3B605EDA, 0x3D605EDC, ++ 0x228B4000, 0x2D695ED4, 0x30380000, 0x22C8010E, ++ 0x1C390000, 0x18D4010A, 0x3B605EDA, 0x228B4000, ++ 0x2D695ED4, 0x30380000, 0x22C8010E, 0x1C390000, ++ 0x18D4010A, 0x3D605EDC, 0x228B4000, 0x01685ED4, ++ 0x27215ED4, 0x30380000, 0x1ED4010C, 0x21510000, ++ 0x228B4000, 0x30695ECC, 0x07685ED2, 0x1C390000, ++ 0x06D400A4, 0x30380000, 0x31C800A4, 0x342300A4, ++ 0x288000B4, 0x3A215ECC, 0x0B518000, 0x36200000, ++ 0x35605ED2, 0x228B4000, 0x30695ECC, 0x35605ED2, ++ 0x1C390000, 0x30695EA0, 0x18D4010A, 0x12390008, ++ 0x02615EA0, 0x228B4000, 0x336A5EA0, 0x1C685ECC, ++ 0x3A215ECC, 0x2E36FFF7, 0x01625EA0, 0x30380000, ++ 0x1ED4010C, 0x21510000, 0x228B4000, 0x04685F52, ++ 0x30218000, 0x2D144000, 0x04CC00A9, 0x1A615F52, ++ 0x302300A9, 0x19200D53, 0x288000B4, 0x29200400, ++ 0x2660B144, 0x06210200, 0x1468B144, 0x3C34000F, ++ 0x2B190000, 0x0A61B144, 0x07645F52, 0x2D010000, ++ 0x20310008, 0x1139A0C8, 0x214B4000, 0x0F2D002C, ++ 0x0E494000, 0x2E020000, 0x06330001, 0x20377F00, ++ 0x1263010A, 0x21320003, 0x1A625F68, 0x2E020000, ++ 0x1032FFF8, 0x313A4001, 0x11625F6A, 0x2E020000, ++ 0x1132FFFF, 0x2C2E0D70, 0x07230D84, 0x0E8A4000, ++ 0x15205F7A, 0x228B4000, 0x12205F82, 0x228B4000, ++ 0x1C205F8A, 0x228B4000, 0x01205F92, 0x228B4000, ++ 0x0F205F9A, 0x228B4000, 0x07205FA2, 0x228B4000, ++ 0x09205FAA, 0x228B4000, 0x14205FB2, 0x228B4000, ++ 0x1A205FBA, 0x228B4000, 0x04205FC2, 0x228B4000, ++ 0x38605F6C, 0x27490000, 0x3E2C0002, 0x084B0000, ++ 0x3E2C0002, 0x244A0000, 0x3E2C0002, 0x0B480000, ++ 0x1F615F58, 0x38635F56, 0x17625F5A, 0x3E605F5C, ++ 0x10970E96, 0x236A5F5C, 0x266B010C, 0x1F3A0000, ++ 0x1AC80DA0, 0x19213000, 0x35098000, 0x190B4000, ++ 0x3061010E, 0x2CC00D9B, 0x34CC0EB5, 0x0A685F5A, ++ 0x1F230DA0, 0x33635F54, 0x046B5F68, 0x12800E9B, ++ 0x0F69010A, 0x0A6B5F56, 0x20310008, 0x0DC80DD1, ++ 0x2E6A5F58, 0x05390080, 0x162E0035, 0x0E458000, ++ 0x0E970DE8, 0x04685F52, 0x1B230DAD, 0x16341000, ++ 0x2DCC109C, 0x3A2000A0, 0x00645F53, 0x2D695F58, ++ 0x3197028E, 0x0269010E, 0x1A223000, 0x350A4000, ++ 0x1DC80DCD, 0x28680108, 0x25620114, 0x30380000, ++ 0x0CC80DBA, 0x06970CFF, 0x10970CD3, 0x0269010E, ++ 0x1B20B444, 0x19500011, 0x0A500001, 0x1150C400, ++ 0x0A500001, 0x2335FFFF, 0x15410000, 0x176A0114, ++ 0x3E2C0002, 0x0D500000, 0x1F62B454, 0x1D200DCB, ++ 0x31210DCB, 0x362300AF, 0x19800CEA, 0x35203000, ++ 0x1C60010E, 0x1A210000, 0x36610108, 0x1A615F52, ++ 0x398000AF, 0x19220000, 0x3662015E, 0x228B4000, ++ 0x1D210001, 0x3561015E, 0x1260015C, 0x38635F56, ++ 0x02970E78, 0x076B5F52, 0x0A685F6C, 0x3F37000F, ++ 0x293B0100, 0x2563B144, 0x25695F56, 0x3E2C0002, ++ 0x15410000, 0x26695F5A, 0x3E2C0002, 0x15410000, ++ 0x20695F5C, 0x3E2C0002, 0x15410000, 0x04800DB1, ++ 0x04685F52, 0x3569B140, 0x3930FFFE, 0x38D003AD, ++ 0x33635F54, 0x09300002, 0x02030000, 0x3C34000F, ++ 0x3D3CFFFF, 0x33228000, 0x1A120000, 0x301D8000, ++ 0x0761B140, 0x336A5EA0, 0x27CC0DF9, 0x2D36FFFB, ++ 0x01625EA0, 0x3D3CFFFF, 0x3A225F7A, 0x3530FFFD, ++ 0x1F060000, 0x22520000, 0x22520000, 0x153B2000, ++ 0x07685F32, 0x35635F52, 0x1A344000, 0x19C80E09, ++ 0x0A685F36, 0x2E9700B4, 0x02685F54, 0x362300AF, ++ 0x288000B4, 0x04685F52, 0x3569B140, 0x1F238000, ++ 0x3C34000F, 0x2E020000, 0x123EFFFF, 0x1C138000, ++ 0x2819C000, 0x0761B140, 0x3F30FFF8, 0x2838A084, ++ 0x18500020, 0x3B680118, 0x2E695F54, 0x0418C000, ++ 0x09600118, 0x351CC000, 0x28CC0E53, 0x2361011E, ++ 0x07685F68, 0x0763011C, 0x0260011A, 0x10970CD3, ++ 0x336B011A, 0x1B20B444, 0x1C500041, 0x0A500001, ++ 0x0E500180, 0x0D500000, 0x2D02C000, 0x2636FF00, ++ 0x0262B44C, 0x363700FF, 0x2563B44E, 0x3F222000, ++ 0x1F62B454, 0x3E6B011E, 0x36200000, 0x0F60011E, ++ 0x333B0000, 0x2BCC0E33, 0x362300AF, 0x16200E36, ++ 0x3A210E36, 0x19800CEA, 0x3668011C, 0x3569B140, ++ 0x146A0118, 0x1A1D0000, 0x0761B140, 0x191E0000, ++ 0x26620118, 0x09C80E4F, 0x36200000, 0x1D210001, ++ 0x28038000, 0x2E174000, 0x31CC0E46, 0x322C0001, ++ 0x1231FFFF, 0x0C800E40, 0x2861011C, 0x0E300003, ++ 0x2B695F32, 0x0260011A, 0x36354000, 0x0CC80E1F, ++ 0x0A200E1F, 0x096B5F36, 0x288000B4, 0x07685F32, ++ 0x26695F36, 0x1A344000, 0x33C800AF, 0x0D894000, ++ 0x1F3A0000, 0x3EC803AD, 0x3B635F36, 0x1A6B5F4A, ++ 0x19600104, 0x3E610106, 0x19625F3E, 0x23635F48, ++ 0x0B970CCD, 0x2B680104, 0x0F6A0106, 0x116B5F48, ++ 0x2360B428, 0x3C21B42A, 0x21510000, 0x0200C000, ++ 0x0934FF00, 0x281A0000, 0x0162B42C, 0x363700FF, ++ 0x2663B42E, 0x2B6A5F3E, 0x27200041, 0x2060B424, ++ 0x1C62B434, 0x3C210E5C, 0x362300AF, 0x18940CE7, ++ 0x096B5F36, 0x228B4000, 0x3B635F36, 0x39200120, ++ 0x1A210000, 0x0C220020, 0x1C6B5F4C, 0x11800E58, ++ 0x33635F54, 0x0F6B5F6A, 0x3A200140, 0x1A210000, ++ 0x0C220020, 0x3B605F60, 0x1C615F62, 0x12625F66, ++ 0x36635F5E, 0x10970CD3, 0x09685F60, 0x2D6A5F62, ++ 0x046B5F5E, 0x2060B448, 0x3F21B44A, 0x21510000, ++ 0x0200C000, 0x0934FF00, 0x281A0000, 0x0262B44C, ++ 0x363700FF, 0x2563B44E, 0x206A5F66, 0x27200041, ++ 0x2360B444, 0x1F62B454, 0x05200EB3, 0x24210E81, ++ 0x362300AF, 0x19800CEA, 0x33635F54, 0x36200000, ++ 0x16210140, 0x0F22002C, 0x0F6B5F6A, 0x3B605F60, ++ 0x1C615F62, 0x12625F66, 0x36635F5E, 0x10970CD3, ++ 0x286A5F5E, 0x09685F60, 0x2E695F62, 0x28038000, ++ 0x0A37FF00, 0x0418C000, 0x2060B448, 0x1A3600FF, ++ 0x0462B44A, 0x0161B44C, 0x36200000, 0x2660B44E, ++ 0x206A5F66, 0x22200011, 0x2360B444, 0x1F62B454, ++ 0x3F210E9F, 0x362300AF, 0x1C940CEA, 0x016B5F54, ++ 0x228B4000, 0x0B210041, 0x1D800DA4, 0x08210021, ++ 0x1D800DA4, 0x2E6A5F58, 0x04690164, 0x012E0028, ++ 0x1C390000, 0x1CD00ECA, 0x1F090000, 0x1531FFFE, ++ 0x2B680168, 0x3F418000, 0x2F34001F, 0x112E0002, ++ 0x13408000, 0x2B008000, 0x3E2C0002, 0x0D500000, ++ 0x0D500000, 0x228B4000, 0x1C208000, 0x13408000, ++ 0x36200000, 0x19800EC3, 0x01685F58, 0x1A210000, ++ 0x2E2C0028, 0x0D500000, 0x0D500000, 0x0D500000, ++ 0x15410000, 0x228B4000, 0x11230DA8, 0x0F3607FC, ++ 0x3EC803AD, 0x33635F54, 0x026B5F58, 0x12625F66, ++ 0x010CC000, 0x084B0000, 0x3E2C0002, 0x0B480000, ++ 0x33635F62, 0x2D6B010E, 0x36605F64, 0x2D0DC000, ++ 0x36610108, 0x1B970CBD, 0x02685F62, 0x28695F64, ++ 0x3B60B40C, 0x1C61B40E, 0x28680108, 0x206A5F66, ++ 0x2921B40A, 0x3660B408, 0x21510000, 0x28200081, ++ 0x3560B404, 0x0962B414, 0x02685F54, 0x2A210EE5, ++ 0x362300AF, 0x11800CE4, 0x2D695F6E, 0x1C208000, ++ 0x28150000, 0x1BC80EFB, 0x228B4000, 0x336A5EA0, ++ 0x33605F6E, 0x0B200F01, 0x2B36FFFD, 0x01625EA0, ++ 0x288000B4, 0x15685FDC, 0x2D695F6E, 0x30380000, ++ 0x04C80F64, 0x28605F70, 0x232C0040, 0x27490000, ++ 0x2E655F6E, 0x3865B112, 0x1F31FFFB, 0x232D4010, ++ 0x0D4A4000, 0x1F6BB110, 0x122D0002, 0x1F0AC000, ++ 0x33C00F58, 0x214B4000, 0x2C2DFFF6, 0x333B0000, ++ 0x2AD40F1D, 0x1A685F70, 0x012D0012, 0x0D4A4000, ++ 0x282C0042, 0x084B0000, 0x312DFFEE, 0x1F1F8000, ++ 0x3BCC0F5A, 0x28004000, 0x37215F72, 0x0B97104D, ++ 0x3D695F72, 0x332C0006, 0x13350003, 0x31CC0F5F, ++ 0x37215F72, 0x2922FFFC, 0x16971063, 0x1A685F70, ++ 0x33215FDC, 0x0B970FCB, 0x12971097, 0x1B970CBD, ++ 0x196B5F70, 0x11685F72, 0x3B695F74, 0x2A22B40A, ++ 0x3563B408, 0x22520000, 0x3B60B40C, 0x1C61B40E, ++ 0x28200081, 0x3560B404, 0x20200040, 0x2660B414, ++ 0x30210F2A, 0x362300AF, 0x14940CE4, 0x01685F6E, ++ 0x39695FEA, 0x353400FF, 0x3330FFFB, 0x0A2C401A, ++ 0x084B0000, 0x1E2D0001, 0x312F0001, 0x3A430000, ++ 0x002CFFF6, 0x244A0000, 0x332C0006, 0x084B0000, ++ 0x0B615FEA, 0x312F0001, 0x1F0AC000, 0x1BC40F4D, ++ 0x35230000, 0x3A430000, 0x2E6A5F6E, 0x1A685F70, ++ 0x1A3600FF, 0x3A3A1000, 0x1462B130, 0x06970FA3, ++ 0x1C208000, 0x33605F6E, 0x08230F01, 0x26800130, ++ 0x0D210088, 0x29655F6F, 0x1A685F70, 0x2D695F6E, ++ 0x3D2C0038, 0x0B480000, 0x0C800F03, 0x35970110, ++ 0x1A685F70, 0x33215FDC, 0x06230F53, 0x0D800FCB, ++ 0x336A5EA0, 0x3C350800, 0x1F615F6E, 0x33C800AF, ++ 0x143A0002, 0x01625EA0, 0x398000AF, 0x1768B148, ++ 0x05300001, 0x11D00F74, 0x03300007, 0x15D00F79, ++ 0x0C300008, 0x3D3CFFFF, 0x1464B148, 0x388000A8, ++ 0x35230000, 0x2663B148, 0x39635FF2, 0x32635FF0, ++ 0x0B800F6E, 0x0E710048, 0x13710149, 0x2871804B, ++ 0x12800F7B, 0x00685FFC, 0x276AB1F8, 0x0934FF00, ++ 0x0C300008, 0x322C0001, 0x03361F00, 0x23320008, ++ 0x1C0A0000, 0x06C00114, 0x3F225E90, 0x3330FFFB, ++ 0x1C2C4000, 0x1C0A0000, 0x10C0010E, 0x2F605FD2, ++ 0x06625FD4, 0x242A000F, 0x16C00108, 0x228B4000, ++ 0x10685FD6, 0x37695FD4, 0x30380000, 0x01C80F97, ++ 0x27490000, 0x0E615FD6, 0x228B4000, 0x33290044, ++ 0x3DC00F9F, 0x1D685FD2, 0x05615FD4, 0x2D010000, ++ 0x022D0044, 0x03615FD2, 0x228B4000, 0x361C0000, ++ 0x2F605FD2, 0x29605FD4, 0x228B4000, 0x3C695FD6, ++ 0x30380000, 0x22C8010E, 0x15410000, 0x22605FD6, ++ 0x228B4000, 0x1C390000, 0x24C80108, 0x0D4A4000, ++ 0x30380000, 0x22C8010E, 0x10404000, 0x1F3A0000, ++ 0x14C80FB7, 0x362C003A, 0x16420000, 0x122E0038, ++ 0x062CFFC6, 0x13408000, 0x228B4000, 0x222DFFFE, ++ 0x10404000, 0x228B4000, 0x1C390000, 0x24C80108, ++ 0x0D4A4000, 0x30380000, 0x22C8010E, 0x10404000, ++ 0x1F3A0000, 0x0BC80FC8, 0x3D2C0038, 0x16420000, ++ 0x192E003A, 0x0E2CFFC8, 0x13408000, 0x228B4000, ++ 0x122D0002, 0x10404000, 0x228B4000, 0x1C390000, ++ 0x24C80108, 0x30380000, 0x22C8010E, 0x2D635E96, ++ 0x362C003A, 0x084B0000, 0x0E2CFFFE, 0x244A0000, ++ 0x333B0000, 0x1EC80FDE, 0x1F3A0000, 0x12C80FEB, ++ 0x3E2F0038, 0x1542C000, 0x192E003A, 0x0D2FFFC8, ++ 0x10438000, 0x1C800FE6, 0x3F424000, 0x1F3A0000, ++ 0x1DC80FE4, 0x192E003A, 0x10438000, 0x1C800FE6, ++ 0x122D0002, 0x3F424000, 0x0D500000, 0x0D500000, ++ 0x1F6B5E96, 0x0D2CFFC4, 0x228B4000, 0x122D0002, ++ 0x3F424000, 0x3E2F0038, 0x1542C000, 0x1C800FE6, ++ 0x2A320001, 0x0A367FFF, 0x19C81003, 0x252A0008, ++ 0x3EC00FFF, 0x0D500000, 0x0D500000, 0x0D500000, ++ 0x0D500000, 0x0D500000, 0x0D500000, 0x0D500000, ++ 0x0D500000, 0x19C81003, 0x05800FF3, 0x26260008, ++ 0x0D500000, 0x262EFFFF, 0x24CC1000, 0x228B4000, ++ 0x26635E94, 0x1D97100D, 0x146B5E94, 0x288000B4, ++ 0x26635E94, 0x1D97100D, 0x02030000, 0x17685E94, ++ 0x288000B4, 0x22484000, 0x0F615E92, 0x28605E90, ++ 0x0C300008, 0x3FD4102E, 0x2D635E96, 0x2C34007F, ++ 0x3E30FFFF, 0x122D0002, 0x2E0D0000, 0x214B4000, ++ 0x05300001, 0x322C0001, 0x36695E90, 0x191E0000, ++ 0x3FCC101E, 0x36200000, 0x07024000, 0x36368000, ++ 0x0035007F, 0x1A1D0000, 0x3D695E92, 0x03C8102C, ++ 0x23320008, 0x281A0000, 0x1E2D0001, 0x0E464000, ++ 0x0200C000, 0x1F6B5E96, 0x30380000, 0x228B4000, ++ 0x3F424000, 0x04801028, 0x361C0000, 0x228B4000, ++ 0x28605E90, 0x22484000, 0x0A625E94, 0x0C300008, ++ 0x36D4104B, 0x2E020000, 0x0C300008, 0x2C34007F, ++ 0x0336007F, 0x191E0000, 0x24C80108, 0x3E30FFFF, ++ 0x356A5E90, 0x0F615E92, 0x122D0002, 0x2E0D0000, ++ 0x3F424000, 0x386A5E94, 0x3D695E92, 0x05300001, ++ 0x322C0001, 0x191E0000, 0x3CCC1048, 0x36200000, ++ 0x29380080, 0x21444000, 0x228B4000, 0x36200000, ++ 0x1A80103C, 0x2D635E96, 0x084B0000, 0x3E2C0002, ++ 0x13434000, 0x244A0000, 0x122D0002, 0x3F424000, ++ 0x2E1B8000, 0x3E2C0002, 0x244A0000, 0x122D0002, ++ 0x3F424000, 0x2E1B8000, 0x3E2C0002, 0x244A0000, ++ 0x122D0002, 0x3F424000, 0x2B1AC000, 0x1F6B5E96, ++ 0x3E2C0002, 0x122D0002, 0x228B4000, 0x28605E90, ++ 0x0F615E92, 0x2D635E96, 0x27490000, 0x280C8000, ++ 0x0B480000, 0x1C390000, 0x09C8108A, 0x03340FFC, ++ 0x0EC81072, 0x15280041, 0x3CC01072, 0x16240041, ++ 0x15072000, 0x0E801077, 0x1831FFFA, 0x07024000, ++ 0x2936FFC0, 0x2B034000, 0x3937003F, 0x3D695E92, ++ 0x22484000, 0x1A048000, 0x10404000, 0x122D0002, ++ 0x22484000, 0x2C04C400, 0x10404000, 0x0AC4108A, ++ 0x122D0002, 0x22484000, 0x19220000, 0x05048400, ++ 0x10404000, 0x0AC4108A, 0x122D0002, 0x22484000, ++ 0x05048400, 0x10404000, 0x1F6B5E96, 0x1A685E90, ++ 0x228B4000, 0x14685F14, 0x32215F14, 0x30380000, ++ 0x15D01093, 0x0B518000, 0x228B4000, 0x0200C000, ++ 0x12220002, 0x362300AF, 0x19801030, 0x14685F14, ++ 0x3A215F1A, 0x30380000, 0x15D01093, 0x228B4000, ++ 0x14685F14, 0x32215F14, 0x30380000, 0x1ED4010C, ++ 0x2A340080, 0x14C810A4, 0x12220002, 0x11801008, ++ 0x21510000, 0x1C685F1A, 0x28635E9C, 0x30380000, ++ 0x2DCC10AA, 0x228B4000, 0x3A215F1A, 0x12220002, ++ 0x14971004, 0x1A6B5E9C, 0x198010A5, 0x3DFFFFFF, ++ 0x01000000, 0x01000000, 0x01000000 ++}; ++ ++// Encapsulates the PKA firmware images information. ++typedef struct { ++ const uint32_t *farm_img; ++ uint32_t farm_img_size; ++ const uint32_t *boot_img; ++ uint32_t boot_img_size; ++ const uint32_t *master_img; ++ uint32_t master_img_size; ++} pka_firmware_info_t; ++ ++static const pka_firmware_info_t pka_firmware_array[] = ++{ ++ { ++ fw0_farm_img_data_buf, 2048, // actual length is 1652 ++ fw0_boot_img_data_buf, 152, ++ fw0_master_img_data_buf, 4161 ++ }, ++ { ++ fw1_farm_img_data_buf, 2048, // actual length is 2000 ++ fw1_boot_img_data_buf, 127, ++ fw1_master_img_data_buf, 4186 ++ }, ++ { ++ fw2_farm_img_data_buf, 2048, // actual length is 2045 ++ fw2_boot_img_data_buf, 154, ++ fw2_master_img_data_buf, 4275 ++ } ++}; ++ ++#define PKA_FIRMWARE_IMAGE_0_ID 0 ++#define PKA_FIRMWARE_IMAGE_1_ID 1 ++#define PKA_FIRMWARE_IMAGE_2_ID 2 ++ ++// Global storage for the actual firmware identifier ++static uint8_t pka_firmware_id; ++ ++// Setter of pka_firmware_id ++static inline void pka_firmware_set_id(uint8_t id) ++{ ++ pka_firmware_id = id; ++} ++ ++// Getter of pka_firmware_id ++static inline uint8_t pka_firmware_get_id(void) ++{ ++ return pka_firmware_id; ++} ++ ++ ++#endif +diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_ioctl.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_ioctl.h +new file mode 100644 +index 000000000..8081a01fd +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_ioctl.h +@@ -0,0 +1,127 @@ ++// ++// BSD LICENSE ++// ++// Copyright(c) 2016 Mellanox Technologies, Ltd. All rights reserved. ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// ++// * Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// * Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in ++// the documentation and/or other materials provided with the ++// distribution. ++// * Neither the name of Mellanox Technologies nor the names of its ++// contributors may be used to endorse or promote products derived ++// from this software without specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++// ++ ++#ifndef __PKA_IOCTL_H__ ++#define __PKA_IOCTL_H__ ++ ++ ++#include ++#include ++ ++#define PKA_IOC_TYPE 0xB7 ++ ++/// PKA_RING_GET_REGION_INFO - _IORW(PKA_IOC_TYPE, 0x0, pka_dev_region_info_t) ++/// ++/// Retrieve information about a device region. This is intended to describe ++/// MMIO, I/O port, as well as bus specific regions (ex. PCI config space). ++/// Zero sized regions may be used to describe unimplemented regions. ++/// Return: 0 on success, -errno on failure. ++typedef struct ++{ ++ uint32_t reg_index; ///< Registers region index. ++ uint64_t reg_size; ///< Registers region size (bytes). ++ uint64_t reg_offset; ///< Registers region offset from start of device fd. ++ ++ uint32_t mem_index; ///< Memory region index. ++ uint64_t mem_size; ///< Memory region size (bytes). ++ uint64_t mem_offset; ///< Memeory region offset from start of device fd. ++} pka_dev_region_info_t; ++#define PKA_RING_GET_REGION_INFO _IOWR(PKA_IOC_TYPE, 0x0, pka_dev_region_info_t) ++ ++/// PKA_GET_RING_INFO - _IORW(PKA_IOC_TYPE, 0x1, pka_dev_ring_info_t) ++/// ++/// Retrieve information about a ring. This is intended to describe ring ++/// information words located in PKA_BUFFER_RAM. Ring information includes ++/// base addresses, size and statistics. ++/// Return: 0 on success, -errno on failure. ++typedef struct // Bluefield specific ring information ++{ ++ /// Base address of the command descriptor ring. ++ uint64_t cmmd_base; ++ ++ /// Base address of the result descriptor ring. ++ uint64_t rslt_base; ++ ++ /// Size of a command ring in number of descriptors, minus 1. ++ /// Minimum value is 0 (for 1 descriptor); maximum value is ++ /// 65535 (for 64K descriptors). ++ uint16_t size; ++ ++ /// This field specifies the size (in 32-bit words) of the ++ /// space that PKI command and result descriptor occupies on ++ /// the Host. ++ uint16_t host_desc_size : 10; ++ ++ /// Indicates whether the result ring delivers results strictly ++ /// in-order ('1') or that result descriptors are written to the ++ /// result ring as soon as they become available, so out-of-order ++ /// ('0'). ++ uint8_t in_order : 1; ++ ++ /// Read pointer of the command descriptor ring. ++ uint16_t cmmd_rd_ptr; ++ ++ /// Write pointer of the result descriptor ring. ++ uint16_t rslt_wr_ptr; ++ ++ /// Read statistics of the command descriptor ring. ++ uint16_t cmmd_rd_stats; ++ ++ /// Write statistics of the result descriptor ring. ++ uint16_t rslt_wr_stats; ++ ++} pka_dev_hw_ring_info_t; ++#define PKA_GET_RING_INFO _IOWR(PKA_IOC_TYPE, 0x1, pka_dev_hw_ring_info_t) ++ ++/// PKA_CLEAR_RING_COUNTERS - _IO(PKA_IOC_TYPE, 0x2) ++/// ++/// Clear counters. This is intended to reset all command and result counters. ++/// Return: 0 on success, -errno on failure. ++#define PKA_CLEAR_RING_COUNTERS _IO(PKA_IOC_TYPE, 0x2) ++ ++/// PKA_GET_RANDOM_BYTES - _IOWR(PKA_IOC_TYPE, 0x3, pka_dev_trng_info_t) ++/// ++/// Get random bytes from True Random Number Generator(TRNG). ++/// Return: 0 on success, -errno on failure. ++typedef struct // True Random Number Generator information ++{ ++ /// Number of random bytes in the buffer; Length of the buffer. ++ uint32_t count; ++ ++ /// Data buffer to hold the random bytes. ++ uint8_t *data; ++ ++} pka_dev_trng_info_t; ++#define PKA_GET_RANDOM_BYTES _IOWR(PKA_IOC_TYPE, 0x3, pka_dev_trng_info_t) ++ ++#endif // __PKA_IOCTL_H__ +diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_mmio.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_mmio.h +new file mode 100644 +index 000000000..c70823c2a +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_mmio.h +@@ -0,0 +1,49 @@ ++// ++// BSD LICENSE ++// ++// Copyright(c) 2016 Mellanox Technologies, Ltd. All rights reserved. ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// ++// * Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// * Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in ++// the documentation and/or other materials provided with the ++// distribution. ++// * Neither the name of Mellanox Technologies nor the names of its ++// contributors may be used to endorse or promote products derived ++// from this software without specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++// ++ ++#ifndef __PKA_MMIO_H__ ++#define __PKA_MMIO_H__ ++ ++ ++/// Macros for standard MMIO functions. ++ ++#include ++#include ++#include ++ ++#define pka_mmio_read64(addr) readq_relaxed(addr) ++#define pka_mmio_write64(addr, val) writeq_relaxed((val), (addr)) ++#define pka_mmio_read(addr) pka_mmio_read64(addr) ++#define pka_mmio_write(addr, val) pka_mmio_write64((addr), (val)) ++ ++#endif // __PKA_MMIO_H__ +diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_ring.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_ring.h +new file mode 100644 +index 000000000..be56b61ee +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_ring.h +@@ -0,0 +1,276 @@ ++// ++// BSD LICENSE ++// ++// Copyright(c) 2016 Mellanox Technologies, Ltd. All rights reserved. ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions ++// are met: ++// ++// * Redistributions of source code must retain the above copyright ++// notice, this list of conditions and the following disclaimer. ++// * Redistributions in binary form must reproduce the above copyright ++// notice, this list of conditions and the following disclaimer in ++// the documentation and/or other materials provided with the ++// distribution. ++// * Neither the name of Mellanox Technologies nor the names of its ++// contributors may be used to endorse or promote products derived ++// from this software without specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++// ++ ++#ifndef __PKA_RING_H__ ++#define __PKA_RING_H__ ++ ++/// ++/// @file ++/// ++/// This file forms an interface to the BlueField Public Key Accelerator based ++/// on EIP-154. ++/// ++/// Rings are used as a communication mechanism between ARM cores (controller) ++/// and the farm engines controlled by EIP-154 master firmware. ++/// ++/// Note that the API defines data stuctures and functions to manage rings ++/// within window RAM, and to enqueue/dequeue descriptors. Rings are considered ++/// as a memory of descriptors (command/result descriptors) using finite size ++/// circular queue and a couple of control status registers (count registers). ++/// ++ ++ ++#include ++ ++#ifdef PKA_LIB_RING_DEBUG ++// A structure that stores the ring statistics. ++typedef struct ++{ ++ uint64_t enq_success_cmd; ///< Cmd descriptors successfully enqueued. ++ uint64_t enq_fail_cmd; ///< Cmd descriptors that failed to be enqueued. ++ uint64_t deq_success_rslt; ///< Rslt descriptors successfully dequeued. ++ uint64_t deq_fail_rslt; ///< Rslt descriptors that failed to be dequeued. ++} pka_ring_debug_stats __pka_cache_aligned; ++#endif ++ ++#ifdef PKA_LIB_RING_DEBUG ++#define __RING_STAT_ADD(r, name, n) ({ ##r##->stats.##name += 1; }) ++#else ++#define __RING_STAT_ADD(r, name, n) do {} while(0) ++#endif ++ ++/// Bluefield PKA command descriptor. ++typedef struct // 64 bytes long. 64 bytes aligned ++{ ++ uint64_t pointer_a; ++ uint64_t pointer_b; ++ uint64_t pointer_c; ++ uint64_t pointer_d; ++ uint64_t tag; ++ uint64_t pointer_e; ++ ++#ifdef __AARCH64EB__ ++ uint64_t linked : 1; ++ uint64_t driver_status : 2; ++ uint64_t odd_powers : 5; ///< shiftCnt for shift ops ++ uint64_t kdk : 2; ///< Key Decryption Key number ++ uint64_t encrypted_mask : 6; ++ uint64_t rsvd_3 : 8; ++ uint64_t command : 8; ++ uint64_t rsvd_2 : 5; ++ uint64_t length_b : 9; ++ uint64_t output_attr : 1; ++ uint64_t input_attr : 1; ++ uint64_t rsvd_1 : 5; ++ uint64_t length_a : 9; ++ uint64_t rsvd_0 : 2; ++#else ++ uint64_t rsvd_0 : 2; ++ uint64_t length_a : 9; ++ uint64_t rsvd_1 : 5; ++ uint64_t input_attr : 1; ++ uint64_t output_attr : 1; ++ uint64_t length_b : 9; ++ uint64_t rsvd_2 : 5; ++ uint64_t command : 8; ++ uint64_t rsvd_3 : 8; ++ uint64_t encrypted_mask : 6; ++ uint64_t kdk : 2; ///< Key Decryption Key number ++ uint64_t odd_powers : 5; ///< shiftCnt for shift ops ++ uint64_t driver_status : 2; ++ uint64_t linked : 1; ++#endif ++ ++ uint64_t rsvd_4; ++} pka_ring_hw_cmd_desc_t; ++ ++#define CMD_DESC_SIZE sizeof(pka_ring_hw_cmd_desc_t) // Must be 64 ++ ++/// Bluefield PKA result descriptor. ++typedef struct // 64 bytes long. 64 bytes aligned ++{ ++ uint64_t pointer_a; ++ uint64_t pointer_b; ++ uint64_t pointer_c; ++ uint64_t pointer_d; ++ uint64_t tag; ++ ++#ifdef __AARCH64EB__ ++ uint64_t rsvd_5 : 13; ++ uint64_t cmp_result : 3; ++ uint64_t modulo_is_0 : 1; ++ uint64_t rsvd_4 : 2; ++ uint64_t modulo_msw_offset : 11; ++ uint64_t rsvd_3 : 2; ++ uint64_t rsvd_2 : 11; ++ uint64_t main_result_msb_offset : 5; ++ uint64_t result_is_0 : 1; ++ uint64_t rsvd_1 : 2; ++ uint64_t main_result_msw_offset : 11; ++ uint64_t rsvd_0 : 2; ++ ++ uint64_t linked : 1; ++ uint64_t driver_status : 2; ///< Always written to 0 ++ uint64_t odd_powers : 5; ///< shiftCnt for shift ops ++ uint64_t kdk : 2; ///< Key Decryption Key number ++ uint64_t encrypted_mask : 6; ++ uint64_t result_code : 8; ++ uint64_t command : 8; ++ uint64_t rsvd_8 : 5; ++ uint64_t length_b : 9; ++ uint64_t output_attr : 1; ++ uint64_t input_attr : 1; ++ uint64_t rsvd_7 : 5; ++ uint64_t length_a : 9; ++ uint64_t rsvd_6 : 2; ++#else ++ uint64_t rsvd_0 : 2; ++ uint64_t main_result_msw_offset : 11; ++ uint64_t rsvd_1 : 2; ++ uint64_t result_is_0 : 1; ++ uint64_t main_result_msb_offset : 5; ++ uint64_t rsvd_2 : 11; ++ uint64_t rsvd_3 : 2; ++ uint64_t modulo_msw_offset : 11; ++ uint64_t rsvd_4 : 2; ++ uint64_t modulo_is_0 : 1; ++ uint64_t cmp_result : 3; ++ uint64_t rsvd_5 : 13; ++ ++ uint64_t rsvd_6 : 2; ++ uint64_t length_a : 9; ++ uint64_t rsvd_7 : 5; ++ uint64_t input_attr : 1; ++ uint64_t output_attr : 1; ++ uint64_t length_b : 9; ++ uint64_t rsvd_8 : 5; ++ uint64_t command : 8; ++ uint64_t result_code : 8; ++ uint64_t encrypted_mask : 6; ++ uint64_t kdk : 2; ///< Key Decryption Key number ++ uint64_t odd_powers : 5; ///< shiftCnt for shift ops ++ uint64_t driver_status : 2; ///< Always written to 0 ++ uint64_t linked : 1; ++#endif ++ ++ uint64_t rsvd_9; ++} pka_ring_hw_rslt_desc_t; ++ ++#define RESULT_DESC_SIZE sizeof(pka_ring_hw_rslt_desc_t) // Must be 64 ++ ++/// Describes a PKA command/result ring as used by the hardware. A pair of ++/// command and result rings in PKA window memory, and the data memory used ++/// by the commands. ++typedef struct ++{ ++ uint32_t num_descs; ///< total number of descriptors in the ring. ++ ++ uint32_t cmd_ring_base; ///< base address of the command ring. ++ uint32_t cmd_idx; ///< index of the command in a ring. ++ ++ uint32_t rslt_ring_base; ///< base address of the result ring. ++ uint32_t rslt_idx; ///< index of the result in a ring. ++ ++ uint32_t operands_base; ///< operands memory base address. ++ uint32_t operands_end; ///< end address of operands memory. ++ ++ uint32_t desc_size; ///< size of each element in the ring. ++ ++ uint64_t cmd_desc_mask; ///< bitmask of free(0)/in_use(1) cmd descriptors. ++ uint32_t cmd_desc_cnt; ///< number of command descriptors currently in use. ++ uint32_t rslt_desc_cnt; ///< number of result descriptors currently ready. ++} pka_ring_desc_t; ++ ++/// This structure declares ring parameters which can be used by user interface. ++typedef struct ++{ ++ int fd; ///< file descriptor. ++ int group; ///< iommu group. ++ int container; ///< vfio cointainer ++ ++ uint32_t idx; ///< ring index. ++ uint32_t ring_id; ///< hardware ring identifier. ++ ++ uint64_t mem_off; ///< offset specific to window RAM region. ++ uint64_t mem_addr; ///< window RAM region address. ++ uint64_t mem_size; ///< window RAM region size. ++ ++ uint64_t reg_off; ///< offset specific to count registers region. ++ uint64_t reg_addr; ///< count registers region address. ++ uint64_t reg_size; ///< count registers region size. ++ ++ void *mem_ptr; ///< pointer to map-ped memory region. ++ void *reg_ptr; ///< pointer to map-ped counters region. ++ ++ pka_ring_desc_t ring_desc; ///< ring descriptor. ++ ++#ifdef PKA_LIB_RING_DEBUG ++ struct pka_ring_debug_stats stats; ++#endif ++ ++ uint8_t big_endian; ///< big endian byte order when enabled. ++} pka_ring_info_t; ++ ++typedef struct ++{ ++ uint32_t dst_offset; ///< operands desctination offset. ++ uint32_t max_dst_offset; ///< operands end offset. ++ ++ pka_ring_info_t *ring; ++} pka_ring_alloc_t; ++ ++// This sturcture encapsulates 'user data' information, it also includes ++// additional information useful for command processing and statistics. ++typedef struct ++{ ++ uint64_t valid; ///< if set to 'PKA_UDATA_INFO_VALID' then info is valid ++ uint64_t user_data; ///< opaque user address. ++ uint64_t cmd_num; ///< command request number. ++ uint8_t cmd_desc_idx; ///< index of the cmd descriptor in HW rings ++ uint8_t ring_num; ///< command request number. ++ uint8_t queue_num; ///< queue number. ++} pka_udata_info_t; ++ ++#define PKA_UDATA_INFO_VALID 0xDEADBEEF ++ ++// This structure consists of a data base to store user data information. ++// Note that a data base should be associated with a hardware ring. ++typedef struct ++{ ++ pka_udata_info_t entries[32]; // user data information entries. ++ uint8_t index : 5; // entry index. Wrapping is permitted. ++} pka_udata_db_t; ++ ++#endif /// __PKA_RING_H__ ++ ++ +-- +2.20.1 + diff --git a/patch/0221-UBUNTU-SAUCE-platform-mellanox-Add-mlxbf-livefish-dr.patch b/patch/0221-UBUNTU-SAUCE-platform-mellanox-Add-mlxbf-livefish-dr.patch new file mode 100644 index 000000000..8f9c4430e --- /dev/null +++ b/patch/0221-UBUNTU-SAUCE-platform-mellanox-Add-mlxbf-livefish-dr.patch @@ -0,0 +1,340 @@ +From 9b0e85d738a43f737ed233e649fcda22b573d372 Mon Sep 17 00:00:00 2001 +From: Shravan Kumar Ramani +Date: Tue, 5 Jul 2022 12:43:45 -0400 +Subject: [PATCH backport 5.10 22/63] UBUNTU: SAUCE: platform/mellanox: Add + mlxbf-livefish driver + +BugLink: https://launchpad.net/bugs/1980761 + +This patch adds the mlxbf-livefish driver which supports update +of the HCA firmware when in livefish mode. + +Signed-off-by: Shravan Kumar Ramani +Signed-off-by: Ike Panhc +--- + drivers/platform/mellanox/Kconfig | 9 + + drivers/platform/mellanox/Makefile | 1 + + drivers/platform/mellanox/mlxbf-livefish.c | 279 +++++++++++++++++++++ + 3 files changed, 289 insertions(+) + create mode 100644 drivers/platform/mellanox/mlxbf-livefish.c + +diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig +index 946bc2375..a5231c23a 100644 +--- a/drivers/platform/mellanox/Kconfig ++++ b/drivers/platform/mellanox/Kconfig +@@ -80,6 +80,15 @@ config MLXBF_BOOTCTL + to the userspace tools, to be used in conjunction with the eMMC + device driver to do necessary initial swap of the boot partition. + ++config MLXBF_LIVEFISH ++ tristate "Mellanox BlueField livefish firmware update driver" ++ depends on ARM64 ++ help ++ If you say yes to this option, support will added for the ++ mlxbf-livefish driver. This driver allows MFT tools to ++ update ConnectX HCA firmware on a Mellanox BlueField SoC ++ when it is in livefish mode. ++ + config MLXBF_PMC + tristate "Mellanox BlueField Performance Monitoring Counters driver" + depends on ARM64 +diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile +index 046347d3a..7c6393ebe 100644 +--- a/drivers/platform/mellanox/Makefile ++++ b/drivers/platform/mellanox/Makefile +@@ -8,6 +8,7 @@ obj-$(CONFIG_MLXBF_BOOTCTL) += mlxbf-bootctl.o + obj-$(CONFIG_MLXBF_PMC) += mlxbf-pmc.o + obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o + obj-$(CONFIG_MLXBF_TRIO) += mlx-trio.o ++obj-$(CONFIG_MLXBF_LIVEFISH) += mlxbf-livefish.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/mlxbf-livefish.c b/drivers/platform/mellanox/mlxbf-livefish.c +new file mode 100644 +index 000000000..c6150117d +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf-livefish.c +@@ -0,0 +1,279 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB ++ ++/* ++ * Mellanox BlueField HCA firmware burning driver. ++ * ++ * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. ++ * ++ * This driver supports burning firmware for the embedded HCA in the ++ * BlueField SoC. Typically firmware is burned through the PCI mlx5 ++ * driver directly, but when the existing firmware is not yet installed ++ * or invalid, the PCI mlx5 driver has no endpoint to bind to, and we ++ * use this driver instead. It provides a character device that gives ++ * access to the same hardware registers at the same offsets as the ++ * mlx5 PCI configuration space does. ++ * ++ * The first 1 MB of the space is available through the TRIO HCA ++ * mapping. However, the efuse area (128 bytes at offset 0x1c1600) is ++ * not available through the HCA mapping, but is available by mapping ++ * the TYU via the RSHIM, so we make it virtually appear at the ++ * correct offset in this driver. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRIVER_VERSION 2.0 ++#define STRINGIFY(s) #s ++ ++static size_t hca_size; ++static phys_addr_t hca_pa; ++static __iomem void *hca_va; ++ ++#define TYU_SIZE 0x80UL ++#define TYU_OFFSET 0x1c1600 ++static phys_addr_t tyu_pa; ++static __iomem void *tyu_va; ++ ++#define MLXBF_LF_BF1 1 ++#define MLXBF_LF_BF2 2 ++static int chip_version; ++ ++#define CRSPACE_SIZE (2 * 1024 * 1024) ++ ++/* ++ * A valid I/O must be entirely within CR space and not extend into ++ * any unmapped areas of CR space. We don't truncate I/O that extends ++ * past the end of the CR space region (unlike the behavior of, for ++ * example, simple_read_from_buffer) but instead just call the whole ++ * I/O invalid. We also enforce 4-byte alignment for all I/O. ++ */ ++static bool valid_range(loff_t offset, size_t len) ++{ ++ if (offset % 4 != 0 || len % 4 != 0) ++ return false; /* unaligned */ ++ if (offset >= 0 && offset + len <= hca_size) ++ return true; /* inside the HCA space */ ++ if (offset >= TYU_OFFSET && offset + len <= TYU_OFFSET + TYU_SIZE) ++ return true; /* inside the TYU space */ ++ return false; ++} ++ ++/* ++ * Read and write to CR space offsets; we assume valid_range(). ++ * Data crossing the TRIO CR Space bridge gets byte-swapped, so we swap ++ * it back. ++ */ ++ ++static u32 crspace_readl(int offset) ++{ ++ u32 data; ++ if (chip_version == MLXBF_LF_BF1) { ++ if (offset < TYU_OFFSET) ++ return swab32(readl_relaxed(hca_va + offset)); ++ else ++ return readl_relaxed(tyu_va + offset - TYU_OFFSET); ++ } else { ++ data = readl_relaxed(hca_va + offset); ++ } ++ return data; ++} ++ ++static void crspace_writel(u32 data, int offset) ++{ ++ if (chip_version == MLXBF_LF_BF1) { ++ if (offset < TYU_OFFSET) ++ writel_relaxed(swab32(data), hca_va + offset); ++ else ++ writel_relaxed(data, tyu_va + offset - TYU_OFFSET); ++ } else { ++ writel_relaxed(data, hca_va + offset); ++ } ++} ++ ++/* ++ * Note that you can seek to illegal areas within the livefish device, ++ * but you won't be able to read or write there. ++ */ ++static loff_t livefish_llseek(struct file *filp, loff_t offset, int whence) ++{ ++ if (offset % 4 != 0) ++ return -EINVAL; ++ return fixed_size_llseek(filp, offset, whence, CRSPACE_SIZE); ++} ++ ++static ssize_t livefish_read(struct file *filp, char __user *to, size_t len, ++ loff_t *ppos) ++{ ++ loff_t pos = *ppos; ++ size_t i; ++ int word; ++ ++ if (!valid_range(pos, len)) ++ return -EINVAL; ++ if (len == 0) ++ return 0; ++ for (i = 0; i < len; i += 4, pos += 4) { ++ word = crspace_readl(pos); ++ if (put_user(word, (int __user *)(to + i)) != 0) ++ break; ++ } ++ *ppos = pos; ++ return i ?: -EFAULT; ++} ++ ++static ssize_t livefish_write(struct file *filp, const char __user *from, ++ size_t len, loff_t *ppos) ++{ ++ loff_t pos = *ppos; ++ size_t i; ++ int word; ++ ++ if (!valid_range(pos, len)) ++ return -EINVAL; ++ if (len == 0) ++ return 0; ++ for (i = 0; i < len; i += 4, pos += 4) { ++ if (get_user(word, (int __user *)(from + i)) != 0) ++ break; ++ crspace_writel(word, pos); ++ } ++ *ppos = pos; ++ return i ?: -EFAULT; ++} ++ ++static const struct file_operations livefish_fops = { ++ .owner = THIS_MODULE, ++ .llseek = livefish_llseek, ++ .read = livefish_read, ++ .write = livefish_write, ++}; ++ ++/* This name causes the correct semantics for the Mellanox MST tools. */ ++static struct miscdevice livefish_dev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "bf-livefish", ++ .mode = 0600, ++ .fops = &livefish_fops ++}; ++ ++/* Release any VA or PA mappings that have been set up. */ ++static void livefish_cleanup_mappings(void) ++{ ++ if (hca_va) ++ iounmap(hca_va); ++ if (hca_pa) ++ release_mem_region(hca_pa, hca_size); ++ if (tyu_va) ++ iounmap(tyu_va); ++ if (tyu_pa) ++ release_mem_region(tyu_pa, TYU_SIZE); ++} ++ ++static int livefish_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ int ret = -EINVAL; ++ struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev); ++ const char *hid = acpi_device_hid(acpi_dev); ++ ++ if (strcmp(hid, "MLNXBF05") == 0) ++ chip_version = MLXBF_LF_BF1; ++ else if (strcmp(hid, "MLNXBF25") == 0) ++ chip_version = MLXBF_LF_BF2; ++ else { ++ dev_err(&pdev->dev, "Invalid device ID %s\n", hid); ++ return -ENODEV; ++ } ++ ++ /* Find and map the HCA region */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res == NULL) ++ return -ENODEV; ++ ++ if (request_mem_region(res->start, resource_size(res), ++ "LiveFish (HCA)") == NULL) ++ return -EINVAL; ++ hca_pa = res->start; ++ hca_va = ioremap(res->start, resource_size(res)); ++ hca_size = resource_size(res); ++ dev_info(&pdev->dev, "HCA Region PA: 0x%llx Size: 0x%llx\n", ++ res->start, resource_size(res)); ++ if (hca_va == NULL) ++ goto err; ++ ++ if (chip_version == MLXBF_LF_BF1) { ++ /* Find and map the TYU efuse region */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (res == NULL) ++ goto err; ++ if (resource_size(res) < TYU_SIZE) { ++ dev_warn(&pdev->dev, "TYU space too small: %#lx, not %#lx\n", ++ (long)resource_size(res), TYU_SIZE); ++ goto err; ++ } ++ if (request_mem_region(res->start, TYU_SIZE, ++ "LiveFish (TYU)") == NULL) ++ goto err; ++ tyu_pa = res->start; ++ tyu_va = ioremap(res->start, TYU_SIZE); ++ if (tyu_va == NULL) ++ goto err; ++ } ++ ++ ret = misc_register(&livefish_dev); ++ if (ret) ++ goto err; ++ ++ dev_info(&pdev->dev, "probed\n"); ++ ++ return 0; ++ ++err: ++ livefish_cleanup_mappings(); ++ return ret; ++} ++ ++static int livefish_remove(struct platform_device *pdev) ++{ ++ misc_deregister(&livefish_dev); ++ livefish_cleanup_mappings(); ++ return 0; ++} ++ ++static const struct of_device_id livefish_of_match[] = { ++ { .compatible = "mellanox,mlxbf-livefish" }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, livefish_of_match); ++ ++static const struct acpi_device_id livefish_acpi_match[] = { ++ { "MLNXBF05", 0 }, ++ { "MLNXBF25", 0 }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(acpi, livefish_acpi_match); ++ ++static struct platform_driver livefish_driver = { ++ .driver = { ++ .name = "mlxbf-livefish", ++ .of_match_table = livefish_of_match, ++ .acpi_match_table = ACPI_PTR(livefish_acpi_match), ++ }, ++ .probe = livefish_probe, ++ .remove = livefish_remove, ++}; ++ ++module_platform_driver(livefish_driver); ++ ++MODULE_DESCRIPTION("Mellanox BlueField LiveFish driver"); ++MODULE_AUTHOR("Shravan Kumar Ramani "); ++MODULE_VERSION(STRINGIFY(DRIVER_VERSION)); ++MODULE_LICENSE("Dual BSD/GPL"); +-- +2.20.1 + diff --git a/patch/0222-workqueue-Add-resource-managed-version-of-delayed-wo.patch b/patch/0222-workqueue-Add-resource-managed-version-of-delayed-wo.patch new file mode 100644 index 000000000..bc42afa80 --- /dev/null +++ b/patch/0222-workqueue-Add-resource-managed-version-of-delayed-wo.patch @@ -0,0 +1,84 @@ +From 48998b5918e9320b47c26c78d3b14cc3e1faac8a Mon Sep 17 00:00:00 2001 +From: Matti Vaittinen +Date: Tue, 23 Mar 2021 15:56:17 +0200 +Subject: [PATCH backport 5.10 23/63] workqueue: Add resource managed version + of delayed work init + +A few drivers which need a delayed work-queue must cancel work at driver +detach. Some of those implement remove() solely for this purpose. Help +drivers to avoid unnecessary remove and error-branch implementation by +adding managed verision of delayed work initialization. This will also +help drivers to avoid mixing manual and devm based unwinding when other +resources are handled by devm. + +Reviewed-by: Hans de Goede +Signed-off-by: Matti Vaittinen +Link: https://lore.kernel.org/r/51769ea4668198deb798fe47fcfb5f5288d61586.1616506559.git.matti.vaittinen@fi.rohmeurope.com +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/devm-helpers.h | 53 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 53 insertions(+) + create mode 100644 include/linux/devm-helpers.h + +diff --git a/include/linux/devm-helpers.h b/include/linux/devm-helpers.h +new file mode 100644 +index 000000000..f64e0c9f3 +--- /dev/null ++++ b/include/linux/devm-helpers.h +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++#ifndef __LINUX_DEVM_HELPERS_H ++#define __LINUX_DEVM_HELPERS_H ++ ++/* ++ * Functions which do automatically cancel operations or release resources upon ++ * driver detach. ++ * ++ * These should be helpful to avoid mixing the manual and devm-based resource ++ * management which can be source of annoying, rarely occurring, ++ * hard-to-reproduce bugs. ++ * ++ * Please take into account that devm based cancellation may be performed some ++ * time after the remove() is ran. ++ * ++ * Thus mixing devm and manual resource management can easily cause problems ++ * when unwinding operations with dependencies. IRQ scheduling a work in a queue ++ * is typical example where IRQs are often devm-managed and WQs are manually ++ * cleaned at remove(). If IRQs are not manually freed at remove() (and this is ++ * often the case when we use devm for IRQs) we have a period of time after ++ * remove() - and before devm managed IRQs are freed - where new IRQ may fire ++ * and schedule a work item which won't be cancelled because remove() was ++ * already ran. ++ */ ++ ++#include ++#include ++ ++static inline void devm_delayed_work_drop(void *res) ++{ ++ cancel_delayed_work_sync(res); ++} ++ ++/** ++ * devm_delayed_work_autocancel - Resource-managed work allocation ++ * @dev: Device which lifetime work is bound to ++ * @pdata: work to be cancelled when driver is detached ++ * ++ * Initialize work which is automatically cancelled when driver is detached. ++ * A few drivers need delayed work which must be cancelled before driver ++ * is detached to avoid accessing removed resources. ++ * devm_delayed_work_autocancel() can be used to omit the explicit ++ * cancelleation when driver is detached. ++ */ ++static inline int devm_delayed_work_autocancel(struct device *dev, ++ struct delayed_work *w, ++ work_func_t worker) ++{ ++ INIT_DELAYED_WORK(w, worker); ++ return devm_add_action(dev, devm_delayed_work_drop, w); ++} ++ ++#endif +-- +2.20.1 + diff --git a/patch/0223-devm-helpers-Fix-devm_delayed_work_autocancel-kernel.patch b/patch/0223-devm-helpers-Fix-devm_delayed_work_autocancel-kernel.patch new file mode 100644 index 000000000..fde92e039 --- /dev/null +++ b/patch/0223-devm-helpers-Fix-devm_delayed_work_autocancel-kernel.patch @@ -0,0 +1,50 @@ +From 64006a4de979012d8a55e67690b9ce743d5be433 Mon Sep 17 00:00:00 2001 +From: Matti Vaittinen +Date: Wed, 21 Apr 2021 21:11:32 +0300 +Subject: [PATCH backport 5.10 24/63] devm-helpers: Fix + devm_delayed_work_autocancel() kerneldoc + +The kerneldoc for devm_delayed_work_autocancel() contains invalid +parameter description. + +Fix the parameter description. And while at it - make it more obvous that +this function operates on delayed_work. That helps differentiating with +resource-managed INIT_WORK description (which should follow in near future) + +Fixes: 0341ce544394 ("workqueue: Add resource managed version of delayed work init") +Reviewed-by: Hans de Goede +Signed-off-by: Matti Vaittinen +Link: https://lore.kernel.org/r/db3a8b4b8899fdf109a0cc760807de12d3b4f09b.1619028482.git.matti.vaittinen@fi.rohmeurope.com +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/devm-helpers.h | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/include/linux/devm-helpers.h b/include/linux/devm-helpers.h +index f64e0c9f3..f40f77717 100644 +--- a/include/linux/devm-helpers.h ++++ b/include/linux/devm-helpers.h +@@ -32,13 +32,14 @@ static inline void devm_delayed_work_drop(void *res) + } + + /** +- * devm_delayed_work_autocancel - Resource-managed work allocation +- * @dev: Device which lifetime work is bound to +- * @pdata: work to be cancelled when driver is detached ++ * devm_delayed_work_autocancel - Resource-managed delayed work allocation ++ * @dev: Device which lifetime work is bound to ++ * @w: Work item to be queued ++ * @worker: Worker function + * +- * Initialize work which is automatically cancelled when driver is detached. +- * A few drivers need delayed work which must be cancelled before driver +- * is detached to avoid accessing removed resources. ++ * Initialize delayed work which is automatically cancelled when driver is ++ * detached. A few drivers need delayed work which must be cancelled before ++ * driver is detached to avoid accessing removed resources. + * devm_delayed_work_autocancel() can be used to omit the explicit + * cancelleation when driver is detached. + */ +-- +2.20.1 + diff --git a/patch/0224-devm-helpers-Add-resource-managed-version-of-work-in.patch b/patch/0224-devm-helpers-Add-resource-managed-version-of-work-in.patch new file mode 100644 index 000000000..b37400e15 --- /dev/null +++ b/patch/0224-devm-helpers-Add-resource-managed-version-of-work-in.patch @@ -0,0 +1,59 @@ +From b73a2da62dcb4d975c1b226280868f951533142b Mon Sep 17 00:00:00 2001 +From: Matti Vaittinen +Date: Tue, 8 Jun 2021 13:09:34 +0300 +Subject: [PATCH backport 5.10 25/63] devm-helpers: Add resource managed + version of work init + +A few drivers which need a work-queue must cancel work at driver detach. +Some of those implement remove() solely for this purpose. Help drivers to +avoid unnecessary remove and error-branch implementation by adding managed +verision of work initialization. This will also help drivers to avoid +mixing manual and devm based unwinding when other resources are handled by +devm. + +Signed-off-by: Matti Vaittinen +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Hans de Goede +Link: https://lore.kernel.org/r/94ff4175e7f2ff134ed2fa7d6e7641005cc9784b.1623146580.git.matti.vaittinen@fi.rohmeurope.com +Signed-off-by: Hans de Goede +--- + include/linux/devm-helpers.h | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/include/linux/devm-helpers.h b/include/linux/devm-helpers.h +index f40f77717..748918022 100644 +--- a/include/linux/devm-helpers.h ++++ b/include/linux/devm-helpers.h +@@ -51,4 +51,29 @@ static inline int devm_delayed_work_autocancel(struct device *dev, + return devm_add_action(dev, devm_delayed_work_drop, w); + } + ++static inline void devm_work_drop(void *res) ++{ ++ cancel_work_sync(res); ++} ++ ++/** ++ * devm_work_autocancel - Resource-managed work allocation ++ * @dev: Device which lifetime work is bound to ++ * @w: Work to be added (and automatically cancelled) ++ * @worker: Worker function ++ * ++ * Initialize work which is automatically cancelled when driver is detached. ++ * A few drivers need to queue work which must be cancelled before driver ++ * is detached to avoid accessing removed resources. ++ * devm_work_autocancel() can be used to omit the explicit ++ * cancelleation when driver is detached. ++ */ ++static inline int devm_work_autocancel(struct device *dev, ++ struct work_struct *w, ++ work_func_t worker) ++{ ++ INIT_WORK(w, worker); ++ return devm_add_action(dev, devm_work_drop, w); ++} ++ + #endif +-- +2.20.1 + diff --git a/patch/0225-UBUNTU-SAUCE-Add-support-to-pwr-mlxbf.c-driver.patch b/patch/0225-UBUNTU-SAUCE-Add-support-to-pwr-mlxbf.c-driver.patch new file mode 100644 index 000000000..a293cc8fa --- /dev/null +++ b/patch/0225-UBUNTU-SAUCE-Add-support-to-pwr-mlxbf.c-driver.patch @@ -0,0 +1,158 @@ +From 66c331a304f41a5f1806a827b42bc97ba090c745 Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Tue, 5 Jul 2022 14:49:03 -0400 +Subject: [PATCH backport 5.10 26/63] UBUNTU: SAUCE: Add support to pwr-mlxbf.c + driver + +BugLink: https://launchpad.net/bugs/1980768 + +Signed-off-by: Asmaa Mnebhi +Signed-off-by: Ike Panhc + +1 + +Signed-off-by: Ike Panhc +--- + drivers/power/reset/Kconfig | 6 ++ + drivers/power/reset/Makefile | 1 + + drivers/power/reset/pwr-mlxbf.c | 103 ++++++++++++++++++++++++++++++++ + 3 files changed, 110 insertions(+) + create mode 100644 drivers/power/reset/pwr-mlxbf.c + +diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig +index d55b3727e..41ee02f87 100644 +--- a/drivers/power/reset/Kconfig ++++ b/drivers/power/reset/Kconfig +@@ -284,5 +284,11 @@ config NVMEM_REBOOT_MODE + then the bootloader can read it and take different + action according to the mode. + ++config POWER_MLXBF ++ tristate "Mellanox BlueField power handling driver" ++ depends on (GPIO_MLXBF2 && ACPI) ++ help ++ This driver supports reset or low power mode handling for Mellanox BlueField. ++ + endif + +diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile +index c51eceba9..51801a5b5 100644 +--- a/drivers/power/reset/Makefile ++++ b/drivers/power/reset/Makefile +@@ -33,3 +33,4 @@ obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o + obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o + obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o + obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o ++obj-$(CONFIG_POWER_MLXBF) += pwr-mlxbf.o +diff --git a/drivers/power/reset/pwr-mlxbf.c b/drivers/power/reset/pwr-mlxbf.c +new file mode 100644 +index 000000000..3f587a372 +--- /dev/null ++++ b/drivers/power/reset/pwr-mlxbf.c +@@ -0,0 +1,103 @@ ++// SPDX-License-Identifier: GPL-2.0-only or BSD-3-Clause ++ ++/* ++ * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define DRV_VERSION "1.1" ++ ++struct pwr_mlxbf { ++ struct work_struct send_work; ++ const char *hid; ++}; ++ ++static void pwr_mlxbf_send_work(struct work_struct *work) ++{ ++ acpi_bus_generate_netlink_event("button/power.*", "Power Button", 0x80, 1); ++} ++ ++static irqreturn_t pwr_mlxbf_irq(int irq, void *ptr) ++{ ++ const char *rst_pwr_hid = "MLNXBF24"; ++ const char *low_pwr_hid = "MLNXBF29"; ++ struct pwr_mlxbf *priv = ptr; ++ ++ if (!strncmp(priv->hid, rst_pwr_hid, 8)) ++ emergency_restart(); ++ ++ if (!strncmp(priv->hid, low_pwr_hid, 8)) ++ schedule_work(&priv->send_work); ++ ++ return IRQ_HANDLED; ++} ++ ++static int pwr_mlxbf_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct acpi_device *adev; ++ struct pwr_mlxbf *priv; ++ const char *hid; ++ int irq, err; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ adev = ACPI_COMPANION(dev); ++ if (!adev) ++ return -ENXIO; ++ ++ hid = acpi_device_hid(adev); ++ priv->hid = hid; ++ ++ irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0); ++ if (irq < 0) ++ return dev_err_probe(dev, irq, "Error getting %s irq.\n", priv->hid); ++ ++ err = devm_work_autocancel(dev, &priv->send_work, pwr_mlxbf_send_work); ++ if (err) ++ return err; ++ ++ err = devm_request_irq(dev, irq, pwr_mlxbf_irq, 0, hid, priv); ++ if (err) ++ dev_err(dev, "Failed request of %s irq\n", priv->hid); ++ ++ return err; ++} ++ ++static const struct acpi_device_id __maybe_unused pwr_mlxbf_acpi_match[] = { ++ { "MLNXBF24", 0 }, ++ { "MLNXBF29", 0 }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(acpi, pwr_mlxbf_acpi_match); ++ ++static struct platform_driver pwr_mlxbf_driver = { ++ .driver = { ++ .name = "pwr_mlxbf", ++ .acpi_match_table = pwr_mlxbf_acpi_match, ++ }, ++ .probe = pwr_mlxbf_probe, ++}; ++ ++module_platform_driver(pwr_mlxbf_driver); ++ ++MODULE_DESCRIPTION("Mellanox BlueField power driver"); ++MODULE_AUTHOR("Asmaa Mnebhi "); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_VERSION(DRV_VERSION); +-- +2.20.1 + diff --git a/patch/0226-Add-Mellanox-BlueField-Gigabit-Ethernet-driver.patch b/patch/0226-Add-Mellanox-BlueField-Gigabit-Ethernet-driver.patch new file mode 100644 index 000000000..eff1c335a --- /dev/null +++ b/patch/0226-Add-Mellanox-BlueField-Gigabit-Ethernet-driver.patch @@ -0,0 +1,2206 @@ +From 0e3f14e4ef0018a4cd75c0620a58484dae635e5d Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Thu, 24 Jun 2021 21:11:46 -0400 +Subject: [PATCH backport 5.10 27/63] Add Mellanox BlueField Gigabit Ethernet + driver + +This patch adds build and driver logic for the "mlxbf_gige" +Ethernet driver from Mellanox Technologies. The second +generation BlueField SoC from Mellanox supports an +out-of-band GigaBit Ethernet management port to the Arm +subsystem. This driver supports TCP/IP network connectivity +for that port, and provides back-end routines to handle +basic ethtool requests. + +The driver interfaces to the Gigabit Ethernet block of +BlueField SoC via MMIO accesses to registers, which contain +control information or pointers describing transmit and +receive resources. There is a single transmit queue, and +the port supports transmit ring sizes of 4 to 256 entries. +There is a single receive queue, and the port supports +receive ring sizes of 32 to 32K entries. The transmit and +receive rings are allocated from DMA coherent memory. There +is a 16-bit producer and consumer index per ring to denote +software ownership and hardware ownership, respectively. + +The main driver logic such as probe(), remove(), and netdev +ops are in "mlxbf_gige_main.c". Logic in "mlxbf_gige_rx.c" +and "mlxbf_gige_tx.c" handles the packet processing for +receive and transmit respectively. + +The logic in "mlxbf_gige_ethtool.c" supports the handling +of some basic ethtool requests: get driver info, get ring +parameters, get registers, and get statistics. + +The logic in "mlxbf_gige_mdio.c" is the driver controlling +the Mellanox BlueField hardware that interacts with a PHY +device via MDIO/MDC pins. This driver does the following: + - At driver probe time, it configures several BlueField MDIO + parameters such as sample rate, full drive, voltage and MDC + - It defines functions to read and write MDIO registers and + registers the MDIO bus. + - It defines the phy interrupt handler reporting a + link up/down status change + - This driver's probe is invoked from the main driver logic + while the phy interrupt handler is registered in ndo_open. + +Driver limitations + - Only supports 1Gbps speed + - Only supports GMII protocol + - Supports maximum packet size of 2KB + - Does not support scatter-gather buffering + +Testing + - Successful build of kernel for ARM64, ARM32, X86_64 + - Tested ARM64 build on FastModels & Palladium + - Tested ARM64 build on several Mellanox boards that are built with + the BlueField-2 SoC. The testing includes coverage in the areas + of networking (e.g. ping, iperf, ifconfig, route), file transfers + (e.g. SCP), and various ethtool options relevant to this driver. + +Signed-off-by: David Thompson +Signed-off-by: Asmaa Mnebhi +Reviewed-by: Liming Sun +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mellanox/Kconfig | 1 + + drivers/net/ethernet/mellanox/Makefile | 1 + + .../net/ethernet/mellanox/mlxbf_gige/Kconfig | 13 + + .../net/ethernet/mellanox/mlxbf_gige/Makefile | 11 + + .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 190 ++++++++ + .../mellanox/mlxbf_gige/mlxbf_gige_ethtool.c | 137 ++++++ + .../mellanox/mlxbf_gige/mlxbf_gige_gpio.c | 212 ++++++++ + .../mellanox/mlxbf_gige/mlxbf_gige_intr.c | 142 ++++++ + .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 452 ++++++++++++++++++ + .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 187 ++++++++ + .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 78 +++ + .../mellanox/mlxbf_gige/mlxbf_gige_rx.c | 320 +++++++++++++ + .../mellanox/mlxbf_gige/mlxbf_gige_tx.c | 284 +++++++++++ + 13 files changed, 2028 insertions(+) + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/Makefile + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c + +diff --git a/drivers/net/ethernet/mellanox/Kconfig b/drivers/net/ethernet/mellanox/Kconfig +index ff6613a5c..b4f66eb9d 100644 +--- a/drivers/net/ethernet/mellanox/Kconfig ++++ b/drivers/net/ethernet/mellanox/Kconfig +@@ -22,5 +22,6 @@ source "drivers/net/ethernet/mellanox/mlx4/Kconfig" + source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig" + source "drivers/net/ethernet/mellanox/mlxsw/Kconfig" + source "drivers/net/ethernet/mellanox/mlxfw/Kconfig" ++source "drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig" + + endif # NET_VENDOR_MELLANOX +diff --git a/drivers/net/ethernet/mellanox/Makefile b/drivers/net/ethernet/mellanox/Makefile +index 79773ac33..d4b5f547a 100644 +--- a/drivers/net/ethernet/mellanox/Makefile ++++ b/drivers/net/ethernet/mellanox/Makefile +@@ -7,3 +7,4 @@ obj-$(CONFIG_MLX4_CORE) += mlx4/ + obj-$(CONFIG_MLX5_CORE) += mlx5/core/ + obj-$(CONFIG_MLXSW_CORE) += mlxsw/ + obj-$(CONFIG_MLXFW) += mlxfw/ ++obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige/ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig +new file mode 100644 +index 000000000..4cdebafaf +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig +@@ -0,0 +1,13 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause ++# ++# Mellanox GigE driver configuration ++# ++ ++config MLXBF_GIGE ++ tristate "Mellanox Technologies BlueField Gigabit Ethernet support" ++ depends on (ARM64 && ACPI) || COMPILE_TEST ++ select PHYLIB ++ help ++ The second generation BlueField SoC from Mellanox Technologies ++ supports an out-of-band Gigabit Ethernet management port to the ++ Arm subsystem. +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile +new file mode 100644 +index 000000000..e57c1375f +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile +@@ -0,0 +1,11 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause ++ ++obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige.o ++ ++mlxbf_gige-y := mlxbf_gige_ethtool.o \ ++ mlxbf_gige_gpio.o \ ++ mlxbf_gige_intr.o \ ++ mlxbf_gige_main.o \ ++ mlxbf_gige_mdio.o \ ++ mlxbf_gige_rx.o \ ++ mlxbf_gige_tx.o +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +new file mode 100644 +index 000000000..e3509e69e +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +@@ -0,0 +1,190 @@ ++/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ ++ ++/* Header file for Gigabit Ethernet driver for Mellanox BlueField SoC ++ * - this file contains software data structures and any chip-specific ++ * data structures (e.g. TX WQE format) that are memory resident. ++ * ++ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES ++ */ ++ ++#ifndef __MLXBF_GIGE_H__ ++#define __MLXBF_GIGE_H__ ++ ++#include ++#include ++#include ++#include ++ ++/* The silicon design supports a maximum RX ring size of ++ * 32K entries. Based on current testing this maximum size ++ * is not required to be supported. Instead the RX ring ++ * will be capped at a realistic value of 1024 entries. ++ */ ++#define MLXBF_GIGE_MIN_RXQ_SZ 32 ++#define MLXBF_GIGE_MAX_RXQ_SZ 1024 ++#define MLXBF_GIGE_DEFAULT_RXQ_SZ 128 ++ ++#define MLXBF_GIGE_MIN_TXQ_SZ 4 ++#define MLXBF_GIGE_MAX_TXQ_SZ 256 ++#define MLXBF_GIGE_DEFAULT_TXQ_SZ 128 ++ ++#define MLXBF_GIGE_DEFAULT_BUF_SZ 2048 ++ ++#define MLXBF_GIGE_DMA_PAGE_SZ 4096 ++#define MLXBF_GIGE_DMA_PAGE_SHIFT 12 ++ ++/* There are four individual MAC RX filters. Currently ++ * two of them are being used: one for the broadcast MAC ++ * (index 0) and one for local MAC (index 1) ++ */ ++#define MLXBF_GIGE_BCAST_MAC_FILTER_IDX 0 ++#define MLXBF_GIGE_LOCAL_MAC_FILTER_IDX 1 ++ ++/* Define for broadcast MAC literal */ ++#define BCAST_MAC_ADDR 0xFFFFFFFFFFFF ++ ++/* There are three individual interrupts: ++ * 1) Errors, "OOB" interrupt line ++ * 2) Receive Packet, "OOB_LLU" interrupt line ++ * 3) LLU and PLU Events, "OOB_PLU" interrupt line ++ */ ++#define MLXBF_GIGE_ERROR_INTR_IDX 0 ++#define MLXBF_GIGE_RECEIVE_PKT_INTR_IDX 1 ++#define MLXBF_GIGE_LLU_PLU_INTR_IDX 2 ++#define MLXBF_GIGE_PHY_INT_N 3 ++ ++#define MLXBF_GIGE_MDIO_DEFAULT_PHY_ADDR 0x3 ++ ++#define MLXBF_GIGE_DEFAULT_PHY_INT_GPIO 12 ++ ++struct mlxbf_gige_stats { ++ u64 hw_access_errors; ++ u64 tx_invalid_checksums; ++ u64 tx_small_frames; ++ u64 tx_index_errors; ++ u64 sw_config_errors; ++ u64 sw_access_errors; ++ u64 rx_truncate_errors; ++ u64 rx_mac_errors; ++ u64 rx_din_dropped_pkts; ++ u64 tx_fifo_full; ++ u64 rx_filter_passed_pkts; ++ u64 rx_filter_discard_pkts; ++}; ++ ++struct mlxbf_gige { ++ void __iomem *base; ++ void __iomem *llu_base; ++ void __iomem *plu_base; ++ struct device *dev; ++ struct net_device *netdev; ++ struct platform_device *pdev; ++ void __iomem *mdio_io; ++ struct mii_bus *mdiobus; ++ void __iomem *gpio_io; ++ struct irq_domain *irqdomain; ++ u32 phy_int_gpio_mask; ++ spinlock_t lock; /* for packet processing indices */ ++ spinlock_t gpio_lock; /* for GPIO bus access */ ++ u16 rx_q_entries; ++ u16 tx_q_entries; ++ u64 *tx_wqe_base; ++ dma_addr_t tx_wqe_base_dma; ++ u64 *tx_wqe_next; ++ u64 *tx_cc; ++ dma_addr_t tx_cc_dma; ++ dma_addr_t *rx_wqe_base; ++ dma_addr_t rx_wqe_base_dma; ++ u64 *rx_cqe_base; ++ dma_addr_t rx_cqe_base_dma; ++ u16 tx_pi; ++ u16 prev_tx_ci; ++ u64 error_intr_count; ++ u64 rx_intr_count; ++ u64 llu_plu_intr_count; ++ struct sk_buff *rx_skb[MLXBF_GIGE_MAX_RXQ_SZ]; ++ struct sk_buff *tx_skb[MLXBF_GIGE_MAX_TXQ_SZ]; ++ int error_irq; ++ int rx_irq; ++ int llu_plu_irq; ++ int phy_irq; ++ int hw_phy_irq; ++ bool promisc_enabled; ++ u8 valid_polarity; ++ struct napi_struct napi; ++ struct mlxbf_gige_stats stats; ++}; ++ ++/* Rx Work Queue Element definitions */ ++#define MLXBF_GIGE_RX_WQE_SZ 8 ++ ++/* Rx Completion Queue Element definitions */ ++#define MLXBF_GIGE_RX_CQE_SZ 8 ++#define MLXBF_GIGE_RX_CQE_PKT_LEN_MASK GENMASK(10, 0) ++#define MLXBF_GIGE_RX_CQE_VALID_MASK GENMASK(11, 11) ++#define MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK GENMASK(15, 12) ++#define MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR GENMASK(12, 12) ++#define MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED GENMASK(13, 13) ++#define MLXBF_GIGE_RX_CQE_CHKSUM_MASK GENMASK(31, 16) ++ ++/* Tx Work Queue Element definitions */ ++#define MLXBF_GIGE_TX_WQE_SZ_QWORDS 2 ++#define MLXBF_GIGE_TX_WQE_SZ 16 ++#define MLXBF_GIGE_TX_WQE_PKT_LEN_MASK GENMASK(10, 0) ++#define MLXBF_GIGE_TX_WQE_UPDATE_MASK GENMASK(31, 31) ++#define MLXBF_GIGE_TX_WQE_CHKSUM_LEN_MASK GENMASK(42, 32) ++#define MLXBF_GIGE_TX_WQE_CHKSUM_START_MASK GENMASK(55, 48) ++#define MLXBF_GIGE_TX_WQE_CHKSUM_OFFSET_MASK GENMASK(63, 56) ++ ++/* Macro to return packet length of specified TX WQE */ ++#define MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr) \ ++ (*((tx_wqe_addr) + 1) & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK) ++ ++/* Tx Completion Count */ ++#define MLXBF_GIGE_TX_CC_SZ 8 ++ ++/* List of resources in ACPI table */ ++enum mlxbf_gige_res { ++ MLXBF_GIGE_RES_MAC, ++ MLXBF_GIGE_RES_MDIO9, ++ MLXBF_GIGE_RES_GPIO0, ++ MLXBF_GIGE_RES_LLU, ++ MLXBF_GIGE_RES_PLU ++}; ++ ++/* Version of register data returned by mlxbf_gige_get_regs() */ ++#define MLXBF_GIGE_REGS_VERSION 1 ++ ++int mlxbf_gige_mdio_probe(struct platform_device *pdev, ++ struct mlxbf_gige *priv); ++void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv); ++irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id); ++void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv); ++ ++void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, ++ unsigned int index, u64 dmac); ++void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv, ++ unsigned int index, u64 *dmac); ++void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv); ++void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv); ++int mlxbf_gige_rx_init(struct mlxbf_gige *priv); ++void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv); ++int mlxbf_gige_tx_init(struct mlxbf_gige *priv); ++void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv); ++bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv); ++netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, ++ struct net_device *netdev); ++struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv, ++ unsigned int map_len, ++ dma_addr_t *buf_dma, ++ enum dma_data_direction dir); ++int mlxbf_gige_request_irqs(struct mlxbf_gige *priv); ++void mlxbf_gige_free_irqs(struct mlxbf_gige *priv); ++int mlxbf_gige_poll(struct napi_struct *napi, int budget); ++extern const struct ethtool_ops mlxbf_gige_ethtool_ops; ++void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv); ++ ++int mlxbf_gige_gpio_init(struct platform_device *pdev, struct mlxbf_gige *priv); ++void mlxbf_gige_gpio_free(struct mlxbf_gige *priv); ++ ++#endif /* !defined(__MLXBF_GIGE_H__) */ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c +new file mode 100644 +index 000000000..92b798f8e +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c +@@ -0,0 +1,137 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause ++ ++/* Ethtool support for Mellanox Gigabit Ethernet driver ++ * ++ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES ++ */ ++ ++#include ++ ++#include "mlxbf_gige.h" ++#include "mlxbf_gige_regs.h" ++ ++/* Start of struct ethtool_ops functions */ ++static int mlxbf_gige_get_regs_len(struct net_device *netdev) ++{ ++ return MLXBF_GIGE_MMIO_REG_SZ; ++} ++ ++static void mlxbf_gige_get_regs(struct net_device *netdev, ++ struct ethtool_regs *regs, void *p) ++{ ++ struct mlxbf_gige *priv = netdev_priv(netdev); ++ ++ regs->version = MLXBF_GIGE_REGS_VERSION; ++ ++ /* Read entire MMIO register space and store results ++ * into the provided buffer. Each 64-bit word is converted ++ * to big-endian to make the output more readable. ++ * ++ * NOTE: by design, a read to an offset without an existing ++ * register will be acknowledged and return zero. ++ */ ++ memcpy_fromio(p, priv->base, MLXBF_GIGE_MMIO_REG_SZ); ++} ++ ++static void mlxbf_gige_get_ringparam(struct net_device *netdev, ++ struct ethtool_ringparam *ering) ++{ ++ struct mlxbf_gige *priv = netdev_priv(netdev); ++ ++ ering->rx_max_pending = MLXBF_GIGE_MAX_RXQ_SZ; ++ ering->tx_max_pending = MLXBF_GIGE_MAX_TXQ_SZ; ++ ering->rx_pending = priv->rx_q_entries; ++ ering->tx_pending = priv->tx_q_entries; ++} ++ ++static const struct { ++ const char string[ETH_GSTRING_LEN]; ++} mlxbf_gige_ethtool_stats_keys[] = { ++ { "hw_access_errors" }, ++ { "tx_invalid_checksums" }, ++ { "tx_small_frames" }, ++ { "tx_index_errors" }, ++ { "sw_config_errors" }, ++ { "sw_access_errors" }, ++ { "rx_truncate_errors" }, ++ { "rx_mac_errors" }, ++ { "rx_din_dropped_pkts" }, ++ { "tx_fifo_full" }, ++ { "rx_filter_passed_pkts" }, ++ { "rx_filter_discard_pkts" }, ++}; ++ ++static int mlxbf_gige_get_sset_count(struct net_device *netdev, int stringset) ++{ ++ if (stringset != ETH_SS_STATS) ++ return -EOPNOTSUPP; ++ return ARRAY_SIZE(mlxbf_gige_ethtool_stats_keys); ++} ++ ++static void mlxbf_gige_get_strings(struct net_device *netdev, u32 stringset, ++ u8 *buf) ++{ ++ if (stringset != ETH_SS_STATS) ++ return; ++ memcpy(buf, &mlxbf_gige_ethtool_stats_keys, ++ sizeof(mlxbf_gige_ethtool_stats_keys)); ++} ++ ++static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, ++ struct ethtool_stats *estats, ++ u64 *data) ++{ ++ struct mlxbf_gige *priv = netdev_priv(netdev); ++ ++ /* Fill data array with interface statistics ++ * ++ * NOTE: the data writes must be in ++ * sync with the strings shown in ++ * the mlxbf_gige_ethtool_stats_keys[] array ++ * ++ * NOTE2: certain statistics below are zeroed upon ++ * port disable, so the calculation below ++ * must include the "cached" value of the stat ++ * plus the value read directly from hardware. ++ * Cached statistics are currently: ++ * rx_din_dropped_pkts ++ * rx_filter_passed_pkts ++ * rx_filter_discard_pkts ++ */ ++ *data++ = priv->stats.hw_access_errors; ++ *data++ = priv->stats.tx_invalid_checksums; ++ *data++ = priv->stats.tx_small_frames; ++ *data++ = priv->stats.tx_index_errors; ++ *data++ = priv->stats.sw_config_errors; ++ *data++ = priv->stats.sw_access_errors; ++ *data++ = priv->stats.rx_truncate_errors; ++ *data++ = priv->stats.rx_mac_errors; ++ *data++ = (priv->stats.rx_din_dropped_pkts + ++ readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER)); ++ *data++ = priv->stats.tx_fifo_full; ++ *data++ = (priv->stats.rx_filter_passed_pkts + ++ readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL)); ++ *data++ = (priv->stats.rx_filter_discard_pkts + ++ readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL)); ++} ++ ++static void mlxbf_gige_get_pauseparam(struct net_device *netdev, ++ struct ethtool_pauseparam *pause) ++{ ++ pause->autoneg = AUTONEG_DISABLE; ++ pause->rx_pause = 1; ++ pause->tx_pause = 1; ++} ++ ++const struct ethtool_ops mlxbf_gige_ethtool_ops = { ++ .get_link = ethtool_op_get_link, ++ .get_ringparam = mlxbf_gige_get_ringparam, ++ .get_regs_len = mlxbf_gige_get_regs_len, ++ .get_regs = mlxbf_gige_get_regs, ++ .get_strings = mlxbf_gige_get_strings, ++ .get_sset_count = mlxbf_gige_get_sset_count, ++ .get_ethtool_stats = mlxbf_gige_get_ethtool_stats, ++ .nway_reset = phy_ethtool_nway_reset, ++ .get_pauseparam = mlxbf_gige_get_pauseparam, ++ .get_link_ksettings = phy_ethtool_get_link_ksettings, ++}; +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c +new file mode 100644 +index 000000000..a8d966db5 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c +@@ -0,0 +1,212 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause ++ ++/* Initialize and handle GPIO interrupt triggered by INT_N PHY signal. ++ * This GPIO interrupt triggers the PHY state machine to bring the link ++ * up/down. ++ * ++ * Copyright (C) 2021 NVIDIA CORPORATION & AFFILIATES ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mlxbf_gige.h" ++#include "mlxbf_gige_regs.h" ++ ++#define MLXBF_GIGE_GPIO_CAUSE_FALL_EN 0x48 ++#define MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x80 ++#define MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0 0x94 ++#define MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE 0x98 ++ ++static void mlxbf_gige_gpio_enable(struct mlxbf_gige *priv) ++{ ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(&priv->gpio_lock, flags); ++ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); ++ val |= priv->phy_int_gpio_mask; ++ writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); ++ ++ /* The INT_N interrupt level is active low. ++ * So enable cause fall bit to detect when GPIO ++ * state goes low. ++ */ ++ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); ++ val |= priv->phy_int_gpio_mask; ++ writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); ++ ++ /* Enable PHY interrupt by setting the priority level */ ++ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); ++ val |= priv->phy_int_gpio_mask; ++ writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); ++ spin_unlock_irqrestore(&priv->gpio_lock, flags); ++} ++ ++static void mlxbf_gige_gpio_disable(struct mlxbf_gige *priv) ++{ ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(&priv->gpio_lock, flags); ++ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); ++ val &= ~priv->phy_int_gpio_mask; ++ writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); ++ spin_unlock_irqrestore(&priv->gpio_lock, flags); ++} ++ ++static irqreturn_t mlxbf_gige_gpio_handler(int irq, void *ptr) ++{ ++ struct mlxbf_gige *priv; ++ u32 val; ++ ++ priv = ptr; ++ ++ /* Check if this interrupt is from PHY device. ++ * Return if it is not. ++ */ ++ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0); ++ if (!(val & priv->phy_int_gpio_mask)) ++ return IRQ_NONE; ++ ++ /* Clear interrupt when done, otherwise, no further interrupt ++ * will be triggered. ++ */ ++ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); ++ val |= priv->phy_int_gpio_mask; ++ writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); ++ ++ generic_handle_irq(priv->phy_irq); ++ ++ return IRQ_HANDLED; ++} ++ ++static void mlxbf_gige_gpio_mask(struct irq_data *irqd) ++{ ++ struct mlxbf_gige *priv = irq_data_get_irq_chip_data(irqd); ++ ++ mlxbf_gige_gpio_disable(priv); ++} ++ ++static void mlxbf_gige_gpio_unmask(struct irq_data *irqd) ++{ ++ struct mlxbf_gige *priv = irq_data_get_irq_chip_data(irqd); ++ ++ mlxbf_gige_gpio_enable(priv); ++} ++ ++static struct irq_chip mlxbf_gige_gpio_chip = { ++ .name = "mlxbf_gige_phy", ++ .irq_mask = mlxbf_gige_gpio_mask, ++ .irq_unmask = mlxbf_gige_gpio_unmask, ++}; ++ ++static int mlxbf_gige_gpio_domain_map(struct irq_domain *d, ++ unsigned int irq, ++ irq_hw_number_t hwirq) ++{ ++ irq_set_chip_data(irq, d->host_data); ++ irq_set_chip_and_handler(irq, &mlxbf_gige_gpio_chip, handle_simple_irq); ++ irq_set_noprobe(irq); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops mlxbf_gige_gpio_domain_ops = { ++ .map = mlxbf_gige_gpio_domain_map, ++ .xlate = irq_domain_xlate_twocell, ++}; ++ ++#ifdef CONFIG_ACPI ++static int mlxbf_gige_gpio_resources(struct acpi_resource *ares, ++ void *data) ++{ ++ struct acpi_resource_gpio *gpio; ++ u32 *phy_int_gpio = data; ++ ++ if (ares->type == ACPI_RESOURCE_TYPE_GPIO) { ++ gpio = &ares->data.gpio; ++ *phy_int_gpio = gpio->pin_table[0]; ++ } ++ ++ return 1; ++} ++#endif ++ ++void mlxbf_gige_gpio_free(struct mlxbf_gige *priv) ++{ ++ irq_dispose_mapping(priv->phy_irq); ++ irq_domain_remove(priv->irqdomain); ++} ++ ++int mlxbf_gige_gpio_init(struct platform_device *pdev, ++ struct mlxbf_gige *priv) ++{ ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ u32 phy_int_gpio = 0; ++ int ret; ++ ++ LIST_HEAD(resources); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_GPIO0); ++ if (!res) ++ return -ENODEV; ++ ++ priv->gpio_io = devm_ioremap(dev, res->start, resource_size(res)); ++ if (!priv->gpio_io) ++ return -ENOMEM; ++ ++#ifdef CONFIG_ACPI ++ ret = acpi_dev_get_resources(ACPI_COMPANION(dev), ++ &resources, mlxbf_gige_gpio_resources, ++ &phy_int_gpio); ++ acpi_dev_free_resource_list(&resources); ++ if (ret < 0 || !phy_int_gpio) { ++ dev_err(dev, "Error retrieving the gpio phy pin"); ++ return -EINVAL; ++ } ++#endif ++ ++ priv->phy_int_gpio_mask = BIT(phy_int_gpio); ++ ++ mlxbf_gige_gpio_disable(priv); ++ ++ priv->hw_phy_irq = platform_get_irq(pdev, MLXBF_GIGE_PHY_INT_N); ++ ++ priv->irqdomain = irq_domain_add_simple(NULL, 1, 0, ++ &mlxbf_gige_gpio_domain_ops, ++ priv); ++ if (!priv->irqdomain) { ++ dev_err(dev, "Failed to add IRQ domain\n"); ++ return -ENOMEM; ++ } ++ ++ priv->phy_irq = irq_create_mapping(priv->irqdomain, 0); ++ if (!priv->phy_irq) { ++ irq_domain_remove(priv->irqdomain); ++ priv->irqdomain = NULL; ++ dev_err(dev, "Error mapping PHY IRQ\n"); ++ return -EINVAL; ++ } ++ ++ ret = devm_request_irq(dev, priv->hw_phy_irq, mlxbf_gige_gpio_handler, ++ IRQF_ONESHOT | IRQF_SHARED, "mlxbf_gige_phy", priv); ++ if (ret) { ++ dev_err(dev, "Failed to request PHY IRQ"); ++ mlxbf_gige_gpio_free(priv); ++ return ret; ++ } ++ ++ return ret; ++} +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c +new file mode 100644 +index 000000000..c38795be0 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c +@@ -0,0 +1,142 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause ++ ++/* Interrupt related logic for Mellanox Gigabit Ethernet driver ++ * ++ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES ++ */ ++ ++#include ++ ++#include "mlxbf_gige.h" ++#include "mlxbf_gige_regs.h" ++ ++static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id) ++{ ++ struct mlxbf_gige *priv; ++ u64 int_status; ++ ++ priv = dev_id; ++ ++ priv->error_intr_count++; ++ ++ int_status = readq(priv->base + MLXBF_GIGE_INT_STATUS); ++ ++ if (int_status & MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR) ++ priv->stats.hw_access_errors++; ++ ++ if (int_status & MLXBF_GIGE_INT_STATUS_TX_CHECKSUM_INPUTS) { ++ priv->stats.tx_invalid_checksums++; ++ /* This error condition is latched into MLXBF_GIGE_INT_STATUS ++ * when the GigE silicon operates on the offending ++ * TX WQE. The write to MLXBF_GIGE_INT_STATUS at the bottom ++ * of this routine clears this error condition. ++ */ ++ } ++ ++ if (int_status & MLXBF_GIGE_INT_STATUS_TX_SMALL_FRAME_SIZE) { ++ priv->stats.tx_small_frames++; ++ /* This condition happens when the networking stack invokes ++ * this driver's "start_xmit()" method with a packet whose ++ * size < 60 bytes. The GigE silicon will automatically pad ++ * this small frame up to a minimum-sized frame before it is ++ * sent. The "tx_small_frame" condition is latched into the ++ * MLXBF_GIGE_INT_STATUS register when the GigE silicon ++ * operates on the offending TX WQE. The write to ++ * MLXBF_GIGE_INT_STATUS at the bottom of this routine ++ * clears this condition. ++ */ ++ } ++ ++ if (int_status & MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE) ++ priv->stats.tx_index_errors++; ++ ++ if (int_status & MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR) ++ priv->stats.sw_config_errors++; ++ ++ if (int_status & MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR) ++ priv->stats.sw_access_errors++; ++ ++ /* Clear all error interrupts by writing '1' back to ++ * all the asserted bits in INT_STATUS. Do not write ++ * '1' back to 'receive packet' bit, since that is ++ * managed separately. ++ */ ++ ++ int_status &= ~MLXBF_GIGE_INT_STATUS_RX_RECEIVE_PACKET; ++ ++ writeq(int_status, priv->base + MLXBF_GIGE_INT_STATUS); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t mlxbf_gige_rx_intr(int irq, void *dev_id) ++{ ++ struct mlxbf_gige *priv; ++ ++ priv = dev_id; ++ ++ priv->rx_intr_count++; ++ ++ /* NOTE: GigE silicon automatically disables "packet rx" interrupt by ++ * setting MLXBF_GIGE_INT_MASK bit0 upon triggering the interrupt ++ * to the ARM cores. Software needs to re-enable "packet rx" ++ * interrupts by clearing MLXBF_GIGE_INT_MASK bit0. ++ */ ++ ++ napi_schedule(&priv->napi); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t mlxbf_gige_llu_plu_intr(int irq, void *dev_id) ++{ ++ struct mlxbf_gige *priv; ++ ++ priv = dev_id; ++ priv->llu_plu_intr_count++; ++ ++ return IRQ_HANDLED; ++} ++ ++int mlxbf_gige_request_irqs(struct mlxbf_gige *priv) ++{ ++ int err; ++ ++ err = request_irq(priv->error_irq, mlxbf_gige_error_intr, 0, ++ "mlxbf_gige_error", priv); ++ if (err) { ++ dev_err(priv->dev, "Request error_irq failure\n"); ++ return err; ++ } ++ ++ err = request_irq(priv->rx_irq, mlxbf_gige_rx_intr, 0, ++ "mlxbf_gige_rx", priv); ++ if (err) { ++ dev_err(priv->dev, "Request rx_irq failure\n"); ++ goto free_error_irq; ++ } ++ ++ err = request_irq(priv->llu_plu_irq, mlxbf_gige_llu_plu_intr, 0, ++ "mlxbf_gige_llu_plu", priv); ++ if (err) { ++ dev_err(priv->dev, "Request llu_plu_irq failure\n"); ++ goto free_rx_irq; ++ } ++ ++ return 0; ++ ++free_rx_irq: ++ free_irq(priv->rx_irq, priv); ++ ++free_error_irq: ++ free_irq(priv->error_irq, priv); ++ ++ return err; ++} ++ ++void mlxbf_gige_free_irqs(struct mlxbf_gige *priv) ++{ ++ free_irq(priv->error_irq, priv); ++ free_irq(priv->rx_irq, priv); ++ free_irq(priv->llu_plu_irq, priv); ++} +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +new file mode 100644 +index 000000000..a0a059e01 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +@@ -0,0 +1,452 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause ++ ++/* Gigabit Ethernet driver for Mellanox BlueField SoC ++ * ++ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mlxbf_gige.h" ++#include "mlxbf_gige_regs.h" ++ ++#define DRV_NAME "mlxbf_gige" ++ ++/* Allocate SKB whose payload pointer aligns with the Bluefield ++ * hardware DMA limitation, i.e. DMA operation can't cross ++ * a 4KB boundary. A maximum packet size of 2KB is assumed in the ++ * alignment formula. The alignment logic overallocates an SKB, ++ * and then adjusts the headroom so that the SKB data pointer is ++ * naturally aligned to a 2KB boundary. ++ */ ++struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv, ++ unsigned int map_len, ++ dma_addr_t *buf_dma, ++ enum dma_data_direction dir) ++{ ++ struct sk_buff *skb; ++ u64 addr, offset; ++ ++ /* Overallocate the SKB so that any headroom adjustment (to ++ * provide 2KB natural alignment) does not exceed payload area ++ */ ++ skb = netdev_alloc_skb(priv->netdev, MLXBF_GIGE_DEFAULT_BUF_SZ * 2); ++ if (!skb) ++ return NULL; ++ ++ /* Adjust the headroom so that skb->data is naturally aligned to ++ * a 2KB boundary, which is the maximum packet size supported. ++ */ ++ addr = (long)skb->data; ++ offset = (addr + MLXBF_GIGE_DEFAULT_BUF_SZ - 1) & ++ ~(MLXBF_GIGE_DEFAULT_BUF_SZ - 1); ++ offset -= addr; ++ if (offset) ++ skb_reserve(skb, offset); ++ ++ /* Return streaming DMA mapping to caller */ ++ *buf_dma = dma_map_single(priv->dev, skb->data, map_len, dir); ++ if (dma_mapping_error(priv->dev, *buf_dma)) { ++ dev_kfree_skb(skb); ++ *buf_dma = (dma_addr_t)0; ++ return NULL; ++ } ++ ++ return skb; ++} ++ ++static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) ++{ ++ u8 mac[ETH_ALEN]; ++ u64 local_mac; ++ ++ memset(mac, 0, ETH_ALEN); ++ mlxbf_gige_get_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, ++ &local_mac); ++ u64_to_ether_addr(local_mac, mac); ++ ++ if (is_valid_ether_addr(mac)) { ++ ether_addr_copy(priv->netdev->dev_addr, mac); ++ } else { ++ /* Provide a random MAC if for some reason the device has ++ * not been configured with a valid MAC address already. ++ */ ++ eth_hw_addr_random(priv->netdev); ++ } ++ ++ local_mac = ether_addr_to_u64(priv->netdev->dev_addr); ++ mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, ++ local_mac); ++} ++ ++static void mlxbf_gige_cache_stats(struct mlxbf_gige *priv) ++{ ++ struct mlxbf_gige_stats *p; ++ ++ /* Cache stats that will be cleared by clean port operation */ ++ p = &priv->stats; ++ p->rx_din_dropped_pkts += readq(priv->base + ++ MLXBF_GIGE_RX_DIN_DROP_COUNTER); ++ p->rx_filter_passed_pkts += readq(priv->base + ++ MLXBF_GIGE_RX_PASS_COUNTER_ALL); ++ p->rx_filter_discard_pkts += readq(priv->base + ++ MLXBF_GIGE_RX_DISC_COUNTER_ALL); ++} ++ ++static int mlxbf_gige_clean_port(struct mlxbf_gige *priv) ++{ ++ u64 control; ++ u64 temp; ++ int err; ++ ++ /* Set the CLEAN_PORT_EN bit to trigger SW reset */ ++ control = readq(priv->base + MLXBF_GIGE_CONTROL); ++ control |= MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; ++ writeq(control, priv->base + MLXBF_GIGE_CONTROL); ++ ++ /* Ensure completion of "clean port" write before polling status */ ++ mb(); ++ ++ err = readq_poll_timeout_atomic(priv->base + MLXBF_GIGE_STATUS, temp, ++ (temp & MLXBF_GIGE_STATUS_READY), ++ 100, 100000); ++ ++ /* Clear the CLEAN_PORT_EN bit at end of this loop */ ++ control = readq(priv->base + MLXBF_GIGE_CONTROL); ++ control &= ~MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; ++ writeq(control, priv->base + MLXBF_GIGE_CONTROL); ++ ++ return err; ++} ++ ++static int mlxbf_gige_open(struct net_device *netdev) ++{ ++ struct mlxbf_gige *priv = netdev_priv(netdev); ++ struct phy_device *phydev = netdev->phydev; ++ u64 int_en; ++ int err; ++ ++ err = mlxbf_gige_request_irqs(priv); ++ if (err) ++ return err; ++ mlxbf_gige_cache_stats(priv); ++ err = mlxbf_gige_clean_port(priv); ++ if (err) ++ goto free_irqs; ++ err = mlxbf_gige_rx_init(priv); ++ if (err) ++ goto free_irqs; ++ err = mlxbf_gige_tx_init(priv); ++ if (err) ++ goto rx_deinit; ++ ++ phy_start(phydev); ++ ++ netif_napi_add(netdev, &priv->napi, mlxbf_gige_poll, NAPI_POLL_WEIGHT); ++ napi_enable(&priv->napi); ++ netif_start_queue(netdev); ++ ++ /* Set bits in INT_EN that we care about */ ++ int_en = MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR | ++ MLXBF_GIGE_INT_EN_TX_CHECKSUM_INPUTS | ++ MLXBF_GIGE_INT_EN_TX_SMALL_FRAME_SIZE | ++ MLXBF_GIGE_INT_EN_TX_PI_CI_EXCEED_WQ_SIZE | ++ MLXBF_GIGE_INT_EN_SW_CONFIG_ERROR | ++ MLXBF_GIGE_INT_EN_SW_ACCESS_ERROR | ++ MLXBF_GIGE_INT_EN_RX_RECEIVE_PACKET; ++ ++ /* Ensure completion of all initialization before enabling interrupts */ ++ mb(); ++ ++ writeq(int_en, priv->base + MLXBF_GIGE_INT_EN); ++ ++ return 0; ++ ++rx_deinit: ++ mlxbf_gige_rx_deinit(priv); ++ ++free_irqs: ++ mlxbf_gige_free_irqs(priv); ++ return err; ++} ++ ++static int mlxbf_gige_stop(struct net_device *netdev) ++{ ++ struct mlxbf_gige *priv = netdev_priv(netdev); ++ ++ writeq(0, priv->base + MLXBF_GIGE_INT_EN); ++ netif_stop_queue(netdev); ++ napi_disable(&priv->napi); ++ netif_napi_del(&priv->napi); ++ mlxbf_gige_free_irqs(priv); ++ ++ phy_stop(netdev->phydev); ++ ++ mlxbf_gige_rx_deinit(priv); ++ mlxbf_gige_tx_deinit(priv); ++ mlxbf_gige_cache_stats(priv); ++ mlxbf_gige_clean_port(priv); ++ ++ return 0; ++} ++ ++static int mlxbf_gige_do_ioctl(struct net_device *netdev, ++ struct ifreq *ifr, int cmd) ++{ ++ if (!(netif_running(netdev))) ++ return -EINVAL; ++ ++ return phy_mii_ioctl(netdev->phydev, ifr, cmd); ++} ++ ++static void mlxbf_gige_set_rx_mode(struct net_device *netdev) ++{ ++ struct mlxbf_gige *priv = netdev_priv(netdev); ++ bool new_promisc_enabled; ++ ++ new_promisc_enabled = netdev->flags & IFF_PROMISC; ++ ++ /* Only write to the hardware registers if the new setting ++ * of promiscuous mode is different from the current one. ++ */ ++ if (new_promisc_enabled != priv->promisc_enabled) { ++ priv->promisc_enabled = new_promisc_enabled; ++ ++ if (new_promisc_enabled) ++ mlxbf_gige_enable_promisc(priv); ++ else ++ mlxbf_gige_disable_promisc(priv); ++ } ++} ++ ++static void mlxbf_gige_get_stats64(struct net_device *netdev, ++ struct rtnl_link_stats64 *stats) ++{ ++ struct mlxbf_gige *priv = netdev_priv(netdev); ++ ++ netdev_stats_to_stats64(stats, &netdev->stats); ++ ++ stats->rx_length_errors = priv->stats.rx_truncate_errors; ++ stats->rx_fifo_errors = priv->stats.rx_din_dropped_pkts + ++ readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER); ++ stats->rx_crc_errors = priv->stats.rx_mac_errors; ++ stats->rx_errors = stats->rx_length_errors + ++ stats->rx_fifo_errors + ++ stats->rx_crc_errors; ++ ++ stats->tx_fifo_errors = priv->stats.tx_fifo_full; ++ stats->tx_errors = stats->tx_fifo_errors; ++} ++ ++static const struct net_device_ops mlxbf_gige_netdev_ops = { ++ .ndo_open = mlxbf_gige_open, ++ .ndo_stop = mlxbf_gige_stop, ++ .ndo_start_xmit = mlxbf_gige_start_xmit, ++ .ndo_set_mac_address = eth_mac_addr, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_do_ioctl = mlxbf_gige_do_ioctl, ++ .ndo_set_rx_mode = mlxbf_gige_set_rx_mode, ++ .ndo_get_stats64 = mlxbf_gige_get_stats64, ++}; ++ ++static void mlxbf_gige_adjust_link(struct net_device *netdev) ++{ ++ struct phy_device *phydev = netdev->phydev; ++ ++ phy_print_status(phydev); ++} ++ ++static int mlxbf_gige_probe(struct platform_device *pdev) ++{ ++ struct phy_device *phydev; ++ struct net_device *netdev; ++ struct resource *mac_res; ++ struct resource *llu_res; ++ struct resource *plu_res; ++ struct mlxbf_gige *priv; ++ void __iomem *llu_base; ++ void __iomem *plu_base; ++ void __iomem *base; ++ u64 control; ++ int addr; ++ int err; ++ ++ mac_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MAC); ++ if (!mac_res) ++ return -ENXIO; ++ ++ base = devm_ioremap_resource(&pdev->dev, mac_res); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ llu_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_LLU); ++ if (!llu_res) ++ return -ENXIO; ++ ++ llu_base = devm_ioremap_resource(&pdev->dev, llu_res); ++ if (IS_ERR(llu_base)) ++ return PTR_ERR(llu_base); ++ ++ plu_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_PLU); ++ if (!plu_res) ++ return -ENXIO; ++ ++ plu_base = devm_ioremap_resource(&pdev->dev, plu_res); ++ if (IS_ERR(plu_base)) ++ return PTR_ERR(plu_base); ++ ++ /* Perform general init of GigE block */ ++ control = readq(base + MLXBF_GIGE_CONTROL); ++ control |= MLXBF_GIGE_CONTROL_PORT_EN; ++ writeq(control, base + MLXBF_GIGE_CONTROL); ++ ++ netdev = devm_alloc_etherdev(&pdev->dev, sizeof(*priv)); ++ if (!netdev) ++ return -ENOMEM; ++ ++ SET_NETDEV_DEV(netdev, &pdev->dev); ++ netdev->netdev_ops = &mlxbf_gige_netdev_ops; ++ netdev->ethtool_ops = &mlxbf_gige_ethtool_ops; ++ priv = netdev_priv(netdev); ++ priv->netdev = netdev; ++ ++ platform_set_drvdata(pdev, priv); ++ priv->dev = &pdev->dev; ++ priv->pdev = pdev; ++ ++ spin_lock_init(&priv->lock); ++ spin_lock_init(&priv->gpio_lock); ++ ++ /* Attach MDIO device */ ++ err = mlxbf_gige_mdio_probe(pdev, priv); ++ if (err) ++ return err; ++ ++ err = mlxbf_gige_gpio_init(pdev, priv); ++ if (err) { ++ dev_err(&pdev->dev, "PHY IRQ initialization failed\n"); ++ mlxbf_gige_mdio_remove(priv); ++ return -ENODEV; ++ } ++ ++ priv->base = base; ++ priv->llu_base = llu_base; ++ priv->plu_base = plu_base; ++ ++ priv->rx_q_entries = MLXBF_GIGE_DEFAULT_RXQ_SZ; ++ priv->tx_q_entries = MLXBF_GIGE_DEFAULT_TXQ_SZ; ++ ++ /* Write initial MAC address to hardware */ ++ mlxbf_gige_initial_mac(priv); ++ ++ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); ++ if (err) { ++ dev_err(&pdev->dev, "DMA configuration failed: 0x%x\n", err); ++ goto out; ++ } ++ ++ priv->error_irq = platform_get_irq(pdev, MLXBF_GIGE_ERROR_INTR_IDX); ++ priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX); ++ priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX); ++ ++ phydev = phy_find_first(priv->mdiobus); ++ if (!phydev) { ++ err = -ENODEV; ++ goto out; ++ } ++ ++ addr = phydev->mdio.addr; ++ priv->mdiobus->irq[addr] = priv->phy_irq; ++ phydev->irq = priv->phy_irq; ++ ++ err = phy_connect_direct(netdev, phydev, ++ mlxbf_gige_adjust_link, ++ PHY_INTERFACE_MODE_GMII); ++ if (err) { ++ dev_err(&pdev->dev, "Could not attach to PHY\n"); ++ goto out; ++ } ++ ++ /* MAC only supports 1000T full duplex mode */ ++ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); ++ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT); ++ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); ++ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); ++ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); ++ ++ /* Only symmetric pause with flow control enabled is supported so no ++ * need to negotiate pause. ++ */ ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising); ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising); ++ ++ /* Display information about attached PHY device */ ++ phy_attached_info(phydev); ++ ++ err = register_netdev(netdev); ++ if (err) { ++ dev_err(&pdev->dev, "Failed to register netdev\n"); ++ phy_disconnect(phydev); ++ goto out; ++ } ++ ++ return 0; ++ ++out: ++ mlxbf_gige_gpio_free(priv); ++ mlxbf_gige_mdio_remove(priv); ++ return err; ++} ++ ++static int mlxbf_gige_remove(struct platform_device *pdev) ++{ ++ struct mlxbf_gige *priv = platform_get_drvdata(pdev); ++ ++ unregister_netdev(priv->netdev); ++ phy_disconnect(priv->netdev->phydev); ++ mlxbf_gige_gpio_free(priv); ++ mlxbf_gige_mdio_remove(priv); ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++static void mlxbf_gige_shutdown(struct platform_device *pdev) ++{ ++ struct mlxbf_gige *priv = platform_get_drvdata(pdev); ++ ++ writeq(0, priv->base + MLXBF_GIGE_INT_EN); ++ mlxbf_gige_clean_port(priv); ++} ++ ++static const struct acpi_device_id __maybe_unused mlxbf_gige_acpi_match[] = { ++ { "MLNXBF17", 0 }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(acpi, mlxbf_gige_acpi_match); ++ ++static struct platform_driver mlxbf_gige_driver = { ++ .probe = mlxbf_gige_probe, ++ .remove = mlxbf_gige_remove, ++ .shutdown = mlxbf_gige_shutdown, ++ .driver = { ++ .name = DRV_NAME, ++ .acpi_match_table = ACPI_PTR(mlxbf_gige_acpi_match), ++ }, ++}; ++ ++module_platform_driver(mlxbf_gige_driver); ++ ++MODULE_DESCRIPTION("Mellanox BlueField SoC Gigabit Ethernet Driver"); ++MODULE_AUTHOR("David Thompson "); ++MODULE_AUTHOR("Asmaa Mnebhi "); ++MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +new file mode 100644 +index 000000000..e32dd34fd +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +@@ -0,0 +1,187 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause ++ ++/* MDIO support for Mellanox Gigabit Ethernet driver ++ * ++ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mlxbf_gige.h" ++ ++#define MLXBF_GIGE_MDIO_GW_OFFSET 0x0 ++#define MLXBF_GIGE_MDIO_CFG_OFFSET 0x4 ++ ++/* Support clause 22 */ ++#define MLXBF_GIGE_MDIO_CL22_ST1 0x1 ++#define MLXBF_GIGE_MDIO_CL22_WRITE 0x1 ++#define MLXBF_GIGE_MDIO_CL22_READ 0x2 ++ ++/* Busy bit is set by software and cleared by hardware */ ++#define MLXBF_GIGE_MDIO_SET_BUSY 0x1 ++ ++/* MDIO GW register bits */ ++#define MLXBF_GIGE_MDIO_GW_AD_MASK GENMASK(15, 0) ++#define MLXBF_GIGE_MDIO_GW_DEVAD_MASK GENMASK(20, 16) ++#define MLXBF_GIGE_MDIO_GW_PARTAD_MASK GENMASK(25, 21) ++#define MLXBF_GIGE_MDIO_GW_OPCODE_MASK GENMASK(27, 26) ++#define MLXBF_GIGE_MDIO_GW_ST1_MASK GENMASK(28, 28) ++#define MLXBF_GIGE_MDIO_GW_BUSY_MASK GENMASK(30, 30) ++ ++/* MDIO config register bits */ ++#define MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK GENMASK(1, 0) ++#define MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK GENMASK(2, 2) ++#define MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK GENMASK(4, 4) ++#define MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK GENMASK(15, 8) ++#define MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK GENMASK(23, 16) ++#define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK GENMASK(31, 24) ++ ++/* Formula for encoding the MDIO period. The encoded value is ++ * passed to the MDIO config register. ++ * ++ * mdc_clk = 2*(val + 1)*i1clk ++ * ++ * 400 ns = 2*(val + 1)*(((1/430)*1000) ns) ++ * ++ * val = (((400 * 430 / 1000) / 2) - 1) ++ */ ++#define MLXBF_GIGE_I1CLK_MHZ 430 ++#define MLXBF_GIGE_MDC_CLK_NS 400 ++ ++#define MLXBF_GIGE_MDIO_PERIOD (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1) ++ ++#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \ ++ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ ++ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ ++ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \ ++ MLXBF_GIGE_MDIO_PERIOD) | \ ++ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ ++ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) ++ ++static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add, ++ int phy_reg, u32 opcode) ++{ ++ u32 gw_reg = 0; ++ ++ gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_AD_MASK, data); ++ gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_DEVAD_MASK, phy_reg); ++ gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_PARTAD_MASK, phy_add); ++ gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_OPCODE_MASK, opcode); ++ gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_ST1_MASK, ++ MLXBF_GIGE_MDIO_CL22_ST1); ++ gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_BUSY_MASK, ++ MLXBF_GIGE_MDIO_SET_BUSY); ++ ++ return gw_reg; ++} ++ ++static int mlxbf_gige_mdio_read(struct mii_bus *bus, int phy_add, int phy_reg) ++{ ++ struct mlxbf_gige *priv = bus->priv; ++ u32 cmd; ++ int ret; ++ u32 val; ++ ++ if (phy_reg & MII_ADDR_C45) ++ return -EOPNOTSUPP; ++ ++ /* Send mdio read request */ ++ cmd = mlxbf_gige_mdio_create_cmd(0, phy_add, phy_reg, MLXBF_GIGE_MDIO_CL22_READ); ++ ++ writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); ++ ++ ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET, ++ val, !(val & MLXBF_GIGE_MDIO_GW_BUSY_MASK), 100, 1000000); ++ ++ if (ret) { ++ writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); ++ return ret; ++ } ++ ++ ret = readl(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); ++ /* Only return ad bits of the gw register */ ++ ret &= MLXBF_GIGE_MDIO_GW_AD_MASK; ++ ++ return ret; ++} ++ ++static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, ++ int phy_reg, u16 val) ++{ ++ struct mlxbf_gige *priv = bus->priv; ++ u32 cmd; ++ int ret; ++ u32 temp; ++ ++ if (phy_reg & MII_ADDR_C45) ++ return -EOPNOTSUPP; ++ ++ /* Send mdio write request */ ++ cmd = mlxbf_gige_mdio_create_cmd(val, phy_add, phy_reg, ++ MLXBF_GIGE_MDIO_CL22_WRITE); ++ writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); ++ ++ /* If the poll timed out, drop the request */ ++ ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET, ++ temp, !(temp & MLXBF_GIGE_MDIO_GW_BUSY_MASK), 100, 1000000); ++ ++ return ret; ++} ++ ++int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) ++{ ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ int ret; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MDIO9); ++ if (!res) ++ return -ENODEV; ++ ++ priv->mdio_io = devm_ioremap_resource(dev, res); ++ if (IS_ERR(priv->mdio_io)) ++ return PTR_ERR(priv->mdio_io); ++ ++ /* Configure mdio parameters */ ++ writel(MLXBF_GIGE_MDIO_CFG_VAL, ++ priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); ++ ++ priv->mdiobus = devm_mdiobus_alloc(dev); ++ if (!priv->mdiobus) { ++ dev_err(dev, "Failed to alloc MDIO bus\n"); ++ return -ENOMEM; ++ } ++ ++ priv->mdiobus->name = "mlxbf-mdio"; ++ priv->mdiobus->read = mlxbf_gige_mdio_read; ++ priv->mdiobus->write = mlxbf_gige_mdio_write; ++ priv->mdiobus->parent = dev; ++ priv->mdiobus->priv = priv; ++ snprintf(priv->mdiobus->id, MII_BUS_ID_SIZE, "%s", ++ dev_name(dev)); ++ ++ ret = mdiobus_register(priv->mdiobus); ++ if (ret) ++ dev_err(dev, "Failed to register MDIO bus\n"); ++ ++ return ret; ++} ++ ++void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv) ++{ ++ mdiobus_unregister(priv->mdiobus); ++} +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +new file mode 100644 +index 000000000..5fb33c929 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +@@ -0,0 +1,78 @@ ++/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ ++ ++/* Header file for Mellanox BlueField GigE register defines ++ * ++ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES ++ */ ++ ++#ifndef __MLXBF_GIGE_REGS_H__ ++#define __MLXBF_GIGE_REGS_H__ ++ ++#define MLXBF_GIGE_STATUS 0x0010 ++#define MLXBF_GIGE_STATUS_READY BIT(0) ++#define MLXBF_GIGE_INT_STATUS 0x0028 ++#define MLXBF_GIGE_INT_STATUS_RX_RECEIVE_PACKET BIT(0) ++#define MLXBF_GIGE_INT_STATUS_RX_MAC_ERROR BIT(1) ++#define MLXBF_GIGE_INT_STATUS_RX_TRN_ERROR BIT(2) ++#define MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR BIT(3) ++#define MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR BIT(4) ++#define MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE BIT(5) ++#define MLXBF_GIGE_INT_STATUS_TX_SMALL_FRAME_SIZE BIT(6) ++#define MLXBF_GIGE_INT_STATUS_TX_CHECKSUM_INPUTS BIT(7) ++#define MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR BIT(8) ++#define MLXBF_GIGE_INT_EN 0x0030 ++#define MLXBF_GIGE_INT_EN_RX_RECEIVE_PACKET BIT(0) ++#define MLXBF_GIGE_INT_EN_RX_MAC_ERROR BIT(1) ++#define MLXBF_GIGE_INT_EN_RX_TRN_ERROR BIT(2) ++#define MLXBF_GIGE_INT_EN_SW_ACCESS_ERROR BIT(3) ++#define MLXBF_GIGE_INT_EN_SW_CONFIG_ERROR BIT(4) ++#define MLXBF_GIGE_INT_EN_TX_PI_CI_EXCEED_WQ_SIZE BIT(5) ++#define MLXBF_GIGE_INT_EN_TX_SMALL_FRAME_SIZE BIT(6) ++#define MLXBF_GIGE_INT_EN_TX_CHECKSUM_INPUTS BIT(7) ++#define MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR BIT(8) ++#define MLXBF_GIGE_INT_MASK 0x0038 ++#define MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET BIT(0) ++#define MLXBF_GIGE_CONTROL 0x0040 ++#define MLXBF_GIGE_CONTROL_PORT_EN BIT(0) ++#define MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN BIT(1) ++#define MLXBF_GIGE_CONTROL_EN_SPECIFIC_MAC BIT(4) ++#define MLXBF_GIGE_CONTROL_CLEAN_PORT_EN BIT(31) ++#define MLXBF_GIGE_RX_WQ_BASE 0x0200 ++#define MLXBF_GIGE_RX_WQE_SIZE_LOG2 0x0208 ++#define MLXBF_GIGE_RX_WQE_SIZE_LOG2_RESET_VAL 7 ++#define MLXBF_GIGE_RX_CQ_BASE 0x0210 ++#define MLXBF_GIGE_TX_WQ_BASE 0x0218 ++#define MLXBF_GIGE_TX_WQ_SIZE_LOG2 0x0220 ++#define MLXBF_GIGE_TX_WQ_SIZE_LOG2_RESET_VAL 7 ++#define MLXBF_GIGE_TX_CI_UPDATE_ADDRESS 0x0228 ++#define MLXBF_GIGE_RX_WQE_PI 0x0230 ++#define MLXBF_GIGE_TX_PRODUCER_INDEX 0x0238 ++#define MLXBF_GIGE_RX_MAC_FILTER 0x0240 ++#define MLXBF_GIGE_RX_MAC_FILTER_STRIDE 0x0008 ++#define MLXBF_GIGE_RX_DIN_DROP_COUNTER 0x0260 ++#define MLXBF_GIGE_TX_CONSUMER_INDEX 0x0310 ++#define MLXBF_GIGE_TX_CONTROL 0x0318 ++#define MLXBF_GIGE_TX_CONTROL_GRACEFUL_STOP BIT(0) ++#define MLXBF_GIGE_TX_STATUS 0x0388 ++#define MLXBF_GIGE_TX_STATUS_DATA_FIFO_FULL BIT(1) ++#define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START 0x0520 ++#define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END 0x0528 ++#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC 0x0540 ++#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC_EN BIT(0) ++#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS 0x0548 ++#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS_EN BIT(0) ++#define MLXBF_GIGE_RX_PASS_COUNTER_ALL 0x0550 ++#define MLXBF_GIGE_RX_DISC_COUNTER_ALL 0x0560 ++#define MLXBF_GIGE_RX 0x0578 ++#define MLXBF_GIGE_RX_STRIP_CRC_EN BIT(1) ++#define MLXBF_GIGE_RX_DMA 0x0580 ++#define MLXBF_GIGE_RX_DMA_EN BIT(0) ++#define MLXBF_GIGE_RX_CQE_PACKET_CI 0x05b0 ++#define MLXBF_GIGE_MAC_CFG 0x05e8 ++ ++/* NOTE: MLXBF_GIGE_MAC_CFG is the last defined register offset, ++ * so use that plus size of single register to derive total size ++ */ ++#define MLXBF_GIGE_MMIO_REG_SZ (MLXBF_GIGE_MAC_CFG + 8) ++ ++#endif /* !defined(__MLXBF_GIGE_REGS_H__) */ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c +new file mode 100644 +index 000000000..afa3b92a6 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c +@@ -0,0 +1,320 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause ++ ++/* Packet receive logic for Mellanox Gigabit Ethernet driver ++ * ++ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES ++ */ ++ ++#include ++#include ++ ++#include "mlxbf_gige.h" ++#include "mlxbf_gige_regs.h" ++ ++void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, ++ unsigned int index, u64 dmac) ++{ ++ void __iomem *base = priv->base; ++ u64 control; ++ ++ /* Write destination MAC to specified MAC RX filter */ ++ writeq(dmac, base + MLXBF_GIGE_RX_MAC_FILTER + ++ (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); ++ ++ /* Enable MAC receive filter mask for specified index */ ++ control = readq(base + MLXBF_GIGE_CONTROL); ++ control |= (MLXBF_GIGE_CONTROL_EN_SPECIFIC_MAC << index); ++ writeq(control, base + MLXBF_GIGE_CONTROL); ++} ++ ++void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv, ++ unsigned int index, u64 *dmac) ++{ ++ void __iomem *base = priv->base; ++ ++ /* Read destination MAC from specified MAC RX filter */ ++ *dmac = readq(base + MLXBF_GIGE_RX_MAC_FILTER + ++ (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); ++} ++ ++void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv) ++{ ++ void __iomem *base = priv->base; ++ u64 control; ++ u64 end_mac; ++ ++ /* Enable MAC_ID_RANGE match functionality */ ++ control = readq(base + MLXBF_GIGE_CONTROL); ++ control |= MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN; ++ writeq(control, base + MLXBF_GIGE_CONTROL); ++ ++ /* Set start of destination MAC range check to 0 */ ++ writeq(0, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START); ++ ++ /* Set end of destination MAC range check to all FFs */ ++ end_mac = BCAST_MAC_ADDR; ++ writeq(end_mac, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END); ++} ++ ++void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv) ++{ ++ void __iomem *base = priv->base; ++ u64 control; ++ ++ /* Disable MAC_ID_RANGE match functionality */ ++ control = readq(base + MLXBF_GIGE_CONTROL); ++ control &= ~MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN; ++ writeq(control, base + MLXBF_GIGE_CONTROL); ++ ++ /* NOTE: no need to change DMAC_RANGE_START or END; ++ * those values are ignored since MAC_ID_RANGE_EN=0 ++ */ ++} ++ ++/* Receive Initialization ++ * 1) Configures RX MAC filters via MMIO registers ++ * 2) Allocates RX WQE array using coherent DMA mapping ++ * 3) Initializes each element of RX WQE array with a receive ++ * buffer pointer (also using coherent DMA mapping) ++ * 4) Allocates RX CQE array using coherent DMA mapping ++ * 5) Completes other misc receive initialization ++ */ ++int mlxbf_gige_rx_init(struct mlxbf_gige *priv) ++{ ++ size_t wq_size, cq_size; ++ dma_addr_t *rx_wqe_ptr; ++ dma_addr_t rx_buf_dma; ++ u64 data; ++ int i, j; ++ ++ /* Configure MAC RX filter #0 to allow RX of broadcast pkts */ ++ mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_BCAST_MAC_FILTER_IDX, ++ BCAST_MAC_ADDR); ++ ++ wq_size = MLXBF_GIGE_RX_WQE_SZ * priv->rx_q_entries; ++ priv->rx_wqe_base = dma_alloc_coherent(priv->dev, wq_size, ++ &priv->rx_wqe_base_dma, ++ GFP_KERNEL); ++ if (!priv->rx_wqe_base) ++ return -ENOMEM; ++ ++ /* Initialize 'rx_wqe_ptr' to point to first RX WQE in array ++ * Each RX WQE is simply a receive buffer pointer, so walk ++ * the entire array, allocating a 2KB buffer for each element ++ */ ++ rx_wqe_ptr = priv->rx_wqe_base; ++ ++ for (i = 0; i < priv->rx_q_entries; i++) { ++ priv->rx_skb[i] = mlxbf_gige_alloc_skb(priv, MLXBF_GIGE_DEFAULT_BUF_SZ, ++ &rx_buf_dma, DMA_FROM_DEVICE); ++ if (!priv->rx_skb[i]) ++ goto free_wqe_and_skb; ++ *rx_wqe_ptr++ = rx_buf_dma; ++ } ++ ++ /* Write RX WQE base address into MMIO reg */ ++ writeq(priv->rx_wqe_base_dma, priv->base + MLXBF_GIGE_RX_WQ_BASE); ++ ++ cq_size = MLXBF_GIGE_RX_CQE_SZ * priv->rx_q_entries; ++ priv->rx_cqe_base = dma_alloc_coherent(priv->dev, cq_size, ++ &priv->rx_cqe_base_dma, ++ GFP_KERNEL); ++ if (!priv->rx_cqe_base) ++ goto free_wqe_and_skb; ++ ++ for (i = 0; i < priv->rx_q_entries; i++) ++ priv->rx_cqe_base[i] |= MLXBF_GIGE_RX_CQE_VALID_MASK; ++ ++ /* Write RX CQE base address into MMIO reg */ ++ writeq(priv->rx_cqe_base_dma, priv->base + MLXBF_GIGE_RX_CQ_BASE); ++ ++ /* Write RX_WQE_PI with current number of replenished buffers */ ++ writeq(priv->rx_q_entries, priv->base + MLXBF_GIGE_RX_WQE_PI); ++ ++ /* Enable removal of CRC during RX */ ++ data = readq(priv->base + MLXBF_GIGE_RX); ++ data |= MLXBF_GIGE_RX_STRIP_CRC_EN; ++ writeq(data, priv->base + MLXBF_GIGE_RX); ++ ++ /* Enable RX MAC filter pass and discard counters */ ++ writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC_EN, ++ priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC); ++ writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS_EN, ++ priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS); ++ ++ /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to ++ * indicate readiness to receive interrupts ++ */ ++ data = readq(priv->base + MLXBF_GIGE_INT_MASK); ++ data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET; ++ writeq(data, priv->base + MLXBF_GIGE_INT_MASK); ++ ++ /* Enable RX DMA to write new packets to memory */ ++ data = readq(priv->base + MLXBF_GIGE_RX_DMA); ++ data |= MLXBF_GIGE_RX_DMA_EN; ++ writeq(data, priv->base + MLXBF_GIGE_RX_DMA); ++ ++ writeq(ilog2(priv->rx_q_entries), ++ priv->base + MLXBF_GIGE_RX_WQE_SIZE_LOG2); ++ ++ return 0; ++ ++free_wqe_and_skb: ++ rx_wqe_ptr = priv->rx_wqe_base; ++ for (j = 0; j < i; j++) { ++ dma_unmap_single(priv->dev, *rx_wqe_ptr, ++ MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE); ++ dev_kfree_skb(priv->rx_skb[j]); ++ rx_wqe_ptr++; ++ } ++ dma_free_coherent(priv->dev, wq_size, ++ priv->rx_wqe_base, priv->rx_wqe_base_dma); ++ return -ENOMEM; ++} ++ ++/* Receive Deinitialization ++ * This routine will free allocations done by mlxbf_gige_rx_init(), ++ * namely the RX WQE and RX CQE arrays, as well as all RX buffers ++ */ ++void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv) ++{ ++ dma_addr_t *rx_wqe_ptr; ++ size_t size; ++ u64 data; ++ int i; ++ ++ /* Disable RX DMA to prevent packet transfers to memory */ ++ data = readq(priv->base + MLXBF_GIGE_RX_DMA); ++ data &= ~MLXBF_GIGE_RX_DMA_EN; ++ writeq(data, priv->base + MLXBF_GIGE_RX_DMA); ++ ++ rx_wqe_ptr = priv->rx_wqe_base; ++ ++ for (i = 0; i < priv->rx_q_entries; i++) { ++ dma_unmap_single(priv->dev, *rx_wqe_ptr, MLXBF_GIGE_DEFAULT_BUF_SZ, ++ DMA_FROM_DEVICE); ++ dev_kfree_skb(priv->rx_skb[i]); ++ rx_wqe_ptr++; ++ } ++ ++ size = MLXBF_GIGE_RX_WQE_SZ * priv->rx_q_entries; ++ dma_free_coherent(priv->dev, size, ++ priv->rx_wqe_base, priv->rx_wqe_base_dma); ++ ++ size = MLXBF_GIGE_RX_CQE_SZ * priv->rx_q_entries; ++ dma_free_coherent(priv->dev, size, ++ priv->rx_cqe_base, priv->rx_cqe_base_dma); ++ ++ priv->rx_wqe_base = NULL; ++ priv->rx_wqe_base_dma = 0; ++ priv->rx_cqe_base = NULL; ++ priv->rx_cqe_base_dma = 0; ++ writeq(0, priv->base + MLXBF_GIGE_RX_WQ_BASE); ++ writeq(0, priv->base + MLXBF_GIGE_RX_CQ_BASE); ++} ++ ++static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) ++{ ++ struct net_device *netdev = priv->netdev; ++ struct sk_buff *skb = NULL, *rx_skb; ++ u16 rx_pi_rem, rx_ci_rem; ++ dma_addr_t *rx_wqe_addr; ++ dma_addr_t rx_buf_dma; ++ u64 *rx_cqe_addr; ++ u64 datalen; ++ u64 rx_cqe; ++ u16 rx_ci; ++ u16 rx_pi; ++ ++ /* Index into RX buffer array is rx_pi w/wrap based on RX_CQE_SIZE */ ++ rx_pi = readq(priv->base + MLXBF_GIGE_RX_WQE_PI); ++ rx_pi_rem = rx_pi % priv->rx_q_entries; ++ ++ rx_wqe_addr = priv->rx_wqe_base + rx_pi_rem; ++ rx_cqe_addr = priv->rx_cqe_base + rx_pi_rem; ++ rx_cqe = *rx_cqe_addr; ++ ++ if ((!!(rx_cqe & MLXBF_GIGE_RX_CQE_VALID_MASK)) != priv->valid_polarity) ++ return false; ++ ++ if ((rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK) == 0) { ++ /* Packet is OK, increment stats */ ++ datalen = rx_cqe & MLXBF_GIGE_RX_CQE_PKT_LEN_MASK; ++ netdev->stats.rx_packets++; ++ netdev->stats.rx_bytes += datalen; ++ ++ skb = priv->rx_skb[rx_pi_rem]; ++ ++ skb_put(skb, datalen); ++ ++ skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */ ++ ++ skb->protocol = eth_type_trans(skb, netdev); ++ ++ /* Alloc another RX SKB for this same index */ ++ rx_skb = mlxbf_gige_alloc_skb(priv, MLXBF_GIGE_DEFAULT_BUF_SZ, ++ &rx_buf_dma, DMA_FROM_DEVICE); ++ if (!rx_skb) ++ return false; ++ priv->rx_skb[rx_pi_rem] = rx_skb; ++ dma_unmap_single(priv->dev, *rx_wqe_addr, ++ MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE); ++ *rx_wqe_addr = rx_buf_dma; ++ } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR) { ++ priv->stats.rx_mac_errors++; ++ } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED) { ++ priv->stats.rx_truncate_errors++; ++ } ++ ++ /* Let hardware know we've replenished one buffer */ ++ rx_pi++; ++ ++ /* Ensure completion of all writes before notifying HW of replenish */ ++ wmb(); ++ writeq(rx_pi, priv->base + MLXBF_GIGE_RX_WQE_PI); ++ ++ (*rx_pkts)++; ++ ++ rx_pi_rem = rx_pi % priv->rx_q_entries; ++ if (rx_pi_rem == 0) ++ priv->valid_polarity ^= 1; ++ rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); ++ rx_ci_rem = rx_ci % priv->rx_q_entries; ++ ++ if (skb) ++ netif_receive_skb(skb); ++ ++ return rx_pi_rem != rx_ci_rem; ++} ++ ++/* Driver poll() function called by NAPI infrastructure */ ++int mlxbf_gige_poll(struct napi_struct *napi, int budget) ++{ ++ struct mlxbf_gige *priv; ++ bool remaining_pkts; ++ int work_done = 0; ++ u64 data; ++ ++ priv = container_of(napi, struct mlxbf_gige, napi); ++ ++ mlxbf_gige_handle_tx_complete(priv); ++ ++ do { ++ remaining_pkts = mlxbf_gige_rx_packet(priv, &work_done); ++ } while (remaining_pkts && work_done < budget); ++ ++ /* If amount of work done < budget, turn off NAPI polling ++ * via napi_complete_done(napi, work_done) and then ++ * re-enable interrupts. ++ */ ++ if (work_done < budget && napi_complete_done(napi, work_done)) { ++ /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to ++ * indicate receive readiness ++ */ ++ data = readq(priv->base + MLXBF_GIGE_INT_MASK); ++ data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET; ++ writeq(data, priv->base + MLXBF_GIGE_INT_MASK); ++ } ++ ++ return work_done; ++} +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c +new file mode 100644 +index 000000000..04982e888 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c +@@ -0,0 +1,284 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause ++ ++/* Packet transmit logic for Mellanox Gigabit Ethernet driver ++ * ++ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES ++ */ ++ ++#include ++ ++#include "mlxbf_gige.h" ++#include "mlxbf_gige_regs.h" ++ ++/* Transmit Initialization ++ * 1) Allocates TX WQE array using coherent DMA mapping ++ * 2) Allocates TX completion counter using coherent DMA mapping ++ */ ++int mlxbf_gige_tx_init(struct mlxbf_gige *priv) ++{ ++ size_t size; ++ ++ size = MLXBF_GIGE_TX_WQE_SZ * priv->tx_q_entries; ++ priv->tx_wqe_base = dma_alloc_coherent(priv->dev, size, ++ &priv->tx_wqe_base_dma, ++ GFP_KERNEL); ++ if (!priv->tx_wqe_base) ++ return -ENOMEM; ++ ++ priv->tx_wqe_next = priv->tx_wqe_base; ++ ++ /* Write TX WQE base address into MMIO reg */ ++ writeq(priv->tx_wqe_base_dma, priv->base + MLXBF_GIGE_TX_WQ_BASE); ++ ++ /* Allocate address for TX completion count */ ++ priv->tx_cc = dma_alloc_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ, ++ &priv->tx_cc_dma, GFP_KERNEL); ++ if (!priv->tx_cc) { ++ dma_free_coherent(priv->dev, size, ++ priv->tx_wqe_base, priv->tx_wqe_base_dma); ++ return -ENOMEM; ++ } ++ ++ /* Write TX CC base address into MMIO reg */ ++ writeq(priv->tx_cc_dma, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS); ++ ++ writeq(ilog2(priv->tx_q_entries), ++ priv->base + MLXBF_GIGE_TX_WQ_SIZE_LOG2); ++ ++ priv->prev_tx_ci = 0; ++ priv->tx_pi = 0; ++ ++ return 0; ++} ++ ++/* Transmit Deinitialization ++ * This routine will free allocations done by mlxbf_gige_tx_init(), ++ * namely the TX WQE array and the TX completion counter ++ */ ++void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv) ++{ ++ u64 *tx_wqe_addr; ++ size_t size; ++ int i; ++ ++ tx_wqe_addr = priv->tx_wqe_base; ++ ++ for (i = 0; i < priv->tx_q_entries; i++) { ++ if (priv->tx_skb[i]) { ++ dma_unmap_single(priv->dev, *tx_wqe_addr, ++ priv->tx_skb[i]->len, DMA_TO_DEVICE); ++ dev_kfree_skb(priv->tx_skb[i]); ++ priv->tx_skb[i] = NULL; ++ } ++ tx_wqe_addr += 2; ++ } ++ ++ size = MLXBF_GIGE_TX_WQE_SZ * priv->tx_q_entries; ++ dma_free_coherent(priv->dev, size, ++ priv->tx_wqe_base, priv->tx_wqe_base_dma); ++ ++ dma_free_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ, ++ priv->tx_cc, priv->tx_cc_dma); ++ ++ priv->tx_wqe_base = NULL; ++ priv->tx_wqe_base_dma = 0; ++ priv->tx_cc = NULL; ++ priv->tx_cc_dma = 0; ++ priv->tx_wqe_next = NULL; ++ writeq(0, priv->base + MLXBF_GIGE_TX_WQ_BASE); ++ writeq(0, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS); ++} ++ ++/* Function that returns status of TX ring: ++ * 0: TX ring is full, i.e. there are no ++ * available un-used entries in TX ring. ++ * non-null: TX ring is not full, i.e. there are ++ * some available entries in TX ring. ++ * The non-null value is a measure of ++ * how many TX entries are available, but ++ * it is not the exact number of available ++ * entries (see below). ++ * ++ * The algorithm makes the assumption that if ++ * (prev_tx_ci == tx_pi) then the TX ring is empty. ++ * An empty ring actually has (tx_q_entries-1) ++ * entries, which allows the algorithm to differentiate ++ * the case of an empty ring vs. a full ring. ++ */ ++static u16 mlxbf_gige_tx_buffs_avail(struct mlxbf_gige *priv) ++{ ++ unsigned long flags; ++ u16 avail; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ if (priv->prev_tx_ci == priv->tx_pi) ++ avail = priv->tx_q_entries - 1; ++ else ++ avail = ((priv->tx_q_entries + priv->prev_tx_ci - priv->tx_pi) ++ % priv->tx_q_entries) - 1; ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ return avail; ++} ++ ++bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv) ++{ ++ struct net_device_stats *stats; ++ u16 tx_wqe_index; ++ u64 *tx_wqe_addr; ++ u64 tx_status; ++ u16 tx_ci; ++ ++ tx_status = readq(priv->base + MLXBF_GIGE_TX_STATUS); ++ if (tx_status & MLXBF_GIGE_TX_STATUS_DATA_FIFO_FULL) ++ priv->stats.tx_fifo_full++; ++ tx_ci = readq(priv->base + MLXBF_GIGE_TX_CONSUMER_INDEX); ++ stats = &priv->netdev->stats; ++ ++ /* Transmit completion logic needs to loop until the completion ++ * index (in SW) equals TX consumer index (from HW). These ++ * parameters are unsigned 16-bit values and the wrap case needs ++ * to be supported, that is TX consumer index wrapped from 0xFFFF ++ * to 0 while TX completion index is still < 0xFFFF. ++ */ ++ for (; priv->prev_tx_ci != tx_ci; priv->prev_tx_ci++) { ++ tx_wqe_index = priv->prev_tx_ci % priv->tx_q_entries; ++ /* Each TX WQE is 16 bytes. The 8 MSB store the 2KB TX ++ * buffer address and the 8 LSB contain information ++ * about the TX WQE. ++ */ ++ tx_wqe_addr = priv->tx_wqe_base + ++ (tx_wqe_index * MLXBF_GIGE_TX_WQE_SZ_QWORDS); ++ ++ stats->tx_packets++; ++ stats->tx_bytes += MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr); ++ ++ dma_unmap_single(priv->dev, *tx_wqe_addr, ++ priv->tx_skb[tx_wqe_index]->len, DMA_TO_DEVICE); ++ dev_consume_skb_any(priv->tx_skb[tx_wqe_index]); ++ priv->tx_skb[tx_wqe_index] = NULL; ++ ++ /* Ensure completion of updates across all cores */ ++ mb(); ++ } ++ ++ /* Since the TX ring was likely just drained, check if TX queue ++ * had previously been stopped and now that there are TX buffers ++ * available the TX queue can be awakened. ++ */ ++ if (netif_queue_stopped(priv->netdev) && ++ mlxbf_gige_tx_buffs_avail(priv)) ++ netif_wake_queue(priv->netdev); ++ ++ return true; ++} ++ ++/* Function to advance the tx_wqe_next pointer to next TX WQE */ ++void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv) ++{ ++ /* Advance tx_wqe_next pointer */ ++ priv->tx_wqe_next += MLXBF_GIGE_TX_WQE_SZ_QWORDS; ++ ++ /* Check if 'next' pointer is beyond end of TX ring */ ++ /* If so, set 'next' back to 'base' pointer of ring */ ++ if (priv->tx_wqe_next == (priv->tx_wqe_base + ++ (priv->tx_q_entries * MLXBF_GIGE_TX_WQE_SZ_QWORDS))) ++ priv->tx_wqe_next = priv->tx_wqe_base; ++} ++ ++netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, ++ struct net_device *netdev) ++{ ++ struct mlxbf_gige *priv = netdev_priv(netdev); ++ long buff_addr, start_dma_page, end_dma_page; ++ struct sk_buff *tx_skb; ++ dma_addr_t tx_buf_dma; ++ unsigned long flags; ++ u64 *tx_wqe_addr; ++ u64 word2; ++ ++ /* If needed, linearize TX SKB as hardware DMA expects this */ ++ if (skb->len > MLXBF_GIGE_DEFAULT_BUF_SZ || skb_linearize(skb)) { ++ dev_kfree_skb(skb); ++ netdev->stats.tx_dropped++; ++ return NETDEV_TX_OK; ++ } ++ ++ buff_addr = (long)skb->data; ++ start_dma_page = buff_addr >> MLXBF_GIGE_DMA_PAGE_SHIFT; ++ end_dma_page = (buff_addr + skb->len - 1) >> MLXBF_GIGE_DMA_PAGE_SHIFT; ++ ++ /* Verify that payload pointer and data length of SKB to be ++ * transmitted does not violate the hardware DMA limitation. ++ */ ++ if (start_dma_page != end_dma_page) { ++ /* DMA operation would fail as-is, alloc new aligned SKB */ ++ tx_skb = mlxbf_gige_alloc_skb(priv, skb->len, ++ &tx_buf_dma, DMA_TO_DEVICE); ++ if (!tx_skb) { ++ /* Free original skb, could not alloc new aligned SKB */ ++ dev_kfree_skb(skb); ++ netdev->stats.tx_dropped++; ++ return NETDEV_TX_OK; ++ } ++ ++ skb_put_data(tx_skb, skb->data, skb->len); ++ ++ /* Free the original SKB */ ++ dev_kfree_skb(skb); ++ } else { ++ tx_skb = skb; ++ tx_buf_dma = dma_map_single(priv->dev, skb->data, ++ skb->len, DMA_TO_DEVICE); ++ if (dma_mapping_error(priv->dev, tx_buf_dma)) { ++ dev_kfree_skb(skb); ++ netdev->stats.tx_dropped++; ++ return NETDEV_TX_OK; ++ } ++ } ++ ++ /* Get address of TX WQE */ ++ tx_wqe_addr = priv->tx_wqe_next; ++ ++ mlxbf_gige_update_tx_wqe_next(priv); ++ ++ /* Put PA of buffer address into first 64-bit word of TX WQE */ ++ *tx_wqe_addr = tx_buf_dma; ++ ++ /* Set TX WQE pkt_len appropriately ++ * NOTE: GigE silicon will automatically pad up to ++ * minimum packet length if needed. ++ */ ++ word2 = tx_skb->len & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK; ++ ++ /* Write entire 2nd word of TX WQE */ ++ *(tx_wqe_addr + 1) = word2; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ priv->tx_skb[priv->tx_pi % priv->tx_q_entries] = tx_skb; ++ priv->tx_pi++; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ if (!netdev_xmit_more()) { ++ /* Create memory barrier before write to TX PI */ ++ wmb(); ++ writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); ++ } ++ ++ /* Check if the last TX entry was just used */ ++ if (!mlxbf_gige_tx_buffs_avail(priv)) { ++ /* TX ring is full, inform stack */ ++ netif_stop_queue(netdev); ++ ++ /* Since there is no separate "TX complete" interrupt, need ++ * to explicitly schedule NAPI poll. This will trigger logic ++ * which processes TX completions, and will hopefully drain ++ * the TX ring allowing the TX queue to be awakened. ++ */ ++ napi_schedule(&priv->napi); ++ } ++ ++ return NETDEV_TX_OK; ++} +-- +2.20.1 + diff --git a/patch/0227-mlxbf_gige-clear-valid_polarity-upon-open.patch b/patch/0227-mlxbf_gige-clear-valid_polarity-upon-open.patch new file mode 100644 index 000000000..bfc544b82 --- /dev/null +++ b/patch/0227-mlxbf_gige-clear-valid_polarity-upon-open.patch @@ -0,0 +1,53 @@ +From 245dc6df595b3c11096d96df641fbde3b38f6bb1 Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Wed, 15 Sep 2021 14:08:48 -0400 +Subject: [PATCH backport 5.10 28/63] mlxbf_gige: clear valid_polarity upon + open + +The network interface managed by the mlxbf_gige driver can +get into a problem state where traffic does not flow. +In this state, the interface will be up and enabled, but +will stop processing received packets. This problem state +will happen if three specific conditions occur: + 1) driver has received more than (N * RxRingSize) packets but + less than (N+1 * RxRingSize) packets, where N is an odd number + Note: the command "ethtool -g " will display the + current receive ring size, which currently defaults to 128 + 2) the driver's interface was disabled via "ifconfig oob_net0 down" + during the window described in #1. + 3) the driver's interface is re-enabled via "ifconfig oob_net0 up" + +This patch ensures that the driver's "valid_polarity" field is +cleared during the open() method so that it always matches the +receive polarity used by hardware. Without this fix, the driver +needs to be unloaded and reloaded to correct this problem state. + +Fixes: f92e1869d74e ("Add Mellanox BlueField Gigabit Ethernet driver") +Reviewed-by: Asmaa Mnebhi +Signed-off-by: David Thompson +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +index a0a059e01..04c7dc224 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +@@ -142,6 +142,13 @@ static int mlxbf_gige_open(struct net_device *netdev) + err = mlxbf_gige_clean_port(priv); + if (err) + goto free_irqs; ++ ++ /* Clear driver's valid_polarity to match hardware, ++ * since the above call to clean_port() resets the ++ * receive polarity used by hardware. ++ */ ++ priv->valid_polarity = 0; ++ + err = mlxbf_gige_rx_init(priv); + if (err) + goto free_irqs; +-- +2.20.1 + diff --git a/patch/0228-net-mellanox-mlxbf_gige-Replace-non-standard-interru.patch b/patch/0228-net-mellanox-mlxbf_gige-Replace-non-standard-interru.patch new file mode 100644 index 000000000..97702355a --- /dev/null +++ b/patch/0228-net-mellanox-mlxbf_gige-Replace-non-standard-interru.patch @@ -0,0 +1,368 @@ +From cad3deaacd8c633ce18a06a550551f029c3dcef1 Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Fri, 15 Oct 2021 12:48:09 -0400 +Subject: [PATCH backport 5.10 29/63] net: mellanox: mlxbf_gige: Replace + non-standard interrupt handling + +BugLink: https://bugs.launchpad.net/bugs/1979827 + +Since the GPIO driver (gpio-mlxbf2.c) supports interrupt handling, +replace the custom routine with simple IRQ request. + +Signed-off-by: Asmaa Mnebhi +Acked-by: David S. Miller +Signed-off-by: Bartosz Golaszewski +(cherry picked from commit 6c2a6ddca763271fa583e22bce10c2805c1ea9f6) +Signed-off-by: Ike Panhc +--- + .../net/ethernet/mellanox/mlxbf_gige/Makefile | 1 - + .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 12 - + .../mellanox/mlxbf_gige/mlxbf_gige_gpio.c | 212 ------------------ + .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 22 +- + 4 files changed, 9 insertions(+), 238 deletions(-) + delete mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile +index e57c1375f..a97c2bef8 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile +@@ -3,7 +3,6 @@ + obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige.o + + mlxbf_gige-y := mlxbf_gige_ethtool.o \ +- mlxbf_gige_gpio.o \ + mlxbf_gige_intr.o \ + mlxbf_gige_main.o \ + mlxbf_gige_mdio.o \ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +index e3509e69e..86826a70f 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +@@ -51,11 +51,6 @@ + #define MLXBF_GIGE_ERROR_INTR_IDX 0 + #define MLXBF_GIGE_RECEIVE_PKT_INTR_IDX 1 + #define MLXBF_GIGE_LLU_PLU_INTR_IDX 2 +-#define MLXBF_GIGE_PHY_INT_N 3 +- +-#define MLXBF_GIGE_MDIO_DEFAULT_PHY_ADDR 0x3 +- +-#define MLXBF_GIGE_DEFAULT_PHY_INT_GPIO 12 + + struct mlxbf_gige_stats { + u64 hw_access_errors; +@@ -81,11 +76,7 @@ struct mlxbf_gige { + struct platform_device *pdev; + void __iomem *mdio_io; + struct mii_bus *mdiobus; +- void __iomem *gpio_io; +- struct irq_domain *irqdomain; +- u32 phy_int_gpio_mask; + spinlock_t lock; /* for packet processing indices */ +- spinlock_t gpio_lock; /* for GPIO bus access */ + u16 rx_q_entries; + u16 tx_q_entries; + u64 *tx_wqe_base; +@@ -184,7 +175,4 @@ int mlxbf_gige_poll(struct napi_struct *napi, int budget); + extern const struct ethtool_ops mlxbf_gige_ethtool_ops; + void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv); + +-int mlxbf_gige_gpio_init(struct platform_device *pdev, struct mlxbf_gige *priv); +-void mlxbf_gige_gpio_free(struct mlxbf_gige *priv); +- + #endif /* !defined(__MLXBF_GIGE_H__) */ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c +deleted file mode 100644 +index a8d966db5..000000000 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c ++++ /dev/null +@@ -1,212 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +- +-/* Initialize and handle GPIO interrupt triggered by INT_N PHY signal. +- * This GPIO interrupt triggers the PHY state machine to bring the link +- * up/down. +- * +- * Copyright (C) 2021 NVIDIA CORPORATION & AFFILIATES +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "mlxbf_gige.h" +-#include "mlxbf_gige_regs.h" +- +-#define MLXBF_GIGE_GPIO_CAUSE_FALL_EN 0x48 +-#define MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x80 +-#define MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0 0x94 +-#define MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE 0x98 +- +-static void mlxbf_gige_gpio_enable(struct mlxbf_gige *priv) +-{ +- unsigned long flags; +- u32 val; +- +- spin_lock_irqsave(&priv->gpio_lock, flags); +- val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); +- val |= priv->phy_int_gpio_mask; +- writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); +- +- /* The INT_N interrupt level is active low. +- * So enable cause fall bit to detect when GPIO +- * state goes low. +- */ +- val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); +- val |= priv->phy_int_gpio_mask; +- writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); +- +- /* Enable PHY interrupt by setting the priority level */ +- val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); +- val |= priv->phy_int_gpio_mask; +- writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); +- spin_unlock_irqrestore(&priv->gpio_lock, flags); +-} +- +-static void mlxbf_gige_gpio_disable(struct mlxbf_gige *priv) +-{ +- unsigned long flags; +- u32 val; +- +- spin_lock_irqsave(&priv->gpio_lock, flags); +- val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); +- val &= ~priv->phy_int_gpio_mask; +- writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); +- spin_unlock_irqrestore(&priv->gpio_lock, flags); +-} +- +-static irqreturn_t mlxbf_gige_gpio_handler(int irq, void *ptr) +-{ +- struct mlxbf_gige *priv; +- u32 val; +- +- priv = ptr; +- +- /* Check if this interrupt is from PHY device. +- * Return if it is not. +- */ +- val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0); +- if (!(val & priv->phy_int_gpio_mask)) +- return IRQ_NONE; +- +- /* Clear interrupt when done, otherwise, no further interrupt +- * will be triggered. +- */ +- val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); +- val |= priv->phy_int_gpio_mask; +- writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); +- +- generic_handle_irq(priv->phy_irq); +- +- return IRQ_HANDLED; +-} +- +-static void mlxbf_gige_gpio_mask(struct irq_data *irqd) +-{ +- struct mlxbf_gige *priv = irq_data_get_irq_chip_data(irqd); +- +- mlxbf_gige_gpio_disable(priv); +-} +- +-static void mlxbf_gige_gpio_unmask(struct irq_data *irqd) +-{ +- struct mlxbf_gige *priv = irq_data_get_irq_chip_data(irqd); +- +- mlxbf_gige_gpio_enable(priv); +-} +- +-static struct irq_chip mlxbf_gige_gpio_chip = { +- .name = "mlxbf_gige_phy", +- .irq_mask = mlxbf_gige_gpio_mask, +- .irq_unmask = mlxbf_gige_gpio_unmask, +-}; +- +-static int mlxbf_gige_gpio_domain_map(struct irq_domain *d, +- unsigned int irq, +- irq_hw_number_t hwirq) +-{ +- irq_set_chip_data(irq, d->host_data); +- irq_set_chip_and_handler(irq, &mlxbf_gige_gpio_chip, handle_simple_irq); +- irq_set_noprobe(irq); +- +- return 0; +-} +- +-static const struct irq_domain_ops mlxbf_gige_gpio_domain_ops = { +- .map = mlxbf_gige_gpio_domain_map, +- .xlate = irq_domain_xlate_twocell, +-}; +- +-#ifdef CONFIG_ACPI +-static int mlxbf_gige_gpio_resources(struct acpi_resource *ares, +- void *data) +-{ +- struct acpi_resource_gpio *gpio; +- u32 *phy_int_gpio = data; +- +- if (ares->type == ACPI_RESOURCE_TYPE_GPIO) { +- gpio = &ares->data.gpio; +- *phy_int_gpio = gpio->pin_table[0]; +- } +- +- return 1; +-} +-#endif +- +-void mlxbf_gige_gpio_free(struct mlxbf_gige *priv) +-{ +- irq_dispose_mapping(priv->phy_irq); +- irq_domain_remove(priv->irqdomain); +-} +- +-int mlxbf_gige_gpio_init(struct platform_device *pdev, +- struct mlxbf_gige *priv) +-{ +- struct device *dev = &pdev->dev; +- struct resource *res; +- u32 phy_int_gpio = 0; +- int ret; +- +- LIST_HEAD(resources); +- +- res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_GPIO0); +- if (!res) +- return -ENODEV; +- +- priv->gpio_io = devm_ioremap(dev, res->start, resource_size(res)); +- if (!priv->gpio_io) +- return -ENOMEM; +- +-#ifdef CONFIG_ACPI +- ret = acpi_dev_get_resources(ACPI_COMPANION(dev), +- &resources, mlxbf_gige_gpio_resources, +- &phy_int_gpio); +- acpi_dev_free_resource_list(&resources); +- if (ret < 0 || !phy_int_gpio) { +- dev_err(dev, "Error retrieving the gpio phy pin"); +- return -EINVAL; +- } +-#endif +- +- priv->phy_int_gpio_mask = BIT(phy_int_gpio); +- +- mlxbf_gige_gpio_disable(priv); +- +- priv->hw_phy_irq = platform_get_irq(pdev, MLXBF_GIGE_PHY_INT_N); +- +- priv->irqdomain = irq_domain_add_simple(NULL, 1, 0, +- &mlxbf_gige_gpio_domain_ops, +- priv); +- if (!priv->irqdomain) { +- dev_err(dev, "Failed to add IRQ domain\n"); +- return -ENOMEM; +- } +- +- priv->phy_irq = irq_create_mapping(priv->irqdomain, 0); +- if (!priv->phy_irq) { +- irq_domain_remove(priv->irqdomain); +- priv->irqdomain = NULL; +- dev_err(dev, "Error mapping PHY IRQ\n"); +- return -EINVAL; +- } +- +- ret = devm_request_irq(dev, priv->hw_phy_irq, mlxbf_gige_gpio_handler, +- IRQF_ONESHOT | IRQF_SHARED, "mlxbf_gige_phy", priv); +- if (ret) { +- dev_err(dev, "Failed to request PHY IRQ"); +- mlxbf_gige_gpio_free(priv); +- return ret; +- } +- +- return ret; +-} +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +index 04c7dc224..e4ed38bbd 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +@@ -283,8 +283,8 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + void __iomem *llu_base; + void __iomem *plu_base; + void __iomem *base; ++ int addr, phy_irq; + u64 control; +- int addr; + int err; + + mac_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MAC); +@@ -331,20 +331,12 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + priv->pdev = pdev; + + spin_lock_init(&priv->lock); +- spin_lock_init(&priv->gpio_lock); + + /* Attach MDIO device */ + err = mlxbf_gige_mdio_probe(pdev, priv); + if (err) + return err; + +- err = mlxbf_gige_gpio_init(pdev, priv); +- if (err) { +- dev_err(&pdev->dev, "PHY IRQ initialization failed\n"); +- mlxbf_gige_mdio_remove(priv); +- return -ENODEV; +- } +- + priv->base = base; + priv->llu_base = llu_base; + priv->plu_base = plu_base; +@@ -365,6 +357,12 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX); + priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX); + ++ phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy-gpios", 0); ++ if (phy_irq < 0) { ++ dev_err(&pdev->dev, "Error getting PHY irq. Use polling instead"); ++ phy_irq = PHY_POLL; ++ } ++ + phydev = phy_find_first(priv->mdiobus); + if (!phydev) { + err = -ENODEV; +@@ -372,8 +370,8 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + } + + addr = phydev->mdio.addr; +- priv->mdiobus->irq[addr] = priv->phy_irq; +- phydev->irq = priv->phy_irq; ++ priv->mdiobus->irq[addr] = phy_irq; ++ phydev->irq = phy_irq; + + err = phy_connect_direct(netdev, phydev, + mlxbf_gige_adjust_link, +@@ -409,7 +407,6 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + return 0; + + out: +- mlxbf_gige_gpio_free(priv); + mlxbf_gige_mdio_remove(priv); + return err; + } +@@ -420,7 +417,6 @@ static int mlxbf_gige_remove(struct platform_device *pdev) + + unregister_netdev(priv->netdev); + phy_disconnect(priv->netdev->phydev); +- mlxbf_gige_gpio_free(priv); + mlxbf_gige_mdio_remove(priv); + platform_set_drvdata(pdev, NULL); + +-- +2.20.1 + diff --git a/patch/0229-mlxbf_gige-increase-MDIO-polling-rate-to-5us.patch b/patch/0229-mlxbf_gige-increase-MDIO-polling-rate-to-5us.patch new file mode 100644 index 000000000..b0020cca1 --- /dev/null +++ b/patch/0229-mlxbf_gige-increase-MDIO-polling-rate-to-5us.patch @@ -0,0 +1,52 @@ +From a8ab0bbc8f17a0099c4982f3e0cb78f6c323fa46 Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Thu, 5 May 2022 12:23:09 -0400 +Subject: [PATCH backport 5.10 30/63] mlxbf_gige: increase MDIO polling rate to + 5us + +BugLink: https://bugs.launchpad.net/bugs/1979827 + +This patch increases the polling rate used by the +mlxbf_gige driver on the MDIO bus. The previous +polling rate was every 100us, and the new rate is +every 5us. With this change the amount of time +spent waiting for the MDIO BUSY signal to de-assert +drops from ~100us to ~27us for each operation. + +Signed-off-by: David Thompson +Signed-off-by: Asmaa Mnebhi +Link: https://lore.kernel.org/r/20220505162309.20050-1-davthompson@nvidia.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit 0a02e282bad4dad455553fc2b9268cf1d003f132) +Signed-off-by: Ike Panhc +--- + drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +index e32dd34fd..6c8a4a529 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +@@ -105,7 +105,8 @@ static int mlxbf_gige_mdio_read(struct mii_bus *bus, int phy_add, int phy_reg) + writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); + + ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET, +- val, !(val & MLXBF_GIGE_MDIO_GW_BUSY_MASK), 100, 1000000); ++ val, !(val & MLXBF_GIGE_MDIO_GW_BUSY_MASK), ++ 5, 1000000); + + if (ret) { + writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); +@@ -137,7 +138,8 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, + + /* If the poll timed out, drop the request */ + ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET, +- temp, !(temp & MLXBF_GIGE_MDIO_GW_BUSY_MASK), 100, 1000000); ++ temp, !(temp & MLXBF_GIGE_MDIO_GW_BUSY_MASK), ++ 5, 1000000); + + return ret; + } +-- +2.20.1 + diff --git a/patch/0230-mlxbf_gige-remove-driver-managed-interrupt-counts.patch b/patch/0230-mlxbf_gige-remove-driver-managed-interrupt-counts.patch new file mode 100644 index 000000000..fb80c63de --- /dev/null +++ b/patch/0230-mlxbf_gige-remove-driver-managed-interrupt-counts.patch @@ -0,0 +1,97 @@ +From 4eafb2c053cc5935fe826da97fda42abadab5fc1 Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Wed, 11 May 2022 09:52:51 -0400 +Subject: [PATCH backport 5.10 31/63] mlxbf_gige: remove driver-managed + interrupt counts + +BugLink: https://bugs.launchpad.net/bugs/1979827 + +The driver currently has three interrupt counters, +which are incremented every time each interrupt handler +executes. These driver-managed counters are not +necessary as the kernel already has logic that manages +interrupt counts and exposes them via /proc/interrupts. +This patch removes the driver-managed counters. + +Signed-off-by: David Thompson +Signed-off-by: Asmaa Mnebhi +Link: https://lore.kernel.org/r/20220511135251.2989-1-davthompson@nvidia.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit f4826443f4d69d2c97c184952c085caf0936a7b8) +Signed-off-by: Ike Panhc +--- + drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 3 --- + .../ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c | 8 +++----- + .../net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c | 9 --------- + 3 files changed, 3 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +index 86826a70f..5fdf9b717 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +@@ -90,9 +90,6 @@ struct mlxbf_gige { + dma_addr_t rx_cqe_base_dma; + u16 tx_pi; + u16 prev_tx_ci; +- u64 error_intr_count; +- u64 rx_intr_count; +- u64 llu_plu_intr_count; + struct sk_buff *rx_skb[MLXBF_GIGE_MAX_RXQ_SZ]; + struct sk_buff *tx_skb[MLXBF_GIGE_MAX_TXQ_SZ]; + int error_irq; +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c +index 92b798f8e..af46b0cd7 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c +@@ -24,11 +24,9 @@ static void mlxbf_gige_get_regs(struct net_device *netdev, + regs->version = MLXBF_GIGE_REGS_VERSION; + + /* Read entire MMIO register space and store results +- * into the provided buffer. Each 64-bit word is converted +- * to big-endian to make the output more readable. +- * +- * NOTE: by design, a read to an offset without an existing +- * register will be acknowledged and return zero. ++ * into the provided buffer. By design, a read to an ++ * offset without an existing register will be ++ * acknowledged and return zero. + */ + memcpy_fromio(p, priv->base, MLXBF_GIGE_MMIO_REG_SZ); + } +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c +index c38795be0..5b3519f0c 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c +@@ -17,8 +17,6 @@ static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id) + + priv = dev_id; + +- priv->error_intr_count++; +- + int_status = readq(priv->base + MLXBF_GIGE_INT_STATUS); + + if (int_status & MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR) +@@ -75,8 +73,6 @@ static irqreturn_t mlxbf_gige_rx_intr(int irq, void *dev_id) + + priv = dev_id; + +- priv->rx_intr_count++; +- + /* NOTE: GigE silicon automatically disables "packet rx" interrupt by + * setting MLXBF_GIGE_INT_MASK bit0 upon triggering the interrupt + * to the ARM cores. Software needs to re-enable "packet rx" +@@ -90,11 +86,6 @@ static irqreturn_t mlxbf_gige_rx_intr(int irq, void *dev_id) + + static irqreturn_t mlxbf_gige_llu_plu_intr(int irq, void *dev_id) + { +- struct mlxbf_gige *priv; +- +- priv = dev_id; +- priv->llu_plu_intr_count++; +- + return IRQ_HANDLED; + } + +-- +2.20.1 + diff --git a/patch/0231-mlxbf_gige-remove-own-module-name-define-and-use-KBU.patch b/patch/0231-mlxbf_gige-remove-own-module-name-define-and-use-KBU.patch new file mode 100644 index 000000000..a21ada96a --- /dev/null +++ b/patch/0231-mlxbf_gige-remove-own-module-name-define-and-use-KBU.patch @@ -0,0 +1,46 @@ +From 62164fc6ed2a1ae28dbf3cf16c9ecfa0c23b2b3d Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Tue, 14 Jun 2022 17:26:02 -0400 +Subject: [PATCH backport 5.10 32/63] mlxbf_gige: remove own module name define + and use KBUILD_MODNAME instead + +BugLink: https://bugs.launchpad.net/bugs/1979827 + +This patch adds use of KBUILD_MODNAME as defined by the build system, +replacing the definition and use of a custom-defined name. + +Signed-off-by: David Thompson +Signed-off-by: Asmaa Mnebhi +Link: https://lore.kernel.org/r/20220614212602.28061-1-davthompson@nvidia.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit linux-next cfbc80e34e3a905f5e89e7c0bc133a9507b05a28) +Signed-off-by: Ike Panhc +--- + drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +index e4ed38bbd..e8f9290a8 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +@@ -19,8 +19,6 @@ + #include "mlxbf_gige.h" + #include "mlxbf_gige_regs.h" + +-#define DRV_NAME "mlxbf_gige" +- + /* Allocate SKB whose payload pointer aligns with the Bluefield + * hardware DMA limitation, i.e. DMA operation can't cross + * a 4KB boundary. A maximum packet size of 2KB is assumed in the +@@ -442,7 +440,7 @@ static struct platform_driver mlxbf_gige_driver = { + .remove = mlxbf_gige_remove, + .shutdown = mlxbf_gige_shutdown, + .driver = { +- .name = DRV_NAME, ++ .name = KBUILD_MODNAME, + .acpi_match_table = ACPI_PTR(mlxbf_gige_acpi_match), + }, + }; +-- +2.20.1 + diff --git a/patch/0232-UBUNTU-SAUCE-mlxbf_gige-add-ethtool-mlxbf_gige_set_r.patch b/patch/0232-UBUNTU-SAUCE-mlxbf_gige-add-ethtool-mlxbf_gige_set_r.patch new file mode 100644 index 000000000..ffa4eabcd --- /dev/null +++ b/patch/0232-UBUNTU-SAUCE-mlxbf_gige-add-ethtool-mlxbf_gige_set_r.patch @@ -0,0 +1,78 @@ +From 422290c8c36a7a92a64fecea45f431794dc99be6 Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Thu, 14 Jul 2022 17:47:18 -0400 +Subject: [PATCH backport 5.10 33/63] UBUNTU: SAUCE: mlxbf_gige: add ethtool + mlxbf_gige_set_ringparam + +This patch adds the "set_ringparam" callback, to be used by +ethtool when changing the size of the mlxbf_gige driver rings. + +BugLink: https://launchpad.net/bugs/1981766 + +Change-Id: I0198f6fbf6b8ea13bd34ed152e13298265138c76 +Signed-off-by: David Thompson +Signed-off-by: Asmaa Mnebhi +Signed-off-by: Ike Panhc +--- + .../mellanox/mlxbf_gige/mlxbf_gige_ethtool.c | 38 +++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c +index af46b0cd7..257724323 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c +@@ -42,6 +42,43 @@ static void mlxbf_gige_get_ringparam(struct net_device *netdev, + ering->tx_pending = priv->tx_q_entries; + } + ++static int mlxbf_gige_set_ringparam(struct net_device *netdev, ++ struct ethtool_ringparam *ering) ++{ ++ const struct net_device_ops *ops = netdev->netdev_ops; ++ struct mlxbf_gige *priv = netdev_priv(netdev); ++ int new_rx_q_entries, new_tx_q_entries; ++ ++ /* Device does not have separate queues for small/large frames */ ++ if (ering->rx_mini_pending || ering->rx_jumbo_pending) ++ return -EINVAL; ++ ++ /* Round up to supported values */ ++ new_rx_q_entries = roundup_pow_of_two(ering->rx_pending); ++ new_tx_q_entries = roundup_pow_of_two(ering->tx_pending); ++ ++ /* Check against min values, core checks against max values */ ++ if (new_tx_q_entries < MLXBF_GIGE_MIN_TXQ_SZ || ++ new_rx_q_entries < MLXBF_GIGE_MIN_RXQ_SZ) ++ return -EINVAL; ++ ++ /* If queue sizes did not change, exit now */ ++ if (new_rx_q_entries == priv->rx_q_entries && ++ new_tx_q_entries == priv->tx_q_entries) ++ return 0; ++ ++ if (netif_running(netdev)) ++ ops->ndo_stop(netdev); ++ ++ priv->rx_q_entries = new_rx_q_entries; ++ priv->tx_q_entries = new_tx_q_entries; ++ ++ if (netif_running(netdev)) ++ ops->ndo_open(netdev); ++ ++ return 0; ++} ++ + static const struct { + const char string[ETH_GSTRING_LEN]; + } mlxbf_gige_ethtool_stats_keys[] = { +@@ -124,6 +161,7 @@ static void mlxbf_gige_get_pauseparam(struct net_device *netdev, + const struct ethtool_ops mlxbf_gige_ethtool_ops = { + .get_link = ethtool_op_get_link, + .get_ringparam = mlxbf_gige_get_ringparam, ++ .set_ringparam = mlxbf_gige_set_ringparam, + .get_regs_len = mlxbf_gige_get_regs_len, + .get_regs = mlxbf_gige_get_regs, + .get_strings = mlxbf_gige_get_strings, +-- +2.20.1 + diff --git a/patch/0233-UBUNTU-SAUCE-Fix-OOB-handling-RX-packets-in-heavy-tr.patch b/patch/0233-UBUNTU-SAUCE-Fix-OOB-handling-RX-packets-in-heavy-tr.patch new file mode 100644 index 000000000..32338657d --- /dev/null +++ b/patch/0233-UBUNTU-SAUCE-Fix-OOB-handling-RX-packets-in-heavy-tr.patch @@ -0,0 +1,108 @@ +From 30e4a53201f1f1cd9ca90057cd8f191c93fdab15 Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Wed, 20 Jul 2022 17:50:36 -0400 +Subject: [PATCH backport 5.10 34/63] UBUNTU: SAUCE: Fix OOB handling RX + packets in heavy traffic + +BugLink: https://bugs.launchpad.net/bugs/1982424 + +This is reproducible on systems which already have heavy background +traffic. On top of that, the user issues one of the 2 docker pulls below: +docker pull nvcr.io/ea-doca-hbn/hbn/hbn:latest +OR +docker pull gitlab-master.nvidia.com:5005/dl/dgx/tritonserver:22.02-py3-qa + +The second one is a very large container (17GB) + +When they run docker pull, the OOB interface stops being pingable, +the docker pull is interrupted for a very long time (>3mn) or +times out. + +The main reason for the above is because RX PI = RX CI. I have verified that +by reading RX_CQE_PACKET_CI and RX_WQE_PI. This means the WQEs are full and +HW has nowhere else to put the RX packets. + +I believe there is a race condition after SW receives a RX interrupt, +and the interrupt is disabled. I believe HW still tries to add RX +packets to the RX WQEs. So we need to stop the RX traffic by disabling +the DMA. Also, move reading the RX CI before writing the increased value +of RX PI to MLXBF_GIGE_RX_WQE_PI. Normally RX PI should always be > RX CI. +I suspect that when entering mlxbf_gige_rx_packet, for example we have: +MLXBF_GIGE_RX_WQE_PI = 128 +RX_CQE_PACKET_CI = 128 +(128 being the max size of the WQE) + +Then this code will make MLXBF_GIGE_RX_WQE_PI = 129: +rx_pi++; +/* Ensure completion of all writes before notifying HW of replenish */ +wmb(); +writeq(rx_pi, priv->base + MLXBF_GIGE_RX_WQE_PI); + +which means HW has one more slot to populate and in that time span, the HW +populates that WQE and increases the RX_CQE_PACKET_CI = 129. + +Then this code is subject to a race condition: + +rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); +rx_ci_rem = rx_ci % priv->rx_q_entries; +return rx_pi_rem != rx_ci_rem; + +because rx_pi_rem will be equal to rx_ci_rem. +so remaining_pkts will be 0 and we will exit mlxbf_gige_poll + +Change-Id: I25a816b9182471643db95b05c803b9f6349bcc87 +Signed-off-by: David Thompson +Signed-off-by: Asmaa Mnebhi +Signed-off-by: Ike Panhc +--- + .../ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c +index afa3b92a6..96230763c 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c +@@ -266,6 +266,9 @@ static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) + priv->stats.rx_truncate_errors++; + } + ++ rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); ++ rx_ci_rem = rx_ci % priv->rx_q_entries; ++ + /* Let hardware know we've replenished one buffer */ + rx_pi++; + +@@ -278,8 +281,6 @@ static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) + rx_pi_rem = rx_pi % priv->rx_q_entries; + if (rx_pi_rem == 0) + priv->valid_polarity ^= 1; +- rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); +- rx_ci_rem = rx_ci % priv->rx_q_entries; + + if (skb) + netif_receive_skb(skb); +@@ -299,6 +300,10 @@ int mlxbf_gige_poll(struct napi_struct *napi, int budget) + + mlxbf_gige_handle_tx_complete(priv); + ++ data = readq(priv->base + MLXBF_GIGE_RX_DMA); ++ data &= ~MLXBF_GIGE_RX_DMA_EN; ++ writeq(data, priv->base + MLXBF_GIGE_RX_DMA); ++ + do { + remaining_pkts = mlxbf_gige_rx_packet(priv, &work_done); + } while (remaining_pkts && work_done < budget); +@@ -314,6 +319,10 @@ int mlxbf_gige_poll(struct napi_struct *napi, int budget) + data = readq(priv->base + MLXBF_GIGE_INT_MASK); + data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET; + writeq(data, priv->base + MLXBF_GIGE_INT_MASK); ++ ++ data = readq(priv->base + MLXBF_GIGE_RX_DMA); ++ data |= MLXBF_GIGE_RX_DMA_EN; ++ writeq(data, priv->base + MLXBF_GIGE_RX_DMA); + } + + return work_done; +-- +2.20.1 + diff --git a/patch/0234-UBUNTU-SAUCE-mlxbf_gige-add-validation-of-ACPI-table.patch b/patch/0234-UBUNTU-SAUCE-mlxbf_gige-add-validation-of-ACPI-table.patch new file mode 100644 index 000000000..3d6cbb213 --- /dev/null +++ b/patch/0234-UBUNTU-SAUCE-mlxbf_gige-add-validation-of-ACPI-table.patch @@ -0,0 +1,62 @@ +From 8c7dd66540096a636aa35406cdb023dd549e2755 Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Wed, 20 Jul 2022 18:17:09 -0400 +Subject: [PATCH backport 5.10 35/63] UBUNTU: SAUCE: mlxbf_gige: add validation + of ACPI table version + +BugLink: https://bugs.launchpad.net/bugs/1982427 + +This patch checks the "version" property in the OOB ACPI table, +ensuring that the driver probe will only succeed if the expected +version is found. + +Change-Id: I8dc1f877338f9b23ab3560c0315a1727e144dd57 +Signed-off-by: David Thompson +Signed-off-by: Ike Panhc +--- + .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +index e8f9290a8..c9176a2e6 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +@@ -19,6 +19,11 @@ + #include "mlxbf_gige.h" + #include "mlxbf_gige_regs.h" + ++/* This setting defines the version of the ACPI table ++ * content that is compatible with this driver version. ++ */ ++#define MLXBF_GIGE_ACPI_TABLE_VERSION 2 ++ + /* Allocate SKB whose payload pointer aligns with the Bluefield + * hardware DMA limitation, i.e. DMA operation can't cross + * a 4KB boundary. A maximum packet size of 2KB is assumed in the +@@ -282,9 +287,23 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + void __iomem *plu_base; + void __iomem *base; + int addr, phy_irq; ++ u32 version; + u64 control; + int err; + ++ version = 0; ++ err = device_property_read_u32(&pdev->dev, "version", &version); ++ if (err) { ++ dev_err(&pdev->dev, "ACPI table version not found\n"); ++ return -EINVAL; ++ } ++ ++ if (version != MLXBF_GIGE_ACPI_TABLE_VERSION) { ++ dev_err(&pdev->dev, "ACPI table version mismatch: expected %d found %d\n", ++ MLXBF_GIGE_ACPI_TABLE_VERSION, version); ++ return -EINVAL; ++ } ++ + mac_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MAC); + if (!mac_res) + return -ENXIO; +-- +2.20.1 + diff --git a/patch/0235-UBUNTU-SAUCE-mlxbf_gige-set-driver-version-to-1.27.patch b/patch/0235-UBUNTU-SAUCE-mlxbf_gige-set-driver-version-to-1.27.patch new file mode 100644 index 000000000..1f0fcabc8 --- /dev/null +++ b/patch/0235-UBUNTU-SAUCE-mlxbf_gige-set-driver-version-to-1.27.patch @@ -0,0 +1,39 @@ +From 438c36fd4f5ca577d03d50d0d037e44a2d25edd1 Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Wed, 20 Jul 2022 18:59:14 -0400 +Subject: [PATCH backport 5.10 36/63] UBUNTU: SAUCE: mlxbf_gige: set driver + version to 1.27 + +BugLink: https://bugs.launchpad.net/bugs/1982431 + +This patch adds logic to specify the driver version +via MODULE_VERSION() and sets the value to 1.27 + +Change-Id: I91f775df119877ad6d6eeaa5e5f93dcf1b55c8d2 +Signed-off-by: David Thompson +Signed-off-by: Ike Panhc +--- + drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +index c9176a2e6..66a50e35f 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +@@ -19,6 +19,8 @@ + #include "mlxbf_gige.h" + #include "mlxbf_gige_regs.h" + ++#define DRV_VERSION 1.27 ++ + /* This setting defines the version of the ACPI table + * content that is compatible with this driver version. + */ +@@ -470,3 +472,4 @@ MODULE_DESCRIPTION("Mellanox BlueField SoC Gigabit Ethernet Driver"); + MODULE_AUTHOR("David Thompson "); + MODULE_AUTHOR("Asmaa Mnebhi "); + MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_VERSION(__stringify(DRV_VERSION)); +-- +2.20.1 + diff --git a/patch/0236-UBUNTU-SAUCE-mlxbf_gige-clear-MDIO-gateway-lock-afte.patch b/patch/0236-UBUNTU-SAUCE-mlxbf_gige-clear-MDIO-gateway-lock-afte.patch new file mode 100644 index 000000000..1376f1169 --- /dev/null +++ b/patch/0236-UBUNTU-SAUCE-mlxbf_gige-clear-MDIO-gateway-lock-afte.patch @@ -0,0 +1,46 @@ +From 7c7da04799f5fe6f7f5751d413dcdf04abe5ea53 Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Tue, 13 Sep 2022 13:15:14 -0400 +Subject: [PATCH backport 5.10 37/63] UBUNTU: SAUCE: mlxbf_gige: clear MDIO + gateway lock after read + +BugLink: https://bugs.launchpad.net/bugs/1989495 + +The MDIO gateway (GW) lock in BlueField-2 GIGE logic is +set after read. This patch adds logic to make sure the +lock is always cleared at the end of each MDIO transaction. + +Reviewed-by: Asmaa Mnebhi +Signed-off-by: David Thompson +Signed-off-by: Ike Panhc +--- + drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +index 6c8a4a529..b7363c6c3 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +@@ -117,6 +117,9 @@ static int mlxbf_gige_mdio_read(struct mii_bus *bus, int phy_add, int phy_reg) + /* Only return ad bits of the gw register */ + ret &= MLXBF_GIGE_MDIO_GW_AD_MASK; + ++ /* The MDIO lock is set on read. To release it, clear gw register */ ++ writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); ++ + return ret; + } + +@@ -141,6 +144,9 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, + temp, !(temp & MLXBF_GIGE_MDIO_GW_BUSY_MASK), + 5, 1000000); + ++ /* The MDIO lock is set on read. To release it, clear gw register */ ++ writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); ++ + return ret; + } + +-- +2.20.1 + diff --git a/patch/0237-mlxbf_gige-compute-MDIO-period-based-on-i1clk.patch b/patch/0237-mlxbf_gige-compute-MDIO-period-based-on-i1clk.patch new file mode 100644 index 000000000..fba0668a5 --- /dev/null +++ b/patch/0237-mlxbf_gige-compute-MDIO-period-based-on-i1clk.patch @@ -0,0 +1,244 @@ +From 793a81817df0dcee08aad3385a6971895437ab80 Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Fri, 26 Aug 2022 11:59:16 -0400 +Subject: [PATCH backport 5.10 38/63] mlxbf_gige: compute MDIO period based on + i1clk + +BugLink: https://launchpad.net/bugs/1989035 + +This patch adds logic to compute the MDIO period based on +the i1clk, and thereafter write the MDIO period into the YU +MDIO config register. The i1clk resource from the ACPI table +is used to provide addressing to YU bootrecord PLL registers. +The values in these registers are used to compute MDIO period. +If the i1clk resource is not present in the ACPI table, then +the current default hardcorded value of 430Mhz is used. +The i1clk clock value of 430MHz is only accurate for boards +with BF2 mid bin and main bin SoCs. The BF2 high bin SoCs +have i1clk = 500MHz, but can support a slower MDIO period. + +Fixes: f92e1869d74e ("Add Mellanox BlueField Gigabit Ethernet driver") +Reviewed-by: Asmaa Mnebhi +Signed-off-by: David Thompson +Link: https://lore.kernel.org/r/20220826155916.12491-1-davthompson@nvidia.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit 3a1a274e933fca73fdc960cb1f60636cd285a265) +Signed-off-by: Ike Panhc +--- + .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 4 +- + .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 121 +++++++++++++++--- + .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 2 + + 3 files changed, 109 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +index 5fdf9b717..5a1027b07 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +@@ -75,6 +75,7 @@ struct mlxbf_gige { + struct net_device *netdev; + struct platform_device *pdev; + void __iomem *mdio_io; ++ void __iomem *clk_io; + struct mii_bus *mdiobus; + spinlock_t lock; /* for packet processing indices */ + u16 rx_q_entries; +@@ -137,7 +138,8 @@ enum mlxbf_gige_res { + MLXBF_GIGE_RES_MDIO9, + MLXBF_GIGE_RES_GPIO0, + MLXBF_GIGE_RES_LLU, +- MLXBF_GIGE_RES_PLU ++ MLXBF_GIGE_RES_PLU, ++ MLXBF_GIGE_RES_CLK + }; + + /* Version of register data returned by mlxbf_gige_get_regs() */ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +index b7363c6c3..736849d07 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +@@ -22,10 +22,23 @@ + #include + + #include "mlxbf_gige.h" ++#include "mlxbf_gige_regs.h" + + #define MLXBF_GIGE_MDIO_GW_OFFSET 0x0 + #define MLXBF_GIGE_MDIO_CFG_OFFSET 0x4 + ++#define MLXBF_GIGE_MDIO_FREQ_REFERENCE 156250000ULL ++#define MLXBF_GIGE_MDIO_COREPLL_CONST 16384ULL ++#define MLXBF_GIGE_MDC_CLK_NS 400 ++#define MLXBF_GIGE_MDIO_PLL_I1CLK_REG1 0x4 ++#define MLXBF_GIGE_MDIO_PLL_I1CLK_REG2 0x8 ++#define MLXBF_GIGE_MDIO_CORE_F_SHIFT 0 ++#define MLXBF_GIGE_MDIO_CORE_F_MASK GENMASK(25, 0) ++#define MLXBF_GIGE_MDIO_CORE_R_SHIFT 26 ++#define MLXBF_GIGE_MDIO_CORE_R_MASK GENMASK(31, 26) ++#define MLXBF_GIGE_MDIO_CORE_OD_SHIFT 0 ++#define MLXBF_GIGE_MDIO_CORE_OD_MASK GENMASK(3, 0) ++ + /* Support clause 22 */ + #define MLXBF_GIGE_MDIO_CL22_ST1 0x1 + #define MLXBF_GIGE_MDIO_CL22_WRITE 0x1 +@@ -50,27 +63,76 @@ + #define MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK GENMASK(23, 16) + #define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK GENMASK(31, 24) + ++#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \ ++ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ ++ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ ++ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ ++ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) ++ ++#define MLXBF_GIGE_BF2_COREPLL_ADDR 0x02800c30 ++#define MLXBF_GIGE_BF2_COREPLL_SIZE 0x0000000c ++ ++static struct resource corepll_params[] = { ++ [MLXBF_GIGE_VERSION_BF2] = { ++ .start = MLXBF_GIGE_BF2_COREPLL_ADDR, ++ .end = MLXBF_GIGE_BF2_COREPLL_ADDR + MLXBF_GIGE_BF2_COREPLL_SIZE - 1, ++ .name = "COREPLL_RES" ++ }, ++}; ++ ++/* Returns core clock i1clk in Hz */ ++static u64 calculate_i1clk(struct mlxbf_gige *priv) ++{ ++ u8 core_od, core_r; ++ u64 freq_output; ++ u32 reg1, reg2; ++ u32 core_f; ++ ++ reg1 = readl(priv->clk_io + MLXBF_GIGE_MDIO_PLL_I1CLK_REG1); ++ reg2 = readl(priv->clk_io + MLXBF_GIGE_MDIO_PLL_I1CLK_REG2); ++ ++ core_f = (reg1 & MLXBF_GIGE_MDIO_CORE_F_MASK) >> ++ MLXBF_GIGE_MDIO_CORE_F_SHIFT; ++ core_r = (reg1 & MLXBF_GIGE_MDIO_CORE_R_MASK) >> ++ MLXBF_GIGE_MDIO_CORE_R_SHIFT; ++ core_od = (reg2 & MLXBF_GIGE_MDIO_CORE_OD_MASK) >> ++ MLXBF_GIGE_MDIO_CORE_OD_SHIFT; ++ ++ /* Compute PLL output frequency as follow: ++ * ++ * CORE_F / 16384 ++ * freq_output = freq_reference * ---------------------------- ++ * (CORE_R + 1) * (CORE_OD + 1) ++ */ ++ freq_output = div_u64((MLXBF_GIGE_MDIO_FREQ_REFERENCE * core_f), ++ MLXBF_GIGE_MDIO_COREPLL_CONST); ++ freq_output = div_u64(freq_output, (core_r + 1) * (core_od + 1)); ++ ++ return freq_output; ++} ++ + /* Formula for encoding the MDIO period. The encoded value is + * passed to the MDIO config register. + * +- * mdc_clk = 2*(val + 1)*i1clk ++ * mdc_clk = 2*(val + 1)*(core clock in sec) + * +- * 400 ns = 2*(val + 1)*(((1/430)*1000) ns) ++ * i1clk is in Hz: ++ * 400 ns = 2*(val + 1)*(1/i1clk) + * +- * val = (((400 * 430 / 1000) / 2) - 1) ++ * val = (((400/10^9) / (1/i1clk) / 2) - 1) ++ * val = (400/2 * i1clk)/10^9 - 1 + */ +-#define MLXBF_GIGE_I1CLK_MHZ 430 +-#define MLXBF_GIGE_MDC_CLK_NS 400 ++static u8 mdio_period_map(struct mlxbf_gige *priv) ++{ ++ u8 mdio_period; ++ u64 i1clk; + +-#define MLXBF_GIGE_MDIO_PERIOD (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1) ++ i1clk = calculate_i1clk(priv); + +-#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \ +- MLXBF_GIGE_MDIO_PERIOD) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) ++ mdio_period = div_u64((MLXBF_GIGE_MDC_CLK_NS >> 1) * i1clk, 1000000000) - 1; ++ ++ return mdio_period; ++} + + static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add, + int phy_reg, u32 opcode) +@@ -127,9 +189,9 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, + int phy_reg, u16 val) + { + struct mlxbf_gige *priv = bus->priv; ++ u32 temp; + u32 cmd; + int ret; +- u32 temp; + + if (phy_reg & MII_ADDR_C45) + return -EOPNOTSUPP; +@@ -150,6 +212,18 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, + return ret; + } + ++static void mlxbf_gige_mdio_cfg(struct mlxbf_gige *priv) ++{ ++ u8 mdio_period; ++ u32 val; ++ ++ mdio_period = mdio_period_map(priv); ++ ++ val = MLXBF_GIGE_MDIO_CFG_VAL; ++ val |= FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdio_period); ++ writel(val, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); ++} ++ + int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) + { + struct device *dev = &pdev->dev; +@@ -164,9 +238,22 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) + if (IS_ERR(priv->mdio_io)) + return PTR_ERR(priv->mdio_io); + +- /* Configure mdio parameters */ +- writel(MLXBF_GIGE_MDIO_CFG_VAL, +- priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); ++ /* clk resource shared with other drivers so cannot use ++ * devm_platform_ioremap_resource ++ */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_CLK); ++ if (!res) { ++ /* For backward compatibility with older ACPI tables, also keep ++ * CLK resource internal to the driver. ++ */ ++ res = &corepll_params[MLXBF_GIGE_VERSION_BF2]; ++ } ++ ++ priv->clk_io = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(priv->clk_io)) ++ return PTR_ERR(priv->clk_io); ++ ++ mlxbf_gige_mdio_cfg(priv); + + priv->mdiobus = devm_mdiobus_alloc(dev); + if (!priv->mdiobus) { +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +index 5fb33c929..7be3a7939 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +@@ -8,6 +8,8 @@ + #ifndef __MLXBF_GIGE_REGS_H__ + #define __MLXBF_GIGE_REGS_H__ + ++#define MLXBF_GIGE_VERSION 0x0000 ++#define MLXBF_GIGE_VERSION_BF2 0x0 + #define MLXBF_GIGE_STATUS 0x0010 + #define MLXBF_GIGE_STATUS_READY BIT(0) + #define MLXBF_GIGE_INT_STATUS 0x0028 +-- +2.20.1 + diff --git a/patch/0238-net-mlxbf_gige-Fix-an-IS_ERR-vs-NULL-bug-in-mlxbf_gi.patch b/patch/0238-net-mlxbf_gige-Fix-an-IS_ERR-vs-NULL-bug-in-mlxbf_gi.patch new file mode 100644 index 000000000..dbbfa9615 --- /dev/null +++ b/patch/0238-net-mlxbf_gige-Fix-an-IS_ERR-vs-NULL-bug-in-mlxbf_gi.patch @@ -0,0 +1,42 @@ +From f6a48751ea5c5943d9eb6e0d7711215ac5aad6c3 Mon Sep 17 00:00:00 2001 +From: Peng Wu +Date: Fri, 30 Sep 2022 11:24:45 -0400 +Subject: [PATCH backport 5.10 39/63] net/mlxbf_gige: Fix an IS_ERR() vs NULL + bug in mlxbf_gige_mdio_probe + +BugLink: https://bugs.launchpad.net/bugs/1991403 + +The devm_ioremap() function returns NULL on error, it doesn't return +error pointers. + +Fixes: 3a1a274e933f ("mlxbf_gige: compute MDIO period based on i1clk") +Signed-off-by: Peng Wu +Link: https://lore.kernel.org/r/20220923023640.116057-1-wupeng58@huawei.com +Signed-off-by: Jakub Kicinski +(cherry picked from commit 4774db8dfc6a2e6649920ebb2fc8e2f062c2080d) +Signed-off-by: David Thompson +Acked-by: Tim Gardner +Acked-by: Kleber Sacilotto de Souza +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +index 736849d07..daa31ddb2 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +@@ -250,8 +250,8 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) + } + + priv->clk_io = devm_ioremap(dev, res->start, resource_size(res)); +- if (IS_ERR(priv->clk_io)) +- return PTR_ERR(priv->clk_io); ++ if (!priv->clk_io) ++ return -ENOMEM; + + mlxbf_gige_mdio_cfg(priv); + +-- +2.20.1 + diff --git a/patch/0239-UBUNTU-SAUCE-mlxbf_gige-add-MDIO-support-for-BlueFie.patch b/patch/0239-UBUNTU-SAUCE-mlxbf_gige-add-MDIO-support-for-BlueFie.patch new file mode 100644 index 000000000..9403bb5ba --- /dev/null +++ b/patch/0239-UBUNTU-SAUCE-mlxbf_gige-add-MDIO-support-for-BlueFie.patch @@ -0,0 +1,484 @@ +From 6073dbcdbce9c9f8e63790217b17913efb5174c5 Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Tue, 25 Oct 2022 16:25:19 -0400 +Subject: [PATCH backport 5.10 40/63] UBUNTU: SAUCE: mlxbf_gige: add MDIO + support for BlueField-3 + +BugLink: https://bugs.launchpad.net/bugs/1995148 + +This patch adds initial MDIO support for the BlueField-3 +SoC. Separate header files for the BlueField-2 and the +BlueField-3 SoCs have been created. These header files +hold the SoC-specific MDIO macros since the register +offsets and bit fields have changed. Also, in BlueField-3 +there is a separate register for writing and reading the +MDIO data. Finally, instead of having "if" statements +everywhere to differentiate between SoC-specific logic, +a mlxbf_gige_mdio_gw_t struct was created for this purpose. + +Signed-off-by: David Thompson +Signed-off-by: Asmaa Mnebhi +--- + .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 19 ++ + .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 2 + + .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 172 +++++++++++++----- + .../mellanox/mlxbf_gige/mlxbf_gige_mdio_bf2.h | 53 ++++++ + .../mellanox/mlxbf_gige/mlxbf_gige_mdio_bf3.h | 54 ++++++ + .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 1 + + 6 files changed, 251 insertions(+), 50 deletions(-) + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf2.h + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf3.h + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +index 5a1027b07..421a0b1b7 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +@@ -67,6 +67,23 @@ struct mlxbf_gige_stats { + u64 rx_filter_discard_pkts; + }; + ++struct mlxbf_gige_reg_param { ++ u32 mask; ++ u32 shift; ++}; ++ ++struct mlxbf_gige_mdio_gw { ++ u32 gw_address; ++ u32 read_data_address; ++ struct mlxbf_gige_reg_param busy; ++ struct mlxbf_gige_reg_param write_data; ++ struct mlxbf_gige_reg_param read_data; ++ struct mlxbf_gige_reg_param devad; ++ struct mlxbf_gige_reg_param partad; ++ struct mlxbf_gige_reg_param opcode; ++ struct mlxbf_gige_reg_param st1; ++}; ++ + struct mlxbf_gige { + void __iomem *base; + void __iomem *llu_base; +@@ -102,6 +119,8 @@ struct mlxbf_gige { + u8 valid_polarity; + struct napi_struct napi; + struct mlxbf_gige_stats stats; ++ u8 hw_version; ++ struct mlxbf_gige_mdio_gw *mdio_gw; + }; + + /* Rx Work Queue Element definitions */ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +index 66a50e35f..49695f3e9 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +@@ -351,6 +351,8 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + + spin_lock_init(&priv->lock); + ++ priv->hw_version = readq(base + MLXBF_GIGE_VERSION); ++ + /* Attach MDIO device */ + err = mlxbf_gige_mdio_probe(pdev, priv); + if (err) +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +index daa31ddb2..4ee3df30c 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +@@ -23,9 +23,75 @@ + + #include "mlxbf_gige.h" + #include "mlxbf_gige_regs.h" ++#include "mlxbf_gige_mdio_bf2.h" ++#include "mlxbf_gige_mdio_bf3.h" + +-#define MLXBF_GIGE_MDIO_GW_OFFSET 0x0 +-#define MLXBF_GIGE_MDIO_CFG_OFFSET 0x4 ++static struct mlxbf_gige_mdio_gw mlxbf_gige_mdio_gw_t[] = { ++ [MLXBF_GIGE_VERSION_BF2] = { ++ .gw_address = MLXBF2_GIGE_MDIO_GW_OFFSET, ++ .read_data_address = MLXBF2_GIGE_MDIO_GW_OFFSET, ++ .busy = { ++ .mask = MLXBF2_GIGE_MDIO_GW_BUSY_MASK, ++ .shift = MLXBF2_GIGE_MDIO_GW_BUSY_SHIFT, ++ }, ++ .read_data = { ++ .mask = MLXBF2_GIGE_MDIO_GW_AD_MASK, ++ .shift = MLXBF2_GIGE_MDIO_GW_AD_SHIFT, ++ }, ++ .write_data = { ++ .mask = MLXBF2_GIGE_MDIO_GW_AD_MASK, ++ .shift = MLXBF2_GIGE_MDIO_GW_AD_SHIFT, ++ }, ++ .devad = { ++ .mask = MLXBF2_GIGE_MDIO_GW_DEVAD_MASK, ++ .shift = MLXBF2_GIGE_MDIO_GW_DEVAD_SHIFT, ++ }, ++ .partad = { ++ .mask = MLXBF2_GIGE_MDIO_GW_PARTAD_MASK, ++ .shift = MLXBF2_GIGE_MDIO_GW_PARTAD_SHIFT, ++ }, ++ .opcode = { ++ .mask = MLXBF2_GIGE_MDIO_GW_OPCODE_MASK, ++ .shift = MLXBF2_GIGE_MDIO_GW_OPCODE_SHIFT, ++ }, ++ .st1 = { ++ .mask = MLXBF2_GIGE_MDIO_GW_ST1_MASK, ++ .shift = MLXBF2_GIGE_MDIO_GW_ST1_SHIFT, ++ }, ++ }, ++ [MLXBF_GIGE_VERSION_BF3] = { ++ .gw_address = MLXBF3_GIGE_MDIO_GW_OFFSET, ++ .read_data_address = MLXBF3_GIGE_MDIO_DATA_READ, ++ .busy = { ++ .mask = MLXBF3_GIGE_MDIO_GW_BUSY_MASK, ++ .shift = MLXBF3_GIGE_MDIO_GW_BUSY_SHIFT, ++ }, ++ .read_data = { ++ .mask = MLXBF3_GIGE_MDIO_GW_DATA_READ_MASK, ++ .shift = MLXBF3_GIGE_MDIO_GW_DATA_READ_SHIFT, ++ }, ++ .write_data = { ++ .mask = MLXBF3_GIGE_MDIO_GW_DATA_MASK, ++ .shift = MLXBF3_GIGE_MDIO_GW_DATA_SHIFT, ++ }, ++ .devad = { ++ .mask = MLXBF3_GIGE_MDIO_GW_DEVAD_MASK, ++ .shift = MLXBF3_GIGE_MDIO_GW_DEVAD_SHIFT, ++ }, ++ .partad = { ++ .mask = MLXBF3_GIGE_MDIO_GW_PARTAD_MASK, ++ .shift = MLXBF3_GIGE_MDIO_GW_PARTAD_SHIFT, ++ }, ++ .opcode = { ++ .mask = MLXBF3_GIGE_MDIO_GW_OPCODE_MASK, ++ .shift = MLXBF3_GIGE_MDIO_GW_OPCODE_SHIFT, ++ }, ++ .st1 = { ++ .mask = MLXBF3_GIGE_MDIO_GW_ST1_MASK, ++ .shift = MLXBF3_GIGE_MDIO_GW_ST1_SHIFT, ++ }, ++ }, ++}; + + #define MLXBF_GIGE_MDIO_FREQ_REFERENCE 156250000ULL + #define MLXBF_GIGE_MDIO_COREPLL_CONST 16384ULL +@@ -47,30 +113,10 @@ + /* Busy bit is set by software and cleared by hardware */ + #define MLXBF_GIGE_MDIO_SET_BUSY 0x1 + +-/* MDIO GW register bits */ +-#define MLXBF_GIGE_MDIO_GW_AD_MASK GENMASK(15, 0) +-#define MLXBF_GIGE_MDIO_GW_DEVAD_MASK GENMASK(20, 16) +-#define MLXBF_GIGE_MDIO_GW_PARTAD_MASK GENMASK(25, 21) +-#define MLXBF_GIGE_MDIO_GW_OPCODE_MASK GENMASK(27, 26) +-#define MLXBF_GIGE_MDIO_GW_ST1_MASK GENMASK(28, 28) +-#define MLXBF_GIGE_MDIO_GW_BUSY_MASK GENMASK(30, 30) +- +-/* MDIO config register bits */ +-#define MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK GENMASK(1, 0) +-#define MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK GENMASK(2, 2) +-#define MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK GENMASK(4, 4) +-#define MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK GENMASK(15, 8) +-#define MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK GENMASK(23, 16) +-#define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK GENMASK(31, 24) +- +-#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ +- FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) +- + #define MLXBF_GIGE_BF2_COREPLL_ADDR 0x02800c30 + #define MLXBF_GIGE_BF2_COREPLL_SIZE 0x0000000c ++#define MLXBF_GIGE_BF3_COREPLL_ADDR 0x13409824 ++#define MLXBF_GIGE_BF3_COREPLL_SIZE 0x00000010 + + static struct resource corepll_params[] = { + [MLXBF_GIGE_VERSION_BF2] = { +@@ -78,6 +124,11 @@ static struct resource corepll_params[] = { + .end = MLXBF_GIGE_BF2_COREPLL_ADDR + MLXBF_GIGE_BF2_COREPLL_SIZE - 1, + .name = "COREPLL_RES" + }, ++ [MLXBF_GIGE_VERSION_BF3] = { ++ .start = MLXBF_GIGE_BF3_COREPLL_ADDR, ++ .end = MLXBF_GIGE_BF3_COREPLL_ADDR + MLXBF_GIGE_BF3_COREPLL_SIZE - 1, ++ .name = "COREPLL_RES" ++ } + }; + + /* Returns core clock i1clk in Hz */ +@@ -134,19 +185,23 @@ static u8 mdio_period_map(struct mlxbf_gige *priv) + return mdio_period; + } + +-static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add, ++static u32 mlxbf_gige_mdio_create_cmd(struct mlxbf_gige_mdio_gw *mdio_gw, u16 data, int phy_add, + int phy_reg, u32 opcode) + { + u32 gw_reg = 0; + +- gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_AD_MASK, data); +- gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_DEVAD_MASK, phy_reg); +- gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_PARTAD_MASK, phy_add); +- gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_OPCODE_MASK, opcode); +- gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_ST1_MASK, +- MLXBF_GIGE_MDIO_CL22_ST1); +- gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_BUSY_MASK, +- MLXBF_GIGE_MDIO_SET_BUSY); ++ gw_reg |= ((data << mdio_gw->write_data.shift) & ++ mdio_gw->write_data.mask); ++ gw_reg |= ((phy_reg << mdio_gw->devad.shift) & ++ mdio_gw->devad.mask); ++ gw_reg |= ((phy_add << mdio_gw->partad.shift) & ++ mdio_gw->partad.mask); ++ gw_reg |= ((opcode << mdio_gw->opcode.shift) & ++ mdio_gw->opcode.mask); ++ gw_reg |= ((MLXBF_GIGE_MDIO_CL22_ST1 << mdio_gw->st1.shift) & ++ mdio_gw->st1.mask); ++ gw_reg |= ((MLXBF_GIGE_MDIO_SET_BUSY << mdio_gw->busy.shift) & ++ mdio_gw->busy.mask); + + return gw_reg; + } +@@ -162,25 +217,26 @@ static int mlxbf_gige_mdio_read(struct mii_bus *bus, int phy_add, int phy_reg) + return -EOPNOTSUPP; + + /* Send mdio read request */ +- cmd = mlxbf_gige_mdio_create_cmd(0, phy_add, phy_reg, MLXBF_GIGE_MDIO_CL22_READ); ++ cmd = mlxbf_gige_mdio_create_cmd(priv->mdio_gw, 0, phy_add, phy_reg, ++ MLXBF_GIGE_MDIO_CL22_READ); + +- writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); ++ writel(cmd, priv->mdio_io + priv->mdio_gw->gw_address); + +- ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET, +- val, !(val & MLXBF_GIGE_MDIO_GW_BUSY_MASK), ++ ret = readl_poll_timeout_atomic(priv->mdio_io + priv->mdio_gw->gw_address, ++ val, !(val & priv->mdio_gw->busy.mask), + 5, 1000000); + + if (ret) { +- writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); ++ writel(0, priv->mdio_io + priv->mdio_gw->gw_address); + return ret; + } + +- ret = readl(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); ++ ret = readl(priv->mdio_io + priv->mdio_gw->read_data_address); + /* Only return ad bits of the gw register */ +- ret &= MLXBF_GIGE_MDIO_GW_AD_MASK; ++ ret &= priv->mdio_gw->read_data.mask; + + /* The MDIO lock is set on read. To release it, clear gw register */ +- writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); ++ writel(0, priv->mdio_io + priv->mdio_gw->gw_address); + + return ret; + } +@@ -197,17 +253,17 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, + return -EOPNOTSUPP; + + /* Send mdio write request */ +- cmd = mlxbf_gige_mdio_create_cmd(val, phy_add, phy_reg, ++ cmd = mlxbf_gige_mdio_create_cmd(priv->mdio_gw, val, phy_add, phy_reg, + MLXBF_GIGE_MDIO_CL22_WRITE); +- writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); ++ writel(cmd, priv->mdio_io + priv->mdio_gw->gw_address); + + /* If the poll timed out, drop the request */ +- ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET, +- temp, !(temp & MLXBF_GIGE_MDIO_GW_BUSY_MASK), ++ ret = readl_poll_timeout_atomic(priv->mdio_io + priv->mdio_gw->gw_address, ++ temp, !(temp & priv->mdio_gw->busy.mask), + 5, 1000000); + + /* The MDIO lock is set on read. To release it, clear gw register */ +- writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); ++ writel(0, priv->mdio_io + priv->mdio_gw->gw_address); + + return ret; + } +@@ -219,9 +275,20 @@ static void mlxbf_gige_mdio_cfg(struct mlxbf_gige *priv) + + mdio_period = mdio_period_map(priv); + +- val = MLXBF_GIGE_MDIO_CFG_VAL; +- val |= FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdio_period); +- writel(val, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); ++ if (priv->hw_version == MLXBF_GIGE_VERSION_BF2) { ++ val = MLXBF2_GIGE_MDIO_CFG_VAL; ++ val |= FIELD_PREP(MLXBF2_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdio_period); ++ writel(val, priv->mdio_io + MLXBF2_GIGE_MDIO_CFG_OFFSET); ++ } else { ++ val = FIELD_PREP(MLXBF3_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | ++ FIELD_PREP(MLXBF3_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1); ++ writel(val, priv->mdio_io + MLXBF3_GIGE_MDIO_CFG_REG0); ++ val = FIELD_PREP(MLXBF3_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdio_period); ++ writel(val, priv->mdio_io + MLXBF3_GIGE_MDIO_CFG_REG1); ++ val = FIELD_PREP(MLXBF3_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | ++ FIELD_PREP(MLXBF3_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13); ++ writel(val, priv->mdio_io + MLXBF3_GIGE_MDIO_CFG_REG2); ++ } + } + + int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) +@@ -230,6 +297,9 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) + struct resource *res; + int ret; + ++ if (priv->hw_version > MLXBF_GIGE_VERSION_BF3) ++ return -ENODEV; ++ + res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MDIO9); + if (!res) + return -ENODEV; +@@ -246,13 +316,15 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) + /* For backward compatibility with older ACPI tables, also keep + * CLK resource internal to the driver. + */ +- res = &corepll_params[MLXBF_GIGE_VERSION_BF2]; ++ res = &corepll_params[priv->hw_version]; + } + + priv->clk_io = devm_ioremap(dev, res->start, resource_size(res)); + if (!priv->clk_io) + return -ENOMEM; + ++ priv->mdio_gw = &mlxbf_gige_mdio_gw_t[priv->hw_version]; ++ + mlxbf_gige_mdio_cfg(priv); + + priv->mdiobus = devm_mdiobus_alloc(dev); +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf2.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf2.h +new file mode 100644 +index 000000000..7f1ff0ac7 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf2.h +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ ++ ++/* MDIO support for Mellanox Gigabit Ethernet driver ++ * ++ * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES, ALL RIGHTS RESERVED. ++ * ++ * This software product is a proprietary product of NVIDIA CORPORATION & ++ * AFFILIATES (the "Company") and all right, title, and interest in and to the ++ * software product, including all associated intellectual property rights, are ++ * and shall remain exclusively with the Company. ++ * ++ * This software product is governed by the End User License Agreement ++ * provided with the software product. ++ */ ++ ++#ifndef __MLXBF_GIGE_MDIO_BF2_H__ ++#define __MLXBF_GIGE_MDIO_BF2_H__ ++ ++#include ++ ++#define MLXBF2_GIGE_MDIO_GW_OFFSET 0x0 ++#define MLXBF2_GIGE_MDIO_CFG_OFFSET 0x4 ++ ++/* MDIO GW register bits */ ++#define MLXBF2_GIGE_MDIO_GW_AD_MASK GENMASK(15, 0) ++#define MLXBF2_GIGE_MDIO_GW_DEVAD_MASK GENMASK(20, 16) ++#define MLXBF2_GIGE_MDIO_GW_PARTAD_MASK GENMASK(25, 21) ++#define MLXBF2_GIGE_MDIO_GW_OPCODE_MASK GENMASK(27, 26) ++#define MLXBF2_GIGE_MDIO_GW_ST1_MASK GENMASK(28, 28) ++#define MLXBF2_GIGE_MDIO_GW_BUSY_MASK GENMASK(30, 30) ++ ++#define MLXBF2_GIGE_MDIO_GW_AD_SHIFT 0 ++#define MLXBF2_GIGE_MDIO_GW_DEVAD_SHIFT 16 ++#define MLXBF2_GIGE_MDIO_GW_PARTAD_SHIFT 21 ++#define MLXBF2_GIGE_MDIO_GW_OPCODE_SHIFT 26 ++#define MLXBF2_GIGE_MDIO_GW_ST1_SHIFT 28 ++#define MLXBF2_GIGE_MDIO_GW_BUSY_SHIFT 30 ++ ++/* MDIO config register bits */ ++#define MLXBF2_GIGE_MDIO_CFG_MDIO_MODE_MASK GENMASK(1, 0) ++#define MLXBF2_GIGE_MDIO_CFG_MDIO3_3_MASK GENMASK(2, 2) ++#define MLXBF2_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK GENMASK(4, 4) ++#define MLXBF2_GIGE_MDIO_CFG_MDC_PERIOD_MASK GENMASK(15, 8) ++#define MLXBF2_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK GENMASK(23, 16) ++#define MLXBF2_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK GENMASK(31, 24) ++ ++#define MLXBF2_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF2_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \ ++ FIELD_PREP(MLXBF2_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ ++ FIELD_PREP(MLXBF2_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ ++ FIELD_PREP(MLXBF2_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ ++ FIELD_PREP(MLXBF2_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) ++ ++#endif /* __MLXBF_GIGE_MDIO_BF2_H__ */ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf3.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf3.h +new file mode 100644 +index 000000000..9dd9144b9 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf3.h +@@ -0,0 +1,54 @@ ++/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ ++ ++/* MDIO support for Mellanox Gigabit Ethernet driver ++ * ++ * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES, ALL RIGHTS RESERVED. ++ * ++ * This software product is a proprietary product of NVIDIA CORPORATION & ++ * AFFILIATES (the "Company") and all right, title, and interest in and to the ++ * software product, including all associated intellectual property rights, are ++ * and shall remain exclusively with the Company. ++ * ++ * This software product is governed by the End User License Agreement ++ * provided with the software product. ++ */ ++ ++#ifndef __MLXBF_GIGE_MDIO_BF3_H__ ++#define __MLXBF_GIGE_MDIO_BF3_H__ ++ ++#include ++ ++#define MLXBF3_GIGE_MDIO_GW_OFFSET 0x80 ++#define MLXBF3_GIGE_MDIO_DATA_READ 0x8c ++#define MLXBF3_GIGE_MDIO_CFG_REG0 0x100 ++#define MLXBF3_GIGE_MDIO_CFG_REG1 0x104 ++#define MLXBF3_GIGE_MDIO_CFG_REG2 0x108 ++ ++/* MDIO GW register bits */ ++#define MLXBF3_GIGE_MDIO_GW_ST1_MASK GENMASK(1, 1) ++#define MLXBF3_GIGE_MDIO_GW_OPCODE_MASK GENMASK(3, 2) ++#define MLXBF3_GIGE_MDIO_GW_PARTAD_MASK GENMASK(8, 4) ++#define MLXBF3_GIGE_MDIO_GW_DEVAD_MASK GENMASK(13, 9) ++/* For BlueField-3, this field is only used for mdio write */ ++#define MLXBF3_GIGE_MDIO_GW_DATA_MASK GENMASK(29, 14) ++#define MLXBF3_GIGE_MDIO_GW_BUSY_MASK GENMASK(30, 30) ++ ++#define MLXBF3_GIGE_MDIO_GW_DATA_READ_MASK GENMASK(15, 0) ++ ++#define MLXBF3_GIGE_MDIO_GW_ST1_SHIFT 1 ++#define MLXBF3_GIGE_MDIO_GW_OPCODE_SHIFT 2 ++#define MLXBF3_GIGE_MDIO_GW_PARTAD_SHIFT 4 ++#define MLXBF3_GIGE_MDIO_GW_DEVAD_SHIFT 9 ++#define MLXBF3_GIGE_MDIO_GW_DATA_SHIFT 14 ++#define MLXBF3_GIGE_MDIO_GW_BUSY_SHIFT 30 ++ ++#define MLXBF3_GIGE_MDIO_GW_DATA_READ_SHIFT 0 ++ ++/* MDIO config register bits */ ++#define MLXBF3_GIGE_MDIO_CFG_MDIO_MODE_MASK GENMASK(1, 0) ++#define MLXBF3_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK GENMASK(2, 2) ++#define MLXBF3_GIGE_MDIO_CFG_MDC_PERIOD_MASK GENMASK(7, 0) ++#define MLXBF3_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK GENMASK(7, 0) ++#define MLXBF3_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK GENMASK(15, 8) ++ ++#endif /* __MLXBF_GIGE_MDIO_BF3_H__ */ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +index 7be3a7939..8d52dbef4 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +@@ -10,6 +10,7 @@ + + #define MLXBF_GIGE_VERSION 0x0000 + #define MLXBF_GIGE_VERSION_BF2 0x0 ++#define MLXBF_GIGE_VERSION_BF3 0x1 + #define MLXBF_GIGE_STATUS 0x0010 + #define MLXBF_GIGE_STATUS_READY BIT(0) + #define MLXBF_GIGE_INT_STATUS 0x0028 +-- +2.20.1 + diff --git a/patch/0240-UBUNTU-SAUCE-mlxbf_gige-support-10M-100M-1G-speeds-o.patch b/patch/0240-UBUNTU-SAUCE-mlxbf_gige-support-10M-100M-1G-speeds-o.patch new file mode 100644 index 000000000..a8a1d325d --- /dev/null +++ b/patch/0240-UBUNTU-SAUCE-mlxbf_gige-support-10M-100M-1G-speeds-o.patch @@ -0,0 +1,237 @@ +From b9f0d98629a7720d2b6e34aed529f943cf421c04 Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Tue, 25 Oct 2022 17:19:27 -0400 +Subject: [PATCH backport 5.10 41/63] UBUNTU: SAUCE: mlxbf_gige: support + 10M/100M/1G speeds on BlueField-3 + +BugLink: https://bugs.launchpad.net/bugs/1995148 + +The BlueField-3 OOB interface supports 10Mbps, 100Mbps, and 1Gbps speeds. +The external PHY is responsible for autonegotiating the speed with the +link partner. Once the autonegotiation is done, the BlueField PLU needs +to be configured accordingly. + +This patch does two things: +1) Initialize the advertised control flow/duplex/speed in the probe + based on the BlueField SoC generation (2 or 3) +2) Adjust the PLU speed config in the PHY interrupt handler + +Signed-off-by: David Thompson +Signed-off-by: Asmaa Mnebhi +--- + .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 8 ++ + .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 109 +++++++++++++++--- + .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 21 ++++ + 3 files changed, 123 insertions(+), 15 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +index 421a0b1b7..a453b9cd9 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + /* The silicon design supports a maximum RX ring size of + * 32K entries. Based on current testing this maximum size +@@ -84,6 +85,12 @@ struct mlxbf_gige_mdio_gw { + struct mlxbf_gige_reg_param st1; + }; + ++struct mlxbf_gige_link_cfg { ++ void (*set_phy_link_mode)(struct phy_device *phydev); ++ void (*adjust_link)(struct net_device *netdev); ++ phy_interface_t phy_mode; ++}; ++ + struct mlxbf_gige { + void __iomem *base; + void __iomem *llu_base; +@@ -121,6 +128,7 @@ struct mlxbf_gige { + struct mlxbf_gige_stats stats; + u8 hw_version; + struct mlxbf_gige_mdio_gw *mdio_gw; ++ int prev_speed; + }; + + /* Rx Work Queue Element definitions */ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +index 49695f3e9..106b83bd6 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +@@ -270,13 +270,103 @@ static const struct net_device_ops mlxbf_gige_netdev_ops = { + .ndo_get_stats64 = mlxbf_gige_get_stats64, + }; + +-static void mlxbf_gige_adjust_link(struct net_device *netdev) ++static void mlxbf_gige_bf2_adjust_link(struct net_device *netdev) + { + struct phy_device *phydev = netdev->phydev; + + phy_print_status(phydev); + } + ++static void mlxbf_gige_bf3_adjust_link(struct net_device *netdev) ++{ ++ struct mlxbf_gige *priv = netdev_priv(netdev); ++ struct phy_device *phydev = netdev->phydev; ++ unsigned long flags; ++ u8 sgmii_mode; ++ u16 ipg_size; ++ u32 val; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ if (phydev->link && phydev->speed != priv->prev_speed) { ++ switch (phydev->speed) { ++ case 1000: ++ ipg_size = MLXBF_GIGE_1G_IPG_SIZE; ++ sgmii_mode = MLXBF_GIGE_1G_SGMII_MODE; ++ break; ++ case 100: ++ ipg_size = MLXBF_GIGE_100M_IPG_SIZE; ++ sgmii_mode = MLXBF_GIGE_100M_SGMII_MODE; ++ break; ++ case 10: ++ ipg_size = MLXBF_GIGE_10M_IPG_SIZE; ++ sgmii_mode = MLXBF_GIGE_10M_SGMII_MODE; ++ break; ++ default: ++ spin_unlock_irqrestore(&priv->lock, flags); ++ return; ++ } ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_PLU_TX_REG0); ++ val &= ~(MLXBF_GIGE_PLU_TX_IPG_SIZE_MASK | MLXBF_GIGE_PLU_TX_SGMII_MODE_MASK); ++ val |= FIELD_PREP(MLXBF_GIGE_PLU_TX_IPG_SIZE_MASK, ipg_size); ++ val |= FIELD_PREP(MLXBF_GIGE_PLU_TX_SGMII_MODE_MASK, sgmii_mode); ++ writel(val, priv->plu_base + MLXBF_GIGE_PLU_TX_REG0); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_PLU_RX_REG0); ++ val &= ~MLXBF_GIGE_PLU_RX_SGMII_MODE_MASK; ++ val |= FIELD_PREP(MLXBF_GIGE_PLU_RX_SGMII_MODE_MASK, sgmii_mode); ++ writel(val, priv->plu_base + MLXBF_GIGE_PLU_RX_REG0); ++ ++ priv->prev_speed = phydev->speed; ++ } ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ phy_print_status(phydev); ++} ++ ++static void mlxbf_gige_bf2_set_phy_link_mode(struct phy_device *phydev) ++{ ++ /* MAC only supports 1000T full duplex mode */ ++ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); ++ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT); ++ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); ++ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); ++ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); ++ ++ /* Only symmetric pause with flow control enabled is supported so no ++ * need to negotiate pause. ++ */ ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising); ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising); ++} ++ ++static void mlxbf_gige_bf3_set_phy_link_mode(struct phy_device *phydev) ++{ ++ /* MAC only supports full duplex mode */ ++ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); ++ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); ++ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); ++ ++ /* Only symmetric pause with flow control enabled is supported so no ++ * need to negotiate pause. ++ */ ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising); ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising); ++} ++ ++static struct mlxbf_gige_link_cfg mlxbf_gige_link_cfgs[] = { ++ [MLXBF_GIGE_VERSION_BF2] = { ++ .set_phy_link_mode = mlxbf_gige_bf2_set_phy_link_mode, ++ .adjust_link = mlxbf_gige_bf2_adjust_link, ++ .phy_mode = PHY_INTERFACE_MODE_GMII ++ }, ++ [MLXBF_GIGE_VERSION_BF3] = { ++ .set_phy_link_mode = mlxbf_gige_bf3_set_phy_link_mode, ++ .adjust_link = mlxbf_gige_bf3_adjust_link, ++ .phy_mode = PHY_INTERFACE_MODE_SGMII ++ } ++}; ++ + static int mlxbf_gige_probe(struct platform_device *pdev) + { + struct phy_device *phydev; +@@ -395,25 +485,14 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + phydev->irq = phy_irq; + + err = phy_connect_direct(netdev, phydev, +- mlxbf_gige_adjust_link, +- PHY_INTERFACE_MODE_GMII); ++ mlxbf_gige_link_cfgs[priv->hw_version].adjust_link, ++ mlxbf_gige_link_cfgs[priv->hw_version].phy_mode); + if (err) { + dev_err(&pdev->dev, "Could not attach to PHY\n"); + goto out; + } + +- /* MAC only supports 1000T full duplex mode */ +- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); +- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT); +- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); +- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); +- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); +- +- /* Only symmetric pause with flow control enabled is supported so no +- * need to negotiate pause. +- */ +- linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising); +- linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising); ++ mlxbf_gige_link_cfgs[priv->hw_version].set_phy_link_mode(phydev); + + /* Display information about attached PHY device */ + phy_attached_info(phydev); +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +index 8d52dbef4..cd0973229 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +@@ -8,6 +8,8 @@ + #ifndef __MLXBF_GIGE_REGS_H__ + #define __MLXBF_GIGE_REGS_H__ + ++#include ++ + #define MLXBF_GIGE_VERSION 0x0000 + #define MLXBF_GIGE_VERSION_BF2 0x0 + #define MLXBF_GIGE_VERSION_BF3 0x1 +@@ -78,4 +80,23 @@ + */ + #define MLXBF_GIGE_MMIO_REG_SZ (MLXBF_GIGE_MAC_CFG + 8) + ++#define MLXBF_GIGE_PLU_TX_REG0 0x80 ++#define MLXBF_GIGE_PLU_TX_IPG_SIZE_MASK GENMASK(11, 0) ++#define MLXBF_GIGE_PLU_TX_SGMII_MODE_MASK GENMASK(15, 14) ++ ++#define MLXBF_GIGE_PLU_RX_REG0 0x10 ++#define MLXBF_GIGE_PLU_RX_SGMII_MODE_MASK GENMASK(25, 24) ++ ++#define MLXBF_GIGE_1G_SGMII_MODE 0x0 ++#define MLXBF_GIGE_10M_SGMII_MODE 0x1 ++#define MLXBF_GIGE_100M_SGMII_MODE 0x2 ++ ++/* ipg_size default value for 1G is fixed by HW to 11 + End = 12. ++ * So for 100M it is 12 * 10 - 1 = 119 ++ * For 10M, it is 12 * 100 - 1 = 1199 ++ */ ++#define MLXBF_GIGE_1G_IPG_SIZE 11 ++#define MLXBF_GIGE_100M_IPG_SIZE 119 ++#define MLXBF_GIGE_10M_IPG_SIZE 1199 ++ + #endif /* !defined(__MLXBF_GIGE_REGS_H__) */ +-- +2.20.1 + diff --git a/patch/0241-UBUNTU-SAUCE-mlxbf_gige-add-BlueField-3-Serdes-confi.patch b/patch/0241-UBUNTU-SAUCE-mlxbf_gige-add-BlueField-3-Serdes-confi.patch new file mode 100644 index 000000000..bdeef431b --- /dev/null +++ b/patch/0241-UBUNTU-SAUCE-mlxbf_gige-add-BlueField-3-Serdes-confi.patch @@ -0,0 +1,1865 @@ +From e2017fcee49f8d2b36a59d5d6076259f4e4feeac Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Tue, 25 Oct 2022 18:24:01 -0400 +Subject: [PATCH backport 5.10 42/63] UBUNTU: SAUCE: mlxbf_gige: add + BlueField-3 Serdes configuration + +BugLink: https://bugs.launchpad.net/bugs/1995148 + +The BlueField-3 out-of-band Ethernet interface requires +SerDes configuration. There are two aspects to this: + +Configuration of PLL: + 1) Initialize UPHY registers to values dependent on p1clk clock + 2) Load PLL best known values via the gateway register + 3) Set the fuses to tune up the SerDes voltage + 4) Lock the PLL + 5) Get the lanes out of functional reset. + 6) Configure the UPHY microcontroller via gateway reads/writes + +Configuration of lanes: + 1) Configure and open TX lanes + 2) Configure and open RX lanes + +Signed-off-by: David Thompson +Signed-off-by: Asmaa Mnebhi +--- + .../net/ethernet/mellanox/mlxbf_gige/Makefile | 3 +- + .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 4 +- + .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 76 +- + .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 36 - + .../mellanox/mlxbf_gige/mlxbf_gige_uphy.c | 1191 +++++++++++++++++ + .../mellanox/mlxbf_gige/mlxbf_gige_uphy.h | 398 ++++++ + 6 files changed, 1645 insertions(+), 63 deletions(-) + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.c + create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.h + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile +index a97c2bef8..524af17ca 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile +@@ -7,4 +7,5 @@ mlxbf_gige-y := mlxbf_gige_ethtool.o \ + mlxbf_gige_main.o \ + mlxbf_gige_mdio.o \ + mlxbf_gige_rx.o \ +- mlxbf_gige_tx.o ++ mlxbf_gige_tx.o \ ++ mlxbf_gige_uphy.o +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +index a453b9cd9..e9bd09ee0 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +@@ -100,6 +100,7 @@ struct mlxbf_gige { + struct platform_device *pdev; + void __iomem *mdio_io; + void __iomem *clk_io; ++ void __iomem *fuse_gw_io; + struct mii_bus *mdiobus; + spinlock_t lock; /* for packet processing indices */ + u16 rx_q_entries; +@@ -166,7 +167,8 @@ enum mlxbf_gige_res { + MLXBF_GIGE_RES_GPIO0, + MLXBF_GIGE_RES_LLU, + MLXBF_GIGE_RES_PLU, +- MLXBF_GIGE_RES_CLK ++ MLXBF_GIGE_RES_CLK, ++ MLXBF_GIGE_RES_FUSE_GW + }; + + /* Version of register data returned by mlxbf_gige_get_regs() */ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +index 106b83bd6..f97e49670 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +@@ -18,13 +18,25 @@ + + #include "mlxbf_gige.h" + #include "mlxbf_gige_regs.h" ++#include "mlxbf_gige_uphy.h" + +-#define DRV_VERSION 1.27 ++#define MLXBF_GIGE_BF2_COREPLL_ADDR 0x02800c30 ++#define MLXBF_GIGE_BF2_COREPLL_SIZE 0x0000000c ++#define MLXBF_GIGE_BF3_COREPLL_ADDR 0x13409824 ++#define MLXBF_GIGE_BF3_COREPLL_SIZE 0x00000020 + +-/* This setting defines the version of the ACPI table +- * content that is compatible with this driver version. +- */ +-#define MLXBF_GIGE_ACPI_TABLE_VERSION 2 ++static struct resource corepll_params[] = { ++ [MLXBF_GIGE_VERSION_BF2] = { ++ .start = MLXBF_GIGE_BF2_COREPLL_ADDR, ++ .end = MLXBF_GIGE_BF2_COREPLL_ADDR + MLXBF_GIGE_BF2_COREPLL_SIZE - 1, ++ .name = "COREPLL_RES" ++ }, ++ [MLXBF_GIGE_VERSION_BF3] = { ++ .start = MLXBF_GIGE_BF3_COREPLL_ADDR, ++ .end = MLXBF_GIGE_BF3_COREPLL_ADDR + MLXBF_GIGE_BF3_COREPLL_SIZE - 1, ++ .name = "COREPLL_RES" ++ } ++}; + + /* Allocate SKB whose payload pointer aligns with the Bluefield + * hardware DMA limitation, i.e. DMA operation can't cross +@@ -371,31 +383,20 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + { + struct phy_device *phydev; + struct net_device *netdev; ++ struct resource *clk_res; + struct resource *mac_res; + struct resource *llu_res; + struct resource *plu_res; + struct mlxbf_gige *priv; + void __iomem *llu_base; + void __iomem *plu_base; ++ void __iomem *clk_io; + void __iomem *base; + int addr, phy_irq; +- u32 version; ++ u64 soc_version; + u64 control; + int err; + +- version = 0; +- err = device_property_read_u32(&pdev->dev, "version", &version); +- if (err) { +- dev_err(&pdev->dev, "ACPI table version not found\n"); +- return -EINVAL; +- } +- +- if (version != MLXBF_GIGE_ACPI_TABLE_VERSION) { +- dev_err(&pdev->dev, "ACPI table version mismatch: expected %d found %d\n", +- MLXBF_GIGE_ACPI_TABLE_VERSION, version); +- return -EINVAL; +- } +- + mac_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MAC); + if (!mac_res) + return -ENXIO; +@@ -404,6 +405,25 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + if (IS_ERR(base)) + return PTR_ERR(base); + ++ soc_version = readq(base + MLXBF_GIGE_VERSION); ++ if (soc_version > MLXBF_GIGE_VERSION_BF3) ++ return -ENODEV; ++ ++ /* clk resource shared with other drivers so cannot use ++ * devm_platform_ioremap_resource ++ */ ++ clk_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_CLK); ++ if (!clk_res) { ++ /* For backward compatibility with older ACPI tables, also keep ++ * CLK resource internal to the driver. ++ */ ++ clk_res = &corepll_params[soc_version]; ++ } ++ ++ clk_io = devm_ioremap(&pdev->dev, clk_res->start, resource_size(clk_res)); ++ if (!clk_io) ++ return -ENOMEM; ++ + llu_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_LLU); + if (!llu_res) + return -ENXIO; +@@ -441,17 +461,23 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + + spin_lock_init(&priv->lock); + +- priv->hw_version = readq(base + MLXBF_GIGE_VERSION); ++ priv->clk_io = clk_io; ++ priv->base = base; ++ priv->llu_base = llu_base; ++ priv->plu_base = plu_base; ++ priv->hw_version = soc_version; ++ ++ if (priv->hw_version == MLXBF_GIGE_VERSION_BF3) { ++ err = mlxbf_gige_config_uphy(priv); ++ if (err) ++ return err; ++ } + + /* Attach MDIO device */ + err = mlxbf_gige_mdio_probe(pdev, priv); + if (err) + return err; + +- priv->base = base; +- priv->llu_base = llu_base; +- priv->plu_base = plu_base; +- + priv->rx_q_entries = MLXBF_GIGE_DEFAULT_RXQ_SZ; + priv->tx_q_entries = MLXBF_GIGE_DEFAULT_TXQ_SZ; + +@@ -553,4 +579,4 @@ MODULE_DESCRIPTION("Mellanox BlueField SoC Gigabit Ethernet Driver"); + MODULE_AUTHOR("David Thompson "); + MODULE_AUTHOR("Asmaa Mnebhi "); + MODULE_LICENSE("Dual BSD/GPL"); +-MODULE_VERSION(__stringify(DRV_VERSION)); ++ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +index 4ee3df30c..21acdcea3 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +@@ -113,24 +113,6 @@ static struct mlxbf_gige_mdio_gw mlxbf_gige_mdio_gw_t[] = { + /* Busy bit is set by software and cleared by hardware */ + #define MLXBF_GIGE_MDIO_SET_BUSY 0x1 + +-#define MLXBF_GIGE_BF2_COREPLL_ADDR 0x02800c30 +-#define MLXBF_GIGE_BF2_COREPLL_SIZE 0x0000000c +-#define MLXBF_GIGE_BF3_COREPLL_ADDR 0x13409824 +-#define MLXBF_GIGE_BF3_COREPLL_SIZE 0x00000010 +- +-static struct resource corepll_params[] = { +- [MLXBF_GIGE_VERSION_BF2] = { +- .start = MLXBF_GIGE_BF2_COREPLL_ADDR, +- .end = MLXBF_GIGE_BF2_COREPLL_ADDR + MLXBF_GIGE_BF2_COREPLL_SIZE - 1, +- .name = "COREPLL_RES" +- }, +- [MLXBF_GIGE_VERSION_BF3] = { +- .start = MLXBF_GIGE_BF3_COREPLL_ADDR, +- .end = MLXBF_GIGE_BF3_COREPLL_ADDR + MLXBF_GIGE_BF3_COREPLL_SIZE - 1, +- .name = "COREPLL_RES" +- } +-}; +- + /* Returns core clock i1clk in Hz */ + static u64 calculate_i1clk(struct mlxbf_gige *priv) + { +@@ -297,9 +279,6 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) + struct resource *res; + int ret; + +- if (priv->hw_version > MLXBF_GIGE_VERSION_BF3) +- return -ENODEV; +- + res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MDIO9); + if (!res) + return -ENODEV; +@@ -308,21 +287,6 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) + if (IS_ERR(priv->mdio_io)) + return PTR_ERR(priv->mdio_io); + +- /* clk resource shared with other drivers so cannot use +- * devm_platform_ioremap_resource +- */ +- res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_CLK); +- if (!res) { +- /* For backward compatibility with older ACPI tables, also keep +- * CLK resource internal to the driver. +- */ +- res = &corepll_params[priv->hw_version]; +- } +- +- priv->clk_io = devm_ioremap(dev, res->start, resource_size(res)); +- if (!priv->clk_io) +- return -ENOMEM; +- + priv->mdio_gw = &mlxbf_gige_mdio_gw_t[priv->hw_version]; + + mlxbf_gige_mdio_cfg(priv); +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.c +new file mode 100644 +index 000000000..9d64eb886 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.c +@@ -0,0 +1,1191 @@ ++// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause ++ ++/* UPHY support for Nvidia Gigabit Ethernet driver ++ * ++ * Copyright (C) 2022 NVIDIA CORPORATION & AFFILIATES ++ */ ++ ++#include ++#include ++#include ++ ++#include "mlxbf_gige.h" ++#include "mlxbf_gige_uphy.h" ++ ++static const struct mlxbf_gige_uphy_cfg_reg ++mlxbf_gige_clm_init[] = { ++ {.addr = 0x001, .wdata = 0x0105}, ++ {.addr = 0x008, .wdata = 0x0001}, ++ {.addr = 0x00B, .wdata = 0x8420}, ++ {.addr = 0x00E, .wdata = 0x0110}, ++ {.addr = 0x010, .wdata = 0x3010}, ++ {.addr = 0x027, .wdata = 0x0104}, ++ {.addr = 0x02F, .wdata = 0x09EA}, ++ {.addr = 0x055, .wdata = 0x0008}, ++ {.addr = 0x058, .wdata = 0x0088}, ++ {.addr = 0x072, .wdata = 0x3222}, ++ {.addr = 0x073, .wdata = 0x7654}, ++ {.addr = 0x074, .wdata = 0xBA98}, ++ {.addr = 0x075, .wdata = 0xDDDC} ++}; ++ ++#define MLXBF_GIGE_UPHY_CLM_INIT_NUM_ENTRIES \ ++ (sizeof(mlxbf_gige_clm_init) / sizeof(struct mlxbf_gige_uphy_cfg_reg)) ++ ++static const struct mlxbf_gige_uphy_cfg_reg ++mlxbf_gige_dlm_imem_init[] = { ++ {.addr = 0x39C, .wdata = 0x0000}, ++ {.addr = 0x39D, .wdata = 0x0095}, ++ {.addr = 0x3BF, .wdata = 0x9027}, ++ {.addr = 0x39E, .wdata = 0xA8F6}, ++ {.addr = 0x39F, .wdata = 0xAA10}, ++ {.addr = 0x3A0, .wdata = 0xA8D4}, ++ {.addr = 0x3A1, .wdata = 0xA7AE}, ++ {.addr = 0x3A2, .wdata = 0xA7CC}, ++ {.addr = 0x3A3, .wdata = 0x9BE4}, ++ {.addr = 0x3A4, .wdata = 0xB2D2}, ++ {.addr = 0x3A5, .wdata = 0xB1F2}, ++ {.addr = 0x3AE, .wdata = 0x7C38}, ++ {.addr = 0x3AF, .wdata = 0x7C4A}, ++ {.addr = 0x3B0, .wdata = 0x7C25}, ++ {.addr = 0x3B1, .wdata = 0x7C74}, ++ {.addr = 0x3B2, .wdata = 0x3C00}, ++ {.addr = 0x3B3, .wdata = 0x3C11}, ++ {.addr = 0x3B4, .wdata = 0x3C5D}, ++ {.addr = 0x3B5, .wdata = 0x3C5D} ++}; ++ ++#define MLXBF_GIGE_UPHY_DLM_IMEM_INIT_NUM_ENTRIES \ ++ (sizeof(mlxbf_gige_dlm_imem_init) / sizeof(struct mlxbf_gige_uphy_cfg_reg)) ++ ++static const struct mlxbf_gige_uphy_cfg_reg ++mlxbf_gige_dlm_seq_imem_wr_en_init = { ++ .addr = 0x39A, .wdata = 0x0001 ++}; ++ ++static const struct mlxbf_gige_uphy_cfg_reg ++mlxbf_gige_dlm_seq_imem_wr_dis_init = { ++ .addr = 0x39A, .wdata = 0x0000 ++}; ++ ++static const struct mlxbf_gige_uphy_cfg_reg ++mlxbf_gige_dlm_imem_data[] = { ++ { /* .iaddr = 0x0000 */ .wdata = 0x02DF}, ++ { /* .iaddr = 0x0001 */ .wdata = 0xEEC0}, ++ { /* .iaddr = 0x0002 */ .wdata = 0xD508}, ++ { /* .iaddr = 0x0003 */ .wdata = 0x022F}, ++ { /* .iaddr = 0x0004 */ .wdata = 0xC401}, ++ { /* .iaddr = 0x0005 */ .wdata = 0xD341}, ++ { /* .iaddr = 0x0006 */ .wdata = 0xC402}, ++ { /* .iaddr = 0x0007 */ .wdata = 0xD342}, ++ { /* .iaddr = 0x0008 */ .wdata = 0xC403}, ++ { /* .iaddr = 0x0009 */ .wdata = 0xD343}, ++ { /* .iaddr = 0x000A */ .wdata = 0xC404}, ++ { /* .iaddr = 0x000B */ .wdata = 0xD344}, ++ { /* .iaddr = 0x000C */ .wdata = 0xC417}, ++ { /* .iaddr = 0x000D */ .wdata = 0xD355}, ++ { /* .iaddr = 0x000E */ .wdata = 0xC418}, ++ { /* .iaddr = 0x000F */ .wdata = 0xD356}, ++ { /* .iaddr = 0x0010 */ .wdata = 0xF021}, ++ { /* .iaddr = 0x0011 */ .wdata = 0xF003}, ++ { /* .iaddr = 0x0012 */ .wdata = 0xE224}, ++ { /* .iaddr = 0x0013 */ .wdata = 0x0DA9}, ++ { /* .iaddr = 0x0014 */ .wdata = 0xF003}, ++ { /* .iaddr = 0x0015 */ .wdata = 0xE21C}, ++ { /* .iaddr = 0x0016 */ .wdata = 0xEEC1}, ++ { /* .iaddr = 0x0017 */ .wdata = 0x0D87}, ++ { /* .iaddr = 0x0018 */ .wdata = 0xEEC1}, ++ { /* .iaddr = 0x0019 */ .wdata = 0xE806}, ++ { /* .iaddr = 0x001A */ .wdata = 0xC3C5}, ++ { /* .iaddr = 0x001B */ .wdata = 0xD306}, ++ { /* .iaddr = 0x001C */ .wdata = 0xEEDF}, ++ { /* .iaddr = 0x001D */ .wdata = 0xE806}, ++ { /* .iaddr = 0x001E */ .wdata = 0xC3C6}, ++ { /* .iaddr = 0x001F */ .wdata = 0xD306}, ++ { /* .iaddr = 0x0020 */ .wdata = 0xF002}, ++ { /* .iaddr = 0x0021 */ .wdata = 0xC3C8}, ++ { /* .iaddr = 0x0022 */ .wdata = 0x409A}, ++ { /* .iaddr = 0x0023 */ .wdata = 0xF021}, ++ { /* .iaddr = 0x0024 */ .wdata = 0xEEE0}, ++ { /* .iaddr = 0x0025 */ .wdata = 0xEEC0}, ++ { /* .iaddr = 0x0026 */ .wdata = 0xD70D}, ++ { /* .iaddr = 0x0027 */ .wdata = 0xC305}, ++ { /* .iaddr = 0x0028 */ .wdata = 0xD328}, ++ { /* .iaddr = 0x0029 */ .wdata = 0xC300}, ++ { /* .iaddr = 0x002A */ .wdata = 0xD314}, ++ { /* .iaddr = 0x002B */ .wdata = 0xC301}, ++ { /* .iaddr = 0x002C */ .wdata = 0xD318}, ++ { /* .iaddr = 0x002D */ .wdata = 0xC303}, ++ { /* .iaddr = 0x002E */ .wdata = 0xD320}, ++ { /* .iaddr = 0x002F */ .wdata = 0xC302}, ++ { /* .iaddr = 0x0030 */ .wdata = 0xD31C}, ++ { /* .iaddr = 0x0031 */ .wdata = 0xC304}, ++ { /* .iaddr = 0x0032 */ .wdata = 0xD324}, ++ { /* .iaddr = 0x0033 */ .wdata = 0xC358}, ++ { /* .iaddr = 0x0034 */ .wdata = 0xD330}, ++ { /* .iaddr = 0x0035 */ .wdata = 0xC307}, ++ { /* .iaddr = 0x0036 */ .wdata = 0xD115}, ++ { /* .iaddr = 0x0037 */ .wdata = 0xF021}, ++ { /* .iaddr = 0x0038 */ .wdata = 0xD70D}, ++ { /* .iaddr = 0x0039 */ .wdata = 0xC305}, ++ { /* .iaddr = 0x003A */ .wdata = 0xD328}, ++ { /* .iaddr = 0x003B */ .wdata = 0xC300}, ++ { /* .iaddr = 0x003C */ .wdata = 0xD314}, ++ { /* .iaddr = 0x003D */ .wdata = 0xC301}, ++ { /* .iaddr = 0x003E */ .wdata = 0xD318}, ++ { /* .iaddr = 0x003F */ .wdata = 0xC303}, ++ { /* .iaddr = 0x0040 */ .wdata = 0xD320}, ++ { /* .iaddr = 0x0041 */ .wdata = 0xC302}, ++ { /* .iaddr = 0x0042 */ .wdata = 0xD31C}, ++ { /* .iaddr = 0x0043 */ .wdata = 0xC304}, ++ { /* .iaddr = 0x0044 */ .wdata = 0xD324}, ++ { /* .iaddr = 0x0045 */ .wdata = 0xC358}, ++ { /* .iaddr = 0x0046 */ .wdata = 0xD330}, ++ { /* .iaddr = 0x0047 */ .wdata = 0xC307}, ++ { /* .iaddr = 0x0048 */ .wdata = 0xD115}, ++ { /* .iaddr = 0x0049 */ .wdata = 0xF021}, ++ { /* .iaddr = 0x004A */ .wdata = 0xC70D}, ++ { /* .iaddr = 0x004B */ .wdata = 0xD70F}, ++ { /* .iaddr = 0x004C */ .wdata = 0xC328}, ++ { /* .iaddr = 0x004D */ .wdata = 0xD305}, ++ { /* .iaddr = 0x004E */ .wdata = 0xC314}, ++ { /* .iaddr = 0x004F */ .wdata = 0xD300}, ++ { /* .iaddr = 0x0050 */ .wdata = 0xC318}, ++ { /* .iaddr = 0x0051 */ .wdata = 0xD301}, ++ { /* .iaddr = 0x0052 */ .wdata = 0xC320}, ++ { /* .iaddr = 0x0053 */ .wdata = 0xD303}, ++ { /* .iaddr = 0x0054 */ .wdata = 0xC31C}, ++ { /* .iaddr = 0x0055 */ .wdata = 0xD302}, ++ { /* .iaddr = 0x0056 */ .wdata = 0xC324}, ++ { /* .iaddr = 0x0057 */ .wdata = 0xD304}, ++ { /* .iaddr = 0x0058 */ .wdata = 0xC330}, ++ { /* .iaddr = 0x0059 */ .wdata = 0xD358}, ++ { /* .iaddr = 0x005A */ .wdata = 0xC115}, ++ { /* .iaddr = 0x005B */ .wdata = 0xD307}, ++ { /* .iaddr = 0x005C */ .wdata = 0xF021}, ++ { /* .iaddr = 0x005D */ .wdata = 0x0249}, ++ { /* .iaddr = 0x005E */ .wdata = 0x0362}, ++ { /* .iaddr = 0x005F */ .wdata = 0x023D}, ++ { /* .iaddr = 0x0060 */ .wdata = 0xEEC1}, ++ { /* .iaddr = 0x0061 */ .wdata = 0x0369}, ++ { /* .iaddr = 0x0062 */ .wdata = 0xEEC1}, ++ { /* .iaddr = 0x0063 */ .wdata = 0x0CEA}, ++ { /* .iaddr = 0x0064 */ .wdata = 0xEEC2}, ++ { /* .iaddr = 0x0065 */ .wdata = 0xD701}, ++ { /* .iaddr = 0x0066 */ .wdata = 0x02C8}, ++ { /* .iaddr = 0x0067 */ .wdata = 0xC3C3}, ++ { /* .iaddr = 0x0068 */ .wdata = 0xD306}, ++ { /* .iaddr = 0x0069 */ .wdata = 0xC3C8}, ++ { /* .iaddr = 0x006A */ .wdata = 0x009A}, ++ { /* .iaddr = 0x006B */ .wdata = 0xC3D1}, ++ { /* .iaddr = 0x006C */ .wdata = 0xD309}, ++ { /* .iaddr = 0x006D */ .wdata = 0x0C46}, ++ { /* .iaddr = 0x006E */ .wdata = 0x0DE7}, ++ { /* .iaddr = 0x006F */ .wdata = 0xEEC0}, ++ { /* .iaddr = 0x0070 */ .wdata = 0xC3D9}, ++ { /* .iaddr = 0x0071 */ .wdata = 0x0DDE}, ++ { /* .iaddr = 0x0072 */ .wdata = 0x02D7}, ++ { /* .iaddr = 0x0073 */ .wdata = 0xF021}, ++ { /* .iaddr = 0x0074 */ .wdata = 0x1441}, ++ { /* .iaddr = 0x0075 */ .wdata = 0xF003}, ++ { /* .iaddr = 0x0076 */ .wdata = 0xC03F}, ++ { /* .iaddr = 0x0077 */ .wdata = 0xF704}, ++ { /* .iaddr = 0x0078 */ .wdata = 0xF009}, ++ { /* .iaddr = 0x0079 */ .wdata = 0xE21A}, ++ { /* .iaddr = 0x007A */ .wdata = 0xF002}, ++ { /* .iaddr = 0x007B */ .wdata = 0x0C52}, ++ { /* .iaddr = 0x007C */ .wdata = 0xE206}, ++ { /* .iaddr = 0x007D */ .wdata = 0xEEC1}, ++ { /* .iaddr = 0x007E */ .wdata = 0xD01A}, ++ { /* .iaddr = 0x007F */ .wdata = 0x3C5D}, ++ { /* .iaddr = 0x0080 */ .wdata = 0xEEC0}, ++ { /* .iaddr = 0x0081 */ .wdata = 0xD01A}, ++ { /* .iaddr = 0x0082 */ .wdata = 0x0E12}, ++ { /* .iaddr = 0x0083 */ .wdata = 0xEEC0}, ++ { /* .iaddr = 0x0084 */ .wdata = 0x13E1}, ++ { /* .iaddr = 0x0085 */ .wdata = 0x1441}, ++ { /* .iaddr = 0x0086 */ .wdata = 0xEEC1}, ++ { /* .iaddr = 0x0087 */ .wdata = 0xD70E}, ++ { /* .iaddr = 0x0088 */ .wdata = 0xD70F}, ++ { /* .iaddr = 0x0089 */ .wdata = 0xEEC0}, ++ { /* .iaddr = 0x008A */ .wdata = 0xD70E}, ++ { /* .iaddr = 0x008B */ .wdata = 0xC458}, ++ { /* .iaddr = 0x008C */ .wdata = 0x13BE}, ++ { /* .iaddr = 0x008D */ .wdata = 0xEEC0}, ++ { /* .iaddr = 0x008E */ .wdata = 0xF29B}, ++ { /* .iaddr = 0x008F */ .wdata = 0xE20A}, ++ { /* .iaddr = 0x0090 */ .wdata = 0xEEC1}, ++ { /* .iaddr = 0x0091 */ .wdata = 0xD01D}, ++ { /* .iaddr = 0x0092 */ .wdata = 0xEEC1}, ++ { /* .iaddr = 0x0093 */ .wdata = 0xD3FD}, ++ { /* .iaddr = 0x0094 */ .wdata = 0xF021} ++}; ++ ++#define MLXBF_GIGE_UPHY_DLM_IMEM_DATA_NUM_ENTRIES \ ++ (sizeof(mlxbf_gige_dlm_imem_data) / sizeof(struct mlxbf_gige_uphy_cfg_reg)) ++ ++static const struct mlxbf_gige_uphy_cfg_reg ++mlxbf_gige_dlm_seq_imem_csum_en = { ++ .addr = 0x39A, .wdata = 0x0004 ++}; ++ ++static const struct mlxbf_gige_uphy_cfg_reg ++mlxbf_gige_dlm_seq_imem_csum_dis = { ++ .addr = 0x39A, .wdata = 0x0000 ++}; ++ ++static const struct mlxbf_gige_uphy_cfg_reg ++mlxbf_gige_dlm_seq_imem_bmap_clr[] = { ++ {.addr = 0x39E, .wdata = 0x0000}, ++ {.addr = 0x39F, .wdata = 0x0000}, ++ {.addr = 0x3A0, .wdata = 0x0000}, ++ {.addr = 0x3A1, .wdata = 0x0000}, ++ {.addr = 0x3A2, .wdata = 0x0000}, ++ {.addr = 0x3A3, .wdata = 0x0000}, ++ {.addr = 0x3A4, .wdata = 0x0000}, ++ {.addr = 0x3A5, .wdata = 0x0000}, ++ {.addr = 0x3A6, .wdata = 0x0000}, ++ {.addr = 0x3A7, .wdata = 0x0000}, ++ {.addr = 0x3A8, .wdata = 0x0000}, ++ {.addr = 0x3A9, .wdata = 0x0000}, ++ {.addr = 0x3AA, .wdata = 0x0000}, ++ {.addr = 0x3AB, .wdata = 0x0000}, ++ {.addr = 0x3AC, .wdata = 0x0000}, ++ {.addr = 0x3AD, .wdata = 0x0000}, ++ {.addr = 0x3AE, .wdata = 0x0000}, ++ {.addr = 0x3AF, .wdata = 0x0000}, ++ {.addr = 0x3B0, .wdata = 0x0000}, ++ {.addr = 0x3B1, .wdata = 0x0000}, ++ {.addr = 0x3B2, .wdata = 0x0000}, ++ {.addr = 0x3B3, .wdata = 0x0000}, ++ {.addr = 0x3B4, .wdata = 0x0000}, ++ {.addr = 0x3B5, .wdata = 0x0000}, ++ {.addr = 0x3B6, .wdata = 0x0000}, ++ {.addr = 0x3B7, .wdata = 0x0000}, ++ {.addr = 0x3B8, .wdata = 0x0000}, ++ {.addr = 0x3B9, .wdata = 0x0000}, ++ {.addr = 0x3BA, .wdata = 0x0000}, ++ {.addr = 0x3BB, .wdata = 0x0000}, ++ {.addr = 0x3BC, .wdata = 0x0000}, ++ {.addr = 0x3BD, .wdata = 0x0000} ++}; ++ ++#define MLXBF_GIGE_DLM_SEQ_IMEM_BMAP_CLR_NUM_ENTRIES \ ++ (sizeof(mlxbf_gige_dlm_seq_imem_bmap_clr) / sizeof(struct mlxbf_gige_uphy_cfg_reg)) ++ ++static const struct mlxbf_gige_uphy_cfg_reg ++mlxbf_gige_dlm_tx_init[] = { ++ {.addr = 0x002, .wdata = 0x5125}, ++ {.addr = 0x01C, .wdata = 0x0018}, ++ {.addr = 0x01E, .wdata = 0x0E00}, ++ {.addr = 0x01F, .wdata = 0xC200}, ++ {.addr = 0x023, .wdata = 0x0277}, ++ {.addr = 0x024, .wdata = 0x026B}, ++ {.addr = 0x053, .wdata = 0x0700}, ++ {.addr = 0x059, .wdata = 0x1011}, ++ {.addr = 0x060, .wdata = 0x0000}, ++ {.addr = 0x062, .wdata = 0x0135}, ++ {.addr = 0x063, .wdata = 0x0443}, ++ {.addr = 0x064, .wdata = 0x0000}, ++ {.addr = 0x066, .wdata = 0x0061}, ++ {.addr = 0x067, .wdata = 0x0042}, ++ {.addr = 0x06A, .wdata = 0x1212}, ++ {.addr = 0x06B, .wdata = 0x1515}, ++ {.addr = 0x06C, .wdata = 0x011A}, ++ {.addr = 0x06D, .wdata = 0x0132}, ++ {.addr = 0x06E, .wdata = 0x0632}, ++ {.addr = 0x06F, .wdata = 0x0643}, ++ {.addr = 0x070, .wdata = 0x0233}, ++ {.addr = 0x071, .wdata = 0x0433}, ++ {.addr = 0x07E, .wdata = 0x6A08}, ++ {.addr = 0x08D, .wdata = 0x2101}, ++ {.addr = 0x093, .wdata = 0x0015}, ++ {.addr = 0x096, .wdata = 0x7555}, ++ {.addr = 0x0A9, .wdata = 0xE754}, ++ {.addr = 0x0AA, .wdata = 0x7ED1}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000} ++}; ++ ++#define MLXBF_GIGE_DLM_TX_NUM_ENTRIES \ ++ (sizeof(mlxbf_gige_dlm_tx_init) / sizeof(struct mlxbf_gige_uphy_cfg_reg)) ++ ++static const struct mlxbf_gige_uphy_cfg_reg ++mlxbf_gige_dlm_rx_init[] = { ++ {.addr = 0x003, .wdata = 0x5125}, ++ {.addr = 0x01D, .wdata = 0x0004}, ++ {.addr = 0x028, .wdata = 0x1000}, ++ {.addr = 0x029, .wdata = 0x1001}, ++ {.addr = 0x02E, .wdata = 0x0004}, ++ {.addr = 0x053, .wdata = 0x0700}, ++ {.addr = 0x057, .wdata = 0x5044}, ++ {.addr = 0x05B, .wdata = 0x1011}, ++ {.addr = 0x0D2, .wdata = 0x0002}, ++ {.addr = 0x0D9, .wdata = 0x0000}, ++ {.addr = 0x0DA, .wdata = 0x0000}, ++ {.addr = 0x0DB, .wdata = 0x0000}, ++ {.addr = 0x0E2, .wdata = 0x0000}, ++ {.addr = 0x0E7, .wdata = 0xBB10}, ++ {.addr = 0x0E8, .wdata = 0xBB10}, ++ {.addr = 0x0EC, .wdata = 0x0111}, ++ {.addr = 0x0ED, .wdata = 0x1C00}, ++ {.addr = 0x0F5, .wdata = 0x0000}, ++ {.addr = 0x102, .wdata = 0x0CA6}, ++ {.addr = 0x107, .wdata = 0x0020}, ++ {.addr = 0x10C, .wdata = 0x1E31}, ++ {.addr = 0x10D, .wdata = 0x1D29}, ++ {.addr = 0x111, .wdata = 0x00E7}, ++ {.addr = 0x112, .wdata = 0x5202}, ++ {.addr = 0x117, .wdata = 0x0493}, ++ {.addr = 0x11B, .wdata = 0x0148}, ++ {.addr = 0x120, .wdata = 0x23DE}, ++ {.addr = 0x121, .wdata = 0x2294}, ++ {.addr = 0x125, .wdata = 0x03FF}, ++ {.addr = 0x126, .wdata = 0x25F0}, ++ {.addr = 0x12B, .wdata = 0xC633}, ++ {.addr = 0x136, .wdata = 0x0F6A}, ++ {.addr = 0x143, .wdata = 0x0000}, ++ {.addr = 0x148, .wdata = 0x0001}, ++ {.addr = 0x14E, .wdata = 0x0000}, ++ {.addr = 0x155, .wdata = 0x2003}, ++ {.addr = 0x15C, .wdata = 0x099B}, ++ {.addr = 0x161, .wdata = 0x0088}, ++ {.addr = 0x16B, .wdata = 0x0433}, ++ {.addr = 0x172, .wdata = 0x099B}, ++ {.addr = 0x17C, .wdata = 0x045D}, ++ {.addr = 0x17D, .wdata = 0x006A}, ++ {.addr = 0x181, .wdata = 0x0000}, ++ {.addr = 0x189, .wdata = 0x1590}, ++ {.addr = 0x18E, .wdata = 0x0080}, ++ {.addr = 0x18F, .wdata = 0x90EC}, ++ {.addr = 0x191, .wdata = 0x79F8}, ++ {.addr = 0x194, .wdata = 0x000A}, ++ {.addr = 0x195, .wdata = 0x000A}, ++ {.addr = 0x1EB, .wdata = 0x0133}, ++ {.addr = 0x1F0, .wdata = 0x0030}, ++ {.addr = 0x1F1, .wdata = 0x0030}, ++ {.addr = 0x1F5, .wdata = 0x3737}, ++ {.addr = 0x1F6, .wdata = 0x3737}, ++ {.addr = 0x1FA, .wdata = 0x2C00}, ++ {.addr = 0x1FF, .wdata = 0x0516}, ++ {.addr = 0x200, .wdata = 0x0516}, ++ {.addr = 0x204, .wdata = 0x3010}, ++ {.addr = 0x209, .wdata = 0x0429}, ++ {.addr = 0x20E, .wdata = 0x0010}, ++ {.addr = 0x213, .wdata = 0x005A}, ++ {.addr = 0x214, .wdata = 0x0000}, ++ {.addr = 0x216, .wdata = 0x0000}, ++ {.addr = 0x218, .wdata = 0x0000}, ++ {.addr = 0x225, .wdata = 0x0000}, ++ {.addr = 0x22A, .wdata = 0x0000}, ++ {.addr = 0x22B, .wdata = 0x0000}, ++ {.addr = 0x231, .wdata = 0x0000}, ++ {.addr = 0x232, .wdata = 0x0000}, ++ {.addr = 0x233, .wdata = 0x0000}, ++ {.addr = 0x245, .wdata = 0x0300}, ++ {.addr = 0x24A, .wdata = 0x0000}, ++ {.addr = 0x24F, .wdata = 0xFFF3}, ++ {.addr = 0x254, .wdata = 0x0000}, ++ {.addr = 0x259, .wdata = 0x0000}, ++ {.addr = 0x25E, .wdata = 0x0000}, ++ {.addr = 0x265, .wdata = 0x0009}, ++ {.addr = 0x267, .wdata = 0x0174}, ++ {.addr = 0x271, .wdata = 0x01F0}, ++ {.addr = 0x273, .wdata = 0x0170}, ++ {.addr = 0x275, .wdata = 0x7828}, ++ {.addr = 0x279, .wdata = 0x3E3A}, ++ {.addr = 0x27D, .wdata = 0x8468}, ++ {.addr = 0x283, .wdata = 0x000C}, ++ {.addr = 0x285, .wdata = 0x7777}, ++ {.addr = 0x288, .wdata = 0x5503}, ++ {.addr = 0x28C, .wdata = 0x0030}, ++ {.addr = 0x28E, .wdata = 0xBBBB}, ++ {.addr = 0x290, .wdata = 0xBBBB}, ++ {.addr = 0x293, .wdata = 0x0021}, ++ {.addr = 0x2FA, .wdata = 0x3B40}, ++ {.addr = 0x2FB, .wdata = 0x7777}, ++ {.addr = 0x30A, .wdata = 0x8022}, ++ {.addr = 0x319, .wdata = 0x205E}, ++ {.addr = 0x31B, .wdata = 0x0000}, ++ {.addr = 0x31D, .wdata = 0x6004}, ++ {.addr = 0x320, .wdata = 0x3014}, ++ {.addr = 0x322, .wdata = 0x6004}, ++ {.addr = 0x326, .wdata = 0x6004}, ++ {.addr = 0x32A, .wdata = 0x5000}, ++ {.addr = 0x32E, .wdata = 0x5000}, ++ {.addr = 0x332, .wdata = 0x6004}, ++ {.addr = 0x336, .wdata = 0x6063}, ++ {.addr = 0x389, .wdata = 0x0310}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000}, ++ {.addr = 0x3FF, .wdata = 0x0000} ++}; ++ ++#define MLXBF_GIGE_DLM_RX_NUM_ENTRIES \ ++ (sizeof(mlxbf_gige_dlm_rx_init) / sizeof(struct mlxbf_gige_uphy_cfg_reg)) ++ ++/* returns plu clock p1clk in Hz */ ++static u64 mlxbf_gige_calculate_p1clk(struct mlxbf_gige *priv) ++{ ++ u8 core_od, core_r; ++ u64 freq_output; ++ u32 reg1, reg2; ++ u32 core_f; ++ ++ reg1 = readl(priv->clk_io + MLXBF_GIGE_P1CLK_REG1); ++ reg2 = readl(priv->clk_io + MLXBF_GIGE_P1CLK_REG2); ++ ++ core_f = (reg1 & MLXBF_GIGE_P1_CORE_F_MASK) >> ++ MLXBF_GIGE_P1_CORE_F_SHIFT; ++ core_r = (reg1 & MLXBF_GIGE_P1_CORE_R_MASK) >> ++ MLXBF_GIGE_P1_CORE_R_SHIFT; ++ core_od = (reg2 & MLXBF_GIGE_P1_CORE_OD_MASK) >> ++ MLXBF_GIGE_P1_CORE_OD_SHIFT; ++ ++ /* Compute PLL output frequency as follow: ++ * ++ * CORE_F / 16384 ++ * freq_output = freq_reference * ---------------------------- ++ * (CORE_R + 1) * (CORE_OD + 1) ++ */ ++ freq_output = div_u64(MLXBF_GIGE_P1_FREQ_REFERENCE * core_f, ++ MLXBF_GIGE_P1_CLK_CONST); ++ freq_output = div_u64(freq_output, (core_r + 1) * (core_od + 1)); ++ ++ return freq_output; ++} ++ ++static void mlxbf_gige_ugl_static_config(struct mlxbf_gige *priv) ++{ ++ u32 val, p1clk_mhz; ++ u32 const_factor; ++ u64 p1clk; ++ ++ /* p1clk is the PLU clock in Hz */ ++ p1clk = mlxbf_gige_calculate_p1clk(priv); ++ ++ /* get p1clk in MHz */ ++ p1clk_mhz = div_u64(p1clk, 1000000); ++ ++ /* Multiply the p1clk clock by 12 according to HW requirements */ ++ const_factor = p1clk_mhz * MLXBF_GIGE_P1CLK_MULT_FACTOR; ++ ++ /* ugl_cr_bridge_desc */ ++ val = readl(priv->plu_base + MLXBF_GIGE_UGL_CR_BRIDGE_DESC); ++ val &= ~MLXBF_GIGE_UGL_CR_BRIDGE_ALL_MASK; ++ val |= FIELD_PREP(MLXBF_GIGE_UGL_CR_BRIDGE_SETUP_MASK, ++ MLXBF_GIGE_UGL_CR_BRIDGE_SETUP_VAL(const_factor)); ++ val |= FIELD_PREP(MLXBF_GIGE_UGL_CR_BRIDGE_PULSE_MASK, ++ MLXBF_GIGE_UGL_CR_BRIDGE_PULSE_VAL(const_factor)); ++ val |= FIELD_PREP(MLXBF_GIGE_UGL_CR_BRIDGE_HOLD_MASK, ++ MLXBF_GIGE_UGL_CR_BRIDGE_HOLD_VAL(const_factor)); ++ writel(val, priv->plu_base + MLXBF_GIGE_UGL_CR_BRIDGE_DESC); ++ ++ /* pll1x_fsm_counters */ ++ val = MLXBF_GIGE_PLL1X_FSM_DEFAULT_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_PLL1X_FSM_DEFAULT_CYCLES); ++ ++ val = MLXBF_GIGE_PLL1X_FSM_SLEEP_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_PLL1X_FSM_SLEEP_CYCLES); ++ ++ val = MLXBF_GIGE_PLL1X_FSM_RCAL_FLOW_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_PLL1X_FSM_RCAL_FLOW_CYCLES); ++ ++ val = MLXBF_GIGE_PLL1X_FSM_CAL_FLOW_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_PLL1X_FSM_CAL_FLOW_CYCLES); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_CYCLES); ++ val &= ~MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_MASK; ++ val |= FIELD_PREP(MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_MASK, ++ MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_VAL(const_factor)); ++ writel(val, priv->plu_base + MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_CYCLES); ++ ++ /* tx_fsm_counters */ ++ val = MLXBF_GIGE_TX_FSM_DEFAULT_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_TX_FSM_DEFAULT_CYCLES); ++ ++ val = MLXBF_GIGE_TX_FSM_SLEEP_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_TX_FSM_SLEEP_CYCLES); ++ ++ val = MLXBF_GIGE_TX_FSM_POWERUP_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_TX_FSM_POWERUP_CYCLES); ++ ++ val = MLXBF_GIGE_TX_FSM_CAL_FLOW_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_TX_FSM_CAL_FLOW_CYCLES); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_TX_FSM_CAL_ABORT_CYCLES); ++ val &= ~MLXBF_GIGE_TX_FSM_CAL_ABORT_MASK; ++ val |= FIELD_PREP(MLXBF_GIGE_TX_FSM_CAL_ABORT_MASK, ++ MLXBF_GIGE_TX_FSM_CAL_ABORT_VAL(const_factor)); ++ writel(val, priv->plu_base + MLXBF_GIGE_TX_FSM_CAL_ABORT_CYCLES); ++ ++ /* rx_fsm_counters */ ++ val = MLXBF_GIGE_RX_FSM_DEFAULT_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_DEFAULT_CYCLES); ++ ++ val = MLXBF_GIGE_RX_FSM_SLEEP_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_SLEEP_CYCLES); ++ ++ val = MLXBF_GIGE_RX_FSM_POWERUP_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_POWERUP_CYCLES); ++ ++ val = MLXBF_GIGE_RX_FSM_TERM_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_TERM_CYCLES); ++ ++ val = MLXBF_GIGE_RX_FSM_CAL_FLOW_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_CAL_FLOW_CYCLES); ++ ++ val = MLXBF_GIGE_RX_FSM_CAL_ABORT_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_CAL_ABORT_CYCLES); ++ ++ val = MLXBF_GIGE_RX_FSM_EQ_FLOW_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_EQ_FLOW_CYCLES); ++ ++ val = MLXBF_GIGE_RX_FSM_EQ_ABORT_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_EQ_ABORT_CYCLES); ++ ++ val = MLXBF_GIGE_RX_FSM_EOM_FLOW_VAL(const_factor); ++ writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_EOM_FLOW_CYCLES); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_RX_FSM_CDR_LOCK_CYCLES); ++ val &= ~MLXBF_GIGE_RX_FSM_CDR_LOCK_MASK; ++ val |= FIELD_PREP(MLXBF_GIGE_RX_FSM_CDR_LOCK_MASK, ++ MLXBF_GIGE_RX_FSM_CDR_LOCK_VAL(const_factor)); ++ writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_CDR_LOCK_CYCLES); ++ ++ /* periodic_flows_timer_max_value */ ++ val = readl(priv->plu_base + MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX); ++ val &= ~MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX_MASK; ++ val |= FIELD_PREP(MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX_MASK, ++ MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX_VAL(const_factor)); ++ writel(val, priv->plu_base + MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX); ++ ++ /* plltop.center.iddq_cycles */ ++ val = readl(priv->plu_base + MLXBF_GIGE_PLL_IDDQ_CYCLES); ++ val &= ~MLXBF_GIGE_PLL_IDDQ_CYCLES_MASK; ++ val |= FIELD_PREP(MLXBF_GIGE_PLL_IDDQ_CYCLES_MASK, ++ MLXBF_GIGE_PLL_IDDQ_CYCLES_VAL(const_factor)); ++ writel(val, priv->plu_base + MLXBF_GIGE_PLL_IDDQ_CYCLES); ++ ++ /* lanetop.center.iddq_cycles */ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_IDDQ_CYCLES); ++ val &= ~MLXBF_GIGE_LANE_IDDQ_CYCLES_MASK; ++ val |= FIELD_PREP(MLXBF_GIGE_LANE_IDDQ_CYCLES_MASK, ++ MLXBF_GIGE_LANE_IDDQ_CYCLES_VAL(const_factor)); ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_IDDQ_CYCLES); ++ ++ /* lanetop.center.power_governor0 */ ++ val = FIELD_PREP(MLXBF_GIGE_LANE_PWR_GOV0_RISE_MASK, ++ MLXBF_GIGE_LANE_PWR_GOV0_RISE_VAL(const_factor)); ++ val |= FIELD_PREP(MLXBF_GIGE_LANE_PWR_GOV0_FALL_MASK, ++ MLXBF_GIGE_LANE_PWR_GOV0_FALL_VAL(const_factor)); ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_PWR_GOV0); ++} ++ ++static int mlxbf_gige_uphy_gw_write(struct mlxbf_gige *priv, u16 addr, ++ u16 data, bool is_pll) ++{ ++ u32 cmd, val; ++ int ret; ++ ++ cmd = MLXBF_GIGE_UPHY_GW_CREATE_CMD(addr, data, 0, is_pll); ++ ++ /* Send PLL or lane GW write request */ ++ writel(cmd, priv->plu_base + MLXBF_GIGE_UPHY_GW(is_pll)); ++ ++ /* If the poll times out, drop the request */ ++ ret = readl_poll_timeout_atomic(priv->plu_base + ++ MLXBF_GIGE_UPHY_GW(is_pll), ++ val, ++ !(val & MLXBF_GIGE_UPHY_GW_BUSY_MASK(is_pll)), ++ 5, 1000000); ++ if (ret) ++ dev_dbg(priv->dev, "Failed to send GW write request\n"); ++ ++ return ret; ++} ++ ++static int mlxbf_gige_uphy_gw_read(struct mlxbf_gige *priv, u16 addr, ++ bool is_pll) ++{ ++ u32 cmd, val; ++ int ret; ++ ++ cmd = MLXBF_GIGE_UPHY_GW_CREATE_CMD(addr, 0, 1, is_pll); ++ ++ /* Send PLL or lane GW read request */ ++ writel(cmd, priv->plu_base + MLXBF_GIGE_UPHY_GW(is_pll)); ++ ++ /* If the poll times out, drop the request */ ++ ret = readl_poll_timeout_atomic(priv->plu_base + ++ MLXBF_GIGE_UPHY_GW(is_pll), ++ val, ++ !(val & MLXBF_GIGE_UPHY_GW_BUSY_MASK(is_pll)), ++ 5, 1000000); ++ if (ret) { ++ dev_dbg(priv->dev, "Failed to send GW read request\n"); ++ return ret; ++ } ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_UPHY_GW_DESC0(is_pll)); ++ val &= MLXBF_GIGE_UPHY_GW_DESC0_DATA_MASK(is_pll); ++ ++ return val; ++} ++ ++static int mlxbf_gige_load_uphy_clm_init_pkg(struct mlxbf_gige *priv) ++{ ++ int ret = 0; ++ int i; ++ ++ for (i = 0; i < MLXBF_GIGE_UPHY_CLM_INIT_NUM_ENTRIES; i++) { ++ ret = mlxbf_gige_uphy_gw_write(priv, ++ mlxbf_gige_clm_init[i].addr, ++ mlxbf_gige_clm_init[i].wdata, ++ true); ++ if (ret) { ++ dev_dbg(priv->dev, "Failed to load clm init pkg\n"); ++ return ret; ++ } ++ } ++ ++ return ret; ++} ++ ++static int mlxbf_gige_load_clm_production_fuses(struct mlxbf_gige *priv) ++{ ++ u8 bg_trim_room; ++ u8 cvb_trim_room; ++ u8 speedo_room; ++ int ret; ++ u32 val; ++ ++ val = readl(priv->fuse_gw_io); ++ bg_trim_room = (val & MLXBF_GIGE_YU_BG_TRIM_ROOM_MASK) >> ++ MLXBF_GIGE_YU_BG_TRIM_ROOM_SHIFT; ++ cvb_trim_room = (val & MLXBF_GIGE_YU_CVB_TRIM_ROOM_MASK) >> ++ MLXBF_GIGE_YU_CVB_TRIM_ROOM_SHIFT; ++ speedo_room = (val & MLXBF_GIGE_YU_SPEEDO_ROOM_MASK) >> ++ MLXBF_GIGE_YU_SPEEDO_ROOM_SHIFT; ++ ++ val = ((bg_trim_room >> MLXBF_GIGE_YU_FUSE_VALID_SHIFT) << ++ MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_BG_TRIM_VLD_SHIFT); ++ val |= ((cvb_trim_room >> MLXBF_GIGE_YU_FUSE_VALID_SHIFT) << ++ MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_CVB_TRIM_VLD_SHIFT); ++ val |= ((speedo_room >> MLXBF_GIGE_YU_FUSE_VALID_SHIFT) << ++ MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_SPEEDO_VLD_SHIFT); ++ val |= ((bg_trim_room & MLXBF_GIGE_YU_FUSE_MASK) << ++ MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_BG_TRIM_SHIFT); ++ val |= ((cvb_trim_room & MLXBF_GIGE_YU_FUSE_MASK) << ++ MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_CVB_TRIM_SHIFT); ++ val |= ((speedo_room & MLXBF_GIGE_YU_FUSE_MASK) << ++ MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_SPEEDO_SHIFT); ++ ++ ret = mlxbf_gige_uphy_gw_write(priv, MLXBF_GIGE_MGMT_BGAP_FUSE_CTRL_ADDR, val, true); ++ if (ret) ++ dev_dbg(priv->dev, "Failed to load clm production fuses\n"); ++ ++ return ret; ++} ++ ++static int mlxbf_gige_init_pll(struct mlxbf_gige *priv) ++{ ++ int ret; ++ ++ ret = mlxbf_gige_load_uphy_clm_init_pkg(priv); ++ if (ret) ++ return ret; ++ ++ ret = mlxbf_gige_load_clm_production_fuses(priv); ++ ++ return ret; ++} ++ ++static int mlxbf_gige_lock_pll(struct mlxbf_gige *priv) ++{ ++ int ret; ++ u32 val; ++ ++ /* plltop.center.uphy_pll_rst_reg_ */ ++ val = readl(priv->plu_base + MLXBF_GIGE_UPHY_PLL_RST_REG); ++ val |= MLXBF_GIGE_UPHY_PLL_RST_REG_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_UPHY_PLL_RST_REG); ++ ++ /* cause_or.clrcause.bulk */ ++ val = readl(priv->plu_base + MLXBF_GIGE_PLL1X_CAUSE_CLRCAUSE_BULK); ++ val |= MLXBF_GIGE_PLL1X_CAUSE_CLRCAUSE_BULK_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_PLL1X_CAUSE_CLRCAUSE_BULK); ++ ++ writel(0, priv->plu_base + MLXBF_GIGE_PLL_CAL); ++ ++ /* Stop polling when fsm state is UGL_PLL1X_FSM_STATE_SLEEP */ ++ ret = readl_poll_timeout_atomic(priv->plu_base + ++ MLXBF_GIGE_PLL_FSM_CTRL, ++ val, (val == MLXBF_GIGE_UGL_PLL1X_FSM_STATE_SLEEP), ++ 5, 1000000); ++ if (ret) { ++ dev_dbg(priv->dev, "Polling timeout on fsm state sleep\n"); ++ return ret; ++ } ++ ++ udelay(MLXBF_GIGE_PLL_STAB_TIME); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_PLL_SLEEP_FW); ++ val |= MLXBF_GIGE_PLL_SLEEP_FW_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_PLL_SLEEP_FW); ++ ++ udelay(MLXBF_GIGE_PLL_STAB_TIME); ++ writel(MLXBF_GIGE_PLL_RCAL_MASK, priv->plu_base + MLXBF_GIGE_PLL_RCAL); ++ ++ /* Stop polling when fsm state is UGL_PLL1X_FSM_STATE_IDLE */ ++ ret = readl_poll_timeout_atomic(priv->plu_base + ++ MLXBF_GIGE_PLL_FSM_CTRL, ++ val, (val == MLXBF_GIGE_UGL_PLL1X_FSM_STATE_IDLE), ++ 5, 1000000); ++ if (ret) { ++ dev_dbg(priv->dev, "Polling timeout on fsm state idle\n"); ++ return ret; ++ } ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_PLL_SLEEP_FW); ++ val &= ~MLXBF_GIGE_PLL_SLEEP_FW_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_PLL_SLEEP_FW); ++ ++ writel(MLXBF_GIGE_PLL_CAL_MASK, priv->plu_base + MLXBF_GIGE_PLL_CAL); ++ ++ /* Stop polling when cal_valid is different from 0 */ ++ ret = readl_poll_timeout_atomic(priv->plu_base + MLXBF_GIGE_PLL_CAL_VLD, ++ val, !!(val & MLXBF_GIGE_PLL_CAL_VLD_MASK), ++ 5, 1000000); ++ if (ret) { ++ dev_dbg(priv->dev, "Polling timeout on cal_valid\n"); ++ return ret; ++ } ++ ++ /* pll_enable */ ++ val = readl(priv->plu_base + MLXBF_GIGE_PLL_ENABLE); ++ val |= MLXBF_GIGE_PLL_ENABLE_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_PLL_ENABLE); ++ ++ return ret; ++} ++ ++static void mlxbf_gige_get_lane_out_of_rst(struct mlxbf_gige *priv) ++{ ++ u32 val; ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_RST_REG); ++ val |= MLXBF_GIGE_LANE_RST_REG_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_RST_REG); ++} ++ ++static int mlxbf_gige_load_imem(struct mlxbf_gige *priv) ++{ ++ u16 csum_status; ++ int ret = 0; ++ int i; ++ ++ for (i = 0; i < MLXBF_GIGE_UPHY_DLM_IMEM_INIT_NUM_ENTRIES; i++) { ++ ret = mlxbf_gige_uphy_gw_write(priv, ++ mlxbf_gige_dlm_imem_init[i].addr, ++ mlxbf_gige_dlm_imem_init[i].wdata, ++ false); ++ if (ret) ++ return ret; ++ } ++ ++ /* Resets the internal counter for MLXBF_GIGE_DLM_IMEM_DATA_ADDR to base address */ ++ ret = mlxbf_gige_uphy_gw_write(priv, ++ mlxbf_gige_dlm_seq_imem_wr_en_init.addr, ++ mlxbf_gige_dlm_seq_imem_wr_en_init.wdata, ++ false); ++ if (ret) ++ return ret; ++ ++ /* HW increments the address MLXBF_GIGE_DLM_IMEM_DATA_ADDR internally. */ ++ for (i = 0; i < MLXBF_GIGE_UPHY_DLM_IMEM_DATA_NUM_ENTRIES; i++) { ++ ret = mlxbf_gige_uphy_gw_write(priv, ++ MLXBF_GIGE_LANE_IMEM_DATA_ADDR, ++ mlxbf_gige_dlm_imem_data[i].wdata, ++ false); ++ if (ret) ++ return ret; ++ } ++ ++ ret = mlxbf_gige_uphy_gw_write(priv, ++ mlxbf_gige_dlm_seq_imem_wr_dis_init.addr, ++ mlxbf_gige_dlm_seq_imem_wr_dis_init.wdata, ++ false); ++ if (ret) ++ return ret; ++ ++ ret = mlxbf_gige_uphy_gw_write(priv, ++ mlxbf_gige_dlm_seq_imem_csum_en.addr, ++ mlxbf_gige_dlm_seq_imem_csum_en.wdata, ++ false); ++ if (ret) ++ return ret; ++ ++ udelay(MLXBF_GIGE_PLL_DLM_IMEM_CSUM_TIMEOUT); ++ ++ ret = mlxbf_gige_uphy_gw_read(priv, MLXBF_GIGE_LANE_CSUM_STS_ADDR, false); ++ if (ret < 0) ++ return ret; ++ ++ csum_status = ((ret & MLXBF_GIGE_IMEM_CSUM_STATUS_MASK) >> ++ MLXBF_GIGE_IMEM_CSUM_STATUS_SHIFT); ++ ++ ret = mlxbf_gige_uphy_gw_write(priv, ++ mlxbf_gige_dlm_seq_imem_csum_dis.addr, ++ mlxbf_gige_dlm_seq_imem_csum_dis.wdata, ++ false); ++ if (ret) ++ return ret; ++ ++ if (csum_status != MLXBF_GIGE_IMEM_CSUM_RUN_AND_VALID) { ++ dev_err(priv->dev, "%s: invalid checksum\n", __func__); ++ ++ /* recovery flow */ ++ for (i = 0; i < MLXBF_GIGE_DLM_SEQ_IMEM_BMAP_CLR_NUM_ENTRIES; i++) { ++ mlxbf_gige_uphy_gw_write(priv, ++ mlxbf_gige_dlm_seq_imem_bmap_clr[i].addr, ++ mlxbf_gige_dlm_seq_imem_bmap_clr[i].wdata, ++ false); ++ } ++ ++ return MLXBF_GIGE_INVALID_IMEM_CSUM; ++ } ++ ++ return ret; ++} ++ ++static int mlxbf_gige_plu_tx_power_ctrl(struct mlxbf_gige *priv, bool is_pwr_on) ++{ ++ int ret = 0; ++ u32 val; ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED); ++ val &= ~MLXBF_GIGE_LANE_TX_SLEEP_VAL_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED); ++ ++ if (is_pwr_on) { ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN); ++ val &= ~MLXBF_GIGE_LANE_TX_IDDQ_VAL_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_PLU_POWERUP); ++ val |= MLXBF_GIGE_PLU_TX_POWERUP_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_PLU_POWERUP); ++ } else { ++ val = readl(priv->plu_base + MLXBF_GIGE_PLU_POWERUP); ++ val &= ~MLXBF_GIGE_PLU_TX_POWERUP_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_PLU_POWERUP); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN); ++ val |= MLXBF_GIGE_LANE_TX_IDDQ_VAL_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN); ++ ++ ret = readl_poll_timeout_atomic(priv->plu_base + ++ MLXBF_GIGE_LANE_TX_FSM_CTRL, val, ++ ((val & MLXBF_GIGE_LANE_TX_FSM_PS_MASK) == MLXBF_GIGE_TX_FSM_IDDQ), ++ 5, 1000000); ++ if (ret) ++ dev_dbg(priv->dev, "Polling timeout on tx fsm iddq state\n"); ++ } ++ ++ return ret; ++} ++ ++static int mlxbf_gige_dlm_tx_init_pkg(struct mlxbf_gige *priv) ++{ ++ int ret = 0; ++ int i; ++ ++ for (i = 0; i < MLXBF_GIGE_DLM_TX_NUM_ENTRIES; i++) { ++ ret = mlxbf_gige_uphy_gw_write(priv, ++ mlxbf_gige_dlm_tx_init[i].addr, ++ mlxbf_gige_dlm_tx_init[i].wdata, ++ false); ++ if (ret) { ++ dev_dbg(priv->dev, "Failed to load dlm tx init pkg\n"); ++ return ret; ++ } ++ } ++ ++ return ret; ++} ++ ++static int mlxbf_gige_tx_lane_open(struct mlxbf_gige *priv) ++{ ++ u32 val; ++ int ret; ++ ++ /* Prepare the TX lane before opening it */ ++ ++ ret = mlxbf_gige_plu_tx_power_ctrl(priv, false); ++ if (ret) ++ return ret; ++ ++ /* Calibration of TX elastic buffer */ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_BITS_SWAP); ++ val &= ~MLXBF_GIGE_TX_EB_BLOCK_PUSH_DIST_MASK_MASK; ++ val |= MLXBF_GIGE_TX_EB_BLOCK_PUSH_DIST_MASK_VAL; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_BITS_SWAP); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN); ++ val |= MLXBF_GIGE_LANE_TX_DATA_EN_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN); ++ ++ writel(MLXBF_GIGE_LANE_TX_CAL_MASK, priv->plu_base + MLXBF_GIGE_LANE_TX_CAL); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN); ++ val &= ~MLXBF_GIGE_LANE_TX_RATE_ID_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED); ++ val &= ~MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED); ++ ++ /* Loading the DLM tx init package should be done before lane power on */ ++ ret = mlxbf_gige_dlm_tx_init_pkg(priv); ++ if (ret) ++ return ret; ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_BITS_SWAP); ++ val &= ~MLXBF_GIGE_LANE_TX_BITS_SWAP_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_BITS_SWAP); ++ ++ ret = mlxbf_gige_plu_tx_power_ctrl(priv, true); ++ if (ret) ++ return ret; ++ ++ /* After preparing the TX lane, open it for data transmission */ ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_BITS_SWAP); ++ val &= ~MLXBF_GIGE_TX_EB_BLOCK_PUSH_DIST_MASK_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_BITS_SWAP); ++ ++ ret = readl_poll_timeout_atomic(priv->plu_base + ++ MLXBF_GIGE_LANE_TX_FSM_CTRL, val, ++ ((val & MLXBF_GIGE_LANE_TX_FSM_PS_MASK) == MLXBF_GIGE_TX_DATA_EN), ++ 5, 1000000); ++ if (ret) { ++ dev_dbg(priv->dev, "Polling timeout on fsm tx data enable state\n"); ++ return ret; ++ } ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN); ++ val |= MLXBF_GIGE_LANE_TX_PERIODIC_CAL_EN_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN); ++ ++ return ret; ++} ++ ++static int mlxbf_gige_dlm_rx_init_pkg(struct mlxbf_gige *priv) ++{ ++ int ret = 0; ++ int i; ++ ++ for (i = 0; i < MLXBF_GIGE_DLM_RX_NUM_ENTRIES; i++) { ++ ret = mlxbf_gige_uphy_gw_write(priv, ++ mlxbf_gige_dlm_rx_init[i].addr, ++ mlxbf_gige_dlm_rx_init[i].wdata, ++ false); ++ if (ret) { ++ dev_dbg(priv->dev, "Failed to load dlm rx init pkg\n"); ++ return ret; ++ } ++ } ++ ++ return ret; ++} ++ ++static int mlxbf_gige_plu_rx_power_ctrl(struct mlxbf_gige *priv, bool is_pwr_on) ++{ ++ int ret = 0; ++ u32 val; ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID); ++ val &= ~MLXBF_GIGE_LANE_RX_SLEEP_VAL_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID); ++ ++ if (is_pwr_on) { ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID); ++ val &= ~MLXBF_GIGE_LANE_RX_IDDQ_VAL_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_PLU_POWERUP); ++ val |= MLXBF_GIGE_PLU_RX_POWERUP_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_PLU_POWERUP); ++ } else { ++ /* Enable HW watchdogs. */ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN); ++ val |= MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN_MASK; ++ val |= MLXBF_GIGE_LANE_RX_CAL_DONE_TIMER_EN_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_PLU_POWERUP); ++ val &= ~MLXBF_GIGE_PLU_RX_POWERUP_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_PLU_POWERUP); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID); ++ val |= MLXBF_GIGE_LANE_RX_IDDQ_VAL_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID); ++ ++ ret = readl_poll_timeout_atomic(priv->plu_base + ++ MLXBF_GIGE_LANE_RX_FSM_CTRL, val, ++ ((val & MLXBF_GIGE_LANE_RX_FSM_PS_MASK) == MLXBF_GIGE_RX_FSM_IDDQ), ++ 5, 1000000); ++ if (ret) { ++ dev_dbg(priv->dev, "Polling timeout on rx fsm iddq state\n"); ++ return ret; ++ } ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN); ++ val &= ~MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN_MASK; ++ val &= ~MLXBF_GIGE_LANE_RX_CAL_DONE_TIMER_EN_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN); ++ } ++ ++ return ret; ++} ++ ++static int mlxbf_gige_rx_lane_open(struct mlxbf_gige *priv) ++{ ++ u32 val; ++ int ret; ++ ++ ret = mlxbf_gige_plu_rx_power_ctrl(priv, false); ++ if (ret) ++ return ret; ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID); ++ val &= ~MLXBF_GIGE_LANE_RX_RATE_ID_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP); ++ val &= ~MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP_RDY_CHICKEN_MASK; ++ val &= ~MLXBF_GIGE_LANE_RX_DATA_SPLIT_LSB_VLD_CHICKEN_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID); ++ val &= ~MLXBF_GIGE_LANE_RX_RATE_ID0_SPEED_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID); ++ ++ ret = mlxbf_gige_dlm_rx_init_pkg(priv); ++ if (ret) ++ return ret; ++ ++ writel(MLXBF_GIGE_LANE_RX_CAL_MASK, priv->plu_base + MLXBF_GIGE_LANE_RX_CAL); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP); ++ val &= ~MLXBF_GIGE_LANE_RX_CDR_RESET_REG_MASK; ++ val |= MLXBF_GIGE_LANE_RX_CDR_EN_MASK; ++ val |= MLXBF_GIGE_LANE_RX_DATA_EN_MASK; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP); ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_EQ_TRAIN); ++ val &= ~MLXBF_GIGE_LANE_RX_EQ_TRAIN_MASK; ++ val |= MLXBF_GIGE_LANE_RX_EQ_TRAIN_VAL; ++ writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_EQ_TRAIN); ++ ++ ret = mlxbf_gige_plu_rx_power_ctrl(priv, true); ++ if (ret) ++ return ret; ++ ++ ret = readl_poll_timeout_atomic(priv->plu_base + ++ MLXBF_GIGE_LANE_RX_FSM_CTRL, val, ++ ((val & MLXBF_GIGE_LANE_RX_FSM_PS_MASK) == MLXBF_GIGE_RX_FSM_ACTIVE), ++ 5, 1000000); ++ if (ret) ++ dev_dbg(priv->dev, "Polling timeout on rx fsm active state\n"); ++ ++ return ret; ++} ++ ++static bool mlxbf_gige_is_uphy_ready(struct mlxbf_gige *priv) ++{ ++ u32 val; ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_FSM_CTRL); ++ if ((val & MLXBF_GIGE_LANE_TX_FSM_PS_MASK) != MLXBF_GIGE_TX_DATA_EN) ++ return false; ++ ++ val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_FSM_CTRL); ++ if ((val & MLXBF_GIGE_LANE_RX_FSM_PS_MASK) != MLXBF_GIGE_RX_FSM_ACTIVE) ++ return false; ++ ++ return true; ++} ++ ++int mlxbf_gige_config_uphy(struct mlxbf_gige *priv) ++{ ++ struct platform_device *pdev = priv->pdev; ++ struct device *dev = &pdev->dev; ++ int ret = 0; ++ ++ priv->fuse_gw_io = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_FUSE_GW); ++ if (IS_ERR(priv->fuse_gw_io)) ++ return PTR_ERR(priv->fuse_gw_io); ++ ++ if (mlxbf_gige_is_uphy_ready(priv)) ++ return 0; ++ ++ mlxbf_gige_ugl_static_config(priv); ++ ret = mlxbf_gige_init_pll(priv); ++ if (ret) { ++ dev_err(dev, "%s: Failed to initialize PLL\n", __func__); ++ return ret; ++ } ++ ++ ret = mlxbf_gige_lock_pll(priv); ++ if (ret) { ++ dev_err(dev, "%s: Failed to lock PLL\n", __func__); ++ return ret; ++ } ++ ++ /* Due to hardware design issue, we need to get the lanes out of reset ++ * before configuring the imem. ++ */ ++ mlxbf_gige_get_lane_out_of_rst(priv); ++ ret = mlxbf_gige_load_imem(priv); ++ if (ret) { ++ dev_err(dev, "%s: Failed to load imem\n", __func__); ++ return ret; ++ } ++ ++ ret = mlxbf_gige_tx_lane_open(priv); ++ if (ret) { ++ dev_err(dev, "%s: Failed to open tx lane\n", __func__); ++ return ret; ++ } ++ ++ ret = mlxbf_gige_rx_lane_open(priv); ++ if (ret) ++ dev_err(dev, "%s: Failed to open rx lane\n", __func__); ++ ++ return ret; ++} +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.h +new file mode 100644 +index 000000000..a32be2407 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.h +@@ -0,0 +1,398 @@ ++/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ ++ ++/* UPHY support for Mellanox Gigabit Ethernet driver ++ * ++ * Copyright (C) 2022 NVIDIA CORPORATION & AFFILIATES ++ */ ++ ++#ifndef __MLXBF_GIGE_UPHY_H__ ++#define __MLXBF_GIGE_UPHY_H__ ++ ++#include ++ ++/* Some registers' values depend on the p1clk clock. The following ++ * formula applies: ++ * ((time_in_ns*const_factor)/MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ */ ++#define MLXBF_GIGE_TIME_FACTOR_TO_USEC 10000 ++ ++/* All addresses represent the offset from the base PLU address */ ++ ++#define MLXBF_GIGE_PLU_POWERUP 0x488 ++#define MLXBF_GIGE_PLU_TX_POWERUP_MASK GENMASK(28, 28) ++#define MLXBF_GIGE_PLU_RX_POWERUP_MASK GENMASK(27, 27) ++ ++#define MLXBF_GIGE_LANE_CFG_FLAT0_BASE 0x23000 ++#define MLXBF_GIGE_AE_SYS_IMEM_RAM_DATA_CTRL_WDATA 0x23ef8 ++#define MLXBF_GIGE_AE_SYS_IMEM_RAM_STAT_IMEM_CSUM_STS 0x23f00 ++#define MLXBF_GIGE_IMEM_CSUM_STATUS_MASK GENMASK(6, 5) ++#define MLXBF_GIGE_IMEM_CSUM_STATUS_SHIFT 5 ++ ++#define MLXBF_GIGE_PLL_CFG_FLAT0_BASE 0x25000 ++#define MLXBF_GIGE_PLL_CFG_FLAT0_MGMT_BGAP_FUSE_CTRL 0x251d8 ++#define MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_BG_TRIM_SHIFT 0 ++#define MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_CVB_TRIM_SHIFT 4 ++#define MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_SPEEDO_SHIFT 8 ++#define MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_BG_TRIM_VLD_SHIFT 12 ++#define MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_CVB_TRIM_VLD_SHIFT 13 ++#define MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_SPEEDO_VLD_SHIFT 14 ++ ++#define MLXBF_GIGE_LANE_TX_FSM_CTRL 0x26000 ++#define MLXBF_GIGE_LANE_TX_FSM_PS_MASK GENMASK(3, 0) ++ ++#define MLXBF_GIGE_LANE_TX_BITS_SWAP 0x2600c ++#define MLXBF_GIGE_TX_EB_BLOCK_PUSH_DIST_MASK_MASK GENMASK(20, 16) ++#define MLXBF_GIGE_TX_EB_BLOCK_PUSH_DIST_MASK_VAL \ ++ FIELD_PREP(MLXBF_GIGE_TX_EB_BLOCK_PUSH_DIST_MASK_MASK, 0x3) ++#define MLXBF_GIGE_LANE_TX_BITS_SWAP_MASK GENMASK(0, 0) ++ ++#define MLXBF_GIGE_LANE_TX_DATA_EN 0x26010 ++#define MLXBF_GIGE_LANE_TX_RATE_ID_MASK GENMASK(30, 28) ++#define MLXBF_GIGE_LANE_TX_DATA_EN_MASK GENMASK(23, 23) ++#define MLXBF_GIGE_LANE_TX_IDDQ_VAL_MASK GENMASK(21, 21) ++#define MLXBF_GIGE_LANE_TX_PERIODIC_CAL_EN_MASK GENMASK(17, 17) ++ ++#define MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED 0x26014 ++#define MLXBF_GIGE_LANE_TX_SLEEP_VAL_MASK GENMASK(9, 8) ++#define MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED_MASK GENMASK(2, 0) ++ ++#define MLXBF_GIGE_LANE_TX_CAL 0x26018 ++#define MLXBF_GIGE_LANE_TX_CAL_MASK GENMASK(0, 0) ++ ++#define MLXBF_GIGE_LANE_RX_FSM_CTRL 0x26040 ++#define MLXBF_GIGE_LANE_RX_FSM_PS_MASK GENMASK(3, 0) ++ ++#define MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN 0x26054 ++#define MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN_MASK GENMASK(31, 31) ++#define MLXBF_GIGE_LANE_RX_CAL_DONE_TIMER_EN_MASK GENMASK(30, 30) ++ ++#define MLXBF_GIGE_LANE_RX_RATE_ID 0x26058 ++#define MLXBF_GIGE_LANE_RX_RATE_ID0_SPEED_MASK GENMASK(18, 16) ++#define MLXBF_GIGE_LANE_RX_RATE_ID_MASK GENMASK(14, 12) ++#define MLXBF_GIGE_LANE_RX_SLEEP_VAL_MASK GENMASK(7, 6) ++#define MLXBF_GIGE_LANE_RX_IDDQ_VAL_MASK GENMASK(4, 4) ++ ++#define MLXBF_GIGE_LANE_RX_CAL 0x2605c ++#define MLXBF_GIGE_LANE_RX_CAL_MASK GENMASK(0, 0) ++ ++#define MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP 0x26060 ++#define MLXBF_GIGE_LANE_RX_DATA_SPLIT_LSB_VLD_CHICKEN_MASK GENMASK(5, 5) ++#define MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP_RDY_CHICKEN_MASK GENMASK(4, 4) ++#define MLXBF_GIGE_LANE_RX_CDR_RESET_REG_MASK GENMASK(3, 3) ++#define MLXBF_GIGE_LANE_RX_CDR_EN_MASK GENMASK(2, 2) ++#define MLXBF_GIGE_LANE_RX_DATA_EN_MASK GENMASK(1, 1) ++ ++#define MLXBF_GIGE_LANE_RX_EQ_TRAIN 0x26064 ++#define MLXBF_GIGE_LANE_RX_EQ_TRAIN_MASK GENMASK(2, 0) ++#define MLXBF_GIGE_LANE_RX_EQ_TRAIN_VAL \ ++ FIELD_PREP(MLXBF_GIGE_LANE_RX_EQ_TRAIN_MASK, 0x3) ++ ++#define MLXBF_GIGE_LANE_GW 0x26100 ++#define MLXBF_GIGE_LANE_GW_ADDR_MASK GENMASK(10, 1) ++#define MLXBF_GIGE_LANE_GW_RW_MASK GENMASK(11, 11) ++#define MLXBF_GIGE_LANE_GW_DATA_MASK GENMASK(27, 12) ++#define MLXBF_GIGE_LANE_GW_DATA_EN_MASK GENMASK(28, 28) ++#define MLXBF_GIGE_LANE_GW_BUSY_MASK GENMASK(30, 30) ++#define MLXBF_GIGE_LANE_GW_ADDR_SHIFT 1 ++#define MLXBF_GIGE_LANE_GW_DESC0 0x2610c ++#define MLXBF_GIGE_LANE_GW_DESC0_DATA_MASK GENMASK(15, 0) ++ ++#define MLXBF_GIGE_TX_FSM_DEFAULT_CYCLES 0x26600 ++#define MLXBF_GIGE_TX_FSM_DEFAULT_VAL(const_factor) \ ++ ((200 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_TX_FSM_SLEEP_CYCLES 0x26604 ++#define MLXBF_GIGE_TX_FSM_SLEEP_VAL(const_factor) \ ++ ((1000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_TX_FSM_POWERUP_CYCLES 0x26608 ++#define MLXBF_GIGE_TX_FSM_POWERUP_VAL(const_factor) \ ++ ((10000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_TX_FSM_CAL_FLOW_CYCLES 0x2660c ++#define MLXBF_GIGE_TX_FSM_CAL_FLOW_VAL(const_factor) \ ++ ((200000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_TX_FSM_CAL_ABORT_CYCLES 0x26610 ++#define MLXBF_GIGE_TX_FSM_CAL_ABORT_VAL(const_factor) \ ++ ((4000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++#define MLXBF_GIGE_TX_FSM_CAL_ABORT_MASK GENMASK(18, 0) ++ ++#define MLXBF_GIGE_RX_FSM_DEFAULT_CYCLES 0x26614 ++#define MLXBF_GIGE_RX_FSM_DEFAULT_VAL(const_factor) \ ++ ((200 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_RX_FSM_SLEEP_CYCLES 0x26618 ++#define MLXBF_GIGE_RX_FSM_SLEEP_VAL(const_factor) \ ++ ((1000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_RX_FSM_POWERUP_CYCLES 0x2661c ++#define MLXBF_GIGE_RX_FSM_POWERUP_VAL(const_factor) \ ++ ((10000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_RX_FSM_TERM_CYCLES 0x26620 ++#define MLXBF_GIGE_RX_FSM_TERM_VAL(const_factor) \ ++ ((200000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_RX_FSM_CAL_FLOW_CYCLES 0x26624 ++#define MLXBF_GIGE_RX_FSM_CAL_FLOW_VAL(const_factor) \ ++ ((200000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_RX_FSM_CAL_ABORT_CYCLES 0x26628 ++#define MLXBF_GIGE_RX_FSM_CAL_ABORT_VAL(const_factor) \ ++ ((4000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_RX_FSM_EQ_FLOW_CYCLES 0x2662c ++#define MLXBF_GIGE_RX_FSM_EQ_FLOW_VAL(const_factor) \ ++ ((48000000 / MLXBF_GIGE_TIME_FACTOR_TO_USEC) * (const_factor)) ++ ++#define MLXBF_GIGE_RX_FSM_EQ_ABORT_CYCLES 0x26630 ++#define MLXBF_GIGE_RX_FSM_EQ_ABORT_VAL(const_factor) \ ++ ((4000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_RX_FSM_EOM_FLOW_CYCLES 0x26634 ++#define MLXBF_GIGE_RX_FSM_EOM_FLOW_VAL(const_factor) \ ++ ((4000000 / MLXBF_GIGE_TIME_FACTOR_TO_USEC) * (const_factor)) ++ ++#define MLXBF_GIGE_RX_FSM_CDR_LOCK_CYCLES 0x26638 ++#define MLXBF_GIGE_RX_FSM_CDR_LOCK_VAL(const_factor) \ ++ ((30000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++#define MLXBF_GIGE_RX_FSM_CDR_LOCK_MASK GENMASK(20, 0) ++ ++#define MLXBF_GIGE_LANE_PWR_GOV0 0x26650 ++#define MLXBF_GIGE_LANE_PWR_GOV0_FALL_VAL(const_factor) \ ++ ((5000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++#define MLXBF_GIGE_LANE_PWR_GOV0_FALL_MASK GENMASK(31, 16) ++#define MLXBF_GIGE_LANE_PWR_GOV0_RISE_VAL(const_factor) \ ++ ((5000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++#define MLXBF_GIGE_LANE_PWR_GOV0_RISE_MASK GENMASK(15, 0) ++ ++#define MLXBF_GIGE_LANE_IDDQ_CYCLES 0x26660 ++#define MLXBF_GIGE_LANE_IDDQ_CYCLES_VAL(const_factor) \ ++ ((2000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++#define MLXBF_GIGE_LANE_IDDQ_CYCLES_MASK GENMASK(28, 16) ++ ++#define MLXBF_GIGE_LANE_RST_REG 0x26660 ++#define MLXBF_GIGE_LANE_RST_REG_MASK GENMASK(7, 6) ++ ++#define MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX 0x26668 ++#define MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX_VAL(const_factor) \ ++ ((2500000 / (MLXBF_GIGE_TIME_FACTOR_TO_USEC * 8)) * (const_factor)) ++#define MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX_MASK GENMASK(22, 0) ++ ++#define MLXBF_GIGE_PLL_FSM_CTRL 0x26800 ++#define MLXBF_GIGE_PLL_FSM_PS_MASK GENMASK(3, 0) ++ ++#define MLXBF_GIGE_PLL_GW 0x26810 ++#define MLXBF_GIGE_PLL_GW_ADDR_MASK GENMASK(10, 1) ++#define MLXBF_GIGE_PLL_GW_RW_MASK GENMASK(11, 11) ++#define MLXBF_GIGE_PLL_GW_DATA_MASK GENMASK(27, 12) ++#define MLXBF_GIGE_PLL_GW_DATA_EN_MASK GENMASK(28, 28) ++#define MLXBF_GIGE_PLL_GW_BUSY_MASK GENMASK(30, 30) ++#define MLXBF_GIGE_PLL_GW_ADDR_SHIFT 1 ++#define MLXBF_GIGE_PLL_GW_DESC0 0x2681c ++#define MLXBF_GIGE_PLL_GW_DESC0_DATA_MASK GENMASK(15, 0) ++ ++#define MLXBF_GIGE_PLL_SLEEP_FW 0x26820 ++#define MLXBF_GIGE_PLL_SLEEP_FW_MASK GENMASK(14, 14) ++ ++#define MLXBF_GIGE_PLL_ENABLE 0x26820 ++#define MLXBF_GIGE_PLL_ENABLE_MASK GENMASK(1, 1) ++ ++#define MLXBF_GIGE_PLL_RCAL 0x26828 ++#define MLXBF_GIGE_PLL_RCAL_MASK GENMASK(0, 0) ++ ++#define MLXBF_GIGE_PLL_CAL_VLD 0x2682c ++#define MLXBF_GIGE_PLL_CAL_VLD_MASK GENMASK(1, 0) ++ ++#define MLXBF_GIGE_PLL_CAL 0x26830 ++#define MLXBF_GIGE_PLL_CAL_MASK GENMASK(0, 0) ++ ++#define MLXBF_GIGE_PLL1X_CAUSE_CLRCAUSE_BULK 0x26878 ++#define MLXBF_GIGE_PLL1X_CAUSE_CLRCAUSE_BULK_MASK GENMASK(16, 0) ++ ++#define MLXBF_GIGE_PLL1X_FSM_DEFAULT_CYCLES 0x26900 ++#define MLXBF_GIGE_PLL1X_FSM_DEFAULT_VAL(const_factor) \ ++ ((250 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_PLL1X_FSM_SLEEP_CYCLES 0x26904 ++#define MLXBF_GIGE_PLL1X_FSM_SLEEP_VAL(const_factor) \ ++ ((5000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_PLL1X_FSM_RCAL_FLOW_CYCLES 0x26908 ++#define MLXBF_GIGE_PLL1X_FSM_RCAL_FLOW_VAL(const_factor) \ ++ ((40000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_PLL1X_FSM_CAL_FLOW_CYCLES 0x2690c ++#define MLXBF_GIGE_PLL1X_FSM_CAL_FLOW_VAL(const_factor) \ ++ ((300000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++#define MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_CYCLES 0x26910 ++#define MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_VAL(const_factor) \ ++ ((100000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++#define MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_MASK GENMASK(18, 0) ++ ++#define MLXBF_GIGE_PLL_IDDQ_CYCLES 0x26914 ++#define MLXBF_GIGE_PLL_IDDQ_CYCLES_VAL(const_factor) \ ++ ((2000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++#define MLXBF_GIGE_PLL_IDDQ_CYCLES_MASK GENMASK(28, 16) ++ ++#define MLXBF_GIGE_UPHY_PLL_RST_REG 0x26914 ++#define MLXBF_GIGE_UPHY_PLL_RST_REG_MASK GENMASK(2, 2) ++ ++#define MLXBF_GIGE_UGL_CR_BRIDGE_DESC 0x26a90 ++#define MLXBF_GIGE_UGL_CR_BRIDGE_SETUP_MASK GENMASK(5, 0) ++#define MLXBF_GIGE_UGL_CR_BRIDGE_PULSE_MASK GENMASK(13, 8) ++#define MLXBF_GIGE_UGL_CR_BRIDGE_HOLD_MASK GENMASK(21, 16) ++#define MLXBF_GIGE_UGL_CR_BRIDGE_ALL_MASK \ ++ (MLXBF_GIGE_UGL_CR_BRIDGE_SETUP_MASK | \ ++ MLXBF_GIGE_UGL_CR_BRIDGE_PULSE_MASK | \ ++ MLXBF_GIGE_UGL_CR_BRIDGE_HOLD_MASK) ++ ++#define MLXBF_GIGE_UGL_CR_BRIDGE_SETUP_VAL(const_factor) \ ++ ((10 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++#define MLXBF_GIGE_UGL_CR_BRIDGE_PULSE_VAL(const_factor) \ ++ ((30 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++#define MLXBF_GIGE_UGL_CR_BRIDGE_HOLD_VAL(const_factor) \ ++ ((10 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC) ++ ++/* rw = 0 for write and 1 for read. ++ * data_en should be set to 1 only for a write transaction. ++ */ ++#define MLXBF_GIGE_PLL_GW_CREATE_CMD(addr, data, rw) \ ++ ((((addr) << MLXBF_GIGE_PLL_GW_ADDR_SHIFT) & MLXBF_GIGE_PLL_GW_ADDR_MASK) | \ ++ FIELD_PREP(MLXBF_GIGE_PLL_GW_RW_MASK, rw) | \ ++ FIELD_PREP(MLXBF_GIGE_PLL_GW_DATA_MASK, data) | \ ++ FIELD_PREP(MLXBF_GIGE_PLL_GW_DATA_EN_MASK, !rw) | \ ++ FIELD_PREP(MLXBF_GIGE_PLL_GW_BUSY_MASK, 1)) ++ ++#define MLXBF_GIGE_LANE_GW_CREATE_CMD(addr, data, rw) \ ++ ((((addr) << MLXBF_GIGE_LANE_GW_ADDR_SHIFT) & MLXBF_GIGE_LANE_GW_ADDR_MASK) | \ ++ FIELD_PREP(MLXBF_GIGE_LANE_GW_RW_MASK, rw) | \ ++ FIELD_PREP(MLXBF_GIGE_LANE_GW_DATA_MASK, data) | \ ++ FIELD_PREP(MLXBF_GIGE_LANE_GW_DATA_EN_MASK, !rw) | \ ++ FIELD_PREP(MLXBF_GIGE_LANE_GW_BUSY_MASK, 1)) ++ ++#define MLXBF_GIGE_UPHY_GW_CREATE_CMD(addr, data, rw, is_pll) \ ++ ((is_pll) ? MLXBF_GIGE_PLL_GW_CREATE_CMD(addr, data, rw) : \ ++ MLXBF_GIGE_LANE_GW_CREATE_CMD(addr, data, rw)) ++ ++#define MLXBF_GIGE_UPHY_GW(is_pll) \ ++ ((is_pll) ? MLXBF_GIGE_PLL_GW : MLXBF_GIGE_LANE_GW) ++ ++#define MLXBF_GIGE_UPHY_GW_DESC0(is_pll) \ ++ ((is_pll) ? MLXBF_GIGE_PLL_GW_DESC0 : MLXBF_GIGE_LANE_GW_DESC0) ++ ++#define MLXBF_GIGE_UPHY_GW_DESC0_DATA_MASK(is_pll) \ ++ ((is_pll) ? MLXBF_GIGE_PLL_GW_DESC0_DATA_MASK : \ ++ MLXBF_GIGE_LANE_GW_DESC0_DATA_MASK) ++ ++#define MLXBF_GIGE_UPHY_GW_BUSY_MASK(is_pll) \ ++ ((is_pll) ? MLXBF_GIGE_PLL_GW_BUSY_MASK : \ ++ MLXBF_GIGE_LANE_GW_BUSY_MASK) ++ ++/* bootrecord p1clk */ ++#define MLXBF_GIGE_P1CLK_REG1 0x14 ++#define MLXBF_GIGE_P1CLK_REG2 0x18 ++#define MLXBF_GIGE_P1_CORE_F_SHIFT 0 ++#define MLXBF_GIGE_P1_CORE_F_MASK GENMASK(25, 0) ++#define MLXBF_GIGE_P1_CORE_R_SHIFT 26 ++#define MLXBF_GIGE_P1_CORE_R_MASK GENMASK(31, 26) ++#define MLXBF_GIGE_P1_CORE_OD_SHIFT 0 ++#define MLXBF_GIGE_P1_CORE_OD_MASK GENMASK(3, 0) ++ ++#define MLXBF_GIGE_P1CLK_MULT_FACTOR 12 ++#define MLXBF_GIGE_P1_FREQ_REFERENCE 156250000ULL ++#define MLXBF_GIGE_P1_CLK_CONST 16384ULL ++ ++/* There is a 32-bit crspace to 16-bit UPHY address encoding. ++ * The 16-bit address can be accessed via the GW register. ++ * Subtract the crspace region base address from the actual ++ * address that needs to be accessed via the gw. ++ * Then divide it by 4 since crspace registers are 4 bit aligned ++ */ ++#define MLXBF_GIGE_32B_TO_16B_ADDR(addr, base) (((addr) - (base)) >> 2) ++ ++#define MLXBF_GIGE_LANE_CSUM_STS_ADDR \ ++ MLXBF_GIGE_32B_TO_16B_ADDR( \ ++ MLXBF_GIGE_AE_SYS_IMEM_RAM_STAT_IMEM_CSUM_STS, \ ++ MLXBF_GIGE_LANE_CFG_FLAT0_BASE) ++ ++#define MLXBF_GIGE_IMEM_CSUM_RUN_AND_VALID 0x3 ++#define MLXBF_GIGE_INVALID_IMEM_CSUM -1 ++ ++#define MLXBF_GIGE_LANE_IMEM_DATA_ADDR \ ++ MLXBF_GIGE_32B_TO_16B_ADDR( \ ++ MLXBF_GIGE_AE_SYS_IMEM_RAM_DATA_CTRL_WDATA, \ ++ MLXBF_GIGE_LANE_CFG_FLAT0_BASE) ++ ++#define MLXBF_GIGE_MGMT_BGAP_FUSE_CTRL_ADDR \ ++ MLXBF_GIGE_32B_TO_16B_ADDR( \ ++ MLXBF_GIGE_PLL_CFG_FLAT0_MGMT_BGAP_FUSE_CTRL, \ ++ MLXBF_GIGE_PLL_CFG_FLAT0_BASE) ++ ++#define MLXBF_GIGE_YU_BG_TRIM_ROOM_MASK GENMASK(4, 0) ++#define MLXBF_GIGE_YU_BG_TRIM_ROOM_SHIFT 0 ++#define MLXBF_GIGE_YU_CVB_TRIM_ROOM_MASK GENMASK(9, 5) ++#define MLXBF_GIGE_YU_CVB_TRIM_ROOM_SHIFT 5 ++#define MLXBF_GIGE_YU_SPEEDO_ROOM_MASK GENMASK(14, 10) ++#define MLXBF_GIGE_YU_SPEEDO_ROOM_SHIFT 10 ++#define MLXBF_GIGE_YU_FUSE_VALID_SHIFT 4 ++/* Fuse mask without valid bit */ ++#define MLXBF_GIGE_YU_FUSE_MASK 0xf ++ ++enum { ++ MLXBF_GIGE_UGL_PLL1X_FSM_STATE_IDDQ, ++ MLXBF_GIGE_UGL_PLL1X_FSM_STATE_SLEEP, ++ MLXBF_GIGE_UGL_PLL1X_FSM_STATE_RCAL_DONE_WAIT1, ++ MLXBF_GIGE_UGL_PLL1X_FSM_STATE_RCAL_DONE_WAIT0, ++ MLXBF_GIGE_UGL_PLL1X_FSM_STATE_IDLE, ++ MLXBF_GIGE_UGL_PLL1X_FSM_STATE_CAL_DONE_WAIT1, ++ MLXBF_GIGE_UGL_PLL1X_FSM_STATE_CAL_DONE_WAIT0, ++ MLXBF_GIGE_UGL_PLL1X_FSM_STATE_ACTIVE, ++ MLXBF_GIGE_UGL_PLL1X_FSM_STATE_LOCK, ++ MLXBF_GIGE_UGL_PLL1X_FSM_STATE_SPEED_CHANGE ++}; ++ ++enum { ++ MLXBF_GIGE_TX_FSM_IDDQ, ++ MLXBF_GIGE_TX_FSM_SLEEP, ++ MLXBF_GIGE_TX_FSM_SPEED_CHANGE, ++ MLXBF_GIGE_TX_FSM_POWERUP, ++ MLXBF_GIGE_TX_UGL_TX_POWERUP, ++ MLXBF_GIGE_TX_CAL_DONE_WAIT1, ++ MLXBF_GIGE_TX_CAL_ABORT, ++ MLXBF_GIGE_TX_CAL_ABORT_DONE_WAIT1, ++ MLXBF_GIGE_TX_CAL_DONE_WAIT0, ++ MLXBF_GIGE_TX_CAL_DONE, ++ MLXBF_GIGE_TX_DATA_READY, ++ MLXBF_GIGE_TX_DATA_EN_RDY, ++ MLXBF_GIGE_TX_DATA_EN ++}; ++ ++enum { ++ MLXBF_GIGE_RX_FSM_IDDQ, ++ MLXBF_GIGE_RX_FSM_SLEEP, ++ MLXBF_GIGE_RX_FSM_SPEED_CHANGE, ++ MLXBF_GIGE_RX_FSM_POWERUP, ++ MLXBF_GIGE_RX_FSM_CAL, ++ MLXBF_GIGE_RX_FSM_WAIT_TERM, ++ MLXBF_GIGE_RX_FSM_DATA_EN_RDY, ++ MLXBF_GIGE_RX_FSM_DATA_EN, ++ MLXBF_GIGE_RX_FSM_CDR_EN, ++ MLXBF_GIGE_RX_FSM_ACTIVE, ++ MLXBF_GIGE_RX_FSM_EQ, ++ MLXBF_GIGE_RX_FSM_EOM ++}; ++ ++#define MLXBF_GIGE_PLL_STAB_TIME 6 /* us */ ++#define MLXBF_GIGE_PLL_DLM_IMEM_CSUM_TIMEOUT 15 /* us */ ++ ++struct mlxbf_gige_uphy_cfg_reg { ++ u16 addr; ++ u16 wdata; ++}; ++ ++int mlxbf_gige_config_uphy(struct mlxbf_gige *priv); ++ ++#endif /* __MLXBF_GIGE_UPHY_H__ */ +-- +2.20.1 + diff --git a/patch/0242-UBUNTU-SAUCE-mlxbf_gige-add-BlueField-3-ethtool_ops.patch b/patch/0242-UBUNTU-SAUCE-mlxbf_gige-add-BlueField-3-ethtool_ops.patch new file mode 100644 index 000000000..d08aafb30 --- /dev/null +++ b/patch/0242-UBUNTU-SAUCE-mlxbf_gige-add-BlueField-3-ethtool_ops.patch @@ -0,0 +1,95 @@ +From 33acf11a1ea46d88fbb27afff1537bdf5dd0e822 Mon Sep 17 00:00:00 2001 +From: David Thompson +Date: Fri, 28 Oct 2022 18:08:46 -0400 +Subject: [PATCH backport 5.10 43/63] UBUNTU: SAUCE: mlxbf_gige: add + BlueField-3 ethtool_ops + +BugLink: https://bugs.launchpad.net/bugs/1995148 + +This patch adds logic to support initialization of a +BlueField-3 specific "ethtool_ops" data structure. The +BlueField-3 data structure supports the "set_link_ksettings" +callback, while the BlueField-2 data structure does not. + +Signed-off-by: David Thompson +Signed-off-by: Asmaa Mnebhi +--- + .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 3 ++- + .../mellanox/mlxbf_gige/mlxbf_gige_ethtool.c | 17 ++++++++++++++++- + .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 4 +++- + 3 files changed, 21 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +index e9bd09ee0..cbabdac3e 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +@@ -200,7 +200,8 @@ struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv, + int mlxbf_gige_request_irqs(struct mlxbf_gige *priv); + void mlxbf_gige_free_irqs(struct mlxbf_gige *priv); + int mlxbf_gige_poll(struct napi_struct *napi, int budget); +-extern const struct ethtool_ops mlxbf_gige_ethtool_ops; ++extern const struct ethtool_ops mlxbf_gige_bf2_ethtool_ops; ++extern const struct ethtool_ops mlxbf_gige_bf3_ethtool_ops; + void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv); + + #endif /* !defined(__MLXBF_GIGE_H__) */ +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c +index 257724323..3156ef064 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c +@@ -158,7 +158,7 @@ static void mlxbf_gige_get_pauseparam(struct net_device *netdev, + pause->tx_pause = 1; + } + +-const struct ethtool_ops mlxbf_gige_ethtool_ops = { ++const struct ethtool_ops mlxbf_gige_bf2_ethtool_ops = { + .get_link = ethtool_op_get_link, + .get_ringparam = mlxbf_gige_get_ringparam, + .set_ringparam = mlxbf_gige_set_ringparam, +@@ -171,3 +171,18 @@ const struct ethtool_ops mlxbf_gige_ethtool_ops = { + .get_pauseparam = mlxbf_gige_get_pauseparam, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + }; ++ ++const struct ethtool_ops mlxbf_gige_bf3_ethtool_ops = { ++ .get_link = ethtool_op_get_link, ++ .get_ringparam = mlxbf_gige_get_ringparam, ++ .set_ringparam = mlxbf_gige_set_ringparam, ++ .get_regs_len = mlxbf_gige_get_regs_len, ++ .get_regs = mlxbf_gige_get_regs, ++ .get_strings = mlxbf_gige_get_strings, ++ .get_sset_count = mlxbf_gige_get_sset_count, ++ .get_ethtool_stats = mlxbf_gige_get_ethtool_stats, ++ .nway_reset = phy_ethtool_nway_reset, ++ .get_pauseparam = mlxbf_gige_get_pauseparam, ++ .get_link_ksettings = phy_ethtool_get_link_ksettings, ++ .set_link_ksettings = phy_ethtool_set_link_ksettings, ++}; +diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +index f97e49670..197ec8ccb 100644 +--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c ++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +@@ -451,7 +451,6 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + + SET_NETDEV_DEV(netdev, &pdev->dev); + netdev->netdev_ops = &mlxbf_gige_netdev_ops; +- netdev->ethtool_ops = &mlxbf_gige_ethtool_ops; + priv = netdev_priv(netdev); + priv->netdev = netdev; + +@@ -468,9 +467,12 @@ static int mlxbf_gige_probe(struct platform_device *pdev) + priv->hw_version = soc_version; + + if (priv->hw_version == MLXBF_GIGE_VERSION_BF3) { ++ netdev->ethtool_ops = &mlxbf_gige_bf3_ethtool_ops; + err = mlxbf_gige_config_uphy(priv); + if (err) + return err; ++ } else { ++ netdev->ethtool_ops = &mlxbf_gige_bf2_ethtool_ops; + } + + /* Attach MDIO device */ +-- +2.20.1 + diff --git a/patch/0243-UBUNTU-SAUCE-bluefield_edac-Add-SMC-support.patch b/patch/0243-UBUNTU-SAUCE-bluefield_edac-Add-SMC-support.patch new file mode 100644 index 000000000..51f40a5b7 --- /dev/null +++ b/patch/0243-UBUNTU-SAUCE-bluefield_edac-Add-SMC-support.patch @@ -0,0 +1,291 @@ +From 9bebe7236f4e3d956feda9911ffee5f31dfbdb13 Mon Sep 17 00:00:00 2001 +From: Shravan Kumar Ramani +Date: Wed, 6 Jul 2022 03:37:38 -0400 +Subject: [PATCH backport 5.10 44/63] UBUNTU: SAUCE: bluefield_edac: Add SMC + support + +BugLink: https://launchpad.net/bugs/1980812 + +This patch adds secure read/write calls to bluefield_edac. The +ACPI table entry decides whether the secure calls need to be +used for accessing the EMI registers. + +Signed-off-by: Shravan Kumar Ramani +Signed-off-by: Ike Panhc +--- + drivers/edac/bluefield_edac.c | 168 +++++++++++++++++++++++++++++++--- + 1 file changed, 154 insertions(+), 14 deletions(-) + +diff --git a/drivers/edac/bluefield_edac.c b/drivers/edac/bluefield_edac.c +index e4736eb37..8e1127a56 100644 +--- a/drivers/edac/bluefield_edac.c ++++ b/drivers/edac/bluefield_edac.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include "edac_module.h" + +@@ -47,6 +48,18 @@ + #define MLXBF_EDAC_MAX_DIMM_PER_MC 2 + #define MLXBF_EDAC_ERROR_GRAIN 8 + ++#define MLNX_WRITE_REG_32 (0x82000009) ++#define MLNX_READ_REG_32 (0x8200000A) ++#define MLNX_WRITE_REG_64 (0x8200000B) ++#define MLNX_READ_REG_64 (0x8200000C) ++#define MLNX_SIP_SVC_UID (0x8200ff01) ++#define MLNX_SIP_SVC_VERSION (0x8200ff03) ++ ++#define SMCCC_ACCESS_VIOLATION (-4) ++ ++#define MLNX_EDAC_SVC_REQ_MAJOR 0 ++#define MLNX_EDAC_SVC_MIN_MINOR 3 ++ + /* + * Request MLNX_SIP_GET_DIMM_INFO + * +@@ -72,9 +85,12 @@ + #define MLXBF_DIMM_INFO__PACKAGE_X GENMASK_ULL(31, 24) + + struct bluefield_edac_priv { ++ struct device *dev; + int dimm_ranks[MLXBF_EDAC_MAX_DIMM_PER_MC]; + void __iomem *emi_base; + int dimm_per_mc; ++ bool svc_sreg_support; ++ uint32_t sreg_tbl_edac; + }; + + static u64 smc_call1(u64 smc_op, u64 smc_arg) +@@ -86,6 +102,73 @@ static u64 smc_call1(u64 smc_op, u64 smc_arg) + return res.a0; + } + ++static int secure_readl(void __iomem *addr, uint32_t *result, uint32_t sreg_tbl) ++{ ++ struct arm_smccc_res res; ++ int status; ++ ++ arm_smccc_smc(MLNX_READ_REG_32, sreg_tbl, (uintptr_t) addr, ++ 0, 0, 0, 0, 0, &res); ++ ++ status = res.a0; ++ ++ switch (status) { ++ case SMCCC_RET_NOT_SUPPORTED: ++ case SMCCC_ACCESS_VIOLATION: ++ return -1; ++ default: ++ *result = (uint32_t)res.a1; ++ return 0; ++ } ++ ++} ++ ++static int secure_writel(void __iomem *addr, uint32_t data, uint32_t sreg_tbl) ++{ ++ struct arm_smccc_res res; ++ int status; ++ ++ arm_smccc_smc(MLNX_WRITE_REG_32, sreg_tbl, data, (uintptr_t) addr, ++ 0, 0, 0, 0, &res); ++ ++ status = res.a0; ++ ++ switch (status) { ++ case SMCCC_RET_NOT_SUPPORTED: ++ case SMCCC_ACCESS_VIOLATION: ++ return -1; ++ default: ++ return 0; ++ } ++ ++} ++ ++static int edac_readl(void __iomem *addr, uint32_t *result, ++ bool sreg_support, uint32_t sreg_tbl) ++{ ++ int err = 0; ++ ++ if (sreg_support) ++ err = secure_readl(addr, result, sreg_tbl); ++ else ++ *result = readl(addr); ++ ++ return err; ++} ++ ++static int edac_writel(void __iomem *addr, uint32_t data, ++ bool sreg_support, uint32_t sreg_tbl) ++{ ++ int err = 0; ++ ++ if (sreg_support) ++ err = secure_writel(addr, data, sreg_tbl); ++ else ++ writel(data, addr); ++ ++ return err; ++} ++ + /* + * Gather the ECC information from the External Memory Interface registers + * and report it to the edac handler. +@@ -99,7 +182,7 @@ static void bluefield_gather_report_ecc(struct mem_ctl_info *mci, + u32 ecc_latch_select, dram_syndrom, serr, derr, syndrom; + enum hw_event_mc_err_type ecc_type; + u64 ecc_dimm_addr; +- int ecc_dimm; ++ int ecc_dimm, err; + + ecc_type = is_single_ecc ? HW_EVENT_ERR_CORRECTED : + HW_EVENT_ERR_UNCORRECTED; +@@ -109,14 +192,22 @@ static void bluefield_gather_report_ecc(struct mem_ctl_info *mci, + * registers with information about the last ECC error occurrence. + */ + ecc_latch_select = MLXBF_ECC_LATCH_SEL__START; +- writel(ecc_latch_select, priv->emi_base + MLXBF_ECC_LATCH_SEL); ++ err = edac_writel(priv->emi_base + MLXBF_ECC_LATCH_SEL, ++ ecc_latch_select, priv->svc_sreg_support, ++ priv->sreg_tbl_edac); ++ if (err) ++ dev_err(priv->dev, "ECC latch select write failed.\n"); + + /* + * Verify that the ECC reported info in the registers is of the + * same type as the one asked to report. If not, just report the + * error without the detailed information. + */ +- dram_syndrom = readl(priv->emi_base + MLXBF_SYNDROM); ++ err = edac_readl(priv->emi_base + MLXBF_SYNDROM, &dram_syndrom, ++ priv->svc_sreg_support, priv->sreg_tbl_edac); ++ if (err) ++ dev_err(priv->dev, "DRAM syndrom read failed.\n"); ++ + serr = FIELD_GET(MLXBF_SYNDROM__SERR, dram_syndrom); + derr = FIELD_GET(MLXBF_SYNDROM__DERR, dram_syndrom); + syndrom = FIELD_GET(MLXBF_SYNDROM__SYN, dram_syndrom); +@@ -127,13 +218,24 @@ static void bluefield_gather_report_ecc(struct mem_ctl_info *mci, + return; + } + +- dram_additional_info = readl(priv->emi_base + MLXBF_ADD_INFO); ++ err = edac_readl(priv->emi_base + MLXBF_ADD_INFO, &dram_additional_info, ++ priv->svc_sreg_support, priv->sreg_tbl_edac); ++ if (err) ++ dev_err(priv->dev, "DRAM additional info read failed.\n"); ++ + err_prank = FIELD_GET(MLXBF_ADD_INFO__ERR_PRANK, dram_additional_info); + + ecc_dimm = (err_prank >= 2 && priv->dimm_ranks[0] <= 2) ? 1 : 0; + +- edea0 = readl(priv->emi_base + MLXBF_ERR_ADDR_0); +- edea1 = readl(priv->emi_base + MLXBF_ERR_ADDR_1); ++ err = edac_readl(priv->emi_base + MLXBF_ERR_ADDR_0, &edea0, ++ priv->svc_sreg_support, priv->sreg_tbl_edac); ++ if (err) ++ dev_err(priv->dev, "Error addr 0 read failed.\n"); ++ ++ err = edac_readl(priv->emi_base + MLXBF_ERR_ADDR_1, &edea1, ++ priv->svc_sreg_support, priv->sreg_tbl_edac); ++ if (err) ++ dev_err(priv->dev, "Error addr 1 read failed.\n"); + + ecc_dimm_addr = ((u64)edea1 << 32) | edea0; + +@@ -147,6 +249,7 @@ static void bluefield_edac_check(struct mem_ctl_info *mci) + { + struct bluefield_edac_priv *priv = mci->pvt_info; + u32 ecc_count, single_error_count, double_error_count, ecc_error = 0; ++ int err; + + /* + * The memory controller might not be initialized by the firmware +@@ -155,7 +258,11 @@ static void bluefield_edac_check(struct mem_ctl_info *mci) + if (mci->edac_cap == EDAC_FLAG_NONE) + return; + +- ecc_count = readl(priv->emi_base + MLXBF_ECC_CNT); ++ err = edac_readl(priv->emi_base + MLXBF_ECC_CNT, &ecc_count, ++ priv->svc_sreg_support, priv->sreg_tbl_edac); ++ if (err) ++ dev_err(priv->dev, "ECC count read failed.\n"); ++ + single_error_count = FIELD_GET(MLXBF_ECC_CNT__SERR_CNT, ecc_count); + double_error_count = FIELD_GET(MLXBF_ECC_CNT__DERR_CNT, ecc_count); + +@@ -172,8 +279,12 @@ static void bluefield_edac_check(struct mem_ctl_info *mci) + } + + /* Write to clear reported errors. */ +- if (ecc_count) +- writel(ecc_error, priv->emi_base + MLXBF_ECC_ERR); ++ if (ecc_count) { ++ err = edac_writel(priv->emi_base + MLXBF_ECC_ERR, ecc_error, ++ priv->svc_sreg_support, priv->sreg_tbl_edac); ++ if (err) ++ dev_err(priv->dev, "ECC Error write failed.\n"); ++ } + } + + /* Initialize the DIMMs information for the given memory controller. */ +@@ -244,6 +355,7 @@ static int bluefield_edac_mc_probe(struct platform_device *pdev) + struct bluefield_edac_priv *priv; + struct device *dev = &pdev->dev; + struct edac_mc_layer layers[1]; ++ struct arm_smccc_res res; + struct mem_ctl_info *mci; + struct resource *emi_res; + unsigned int mc_idx, dimm_count; +@@ -280,12 +392,40 @@ static int bluefield_edac_mc_probe(struct platform_device *pdev) + + priv = mci->pvt_info; + ++ /* ++ * ACPI indicates whether we use SMCs to access registers or not. ++ * If sreg_tbl_perf is not present, just assume we're not using SMCs. ++ */ ++ if (device_property_read_u32(dev, ++ "sec_reg_block", &priv->sreg_tbl_edac)) { ++ priv->svc_sreg_support = false; ++ } else { ++ /* ++ * Check service version to see if we actually do support the ++ * needed SMCs. If we have the calls we need, mark support for ++ * them in the pmc struct. ++ */ ++ arm_smccc_smc(MLNX_SIP_SVC_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); ++ if (res.a0 == MLNX_EDAC_SVC_REQ_MAJOR && ++ res.a1 >= MLNX_EDAC_SVC_MIN_MINOR) ++ priv->svc_sreg_support = true; ++ else { ++ dev_err(dev, "Required SMCs are not supported.\n"); ++ ret = -EINVAL; ++ goto err; ++ } ++ } ++ + priv->dimm_per_mc = dimm_count; +- priv->emi_base = devm_ioremap_resource(dev, emi_res); +- if (IS_ERR(priv->emi_base)) { +- dev_err(dev, "failed to map EMI IO resource\n"); +- ret = PTR_ERR(priv->emi_base); +- goto err; ++ if (!priv->svc_sreg_support) { ++ priv->emi_base = devm_ioremap_resource(dev, emi_res); ++ if (IS_ERR(priv->emi_base)) { ++ dev_err(dev, "failed to map EMI IO resource\n"); ++ ret = PTR_ERR(priv->emi_base); ++ goto err; ++ } ++ } else { ++ priv->emi_base = (void __iomem *) emi_res->start; + } + + mci->pdev = dev; +-- +2.20.1 + diff --git a/patch/0244-UBUNTU-SAUCE-bluefield_edac-Update-license-and-copyr.patch b/patch/0244-UBUNTU-SAUCE-bluefield_edac-Update-license-and-copyr.patch new file mode 100644 index 000000000..1e80cc4bb --- /dev/null +++ b/patch/0244-UBUNTU-SAUCE-bluefield_edac-Update-license-and-copyr.patch @@ -0,0 +1,40 @@ +From 8f60f2a6f44e75005bb94add0288d2c390870b11 Mon Sep 17 00:00:00 2001 +From: Shravan Kumar Ramani +Date: Thu, 7 Jul 2022 05:13:21 -0400 +Subject: [PATCH backport 5.10 45/63] UBUNTU: SAUCE: bluefield_edac: Update + license and copyright info + +BugLink: https://launchpad.net/bugs/1980812 + +Signed-off-by: Shravan Kumar Ramani +Signed-off-by: Ike Panhc +--- + drivers/edac/bluefield_edac.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/edac/bluefield_edac.c b/drivers/edac/bluefield_edac.c +index 8e1127a56..c21eb015f 100644 +--- a/drivers/edac/bluefield_edac.c ++++ b/drivers/edac/bluefield_edac.c +@@ -1,8 +1,8 @@ +-// SPDX-License-Identifier: GPL-2.0 ++// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause + /* + * Bluefield-specific EDAC driver. + * +- * Copyright (c) 2019 Mellanox Technologies. ++ * Copyright (c) 2022 NVIDIA Corporation. + */ + + #include +@@ -492,5 +492,5 @@ static struct platform_driver bluefield_edac_mc_driver = { + module_platform_driver(bluefield_edac_mc_driver); + + MODULE_DESCRIPTION("Mellanox BlueField memory edac driver"); +-MODULE_AUTHOR("Mellanox Technologies"); +-MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Shravan Kumar Ramani "); ++MODULE_LICENSE("Dual BSD/GPL"); +-- +2.20.1 + diff --git a/patch/0245-gpio-mlxbf2-Convert-to-device-PM-ops.patch b/patch/0245-gpio-mlxbf2-Convert-to-device-PM-ops.patch new file mode 100644 index 000000000..18c464770 --- /dev/null +++ b/patch/0245-gpio-mlxbf2-Convert-to-device-PM-ops.patch @@ -0,0 +1,93 @@ +From c1facb3e3527a3f0d9125cc2336ae407acbbcc03 Mon Sep 17 00:00:00 2001 +From: Andy Shevchenko +Date: Mon, 16 Aug 2021 14:59:48 +0300 +Subject: [PATCH backport 5.10 46/63] gpio: mlxbf2: Convert to device PM ops + +Convert driver to use modern device PM ops interface. + +Signed-off-by: Andy Shevchenko +Acked-by: Asmaa Mnebhi +Signed-off-by: Bartosz Golaszewski +--- + drivers/gpio/gpio-mlxbf2.c | 21 ++++++--------------- + 1 file changed, 6 insertions(+), 15 deletions(-) + +diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c +index befa5e109..68c471c10 100644 +--- a/drivers/gpio/gpio-mlxbf2.c ++++ b/drivers/gpio/gpio-mlxbf2.c +@@ -47,12 +47,10 @@ + #define YU_GPIO_MODE0_SET 0x54 + #define YU_GPIO_MODE0_CLEAR 0x58 + +-#ifdef CONFIG_PM + struct mlxbf2_gpio_context_save_regs { + u32 gpio_mode0; + u32 gpio_mode1; + }; +-#endif + + /* BlueField-2 gpio block context structure. */ + struct mlxbf2_gpio_context { +@@ -61,9 +59,7 @@ struct mlxbf2_gpio_context { + /* YU GPIO blocks address */ + void __iomem *gpio_io; + +-#ifdef CONFIG_PM + struct mlxbf2_gpio_context_save_regs *csave_regs; +-#endif + }; + + /* BlueField-2 gpio shared structure. */ +@@ -284,11 +280,9 @@ mlxbf2_gpio_probe(struct platform_device *pdev) + return 0; + } + +-#ifdef CONFIG_PM +-static int mlxbf2_gpio_suspend(struct platform_device *pdev, +- pm_message_t state) ++static int __maybe_unused mlxbf2_gpio_suspend(struct device *dev) + { +- struct mlxbf2_gpio_context *gs = platform_get_drvdata(pdev); ++ struct mlxbf2_gpio_context *gs = dev_get_drvdata(dev); + + gs->csave_regs->gpio_mode0 = readl(gs->gpio_io + + YU_GPIO_MODE0); +@@ -298,9 +292,9 @@ static int mlxbf2_gpio_suspend(struct platform_device *pdev, + return 0; + } + +-static int mlxbf2_gpio_resume(struct platform_device *pdev) ++static int __maybe_unused mlxbf2_gpio_resume(struct device *dev) + { +- struct mlxbf2_gpio_context *gs = platform_get_drvdata(pdev); ++ struct mlxbf2_gpio_context *gs = dev_get_drvdata(dev); + + writel(gs->csave_regs->gpio_mode0, gs->gpio_io + + YU_GPIO_MODE0); +@@ -309,7 +303,7 @@ static int mlxbf2_gpio_resume(struct platform_device *pdev) + + return 0; + } +-#endif ++static SIMPLE_DEV_PM_OPS(mlxbf2_pm_ops, mlxbf2_gpio_suspend, mlxbf2_gpio_resume); + + static const struct acpi_device_id __maybe_unused mlxbf2_gpio_acpi_match[] = { + { "MLNXBF22", 0 }, +@@ -321,12 +315,9 @@ static struct platform_driver mlxbf2_gpio_driver = { + .driver = { + .name = "mlxbf2_gpio", + .acpi_match_table = ACPI_PTR(mlxbf2_gpio_acpi_match), ++ .pm = &mlxbf2_pm_ops, + }, + .probe = mlxbf2_gpio_probe, +-#ifdef CONFIG_PM +- .suspend = mlxbf2_gpio_suspend, +- .resume = mlxbf2_gpio_resume, +-#endif + }; + + module_platform_driver(mlxbf2_gpio_driver); +-- +2.20.1 + diff --git a/patch/0246-gpio-mlxbf2-Drop-wrong-use-of-ACPI_PTR.patch b/patch/0246-gpio-mlxbf2-Drop-wrong-use-of-ACPI_PTR.patch new file mode 100644 index 000000000..7f5810160 --- /dev/null +++ b/patch/0246-gpio-mlxbf2-Drop-wrong-use-of-ACPI_PTR.patch @@ -0,0 +1,50 @@ +From 6b12d567b86b79ff28397aa428778d9f159fb8da Mon Sep 17 00:00:00 2001 +From: Andy Shevchenko +Date: Mon, 16 Aug 2021 14:59:49 +0300 +Subject: [PATCH backport 5.10 47/63] gpio: mlxbf2: Drop wrong use of + ACPI_PTR() + +ACPI_PTR() is more harmful than helpful. For example, in this case +if CONFIG_ACPI=n, the ID table left unused which is not what we want. + +Instead of adding ifdeffery here and there, drop ACPI_PTR() and +replace acpi.h with mod_devicetable.h. + +Signed-off-by: Andy Shevchenko +Acked-by: Asmaa Mnehi +Signed-off-by: Bartosz Golaszewski +--- + drivers/gpio/gpio-mlxbf2.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c +index 68c471c10..8e6f78092 100644 +--- a/drivers/gpio/gpio-mlxbf2.c ++++ b/drivers/gpio/gpio-mlxbf2.c +@@ -1,6 +1,5 @@ + // SPDX-License-Identifier: GPL-2.0 + +-#include + #include + #include + #include +@@ -8,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -314,7 +314,7 @@ MODULE_DEVICE_TABLE(acpi, mlxbf2_gpio_acpi_match); + static struct platform_driver mlxbf2_gpio_driver = { + .driver = { + .name = "mlxbf2_gpio", +- .acpi_match_table = ACPI_PTR(mlxbf2_gpio_acpi_match), ++ .acpi_match_table = mlxbf2_gpio_acpi_match, + .pm = &mlxbf2_pm_ops, + }, + .probe = mlxbf2_gpio_probe, +-- +2.20.1 + diff --git a/patch/0247-gpio-mlxbf2-Use-devm_platform_ioremap_resource.patch b/patch/0247-gpio-mlxbf2-Use-devm_platform_ioremap_resource.patch new file mode 100644 index 000000000..dc24c6dc4 --- /dev/null +++ b/patch/0247-gpio-mlxbf2-Use-devm_platform_ioremap_resource.patch @@ -0,0 +1,48 @@ +From a75294f3e540e2d76a39583dbae875c428196f79 Mon Sep 17 00:00:00 2001 +From: Andy Shevchenko +Date: Mon, 16 Aug 2021 14:59:50 +0300 +Subject: [PATCH backport 5.10 48/63] gpio: mlxbf2: Use + devm_platform_ioremap_resource() + +Simplify the platform_get_resource() and devm_ioremap_resource() +calls with devm_platform_ioremap_resource(). + +Signed-off-by: Andy Shevchenko +Acked-by: Asmaa Mnebhi +Signed-off-by: Bartosz Golaszewski +--- + drivers/gpio/gpio-mlxbf2.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c +index 8e6f78092..661d5a831 100644 +--- a/drivers/gpio/gpio-mlxbf2.c ++++ b/drivers/gpio/gpio-mlxbf2.c +@@ -228,7 +228,6 @@ mlxbf2_gpio_probe(struct platform_device *pdev) + struct mlxbf2_gpio_context *gs; + struct device *dev = &pdev->dev; + struct gpio_chip *gc; +- struct resource *res; + unsigned int npins; + int ret; + +@@ -237,13 +236,9 @@ mlxbf2_gpio_probe(struct platform_device *pdev) + return -ENOMEM; + + /* YU GPIO block address */ +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!res) +- return -ENODEV; +- +- gs->gpio_io = devm_ioremap(dev, res->start, resource_size(res)); +- if (!gs->gpio_io) +- return -ENOMEM; ++ gs->gpio_io = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(gs->gpio_io)) ++ return PTR_ERR(gs->gpio_io); + + ret = mlxbf2_gpio_get_lock_res(pdev); + if (ret) { +-- +2.20.1 + diff --git a/patch/0248-gpio-mlxbf2-Use-DEFINE_RES_MEM_NAMED-helper-macro.patch b/patch/0248-gpio-mlxbf2-Use-DEFINE_RES_MEM_NAMED-helper-macro.patch new file mode 100644 index 000000000..441d83e30 --- /dev/null +++ b/patch/0248-gpio-mlxbf2-Use-DEFINE_RES_MEM_NAMED-helper-macro.patch @@ -0,0 +1,37 @@ +From e3e44e5389d723c49f187d91c16df0ec1b67ce53 Mon Sep 17 00:00:00 2001 +From: Andy Shevchenko +Date: Mon, 16 Aug 2021 14:59:51 +0300 +Subject: [PATCH backport 5.10 49/63] gpio: mlxbf2: Use DEFINE_RES_MEM_NAMED() + helper macro + +Use DEFINE_RES_MEM_NAMED() to save a couple of lines of code, which makes +the code a bit shorter and easier to read. + +Signed-off-by: Andy Shevchenko +Acked-by: Asmaa Mnebhi +Signed-off-by: Bartosz Golaszewski +--- + drivers/gpio/gpio-mlxbf2.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c +index 661d5a831..177d03ef4 100644 +--- a/drivers/gpio/gpio-mlxbf2.c ++++ b/drivers/gpio/gpio-mlxbf2.c +@@ -69,11 +69,8 @@ struct mlxbf2_gpio_param { + struct mutex *lock; + }; + +-static struct resource yu_arm_gpio_lock_res = { +- .start = YU_ARM_GPIO_LOCK_ADDR, +- .end = YU_ARM_GPIO_LOCK_ADDR + YU_ARM_GPIO_LOCK_SIZE - 1, +- .name = "YU_ARM_GPIO_LOCK", +-}; ++static struct resource yu_arm_gpio_lock_res = ++ DEFINE_RES_MEM_NAMED(YU_ARM_GPIO_LOCK_ADDR, YU_ARM_GPIO_LOCK_SIZE, "YU_ARM_GPIO_LOCK"); + + static DEFINE_MUTEX(yu_arm_gpio_lock_mutex); + +-- +2.20.1 + diff --git a/patch/0249-gpio-mlxbf2-Introduce-IRQ-support.patch b/patch/0249-gpio-mlxbf2-Introduce-IRQ-support.patch new file mode 100644 index 000000000..0bde44f14 --- /dev/null +++ b/patch/0249-gpio-mlxbf2-Introduce-IRQ-support.patch @@ -0,0 +1,222 @@ +From 1eac5d74f7cd42e661479080a47547b657c16a18 Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Fri, 15 Oct 2021 12:48:08 -0400 +Subject: [PATCH backport 5.10 51/63] gpio: mlxbf2: Introduce IRQ support + +BugLink: https://bugs.launchpad.net/bugs/1979827 + +Introduce standard IRQ handling in the gpio-mlxbf2.c +driver. + +Signed-off-by: Asmaa Mnebhi +Acked-by: David S. Miller +Signed-off-by: Bartosz Golaszewski +(cherry picked from commit 2b725265cb08d6a0001bf81631ccb5728d095229) +Signed-off-by: Ike Panhc +--- + drivers/gpio/gpio-mlxbf2.c | 142 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 140 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c +index 40a052bc6..3d89912a0 100644 +--- a/drivers/gpio/gpio-mlxbf2.c ++++ b/drivers/gpio/gpio-mlxbf2.c +@@ -1,9 +1,14 @@ + // SPDX-License-Identifier: GPL-2.0 + ++/* ++ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES ++ */ ++ + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -43,9 +48,14 @@ + #define YU_GPIO_MODE0 0x0c + #define YU_GPIO_DATASET 0x14 + #define YU_GPIO_DATACLEAR 0x18 ++#define YU_GPIO_CAUSE_RISE_EN 0x44 ++#define YU_GPIO_CAUSE_FALL_EN 0x48 + #define YU_GPIO_MODE1_CLEAR 0x50 + #define YU_GPIO_MODE0_SET 0x54 + #define YU_GPIO_MODE0_CLEAR 0x58 ++#define YU_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x80 ++#define YU_GPIO_CAUSE_OR_EVTEN0 0x94 ++#define YU_GPIO_CAUSE_OR_CLRCAUSE 0x98 + + struct mlxbf2_gpio_context_save_regs { + u32 gpio_mode0; +@@ -55,6 +65,7 @@ struct mlxbf2_gpio_context_save_regs { + /* BlueField-2 gpio block context structure. */ + struct mlxbf2_gpio_context { + struct gpio_chip gc; ++ struct irq_chip irq_chip; + + /* YU GPIO blocks address */ + void __iomem *gpio_io; +@@ -218,15 +229,114 @@ static int mlxbf2_gpio_direction_output(struct gpio_chip *chip, + return ret; + } + ++static void mlxbf2_gpio_irq_enable(struct irq_data *irqd) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); ++ struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc); ++ int offset = irqd_to_hwirq(irqd); ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(&gs->gc.bgpio_lock, flags); ++ val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); ++ val |= BIT(offset); ++ writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); ++ ++ val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); ++ val |= BIT(offset); ++ writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); ++ spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); ++} ++ ++static void mlxbf2_gpio_irq_disable(struct irq_data *irqd) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); ++ struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc); ++ int offset = irqd_to_hwirq(irqd); ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(&gs->gc.bgpio_lock, flags); ++ val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); ++ val &= ~BIT(offset); ++ writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); ++ spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); ++} ++ ++static irqreturn_t mlxbf2_gpio_irq_handler(int irq, void *ptr) ++{ ++ struct mlxbf2_gpio_context *gs = ptr; ++ struct gpio_chip *gc = &gs->gc; ++ unsigned long pending; ++ u32 level; ++ ++ pending = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CAUSE_EVTEN0); ++ writel(pending, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); ++ ++ for_each_set_bit(level, &pending, gc->ngpio) { ++ int gpio_irq = irq_find_mapping(gc->irq.domain, level); ++ generic_handle_irq(gpio_irq); ++ } ++ ++ return IRQ_RETVAL(pending); ++} ++ ++static int ++mlxbf2_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); ++ struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc); ++ int offset = irqd_to_hwirq(irqd); ++ unsigned long flags; ++ bool fall = false; ++ bool rise = false; ++ u32 val; ++ ++ switch (type & IRQ_TYPE_SENSE_MASK) { ++ case IRQ_TYPE_EDGE_BOTH: ++ fall = true; ++ rise = true; ++ break; ++ case IRQ_TYPE_EDGE_RISING: ++ rise = true; ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ fall = true; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&gs->gc.bgpio_lock, flags); ++ if (fall) { ++ val = readl(gs->gpio_io + YU_GPIO_CAUSE_FALL_EN); ++ val |= BIT(offset); ++ writel(val, gs->gpio_io + YU_GPIO_CAUSE_FALL_EN); ++ } ++ ++ if (rise) { ++ val = readl(gs->gpio_io + YU_GPIO_CAUSE_RISE_EN); ++ val |= BIT(offset); ++ writel(val, gs->gpio_io + YU_GPIO_CAUSE_RISE_EN); ++ } ++ spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); ++ ++ return 0; ++} ++ + /* BlueField-2 GPIO driver initialization routine. */ + static int + mlxbf2_gpio_probe(struct platform_device *pdev) + { + struct mlxbf2_gpio_context *gs; + struct device *dev = &pdev->dev; ++ struct gpio_irq_chip *girq; + struct gpio_chip *gc; + unsigned int npins; +- int ret; ++ const char *name; ++ int ret, irq; ++ ++ name = dev_name(dev); + + gs = devm_kzalloc(dev, sizeof(*gs), GFP_KERNEL); + if (!gs) +@@ -266,6 +376,34 @@ mlxbf2_gpio_probe(struct platform_device *pdev) + gc->ngpio = npins; + gc->owner = THIS_MODULE; + ++ irq = platform_get_irq(pdev, 0); ++ if (irq >= 0) { ++ gs->irq_chip.name = name; ++ gs->irq_chip.irq_set_type = mlxbf2_gpio_irq_set_type; ++ gs->irq_chip.irq_enable = mlxbf2_gpio_irq_enable; ++ gs->irq_chip.irq_disable = mlxbf2_gpio_irq_disable; ++ ++ girq = &gs->gc.irq; ++ girq->chip = &gs->irq_chip; ++ girq->handler = handle_simple_irq; ++ girq->default_type = IRQ_TYPE_NONE; ++ /* This will let us handle the parent IRQ in the driver */ ++ girq->num_parents = 0; ++ girq->parents = NULL; ++ girq->parent_handler = NULL; ++ ++ /* ++ * Directly request the irq here instead of passing ++ * a flow-handler because the irq is shared. ++ */ ++ ret = devm_request_irq(dev, irq, mlxbf2_gpio_irq_handler, ++ IRQF_SHARED, name, gs); ++ if (ret) { ++ dev_err(dev, "failed to request IRQ"); ++ return ret; ++ } ++ } ++ + platform_set_drvdata(pdev, gs); + + ret = devm_gpiochip_add_data(dev, &gs->gc, gs); +@@ -320,5 +458,5 @@ static struct platform_driver mlxbf2_gpio_driver = { + module_platform_driver(mlxbf2_gpio_driver); + + MODULE_DESCRIPTION("Mellanox BlueField-2 GPIO Driver"); +-MODULE_AUTHOR("Mellanox Technologies"); ++MODULE_AUTHOR("Asmaa Mnebhi "); + MODULE_LICENSE("GPL v2"); +-- +2.20.1 + diff --git a/patch/0250-UBUNTU-SAUCE-gpio-mlxbf2.c-support-driver-version.patch b/patch/0250-UBUNTU-SAUCE-gpio-mlxbf2.c-support-driver-version.patch new file mode 100644 index 000000000..1bdc64da2 --- /dev/null +++ b/patch/0250-UBUNTU-SAUCE-gpio-mlxbf2.c-support-driver-version.patch @@ -0,0 +1,35 @@ +From e71b4be56c799c407a4b8b08528dc3a1bb31cda3 Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Fri, 8 Jul 2022 16:56:40 -0400 +Subject: [PATCH backport 5.10 52/63] UBUNTU: SAUCE: gpio-mlxbf2.c: support + driver version + +BugLink: https://launchpad.net/bugs/1981108 + +Signed-off-by: Asmaa Mnebhi +Signed-off-by: Ike Panhc +--- + drivers/gpio/gpio-mlxbf2.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c +index 3d89912a0..cf9dbe8e5 100644 +--- a/drivers/gpio/gpio-mlxbf2.c ++++ b/drivers/gpio/gpio-mlxbf2.c +@@ -20,6 +20,8 @@ + #include + #include + ++#define DRV_VERSION "1.5" ++ + /* + * There are 3 YU GPIO blocks: + * gpio[0]: HOST_GPIO0->HOST_GPIO31 +@@ -460,3 +462,4 @@ module_platform_driver(mlxbf2_gpio_driver); + MODULE_DESCRIPTION("Mellanox BlueField-2 GPIO Driver"); + MODULE_AUTHOR("Asmaa Mnebhi "); + MODULE_LICENSE("GPL v2"); ++MODULE_VERSION(DRV_VERSION); +-- +2.20.1 + diff --git a/patch/0251-mmc-sdhci-of-dwcmshc-add-rockchip-platform-support.patch b/patch/0251-mmc-sdhci-of-dwcmshc-add-rockchip-platform-support.patch new file mode 100644 index 000000000..0f4e702ba --- /dev/null +++ b/patch/0251-mmc-sdhci-of-dwcmshc-add-rockchip-platform-support.patch @@ -0,0 +1,395 @@ +From 6995d23f8b01b24dd6786413f9219334136b6d32 Mon Sep 17 00:00:00 2001 +From: Shawn Lin +Date: Tue, 16 Mar 2021 15:18:22 +0800 +Subject: [PATCH backport 5.10 53/63] mmc: sdhci-of-dwcmshc: add rockchip + platform support + +sdhci based synopsys MMC IP is also used on some rockchip platforms, +so add a basic support here. + +Signed-off-by: Shawn Lin +Link: https://lore.kernel.org/r/1615879102-45919-3-git-send-email-shawn.lin@rock-chips.com +Signed-off-by: Ulf Hansson +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 261 +++++++++++++++++++++++++++- + 1 file changed, 253 insertions(+), 8 deletions(-) + +diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c +index 59d8d96ce..06873686d 100644 +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -9,9 +9,11 @@ + + #include + #include ++#include + #include + #include + #include ++#include + #include + + #include "sdhci-pltfm.h" +@@ -21,11 +23,52 @@ + /* DWCMSHC specific Mode Select value */ + #define DWCMSHC_CTRL_HS400 0x7 + ++/* DWC IP vendor area 1 pointer */ ++#define DWCMSHC_P_VENDOR_AREA1 0xe8 ++#define DWCMSHC_AREA1_MASK GENMASK(11, 0) ++/* Offset inside the vendor area 1 */ ++#define DWCMSHC_HOST_CTRL3 0x8 ++#define DWCMSHC_EMMC_CONTROL 0x2c ++#define DWCMSHC_ENHANCED_STROBE BIT(8) ++#define DWCMSHC_EMMC_ATCTRL 0x40 ++ ++/* Rockchip specific Registers */ ++#define DWCMSHC_EMMC_DLL_CTRL 0x800 ++#define DWCMSHC_EMMC_DLL_RXCLK 0x804 ++#define DWCMSHC_EMMC_DLL_TXCLK 0x808 ++#define DWCMSHC_EMMC_DLL_STRBIN 0x80c ++#define DLL_STRBIN_TAPNUM_FROM_SW BIT(24) ++#define DWCMSHC_EMMC_DLL_STATUS0 0x840 ++#define DWCMSHC_EMMC_DLL_START BIT(0) ++#define DWCMSHC_EMMC_DLL_LOCKED BIT(8) ++#define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9) ++#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29 ++#define DWCMSHC_EMMC_DLL_START_POINT 16 ++#define DWCMSHC_EMMC_DLL_INC 8 ++#define DWCMSHC_EMMC_DLL_DLYENA BIT(27) ++#define DLL_TXCLK_TAPNUM_DEFAULT 0x8 ++#define DLL_STRBIN_TAPNUM_DEFAULT 0x8 ++#define DLL_TXCLK_TAPNUM_FROM_SW BIT(24) ++#define DLL_RXCLK_NO_INVERTER 1 ++#define DLL_RXCLK_INVERTER 0 ++#define DLL_LOCK_WO_TMOUT(x) \ ++ ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \ ++ (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) ++#define RK3568_MAX_CLKS 3 ++ + #define BOUNDARY_OK(addr, len) \ + ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) + ++struct rk3568_priv { ++ /* Rockchip specified optional clocks */ ++ struct clk_bulk_data rockchip_clks[RK3568_MAX_CLKS]; ++ u8 txclk_tapnum; ++}; ++ + struct dwcmshc_priv { + struct clk *bus_clk; ++ int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */ ++ void *priv; /* pointer to SoC private stuff */ + }; + + /* +@@ -100,6 +143,107 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); + } + ++static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc, ++ struct mmc_ios *ios) ++{ ++ u32 vendor; ++ struct sdhci_host *host = mmc_priv(mmc); ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ int reg = priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL; ++ ++ vendor = sdhci_readl(host, reg); ++ if (ios->enhanced_strobe) ++ vendor |= DWCMSHC_ENHANCED_STROBE; ++ else ++ vendor &= ~DWCMSHC_ENHANCED_STROBE; ++ ++ sdhci_writel(host, vendor, reg); ++} ++ ++static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host); ++ struct rk3568_priv *priv = dwc_priv->priv; ++ u8 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; ++ u32 extra, reg; ++ int err; ++ ++ host->mmc->actual_clock = 0; ++ ++ /* ++ * DO NOT TOUCH THIS SETTING. RX clk inverter unit is enabled ++ * by default, but it shouldn't be enabled. We should anyway ++ * disable it before issuing any cmds. ++ */ ++ extra = DWCMSHC_EMMC_DLL_DLYENA | ++ DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL; ++ sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); ++ ++ if (clock == 0) ++ return; ++ ++ /* Rockchip platform only support 375KHz for identify mode */ ++ if (clock <= 400000) ++ clock = 375000; ++ ++ err = clk_set_rate(pltfm_host->clk, clock); ++ if (err) ++ dev_err(mmc_dev(host->mmc), "fail to set clock %d", clock); ++ ++ sdhci_set_clock(host, clock); ++ ++ /* Disable cmd conflict check */ ++ reg = dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3; ++ extra = sdhci_readl(host, reg); ++ extra &= ~BIT(0); ++ sdhci_writel(host, extra, reg); ++ ++ if (clock <= 400000) { ++ /* Disable DLL to reset sample clock */ ++ sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); ++ return; ++ } ++ ++ /* Reset DLL */ ++ sdhci_writel(host, BIT(1), DWCMSHC_EMMC_DLL_CTRL); ++ udelay(1); ++ sdhci_writel(host, 0x0, DWCMSHC_EMMC_DLL_CTRL); ++ ++ /* Init DLL settings */ ++ extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT | ++ 0x2 << DWCMSHC_EMMC_DLL_INC | ++ DWCMSHC_EMMC_DLL_START; ++ sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL); ++ err = readl_poll_timeout(host->ioaddr + DWCMSHC_EMMC_DLL_STATUS0, ++ extra, DLL_LOCK_WO_TMOUT(extra), 1, ++ 500 * USEC_PER_MSEC); ++ if (err) { ++ dev_err(mmc_dev(host->mmc), "DLL lock timeout!\n"); ++ return; ++ } ++ ++ extra = 0x1 << 16 | /* tune clock stop en */ ++ 0x2 << 17 | /* pre-change delay */ ++ 0x3 << 19; /* post-change delay */ ++ sdhci_writel(host, extra, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); ++ ++ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200 || ++ host->mmc->ios.timing == MMC_TIMING_MMC_HS400) ++ txclk_tapnum = priv->txclk_tapnum; ++ ++ extra = DWCMSHC_EMMC_DLL_DLYENA | ++ DLL_TXCLK_TAPNUM_FROM_SW | ++ txclk_tapnum; ++ sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK); ++ ++ extra = DWCMSHC_EMMC_DLL_DLYENA | ++ DLL_STRBIN_TAPNUM_DEFAULT | ++ DLL_STRBIN_TAPNUM_FROM_SW; ++ sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); ++} ++ + static const struct sdhci_ops sdhci_dwcmshc_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, +@@ -109,21 +253,93 @@ static const struct sdhci_ops sdhci_dwcmshc_ops = { + .adma_write_desc = dwcmshc_adma_write_desc, + }; + ++static const struct sdhci_ops sdhci_dwcmshc_rk3568_ops = { ++ .set_clock = dwcmshc_rk3568_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .set_uhs_signaling = dwcmshc_set_uhs_signaling, ++ .get_max_clock = sdhci_pltfm_clk_get_max_clock, ++ .reset = sdhci_reset, ++ .adma_write_desc = dwcmshc_adma_write_desc, ++}; ++ + static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { + .ops = &sdhci_dwcmshc_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + }; + ++static const struct sdhci_pltfm_data sdhci_dwcmshc_rk3568_pdata = { ++ .ops = &sdhci_dwcmshc_rk3568_ops, ++ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | ++ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, ++ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | ++ SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, ++}; ++ ++static int dwcmshc_rk3568_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) ++{ ++ int err; ++ struct rk3568_priv *priv = dwc_priv->priv; ++ ++ priv->rockchip_clks[0].id = "axi"; ++ priv->rockchip_clks[1].id = "block"; ++ priv->rockchip_clks[2].id = "timer"; ++ err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), RK3568_MAX_CLKS, ++ priv->rockchip_clks); ++ if (err) { ++ dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err); ++ return err; ++ } ++ ++ err = clk_bulk_prepare_enable(RK3568_MAX_CLKS, priv->rockchip_clks); ++ if (err) { ++ dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err); ++ return err; ++ } ++ ++ if (of_property_read_u8(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum", ++ &priv->txclk_tapnum)) ++ priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; ++ ++ /* Disable cmd conflict check */ ++ sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3); ++ /* Reset previous settings */ ++ sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); ++ sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN); ++ ++ return 0; ++} ++ ++static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { ++ { ++ .compatible = "rockchip,rk3568-dwcmshc", ++ .data = &sdhci_dwcmshc_rk3568_pdata, ++ }, ++ { ++ .compatible = "snps,dwcmshc-sdhci", ++ .data = &sdhci_dwcmshc_pdata, ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); ++ + static int dwcmshc_probe(struct platform_device *pdev) + { + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_host *host; + struct dwcmshc_priv *priv; ++ struct rk3568_priv *rk_priv = NULL; ++ const struct sdhci_pltfm_data *pltfm_data; + int err; + u32 extra; + +- host = sdhci_pltfm_init(pdev, &sdhci_dwcmshc_pdata, ++ pltfm_data = of_device_get_match_data(&pdev->dev); ++ if (!pltfm_data) { ++ dev_err(&pdev->dev, "Error: No device match data found\n"); ++ return -ENODEV; ++ } ++ ++ host = sdhci_pltfm_init(pdev, pltfm_data, + sizeof(struct dwcmshc_priv)); + if (IS_ERR(host)) + return PTR_ERR(host); +@@ -159,7 +375,23 @@ static int dwcmshc_probe(struct platform_device *pdev) + + sdhci_get_of_property(pdev); + ++ priv->vendor_specific_area1 = ++ sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK; ++ + host->mmc_host_ops.request = dwcmshc_request; ++ host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe; ++ ++ if (pltfm_data == &sdhci_dwcmshc_rk3568_pdata) { ++ rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk3568_priv), GFP_KERNEL); ++ if (!rk_priv) ++ goto err_clk; ++ ++ priv->priv = rk_priv; ++ ++ err = dwcmshc_rk3568_init(host, priv); ++ if (err) ++ goto err_clk; ++ } + + err = sdhci_add_host(host); + if (err) +@@ -170,6 +402,9 @@ static int dwcmshc_probe(struct platform_device *pdev) + err_clk: + clk_disable_unprepare(pltfm_host->clk); + clk_disable_unprepare(priv->bus_clk); ++ if (rk_priv) ++ clk_bulk_disable_unprepare(RK3568_MAX_CLKS, ++ rk_priv->rockchip_clks); + free_pltfm: + sdhci_pltfm_free(pdev); + return err; +@@ -180,12 +415,15 @@ static int dwcmshc_remove(struct platform_device *pdev) + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ struct rk3568_priv *rk_priv = priv->priv; + + sdhci_remove_host(host, 0); + + clk_disable_unprepare(pltfm_host->clk); + clk_disable_unprepare(priv->bus_clk); +- ++ if (rk_priv) ++ clk_bulk_disable_unprepare(RK3568_MAX_CLKS, ++ rk_priv->rockchip_clks); + sdhci_pltfm_free(pdev); + + return 0; +@@ -197,6 +435,7 @@ static int dwcmshc_suspend(struct device *dev) + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ struct rk3568_priv *rk_priv = priv->priv; + int ret; + + ret = sdhci_suspend_host(host); +@@ -207,6 +446,10 @@ static int dwcmshc_suspend(struct device *dev) + if (!IS_ERR(priv->bus_clk)) + clk_disable_unprepare(priv->bus_clk); + ++ if (rk_priv) ++ clk_bulk_disable_unprepare(RK3568_MAX_CLKS, ++ rk_priv->rockchip_clks); ++ + return ret; + } + +@@ -215,6 +458,7 @@ static int dwcmshc_resume(struct device *dev) + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ struct rk3568_priv *rk_priv = priv->priv; + int ret; + + ret = clk_prepare_enable(pltfm_host->clk); +@@ -227,18 +471,19 @@ static int dwcmshc_resume(struct device *dev) + return ret; + } + ++ if (rk_priv) { ++ ret = clk_bulk_prepare_enable(RK3568_MAX_CLKS, ++ rk_priv->rockchip_clks); ++ if (ret) ++ return ret; ++ } ++ + return sdhci_resume_host(host); + } + #endif + + static SIMPLE_DEV_PM_OPS(dwcmshc_pmops, dwcmshc_suspend, dwcmshc_resume); + +-static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { +- { .compatible = "snps,dwcmshc-sdhci" }, +- {} +-}; +-MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); +- + static struct platform_driver sdhci_dwcmshc_driver = { + .driver = { + .name = "sdhci-dwcmshc", +-- +2.20.1 + diff --git a/patch/0252-mmc-sdhci-of-dwcmshc-add-ACPI-support-for-BlueField-.patch b/patch/0252-mmc-sdhci-of-dwcmshc-add-ACPI-support-for-BlueField-.patch new file mode 100644 index 000000000..e6d3107e8 --- /dev/null +++ b/patch/0252-mmc-sdhci-of-dwcmshc-add-ACPI-support-for-BlueField-.patch @@ -0,0 +1,130 @@ +From 44448fdaef6bbd1b1fd42e41b072d4960d163708 Mon Sep 17 00:00:00 2001 +From: Liming Sun +Date: Mon, 22 Mar 2021 18:46:51 -0400 +Subject: [PATCH backport 5.10 54/63] mmc: sdhci-of-dwcmshc: add ACPI support + for BlueField-3 SoC + +This commit adds ACPI support in the sdhci-of-dwcmshc driver for +BlueField-3 SoC. It has changes to only use the clock hierarchy +for Deviec Tree since the clk is not supported by ACPI. Instead, +ACPI can define 'clock-frequency' which is parsed by existing +sdhci_get_property(). This clock value will be returned in function +dwcmshc_get_max_clock(). + +Signed-off-by: Liming Sun +Reviewed-by: Khalil Blaiech +Link: https://lore.kernel.org/r/1616453211-275165-1-git-send-email-limings@nvidia.com +Signed-off-by: Ulf Hansson +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 50 +++++++++++++++++++++-------- + 1 file changed, 36 insertions(+), 14 deletions(-) + +diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c +index 06873686d..1113a56fe 100644 +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -7,6 +7,7 @@ + * Author: Jisheng Zhang + */ + ++#include + #include + #include + #include +@@ -94,6 +95,16 @@ static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc, + sdhci_adma_write_desc(host, desc, addr, len, cmd); + } + ++static unsigned int dwcmshc_get_max_clock(struct sdhci_host *host) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ ++ if (pltfm_host->clk) ++ return sdhci_pltfm_clk_get_max_clock(host); ++ else ++ return pltfm_host->clock; ++} ++ + static void dwcmshc_check_auto_cmd23(struct mmc_host *mmc, + struct mmc_request *mrq) + { +@@ -248,7 +259,7 @@ static const struct sdhci_ops sdhci_dwcmshc_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = dwcmshc_set_uhs_signaling, +- .get_max_clock = sdhci_pltfm_clk_get_max_clock, ++ .get_max_clock = dwcmshc_get_max_clock, + .reset = sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, + }; +@@ -323,8 +334,16 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { + }; + MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); + ++#ifdef CONFIG_ACPI ++static const struct acpi_device_id sdhci_dwcmshc_acpi_ids[] = { ++ { .id = "MLNXBF30" }, ++ {} ++}; ++#endif ++ + static int dwcmshc_probe(struct platform_device *pdev) + { ++ struct device *dev = &pdev->dev; + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_host *host; + struct dwcmshc_priv *priv; +@@ -347,7 +366,7 @@ static int dwcmshc_probe(struct platform_device *pdev) + /* + * extra adma table cnt for cross 128M boundary handling. + */ +- extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M); ++ extra = DIV_ROUND_UP_ULL(dma_get_required_mask(dev), SZ_128M); + if (extra > SDHCI_MAX_SEGS) + extra = SDHCI_MAX_SEGS; + host->adma_table_cnt += extra; +@@ -355,19 +374,21 @@ static int dwcmshc_probe(struct platform_device *pdev) + pltfm_host = sdhci_priv(host); + priv = sdhci_pltfm_priv(pltfm_host); + +- pltfm_host->clk = devm_clk_get(&pdev->dev, "core"); +- if (IS_ERR(pltfm_host->clk)) { +- err = PTR_ERR(pltfm_host->clk); +- dev_err(&pdev->dev, "failed to get core clk: %d\n", err); +- goto free_pltfm; +- } +- err = clk_prepare_enable(pltfm_host->clk); +- if (err) +- goto free_pltfm; ++ if (dev->of_node) { ++ pltfm_host->clk = devm_clk_get(dev, "core"); ++ if (IS_ERR(pltfm_host->clk)) { ++ err = PTR_ERR(pltfm_host->clk); ++ dev_err(dev, "failed to get core clk: %d\n", err); ++ goto free_pltfm; ++ } ++ err = clk_prepare_enable(pltfm_host->clk); ++ if (err) ++ goto free_pltfm; + +- priv->bus_clk = devm_clk_get(&pdev->dev, "bus"); +- if (!IS_ERR(priv->bus_clk)) +- clk_prepare_enable(priv->bus_clk); ++ priv->bus_clk = devm_clk_get(dev, "bus"); ++ if (!IS_ERR(priv->bus_clk)) ++ clk_prepare_enable(priv->bus_clk); ++ } + + err = mmc_of_parse(host->mmc); + if (err) +@@ -489,6 +510,7 @@ static struct platform_driver sdhci_dwcmshc_driver = { + .name = "sdhci-dwcmshc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = sdhci_dwcmshc_dt_ids, ++ .acpi_match_table = ACPI_PTR(sdhci_dwcmshc_acpi_ids), + .pm = &dwcmshc_pmops, + }, + .probe = dwcmshc_probe, +-- +2.20.1 + diff --git a/patch/0253-mmc-sdhci-of-dwcmshc-fix-error-return-code-in-dwcmsh.patch b/patch/0253-mmc-sdhci-of-dwcmshc-fix-error-return-code-in-dwcmsh.patch new file mode 100644 index 000000000..7f49a35cc --- /dev/null +++ b/patch/0253-mmc-sdhci-of-dwcmshc-fix-error-return-code-in-dwcmsh.patch @@ -0,0 +1,37 @@ +From 72d369a9be4bc4b92ab1e006dc36c612f0305b46 Mon Sep 17 00:00:00 2001 +From: Wei Yongjun +Date: Tue, 23 Mar 2021 11:29:56 +0000 +Subject: [PATCH backport 5.10 55/63] mmc: sdhci-of-dwcmshc: fix error return + code in dwcmshc_probe() + +Fix to return negative error code -ENOMEM from the error handling +case instead of 0, as done elsewhere in this function. + +Fixes: c2c4da37837e ("mmc: sdhci-of-dwcmshc: add rockchip platform support") +Reported-by: Hulk Robot +Signed-off-by: Wei Yongjun +Link: https://lore.kernel.org/r/20210323112956.1016884-1-weiyongjun1@huawei.com +Signed-off-by: Ulf Hansson +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c +index 1113a56fe..34d26e388 100644 +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -404,8 +404,10 @@ static int dwcmshc_probe(struct platform_device *pdev) + + if (pltfm_data == &sdhci_dwcmshc_rk3568_pdata) { + rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk3568_priv), GFP_KERNEL); +- if (!rk_priv) ++ if (!rk_priv) { ++ err = -ENOMEM; + goto err_clk; ++ } + + priv->priv = rk_priv; + +-- +2.20.1 + diff --git a/patch/0254-mmc-sdhci-of-dwcmshc-set-MMC_CAP_WAIT_WHILE_BUSY.patch b/patch/0254-mmc-sdhci-of-dwcmshc-set-MMC_CAP_WAIT_WHILE_BUSY.patch new file mode 100644 index 000000000..04b8970eb --- /dev/null +++ b/patch/0254-mmc-sdhci-of-dwcmshc-set-MMC_CAP_WAIT_WHILE_BUSY.patch @@ -0,0 +1,32 @@ +From 17e98239da6fd921a76cbee7ac8dcc3c437ad5d6 Mon Sep 17 00:00:00 2001 +From: Jisheng Zhang +Date: Wed, 24 Mar 2021 15:47:21 +0800 +Subject: [PATCH backport 5.10 56/63] mmc: sdhci-of-dwcmshc: set + MMC_CAP_WAIT_WHILE_BUSY + +The host supports HW busy detection of the device busy signaling over +dat0 line. Set MMC_CAP_wAIT_WHILE_BUSY host capability. + +Signed-off-by: Jisheng Zhang +Link: https://lore.kernel.org/r/20210324154703.69f97fde@xhacker.debian +Signed-off-by: Ulf Hansson +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c +index 34d26e388..bac874ab0 100644 +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -416,6 +416,8 @@ static int dwcmshc_probe(struct platform_device *pdev) + goto err_clk; + } + ++ host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; ++ + err = sdhci_add_host(host); + if (err) + goto err_clk; +-- +2.20.1 + diff --git a/patch/0255-mmc-sdhci-of-dwcmshc-Re-enable-support-for-the-BlueF.patch b/patch/0255-mmc-sdhci-of-dwcmshc-Re-enable-support-for-the-BlueF.patch new file mode 100644 index 000000000..6f5e69051 --- /dev/null +++ b/patch/0255-mmc-sdhci-of-dwcmshc-Re-enable-support-for-the-BlueF.patch @@ -0,0 +1,77 @@ +From 990bb46dc1f0fd103e9d01d8e87c046fbe879d53 Mon Sep 17 00:00:00 2001 +From: Liming Sun +Date: Tue, 9 Aug 2022 13:37:42 -0400 +Subject: [PATCH] mmc: sdhci-of-dwcmshc: Re-enable support for the BlueField-3 + SoC +X-NVConfidentiality: public + +BugLink: https://bugs.launchpad.net/bugs/1991831 + +[ Upstream commit a0753ef66c34c1739580219dca664eda648164b7 ] + +The commit 08f3dff799d4 (mmc: sdhci-of-dwcmshc: add rockchip platform +support") introduces the use of_device_get_match_data() to check for some +chips. Unfortunately, it also breaks the BlueField-3 FW, which uses ACPI. + +To fix the problem, let's add the ACPI match data and the corresponding +quirks to re-enable the support for the BlueField-3 SoC. + +Reviewed-by: David Woods +Signed-off-by: Liming Sun +Acked-by: Adrian Hunter +Fixes: 08f3dff799d4 ("mmc: sdhci-of-dwcmshc: add rockchip platform support") +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/r/20220809173742.178440-1-limings@nvidia.com +[Ulf: Clarified the commit message a bit] +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +Signed-off-by: Kamal Mostafa +Signed-off-by: Stefan Bader +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c +index bac874ab0..a0c73ddaa 100644 +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -279,6 +279,15 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + }; + ++#ifdef CONFIG_ACPI ++static const struct sdhci_pltfm_data sdhci_dwcmshc_bf3_pdata = { ++ .ops = &sdhci_dwcmshc_ops, ++ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, ++ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | ++ SDHCI_QUIRK2_ACMD23_BROKEN, ++}; ++#endif ++ + static const struct sdhci_pltfm_data sdhci_dwcmshc_rk3568_pdata = { + .ops = &sdhci_dwcmshc_rk3568_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | +@@ -336,7 +345,10 @@ MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); + + #ifdef CONFIG_ACPI + static const struct acpi_device_id sdhci_dwcmshc_acpi_ids[] = { +- { .id = "MLNXBF30" }, ++ { ++ .id = "MLNXBF30", ++ .driver_data = (kernel_ulong_t)&sdhci_dwcmshc_bf3_pdata, ++ }, + {} + }; + #endif +@@ -352,7 +364,7 @@ static int dwcmshc_probe(struct platform_device *pdev) + int err; + u32 extra; + +- pltfm_data = of_device_get_match_data(&pdev->dev); ++ pltfm_data = device_get_match_data(&pdev->dev); + if (!pltfm_data) { + dev_err(&pdev->dev, "Error: No device match data found\n"); + return -ENODEV; +-- +2.14.1 + diff --git a/patch/0256-UBUNTU-SAUCE-Support-BlueField-3-GPIO-driver.patch b/patch/0256-UBUNTU-SAUCE-Support-BlueField-3-GPIO-driver.patch new file mode 100644 index 000000000..976dadb85 --- /dev/null +++ b/patch/0256-UBUNTU-SAUCE-Support-BlueField-3-GPIO-driver.patch @@ -0,0 +1,402 @@ +From a97cbefdc2d699a53b9717f4c11aadba176b7987 Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Thu, 27 Oct 2022 12:36:19 -0400 +Subject: [PATCH 02/12] UBUNTU: SAUCE: Support BlueField-3 GPIO driver +X-NVConfidentiality: public + +BugLink: https://bugs.launchpad.net/bugs/1994897 + +This patch adds support for the BlueField-3 SoC GPIO driver which allows: +- setting certain GPIOs as interrupts from other dependent drivers +- ability to manipulate certain GPIO values from user space + +Signed-off-by: Asmaa Mnebhi +Acked-by: Tim Gardner +Acked-by: Cory Todd +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/gpio/Kconfig | 7 + + drivers/gpio/Makefile | 1 + + drivers/gpio/gpio-mlxbf3.c | 340 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 348 insertions(+) + create mode 100644 drivers/gpio/gpio-mlxbf3.c + +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index d1300fc00..bf1b2b787 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -1459,6 +1459,13 @@ config GPIO_MLXBF2 + help + Say Y here if you want GPIO support on Mellanox BlueField 2 SoC. + ++config GPIO_MLXBF3 ++ tristate "Mellanox BlueField 3 SoC GPIO" ++ depends on (MELLANOX_PLATFORM && ARM64 && ACPI) || (64BIT && COMPILE_TEST) ++ select GPIO_GENERIC ++ help ++ Say Y here if you want GPIO support on Mellanox BlueField 3 SoC. ++ + config GPIO_ML_IOH + tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" + depends on X86 || COMPILE_TEST +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile +index 09dada80a..f11a9cf0b 100644 +--- a/drivers/gpio/Makefile ++++ b/drivers/gpio/Makefile +@@ -96,6 +96,7 @@ obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o + obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o + obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o + obj-$(CONFIG_GPIO_MLXBF2) += gpio-mlxbf2.o ++obj-$(CONFIG_GPIO_MLXBF3) += gpio-mlxbf3.o + obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o + obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o + obj-$(CONFIG_GPIO_MOXTET) += gpio-moxtet.o +diff --git a/drivers/gpio/gpio-mlxbf3.c b/drivers/gpio/gpio-mlxbf3.c +new file mode 100644 +index 000000000..45f0946ac +--- /dev/null ++++ b/drivers/gpio/gpio-mlxbf3.c +@@ -0,0 +1,340 @@ ++// SPDX-License-Identifier: GPL-2.0-only or BSD-3-Clause ++ ++/* ++ * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRV_VERSION "1.0" ++ ++/* ++ * There are 2 YU GPIO blocks: ++ * gpio[0]: HOST_GPIO0->HOST_GPIO31 ++ * gpio[1]: HOST_GPIO32->HOST_GPIO55 ++ */ ++#define MLXBF3_GPIO_MAX_PINS_PER_BLOCK 32 ++ ++/* ++ * fw_gpio[x] block registers and their offset ++ */ ++#define YU_GPIO_FW_CONTROL_SET 0x00 ++#define YU_GPIO_FW_OUTPUT_ENABLE_SET 0x04 ++#define YU_GPIO_FW_DATA_OUT_SET 0x08 ++#define YU_GPIO_FW_CONTROL_CLEAR 0x14 ++#define YU_GPIO_FW_OUTPUT_ENABLE_CLEAR 0x18 ++#define YU_GPIO_FW_DATA_OUT_CLEAR 0x1c ++#define YU_GPIO_CAUSE_RISE_EN 0x28 ++#define YU_GPIO_CAUSE_FALL_EN 0x2c ++#define YU_GPIO_READ_DATA_IN 0x30 ++#define YU_GPIO_READ_OUTPUT_ENABLE 0x34 ++#define YU_GPIO_READ_DATA_OUT 0x38 ++#define YU_GPIO_READ_FW_CONTROL 0x44 ++ ++#define YU_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x00 ++#define YU_GPIO_CAUSE_OR_EVTEN0 0x14 ++#define YU_GPIO_CAUSE_OR_CLRCAUSE 0x18 ++ ++/* BlueField-3 gpio block context structure. */ ++struct mlxbf3_gpio_context { ++ struct gpio_chip gc; ++ struct irq_chip irq_chip; ++ ++ /* YU GPIO blocks address */ ++ void __iomem *gpio_io; ++ ++ /* YU GPIO cause block address */ ++ void __iomem *gpio_cause_io; ++ ++ uint32_t ctrl_gpio_mask; ++}; ++ ++static void mlxbf3_gpio_set(struct gpio_chip *chip, unsigned int offset, int val) ++{ ++ struct mlxbf3_gpio_context *gs = gpiochip_get_data(chip); ++ ++ /* Software can only control GPIO pins defined by ctrl_gpio_mask */ ++ if (!(BIT(offset) & gs->ctrl_gpio_mask)) ++ return; ++ ++ if (val) { ++ writel(BIT(offset), gs->gpio_io + YU_GPIO_FW_DATA_OUT_SET); ++ } else { ++ writel(BIT(offset), gs->gpio_io + YU_GPIO_FW_DATA_OUT_CLEAR); ++ } ++ ++ wmb(); ++ ++ /* This needs to be done last to avoid glitches */ ++ writel(BIT(offset), gs->gpio_io + YU_GPIO_FW_CONTROL_SET); ++} ++ ++static int mlxbf3_gpio_direction_input(struct gpio_chip *chip, ++ unsigned int offset) ++{ ++ struct mlxbf3_gpio_context *gs = gpiochip_get_data(chip); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gs->gc.bgpio_lock, flags); ++ ++ writel(BIT(offset), gs->gpio_io + YU_GPIO_FW_OUTPUT_ENABLE_CLEAR); ++ writel(BIT(offset), gs->gpio_io + YU_GPIO_FW_CONTROL_CLEAR); ++ ++ spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); ++ ++ return 0; ++} ++ ++static int mlxbf3_gpio_direction_output(struct gpio_chip *chip, ++ unsigned int offset, ++ int value) ++{ ++ struct mlxbf3_gpio_context *gs = gpiochip_get_data(chip); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gs->gc.bgpio_lock, flags); ++ ++ writel(BIT(offset), gs->gpio_io + YU_GPIO_FW_OUTPUT_ENABLE_SET); ++ ++ spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); ++ ++ return 0; ++} ++ ++static void mlxbf3_gpio_irq_enable(struct irq_data *irqd) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); ++ struct mlxbf3_gpio_context *gs = gpiochip_get_data(gc); ++ int offset = irqd_to_hwirq(irqd); ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(&gs->gc.bgpio_lock, flags); ++ writel(BIT(offset), gs->gpio_cause_io + YU_GPIO_CAUSE_OR_CLRCAUSE); ++ ++ val = readl(gs->gpio_cause_io + YU_GPIO_CAUSE_OR_EVTEN0); ++ val |= BIT(offset); ++ writel(val, gs->gpio_cause_io + YU_GPIO_CAUSE_OR_EVTEN0); ++ spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); ++} ++ ++static void mlxbf3_gpio_irq_disable(struct irq_data *irqd) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); ++ struct mlxbf3_gpio_context *gs = gpiochip_get_data(gc); ++ int offset = irqd_to_hwirq(irqd); ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(&gs->gc.bgpio_lock, flags); ++ val = readl(gs->gpio_cause_io + YU_GPIO_CAUSE_OR_EVTEN0); ++ val &= ~BIT(offset); ++ writel(val, gs->gpio_cause_io + YU_GPIO_CAUSE_OR_EVTEN0); ++ spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); ++} ++ ++static irqreturn_t mlxbf3_gpio_irq_handler(int irq, void *ptr) ++{ ++ struct mlxbf3_gpio_context *gs = ptr; ++ struct gpio_chip *gc = &gs->gc; ++ unsigned long pending; ++ u32 level; ++ ++ pending = readl(gs->gpio_cause_io + YU_GPIO_CAUSE_OR_CAUSE_EVTEN0); ++ writel(pending, gs->gpio_cause_io + YU_GPIO_CAUSE_OR_CLRCAUSE); ++ ++ for_each_set_bit(level, &pending, gc->ngpio) { ++ int gpio_irq = irq_find_mapping(gc->irq.domain, level); ++ generic_handle_irq(gpio_irq); ++ } ++ ++ return IRQ_RETVAL(pending); ++} ++ ++static int ++mlxbf3_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) ++{ ++ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); ++ struct mlxbf3_gpio_context *gs = gpiochip_get_data(gc); ++ int offset = irqd_to_hwirq(irqd); ++ unsigned long flags; ++ bool fall = false; ++ bool rise = false; ++ u32 val; ++ ++ switch (type & IRQ_TYPE_SENSE_MASK) { ++ case IRQ_TYPE_EDGE_BOTH: ++ fall = true; ++ rise = true; ++ break; ++ case IRQ_TYPE_EDGE_RISING: ++ rise = true; ++ break; ++ case IRQ_TYPE_EDGE_FALLING: ++ fall = true; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&gs->gc.bgpio_lock, flags); ++ if (fall) { ++ val = readl(gs->gpio_io + YU_GPIO_CAUSE_FALL_EN); ++ val |= BIT(offset); ++ writel(val, gs->gpio_io + YU_GPIO_CAUSE_FALL_EN); ++ } ++ ++ if (rise) { ++ val = readl(gs->gpio_io + YU_GPIO_CAUSE_RISE_EN); ++ val |= BIT(offset); ++ writel(val, gs->gpio_io + YU_GPIO_CAUSE_RISE_EN); ++ } ++ spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); ++ ++ return 0; ++} ++ ++/* BlueField-3 GPIO driver initialization routine. */ ++static int ++mlxbf3_gpio_probe(struct platform_device *pdev) ++{ ++ struct mlxbf3_gpio_context *gs; ++ struct device *dev = &pdev->dev; ++ struct gpio_irq_chip *girq; ++ struct gpio_chip *gc; ++ unsigned int npins; ++ const char *name; ++ int ret, irq; ++ ++ name = dev_name(dev); ++ ++ gs = devm_kzalloc(dev, sizeof(*gs), GFP_KERNEL); ++ if (!gs) ++ return -ENOMEM; ++ ++ /* YU GPIO block address */ ++ gs->gpio_io = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(gs->gpio_io)) ++ return PTR_ERR(gs->gpio_io); ++ ++ /* YU GPIO block address */ ++ gs->gpio_cause_io = devm_platform_ioremap_resource(pdev, 1); ++ if (IS_ERR(gs->gpio_cause_io)) ++ return PTR_ERR(gs->gpio_cause_io); ++ ++ if (device_property_read_u32(dev, "npins", &npins)) ++ npins = MLXBF3_GPIO_MAX_PINS_PER_BLOCK; ++ ++ if (device_property_read_u32(dev, "ctrl_gpio_mask", &gs->ctrl_gpio_mask)) ++ gs->ctrl_gpio_mask = 0x0; ++ ++ gc = &gs->gc; ++ ++ /* To set the direction to input, just give control to HW by setting ++ * YU_GPIO_FW_CONTROL_CLEAR. ++ * If the GPIO is controlled by HW, read its value via read_data_in register. ++ * ++ * When the direction = output, the GPIO is controlled by SW and ++ * datain=dataout. If software modifies the value of the GPIO pin, ++ * the value can be read from read_data_in without changing the direction. ++ */ ++ ret = bgpio_init(gc, dev, 4, ++ gs->gpio_io + YU_GPIO_READ_DATA_IN, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ 0); ++ ++ gc->set = mlxbf3_gpio_set; ++ gc->direction_input = mlxbf3_gpio_direction_input; ++ gc->direction_output = mlxbf3_gpio_direction_output; ++ ++ gc->ngpio = npins; ++ gc->owner = THIS_MODULE; ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq >= 0) { ++ gs->irq_chip.name = name; ++ gs->irq_chip.irq_set_type = mlxbf3_gpio_irq_set_type; ++ gs->irq_chip.irq_enable = mlxbf3_gpio_irq_enable; ++ gs->irq_chip.irq_disable = mlxbf3_gpio_irq_disable; ++ ++ girq = &gs->gc.irq; ++ girq->chip = &gs->irq_chip; ++ girq->handler = handle_simple_irq; ++ girq->default_type = IRQ_TYPE_NONE; ++ /* This will let us handle the parent IRQ in the driver */ ++ girq->num_parents = 0; ++ girq->parents = NULL; ++ girq->parent_handler = NULL; ++ ++ /* ++ * Directly request the irq here instead of passing ++ * a flow-handler because the irq is shared. ++ */ ++ ret = devm_request_irq(dev, irq, mlxbf3_gpio_irq_handler, ++ IRQF_SHARED, name, gs); ++ if (ret) { ++ dev_err(dev, "failed to request IRQ"); ++ return ret; ++ } ++ } ++ ++ platform_set_drvdata(pdev, gs); ++ ++ ret = devm_gpiochip_add_data(dev, &gs->gc, gs); ++ if (ret) { ++ dev_err(dev, "Failed adding memory mapped gpiochip\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int mlxbf3_gpio_remove(struct platform_device *pdev) ++{ ++ struct mlxbf3_gpio_context *gs = platform_get_drvdata(pdev); ++ ++ /* Set the GPIO control back to HW */ ++ writel(gs->ctrl_gpio_mask, gs->gpio_io + YU_GPIO_FW_CONTROL_CLEAR); ++ ++ return 0; ++} ++ ++static const struct acpi_device_id __maybe_unused mlxbf3_gpio_acpi_match[] = { ++ { "MLNXBF33", 0 }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(acpi, mlxbf3_gpio_acpi_match); ++ ++static struct platform_driver mlxbf3_gpio_driver = { ++ .driver = { ++ .name = "mlxbf3_gpio", ++ .acpi_match_table = mlxbf3_gpio_acpi_match, ++ }, ++ .probe = mlxbf3_gpio_probe, ++ .remove = mlxbf3_gpio_remove, ++}; ++ ++module_platform_driver(mlxbf3_gpio_driver); ++ ++MODULE_DESCRIPTION("Mellanox BlueField-3 GPIO Driver"); ++MODULE_AUTHOR("Asmaa Mnebhi "); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_VERSION(DRV_VERSION); +-- +2.14.1 + diff --git a/patch/0257-regmap-debugfs-Enable-writing-to-the-regmap-debugfs-.patch b/patch/0257-regmap-debugfs-Enable-writing-to-the-regmap-debugfs-.patch new file mode 100644 index 000000000..53813dbaf --- /dev/null +++ b/patch/0257-regmap-debugfs-Enable-writing-to-the-regmap-debugfs-.patch @@ -0,0 +1,27 @@ +From 5a6717305bc0ee08d08dc27f8f3415c4bb1c34c3 Mon Sep 17 00:00:00 2001 +From: Felix Radensky +Date: Sun, 20 Nov 2022 15:25:58 +0200 +Subject: [PATCH backport 5.10 59/63] regmap: debugfs: Enable writing to the + regmap debugfs registers + +Signed-off-by: Felix Radensky +--- + drivers/base/regmap/regmap-debugfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c +index 211a335a6..ee3cccaf5 100644 +--- a/drivers/base/regmap/regmap-debugfs.c ++++ b/drivers/base/regmap/regmap-debugfs.c +@@ -290,7 +290,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, + count, ppos); + } + +-#undef REGMAP_ALLOW_WRITE_DEBUGFS ++#define REGMAP_ALLOW_WRITE_DEBUGFS + #ifdef REGMAP_ALLOW_WRITE_DEBUGFS + /* + * This can be dangerous especially when we have clients such as +-- +2.20.1 + diff --git a/patch/0258-UBUNTU-SAUCE-mlx-bootctl-support-icm-carveout-eeprom.patch b/patch/0258-UBUNTU-SAUCE-mlx-bootctl-support-icm-carveout-eeprom.patch new file mode 100644 index 000000000..6448866c0 --- /dev/null +++ b/patch/0258-UBUNTU-SAUCE-mlx-bootctl-support-icm-carveout-eeprom.patch @@ -0,0 +1,118 @@ +From 02aa895d298c83e5e6e0f6e64f04895e50235a33 Mon Sep 17 00:00:00 2001 +From: Asmaa Mnebhi +Date: Mon, 31 Oct 2022 12:18:52 -0400 +Subject: [PATCH backport 5.10 60/63] UBUNTU: SAUCE: mlx-bootctl: support icm + carveout eeprom region read/write + +BugLink: https://bugs.launchpad.net/bugs/1995296 + +The BlueField-3 ICM carveout feature will enable NIC FW to bypass the SMMU block +to access DRAM memory. The amount of memory accessible by FW will be controlled by ARM. +This patch enables setting the size of the large ICM carveout from +userspace. The max size is 1TB, has a granularity of 128MB and will be passed +and printed in hex. The size unit is MB. + +Signed-off-by: Asmaa Mnebhi +Acked-by: Tim Gardner +Acked-by: Cory Todd +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/platform/mellanox/mlxbf-bootctl.c | 40 +++++++++++++++++++++++ + drivers/platform/mellanox/mlxbf-bootctl.h | 9 +++++ + 2 files changed, 49 insertions(+) + +diff --git a/drivers/platform/mellanox/mlxbf-bootctl.c b/drivers/platform/mellanox/mlxbf-bootctl.c +index 2302e1e09..e8877a19d 100644 +--- a/drivers/platform/mellanox/mlxbf-bootctl.c ++++ b/drivers/platform/mellanox/mlxbf-bootctl.c +@@ -104,6 +104,7 @@ enum { + + /* This mutex is used to serialize MFG write and lock operations. */ + static DEFINE_MUTEX(mfg_ops_lock); ++static DEFINE_MUTEX(icm_ops_lock); + + #define MLNX_MFG_OOB_MAC_LEN ETH_ALEN + #define MLNX_MFG_OPN_VAL_LEN 24 +@@ -383,6 +384,43 @@ static ssize_t oob_mac_store(struct device_driver *drv, const char *buf, + return res.a0 ? -EPERM : count; + } + ++static ssize_t large_icm_show(struct device_driver *drv, char *buf) ++{ ++ char icm_str[MAX_ICM_BUFFER_SIZE] = { 0 }; ++ struct arm_smccc_res res; ++ ++ arm_smccc_smc(MLNX_HANDLE_GET_ICM_INFO, 0, 0, 0, 0, ++ 0, 0, 0, &res); ++ if (res.a0) ++ return -EPERM; ++ ++ sprintf(icm_str, "0x%lx", res.a1); ++ ++ return snprintf(buf, sizeof(icm_str), "%s", icm_str); ++} ++ ++static ssize_t large_icm_store(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ struct arm_smccc_res res; ++ unsigned long icm_data; ++ int err; ++ ++ err = kstrtoul(buf, 16, &icm_data); ++ if (err) ++ return err; ++ ++ if (((icm_data != 0) && (icm_data < 0x80)) || ++ (icm_data > 0x100000) || (icm_data % 128)) ++ return -EPERM; ++ ++ mutex_lock(&icm_ops_lock); ++ arm_smccc_smc(MLNX_HANDLE_SET_ICM_INFO, icm_data, 0, 0, 0, 0, 0, 0, &res); ++ mutex_unlock(&icm_ops_lock); ++ ++ return res.a0 ? -EPERM : count; ++} ++ + static ssize_t opn_show(struct device_driver *drv, char *buf) + { + u64 opn_data[MLNX_MFG_VAL_QWORD_CNT(OPN)] = { 0 }; +@@ -1170,6 +1208,7 @@ static DRIVER_ATTR_RW(uuid); + static DRIVER_ATTR_RW(rev); + static DRIVER_ATTR_WO(mfg_lock); + static DRIVER_ATTR_RW(rsh_log); ++static DRIVER_ATTR_RW(large_icm); + + static struct attribute *mbc_dev_attrs[] = { + &driver_attr_post_reset_wdog.attr, +@@ -1187,6 +1226,7 @@ static struct attribute *mbc_dev_attrs[] = { + &driver_attr_rev.attr, + &driver_attr_mfg_lock.attr, + &driver_attr_rsh_log.attr, ++ &driver_attr_large_icm.attr, + NULL + }; + +diff --git a/drivers/platform/mellanox/mlxbf-bootctl.h b/drivers/platform/mellanox/mlxbf-bootctl.h +index 3e9dda829..c70204770 100644 +--- a/drivers/platform/mellanox/mlxbf-bootctl.h ++++ b/drivers/platform/mellanox/mlxbf-bootctl.h +@@ -95,6 +95,15 @@ + #define MLNX_HANDLE_GET_MFG_INFO 0x8200000F + #define MLNX_HANDLE_LOCK_MFG_INFO 0x82000011 + ++/* ++ * SMC function IDs to set and get the large ICM carveout size ++ * stored in the eeprom. ++ */ ++#define MLNX_HANDLE_SET_ICM_INFO 0x82000012 ++#define MLNX_HANDLE_GET_ICM_INFO 0x82000013 ++ ++#define MAX_ICM_BUFFER_SIZE 10 ++ + /* SMC function IDs for SiP Service queries */ + #define MLNX_SIP_SVC_CALL_COUNT 0x8200ff00 + #define MLNX_SIP_SVC_UID 0x8200ff01 +-- +2.20.1 + diff --git a/patch/0259-mmc-sdhci-of-dwcmshc-Enable-host-V4-support-for-Blue.patch b/patch/0259-mmc-sdhci-of-dwcmshc-Enable-host-V4-support-for-Blue.patch new file mode 100644 index 000000000..34103898d --- /dev/null +++ b/patch/0259-mmc-sdhci-of-dwcmshc-Enable-host-V4-support-for-Blue.patch @@ -0,0 +1,35 @@ +From 8650b784688c0822951993d98f196e1c7689a5cc Mon Sep 17 00:00:00 2001 +From: Liming Sun +Date: Fri, 25 Nov 2022 22:29:23 -0500 +Subject: [PATCH backport 5.10 61/63] mmc: sdhci-of-dwcmshc: Enable host V4 + support for BlueField-3 SoC + +This commit enables SDHCI Host V4 support on Bluefield-3 SoC to be +consistent with UEFI setting. + +Change-Id: I4d5ea43ca5f36c6c642443b9335c321924cca2ed +Signed-off-by: Liming Sun +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c +index 173a9167a..ea972bd3c 100644 +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -426,6 +426,12 @@ static int dwcmshc_probe(struct platform_device *pdev) + goto err_clk; + } + ++#ifdef CONFIG_ACPI ++ if (pltfm_data == &sdhci_dwcmshc_bf3_pdata) { ++ sdhci_enable_v4_mode(host); ++ } ++#endif ++ + host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; + + err = sdhci_add_host(host); +-- +2.20.1 + diff --git a/patch/0260-UBUNTU-SAUCE-mlxbf-pka-Fix-kernel-crash-with-pka-TRN.patch b/patch/0260-UBUNTU-SAUCE-mlxbf-pka-Fix-kernel-crash-with-pka-TRN.patch new file mode 100644 index 000000000..6196e707d --- /dev/null +++ b/patch/0260-UBUNTU-SAUCE-mlxbf-pka-Fix-kernel-crash-with-pka-TRN.patch @@ -0,0 +1,67 @@ +From 9d0cd0fb6fbdf825454b3d9f9518d8b569b0cdea Mon Sep 17 00:00:00 2001 +From: Shih-Yi Chen +Date: Wed, 4 Jan 2023 10:03:06 -0500 +Subject: [PATCH backport 5.10 1/6] UBUNTU: SAUCE: mlxbf-pka: Fix kernel crash + with pka TRNG ioctl call + +BugLink: https://bugs.launchpad.net/bugs/2001564 + +Bluefield encounters kernel crash/oops when HTTPS client uses OpenSSL +with PKA engine during TLS handshake. The issue is with TRNG ioctl call. +The kernel logs show the following errors. + +Unable to handle kernel access to user memory outside uaccess routines at virtual address 0000ffffce65d328 + +Signed-off-by: Shih-Yi Chen +Acked-by: Tim Gardner +Acked-by: Cengiz Can +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_drv.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_drv.c b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_drv.c +index b8b5a465e..9e26ccf21 100644 +--- a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_drv.c ++++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_drv.c +@@ -467,7 +467,7 @@ static long pka_drv_ring_ioctl(void *device_data, + } else if (cmd == PKA_CLEAR_RING_COUNTERS) { + return pka_dev_clear_ring_counters(ring_dev->ring); + } else if (cmd == PKA_GET_RANDOM_BYTES) { +- pka_dev_trng_info_t *trng_data; ++ pka_dev_trng_info_t trng_data; + pka_dev_shim_t *shim; + bool trng_present; + uint32_t byte_cnt; +@@ -476,12 +476,17 @@ static long pka_drv_ring_ioctl(void *device_data, + + ret = -ENOENT; + shim = ring_dev->ring->shim; +- trng_data = (pka_dev_trng_info_t *)arg; ++ ret = copy_from_user(&trng_data, (void __user *)(arg), sizeof(pka_dev_trng_info_t)); ++ if (ret) { ++ PKA_DEBUG(PKA_DRIVER, "Failed to copy user request.\n"); ++ return -EFAULT; ++ } ++ + /* + * We need byte count which is multiple of 4 as + * required by pka_dev_trng_read() interface. + */ +- byte_cnt = round_up(trng_data->count, 4); ++ byte_cnt = round_up(trng_data.count, 4); + + data = kzalloc(byte_cnt, GFP_KERNEL); + if (data == NULL) { +@@ -502,7 +507,7 @@ static long pka_drv_ring_ioctl(void *device_data, + return ret; + } + +- ret = copy_to_user((void __user *)(trng_data->data), data, trng_data->count); ++ ret = copy_to_user((void __user *)(trng_data.data), data, trng_data.count); + kfree(data); + return ret ? -EFAULT : 0; + } +-- +2.20.1 + diff --git a/patch/0261-mlxbf-ptm-power-and-thermal-management-debugfs-drive.patch b/patch/0261-mlxbf-ptm-power-and-thermal-management-debugfs-drive.patch new file mode 100644 index 000000000..a58881c4a --- /dev/null +++ b/patch/0261-mlxbf-ptm-power-and-thermal-management-debugfs-drive.patch @@ -0,0 +1,256 @@ +From 1193879b92e665c100056085385ffdb4ab2715cb Mon Sep 17 00:00:00 2001 +From: Jitendra Lanka +Date: Fri, 13 Jan 2023 15:21:02 -0500 +Subject: [PATCH backport 5.10 2/6] mlxbf-ptm: power and thermal management + debugfs driver + +mlxbf-ptm driver implements debugfs interface for Bluefield +devices power and thermal management. It provides some parameters +that can be monitored by system software. + +Change-Id: I241e1406962548cef9b33c4b3dea925e675c3c88 +Signed-off-by: Jitendra Lanka +--- + drivers/platform/mellanox/Kconfig | 10 ++ + drivers/platform/mellanox/Makefile | 1 + + drivers/platform/mellanox/mlxbf-ptm.c | 195 ++++++++++++++++++++++++++ + 3 files changed, 206 insertions(+) + create mode 100644 drivers/platform/mellanox/mlxbf-ptm.c + +diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig +index a5231c23a..48bd61f61 100644 +--- a/drivers/platform/mellanox/Kconfig ++++ b/drivers/platform/mellanox/Kconfig +@@ -106,6 +106,16 @@ config MLXBF_TRIO + This driver supports the TRIO PCIe root complex interface on + Mellanox BlueField SoCs. + ++config MLXBF_PTM ++ tristate "BlueField Power and Thermal Management debugfs interface" ++ depends on ARM64 ++ depends on DEBUG_FS ++ help ++ If you say yes to this option, support will be added for the ++ mlxbf-ptm driver. This driver provides debugfs interface ++ to userspace with information related to power and thermal ++ management of the Bluefield device. ++ + source "drivers/platform/mellanox/mlxbf_pka/Kconfig" + + config NVSW_SN2201 +diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile +index 7c6393ebe..6aa0ab157 100644 +--- a/drivers/platform/mellanox/Makefile ++++ b/drivers/platform/mellanox/Makefile +@@ -9,6 +9,7 @@ obj-$(CONFIG_MLXBF_PMC) += mlxbf-pmc.o + obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o + obj-$(CONFIG_MLXBF_TRIO) += mlx-trio.o + obj-$(CONFIG_MLXBF_LIVEFISH) += mlxbf-livefish.o ++obj-$(CONFIG_MLXBF_PTM) += mlxbf-ptm.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/mlxbf-ptm.c b/drivers/platform/mellanox/mlxbf-ptm.c +new file mode 100644 +index 000000000..307ba1f33 +--- /dev/null ++++ b/drivers/platform/mellanox/mlxbf-ptm.c +@@ -0,0 +1,195 @@ ++// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause ++/* ++ * Copyright (C) 2023 NVIDIA Corporation & Affiliates. ++ * ++ * Nvidia Bluefield power and thermal debugfs driver ++ * This driver provides a debugfs interface for systems management ++ * software to monitor power and thermal actions. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/* SMC IDs */ ++#define MLNX_PTM_GET_VR0_POWER 0x82000101 ++#define MLNX_PTM_GET_VR1_POWER 0x82000102 ++#define MLNX_PTM_GET_THROTTLE_STATE 0x82000103 ++#define MLNX_PTM_GET_DDR_THLD 0x82000104 ++#define MLNX_PTM_GET_STATUS_REG 0x82000105 ++#define MLNX_PTM_GET_PTHROTTLE 0x82000106 ++#define MLNX_PTM_GET_TTHROTTLE 0x82000107 ++#define MLNX_PTM_GET_MAX_TEMP 0x82000108 ++#define MLNX_PTM_GET_PWR_EVT_CNT 0x82000109 ++#define MLNX_PTM_GET_TEMP_EVT_CNT 0x8200010A ++ ++#define MLNX_POWER_ERROR 300 ++ ++struct dentry *monitors; ++ ++static int smc_call1(unsigned int smc_op, int smc_arg) ++{ ++ struct arm_smccc_res res; ++ ++ arm_smccc_smc(smc_op, smc_arg, 0, 0, 0, 0, 0, 0, &res); ++ ++ return res.a0; ++} ++ ++#define smc_call0(smc_op) smc_call1(smc_op, 0) ++ ++static int throttling_state_show(void *data, u64 *val) ++{ ++ *val = smc_call0(MLNX_PTM_GET_THROTTLE_STATE); ++ ++ return 0; ++} ++DEFINE_SIMPLE_ATTRIBUTE(throttling_state_fops, ++ throttling_state_show, NULL, "%llu\n"); ++ ++static int pthrottling_state_show(void *data, u64 *val) ++{ ++ *val = smc_call0(MLNX_PTM_GET_PTHROTTLE); ++ ++ return 0; ++} ++DEFINE_SIMPLE_ATTRIBUTE(pthrottling_state_fops, ++ pthrottling_state_show, NULL, "%llu\n"); ++ ++static int tthrottling_state_show(void *data, u64 *val) ++{ ++ *val = smc_call0(MLNX_PTM_GET_TTHROTTLE); ++ ++ return 0; ++} ++DEFINE_SIMPLE_ATTRIBUTE(tthrottling_state_fops, ++ tthrottling_state_show, NULL, "%llu\n"); ++ ++static int core_temp_show(void *data, u64 *val) ++{ ++ *val = smc_call0(MLNX_PTM_GET_MAX_TEMP); ++ ++ return 0; ++} ++DEFINE_SIMPLE_ATTRIBUTE(core_temp_fops, ++ core_temp_show, NULL, "%lld\n"); ++ ++static int pwr_evt_counter_show(void *data, u64 *val) ++{ ++ *val = smc_call0(MLNX_PTM_GET_PWR_EVT_CNT); ++ ++ return 0; ++} ++DEFINE_SIMPLE_ATTRIBUTE(pwr_evt_counter_fops, ++ pwr_evt_counter_show, NULL, "%llu\n"); ++ ++static int temp_evt_counter_show(void *data, u64 *val) ++{ ++ *val = smc_call0(MLNX_PTM_GET_TEMP_EVT_CNT); ++ ++ return 0; ++} ++DEFINE_SIMPLE_ATTRIBUTE(temp_evt_counter_fops, ++ temp_evt_counter_show, NULL, "%llu\n"); ++ ++static int vr0_power_show(void *data, u64 *val) ++{ ++ *val = smc_call0(MLNX_PTM_GET_VR0_POWER); ++ ++ return 0; ++} ++DEFINE_SIMPLE_ATTRIBUTE(vr0_power_fops, vr0_power_show, NULL, "%llu\n"); ++ ++static int vr1_power_show(void *data, u64 *val) ++{ ++ *val = smc_call0(MLNX_PTM_GET_VR1_POWER); ++ ++ return 0; ++} ++DEFINE_SIMPLE_ATTRIBUTE(vr1_power_fops, vr1_power_show, NULL, "%llu\n"); ++ ++static int total_power_show(void *data, u64 *val) ++{ ++ u64 v0, v1; ++ ++ v0 = smc_call0(MLNX_PTM_GET_VR0_POWER); ++ if (v0 > MLNX_POWER_ERROR) ++ v0 = 0; ++ v1 = smc_call0(MLNX_PTM_GET_VR1_POWER); ++ if (v1 > MLNX_POWER_ERROR) ++ v1 = 0; ++ *val = (v0 + v1); ++ ++ return 0; ++} ++DEFINE_SIMPLE_ATTRIBUTE(total_power_fops, total_power_show, NULL, "%llu\n"); ++ ++static int ddr_thld_show(void *data, u64 *val) ++{ ++ *val = smc_call0(MLNX_PTM_GET_DDR_THLD); ++ ++ return 0; ++} ++DEFINE_SIMPLE_ATTRIBUTE(ddr_thld_fops, ddr_thld_show, NULL, "%llu\n"); ++ ++static int error_status_show(void *data, u64 *val) ++{ ++ *val = smc_call0(MLNX_PTM_GET_STATUS_REG); ++ ++ return 0; ++} ++DEFINE_SIMPLE_ATTRIBUTE(error_status_fops, ++ error_status_show, NULL, "%llu\n"); ++ ++ ++static int __init mlxbf_ptm_init(void) ++{ ++ struct dentry *ptm_root, *status; ++ ++ ptm_root = debugfs_lookup("mlxbf-ptm", NULL); ++ if (!ptm_root) ++ ptm_root = debugfs_create_dir("mlxbf-ptm", NULL); ++ ++ monitors = debugfs_create_dir("monitors", ptm_root); ++ status = debugfs_create_dir("status", monitors); ++ ++ debugfs_create_file("vr0_power", S_IRUGO, status, NULL, ++ &vr0_power_fops); ++ debugfs_create_file("vr1_power", S_IRUGO, status, NULL, ++ &vr1_power_fops); ++ debugfs_create_file("total_power", S_IRUGO, status, NULL, ++ &total_power_fops); ++ debugfs_create_file("ddr_temp", S_IRUGO, status, ++ NULL, &ddr_thld_fops); ++ debugfs_create_file("core_temp", S_IRUGO, status, ++ NULL, &core_temp_fops); ++ debugfs_create_file("power_throttling_event_count", S_IRUGO, status, ++ NULL, &pwr_evt_counter_fops); ++ debugfs_create_file("thermal_throttling_event_count", S_IRUGO, status, ++ NULL, &temp_evt_counter_fops); ++ debugfs_create_file("throttling_state", S_IRUGO, status, ++ NULL, &throttling_state_fops); ++ debugfs_create_file("power_throttling_state", S_IRUGO, status, ++ NULL, &pthrottling_state_fops); ++ debugfs_create_file("thermal_throttling_state", S_IRUGO, status, ++ NULL, &tthrottling_state_fops); ++ debugfs_create_file("error_state", S_IRUGO, status, ++ NULL, &error_status_fops); ++ ++ return 0; ++} ++ ++static void __exit mlxbf_ptm_exit(void) ++{ ++ debugfs_remove_recursive(monitors); ++} ++ ++module_init(mlxbf_ptm_init); ++module_exit(mlxbf_ptm_exit); ++ ++MODULE_AUTHOR("Jitendra Lanka "); ++MODULE_DESCRIPTION("Nvidia Bluefield power and thermal debugfs driver"); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_VERSION("1.0"); +-- +2.20.1 + diff --git a/patch/0262-UBUNTU-SAUCE-mlxbf-pmc-Fix-event-string-typo.patch b/patch/0262-UBUNTU-SAUCE-mlxbf-pmc-Fix-event-string-typo.patch new file mode 100644 index 000000000..21783e273 --- /dev/null +++ b/patch/0262-UBUNTU-SAUCE-mlxbf-pmc-Fix-event-string-typo.patch @@ -0,0 +1,36 @@ +From 127bcf5d9412ee246b6620d9b38b7fca6fe4d66d Mon Sep 17 00:00:00 2001 +From: James Hurley +Date: Tue, 6 Dec 2022 11:31:55 -0500 +Subject: [PATCH backport 5.10 3/6] UBUNTU: SAUCE: mlxbf-pmc: Fix event string + typo + +BugLink: https://bugs.launchpad.net/bugs/1998863 + +Fix event string typo so that the proper events are displayed. + +Signed-off-by: James hurley +Reviewed-by: David Thompson +Signed-off-by: James hurley +Acked-by: Tim Gardner +Acked-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/platform/mellanox/mlxbf-pmc.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/platform/mellanox/mlxbf-pmc.h b/drivers/platform/mellanox/mlxbf-pmc.h +index 894c3cc88..a6f7aade4 100644 +--- a/drivers/platform/mellanox/mlxbf-pmc.h ++++ b/drivers/platform/mellanox/mlxbf-pmc.h +@@ -364,7 +364,7 @@ struct mlxbf_pmc_events mlxbf2_hnfnet_events[] = { + {0x32, "DDN_DIAG_W_INGRESS"}, + {0x33, "DDN_DIAG_C_INGRESS"}, + {0x34, "DDN_DIAG_CORE_SENT"}, +-{0x35, "NDN_DIAG_S_OUT_OF_CRED"}, ++{0x35, "NDN_DIAG_N_OUT_OF_CRED"}, + {0x36, "NDN_DIAG_S_OUT_OF_CRED"}, + {0x37, "NDN_DIAG_E_OUT_OF_CRED"}, + {0x38, "NDN_DIAG_W_OUT_OF_CRED"}, +-- +2.20.1 + diff --git a/patch/0263-UBUNTU-SAUCE-mlxbf-pmc-Support-for-BlueField-3-perfo.patch b/patch/0263-UBUNTU-SAUCE-mlxbf-pmc-Support-for-BlueField-3-perfo.patch new file mode 100644 index 000000000..f461a89e4 --- /dev/null +++ b/patch/0263-UBUNTU-SAUCE-mlxbf-pmc-Support-for-BlueField-3-perfo.patch @@ -0,0 +1,929 @@ +From 9325ac1c6648be97da5b6e2504b70a3f31a66690 Mon Sep 17 00:00:00 2001 +From: Shravan Kumar Ramani +Date: Wed, 11 Jan 2023 04:49:23 -0500 +Subject: [PATCH backport 5.10 4/6] UBUNTU: SAUCE: mlxbf-pmc: Support for + BlueField-3 performance counters + +BugLink: https://bugs.launchpad.net/bugs/2002501 + +Add new mechanism for programming and reading the counters in +BlueField-3, along with the updated event list supported in each block. +Read llt_enable and mss_enable info from the ACPI table entry to +identify the enabled blocks. + +Signed-off-by: Shravan Kumar Ramani +Acked-by: Bartlomiej Zolnierkiewicz +Acked-by: Tim Gardner +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/platform/mellanox/mlxbf-pmc.c | 252 +++++++++++++-- + drivers/platform/mellanox/mlxbf-pmc.h | 445 +++++++++++++++++++++++++- + 2 files changed, 658 insertions(+), 39 deletions(-) + +diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c +index 106acea8c..285b7433e 100644 +--- a/drivers/platform/mellanox/mlxbf-pmc.c ++++ b/drivers/platform/mellanox/mlxbf-pmc.c +@@ -243,17 +243,32 @@ struct mlxbf_pmc_events *mlxbf_pmc_event_list(char *blk) + break; + } + else if (strstr(blk, "mss")) +- events = mlxbf_mss_events; ++ switch (pmc->event_set) { ++ case MLNX_EVENT_SET_BF1: ++ case MLNX_EVENT_SET_BF2: ++ events = mlxbf_mss_events; ++ break; ++ case MLNX_EVENT_SET_BF3: ++ events = mlxbf3_mss_events; ++ break; ++ default: ++ events = NULL; ++ break; ++ } + else if (strstr(blk, "ecc")) + events = mlxbf_ecc_events; + else if (strstr(blk, "pcie")) + events = mlxbf_pcie_events; + else if (strstr(blk, "l3cache")) + events = mlxbf_l3cache_events; +- else if (strstr(blk, "gic")) ++ else if (strstr(blk, "gic")) + events = mlxbf_smgen_events; +- else if (strstr(blk, "smmu")) ++ else if (strstr(blk, "smmu")) + events = mlxbf_smgen_events; ++ else if (strstr(blk, "llt_miss")) ++ events = mlxbf3_llt_miss_events; ++ else if (strstr(blk, "llt")) ++ events = mlxbf3_llt_events; + else + events = NULL; + +@@ -378,6 +393,46 @@ int mlxbf_program_l3_counter(int blk_num, uint32_t cnt_num, uint32_t evt) + return mlxbf_pmc_writel(*wordaddr, pmcaddr); + } + ++/* Method to handle crspace counter programming */ ++int mlxbf_program_crspace_counter(int blk_num, uint32_t cnt_num, uint32_t evt) ++{ ++ int reg_num, ret; ++ uint32_t word; ++ void *addr; ++ ++ reg_num = (cnt_num / 2); ++ addr = pmc->block[blk_num].mmio_base + (reg_num * 4); ++ ++ ret = mlxbf_pmc_readl(&word, addr); ++ if (ret) ++ return ret; ++ ++ switch(cnt_num % 2) { ++ case 0: ++ word &= ~MLXBF_CRSPACE_PERFSEL0; ++ word |= FIELD_PREP(MLXBF_CRSPACE_PERFSEL0, evt); ++ break; ++ case 1: ++ word &= ~MLXBF_CRSPACE_PERFSEL1; ++ word |= FIELD_PREP(MLXBF_CRSPACE_PERFSEL1, evt); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return mlxbf_pmc_writel(word, addr); ++} ++ ++int mlxbf_clear_crspace_counter(int blk_num, uint32_t cnt_num) ++{ ++ void *addr; ++ ++ addr = pmc->block[blk_num].mmio_base + MLXBF_CRSPACE_PERFMON_VAL0 + ++ (cnt_num * 4); ++ ++ return mlxbf_pmc_writel(0x0, addr); ++} ++ + /* Method to program a counter to monitor an event */ + int mlxbf_program_counter(int blk_num, uint32_t cnt_num, uint32_t evt, + bool is_l3) +@@ -390,6 +445,9 @@ int mlxbf_program_counter(int blk_num, uint32_t cnt_num, uint32_t evt, + if (is_l3) + return mlxbf_program_l3_counter(blk_num, cnt_num, evt); + ++ if (pmc->block[blk_num].type == MLXBF_PERFTYPE_CRSPACE) ++ return mlxbf_program_crspace_counter(blk_num, cnt_num, evt); ++ + /* Configure the counter */ + perfctl = 0; + perfctl |= FIELD_PREP(MLXBF_GEN_PERFCTL__EN0, 1); +@@ -467,6 +525,22 @@ int mlxbf_read_l3_counter(int blk_num, uint32_t cnt_num, uint64_t *result) + return 0; + } + ++/* Method to handle crspace counter reads */ ++int mlxbf_read_crspace_counter(int blk_num, uint32_t cnt_num, uint64_t *result) ++{ ++ uint32_t value; ++ int status = 0; ++ ++ status = mlxbf_pmc_readl(&value, pmc->block[blk_num].mmio_base + ++ MLXBF_CRSPACE_PERFMON_VAL0 + (cnt_num * 4)); ++ if (status) ++ return status; ++ ++ *result = value; ++ ++ return 0; ++} ++ + /* Method to read the counter value */ + int mlxbf_read_counter(int blk_num, uint32_t cnt_num, bool is_l3, + uint64_t *result) +@@ -481,6 +555,9 @@ int mlxbf_read_counter(int blk_num, uint32_t cnt_num, bool is_l3, + if (is_l3) + return mlxbf_read_l3_counter(blk_num, cnt_num, result); + ++ if (pmc->block[blk_num].type == MLXBF_PERFTYPE_CRSPACE) ++ return mlxbf_read_crspace_counter(blk_num, cnt_num, result); ++ + perfcfg_offset = cnt_num * 8; + perfval_offset = perfcfg_offset + pmc->block[blk_num].counters * 8; + +@@ -557,6 +634,34 @@ int mlxbf_read_l3_event(int blk_num, uint32_t cnt_num, uint64_t *result) + return 0; + } + ++int mlxbf_read_crspace_event(int blk_num, uint32_t cnt_num, uint64_t *result) ++{ ++ uint32_t word, evt; ++ int reg_num, ret; ++ void *addr; ++ ++ reg_num = (cnt_num / 2); ++ addr = pmc->block[blk_num].mmio_base + (reg_num * 4); ++ ++ ret = mlxbf_pmc_readl(&word, addr); ++ if (ret) ++ return ret; ++ ++ switch(cnt_num % 2) { ++ case 0: ++ evt = FIELD_GET(MLXBF_CRSPACE_PERFSEL0, word); ++ break; ++ case 1: ++ evt = FIELD_GET(MLXBF_CRSPACE_PERFSEL1, word); ++ break; ++ default: ++ return -EINVAL; ++ } ++ *result = evt; ++ ++ return 0; ++} ++ + /* Method to find the event currently being monitored by a counter */ + int mlxbf_read_event(int blk_num, uint32_t cnt_num, bool is_l3, + uint64_t *result) +@@ -570,6 +675,10 @@ int mlxbf_read_event(int blk_num, uint32_t cnt_num, bool is_l3, + if (is_l3) + return mlxbf_read_l3_event(blk_num, cnt_num, result); + ++ if (pmc->block[blk_num].type == MLXBF_PERFTYPE_CRSPACE) ++ return mlxbf_read_crspace_event(blk_num, cnt_num, result); ++ ++ + perfcfg_offset = cnt_num * 8; + perfval_offset = perfcfg_offset + pmc->block[blk_num].counters * 8; + +@@ -645,7 +754,8 @@ static ssize_t mlxbf_counter_read(struct kobject *ko, + if (strstr(ko->name, "l3cache")) + is_l3 = true; + +- if (pmc->block[blk_num].type == MLXBF_PERFTYPE_COUNTER) { ++ if ((pmc->block[blk_num].type == MLXBF_PERFTYPE_COUNTER) || ++ (pmc->block[blk_num].type == MLXBF_PERFTYPE_CRSPACE)) { + err = sscanf(attr->attr.name, "counter%d", &cnt_num); + if (err < 0) + return -EINVAL; +@@ -706,6 +816,11 @@ static ssize_t mlxbf_counter_clear(struct kobject *ko, + err = mlxbf_write_reg(blk_num, offset, data); + if (err < 0) + return -EINVAL; ++ } else if (pmc->block[blk_num].type == MLXBF_PERFTYPE_CRSPACE) { ++ err = sscanf(attr->attr.name, "counter%d", &cnt_num); ++ if (err < 0) ++ return -EINVAL; ++ err = mlxbf_clear_crspace_counter(blk_num, cnt_num); + } else + return -EINVAL; + +@@ -738,7 +853,8 @@ static ssize_t mlxbf_event_find(struct kobject *ko, + + evt_name = mlxbf_pmc_get_event_name((char *)ko->name, evt_num); + +- return snprintf(buf, PAGE_SIZE, "0x%llx: %s\n", evt_num, evt_name); ++ return snprintf(buf, PAGE_SIZE, ++ "0x%llx: %s\n", evt_num, evt_name); + } + + /* Store function for "event" sysfs files */ +@@ -806,32 +922,41 @@ static ssize_t mlxbf_print_event_list(struct kobject *ko, + return ret; + } + +-/* Show function for "enable" sysfs files - only for l3cache */ ++/* Show function for "enable" sysfs files - only for l3cache and crspace */ + static ssize_t mlxbf_show_counter_state(struct kobject *ko, + struct kobj_attribute *attr, char *buf) + { +- uint32_t perfcnt_cfg; +- int blk_num, value; ++ uint32_t perfcnt_cfg, word; ++ int blk_num, value, err; + + blk_num = mlxbf_pmc_get_block_num(ko->name); + if (blk_num < 0) + return -EINVAL; + +- if (mlxbf_pmc_readl(&perfcnt_cfg, +- pmc->block[blk_num].mmio_base + MLXBF_L3C_PERF_CNT_CFG)) +- return -EINVAL; ++ if (pmc->block[blk_num].type == MLXBF_PERFTYPE_CRSPACE) { ++ err = mlxbf_pmc_readl(&word, pmc->block[blk_num].mmio_base + ++ MLXBF_CRSPACE_PERFMON_CTL); ++ if (err) ++ return -EINVAL; ++ value = FIELD_GET(MLXBF_CRSPACE_PERFMON_EN, word); ++ } else { ++ if (mlxbf_pmc_readl(&perfcnt_cfg, pmc->block[blk_num].mmio_base ++ + MLXBF_L3C_PERF_CNT_CFG)) ++ return -EINVAL; + +- value = FIELD_GET(MLXBF_L3C_PERF_CNT_CFG__EN, perfcnt_cfg); ++ value = FIELD_GET(MLXBF_L3C_PERF_CNT_CFG__EN, perfcnt_cfg); ++ } + + return snprintf(buf, PAGE_SIZE, "%d\n", value); + } + +-/* Store function for "enable" sysfs files - only for l3cache */ ++/* Store function for "enable" sysfs files - only for l3cache and crspace */ + static ssize_t mlxbf_enable_counters(struct kobject *ko, + struct kobj_attribute *attr, + const char *buf, size_t count) + { + int err, en, blk_num; ++ uint32_t word; + + blk_num = mlxbf_pmc_get_block_num(ko->name); + if (blk_num < 0) +@@ -840,20 +965,32 @@ static ssize_t mlxbf_enable_counters(struct kobject *ko, + err = sscanf(buf, "%x\n", &en); + if (err < 0) + return err; +- +- if (en == 0) { +- err = mlxbf_config_l3_counters(blk_num, false, false); +- if (err) +- return err; +- } else if (en == 1) { +- err = mlxbf_config_l3_counters(blk_num, false, true); +- if (err) +- return err; +- err = mlxbf_config_l3_counters(blk_num, true, false); ++ if (pmc->block[blk_num].type == MLXBF_PERFTYPE_CRSPACE) { ++ err = mlxbf_pmc_readl(&word, pmc->block[blk_num].mmio_base + ++ MLXBF_CRSPACE_PERFMON_CTL); + if (err) +- return err; +- } else +- return -EINVAL; ++ return -EINVAL; ++ word &= ~MLXBF_CRSPACE_PERFMON_EN; ++ word |= FIELD_PREP(MLXBF_CRSPACE_PERFMON_EN, en); ++ if (en) ++ word |= FIELD_PREP(MLXBF_CRSPACE_PERFMON_CLR, 1); ++ mlxbf_pmc_writel(word, pmc->block[blk_num].mmio_base + ++ MLXBF_CRSPACE_PERFMON_CTL); ++ } else { ++ if (en == 0) { ++ err = mlxbf_config_l3_counters(blk_num, false, false); ++ if (err) ++ return err; ++ } else if (en == 1) { ++ err = mlxbf_config_l3_counters(blk_num, false, true); ++ if (err) ++ return err; ++ err = mlxbf_config_l3_counters(blk_num, true, false); ++ if (err) ++ return err; ++ } else ++ return -EINVAL; ++ } + + return count; + } +@@ -871,7 +1008,8 @@ int mlxbf_pmc_create_sysfs(struct device *dev, struct kobject *ko, int blk_num) + return -EFAULT; + } + +- if (pmc->block[blk_num].type == MLXBF_PERFTYPE_COUNTER) { ++ if ((pmc->block[blk_num].type == MLXBF_PERFTYPE_COUNTER) || ++ (pmc->block[blk_num].type == MLXBF_PERFTYPE_CRSPACE)) { + pmc->block[blk_num].attr_event_list.attr.mode = 0444; + pmc->block[blk_num].attr_event_list.show = + mlxbf_print_event_list; +@@ -888,7 +1026,8 @@ int mlxbf_pmc_create_sysfs(struct device *dev, struct kobject *ko, int blk_num) + return err; + } + +- if (strstr(pmc->block_name[blk_num], "l3cache")) { ++ if ((strstr(pmc->block_name[blk_num], "l3cache")) || ++ (pmc->block[blk_num].type == MLXBF_PERFTYPE_CRSPACE)) { + pmc->block[blk_num].attr_enable.attr.mode = + 0644; + pmc->block[blk_num].attr_enable.show = +@@ -1092,6 +1231,8 @@ static int mlxbf_pmc_probe(struct platform_device *pdev) + pmc->event_set = MLNX_EVENT_SET_BF1; + else if (strcmp(hid, "MLNXBFD1") == 0) + pmc->event_set = MLNX_EVENT_SET_BF2; ++ else if (strcmp(hid, "MLNXBFD2") == 0) ++ pmc->event_set = MLNX_EVENT_SET_BF3; + else { + dev_err(dev, "Invalid device ID %s\n", hid); + err = -ENODEV; +@@ -1115,13 +1256,23 @@ static int mlxbf_pmc_probe(struct platform_device *pdev) + } + + if (device_property_read_u32(dev, "tile_num", &pmc->tile_count)) { +- dev_err(dev, "Number of tiles undefined\n"); +- err = -EINVAL; +- goto error; ++ if (device_property_read_u8(dev, "llt_enable", ++ &pmc->llt_enable)) { ++ dev_err(dev, "Number of tiles/LLTs undefined\n"); ++ err = -EINVAL; ++ goto error; ++ } ++ if (device_property_read_u8(dev, "mss_enable", ++ &pmc->mss_enable)) { ++ dev_err(dev, "Number of tiles/MSSs undefined\n"); ++ err = -EINVAL; ++ goto error; ++ } + } + + /* Map the Performance Counters from the varios blocks */ + for (i = 0; i < pmc->total_blocks; ++i) { ++ /* Check if block number is within tile_count */ + if (strstr(pmc->block_name[i], "tile")) { + int tile_num; + +@@ -1133,6 +1284,44 @@ static int mlxbf_pmc_probe(struct platform_device *pdev) + if (tile_num >= pmc->tile_count) + continue; + } ++ ++ /* Create sysfs directories only for enabled MSS blocks */ ++ if (strstr(pmc->block_name[i], "mss") && ++ pmc->event_set == MLNX_EVENT_SET_BF3) { ++ int mss_num; ++ ++ ret = sscanf(pmc->block_name[i], "mss%d", &mss_num); ++ if (ret < 0) { ++ err = -EINVAL; ++ goto error; ++ } ++ if (!((pmc->mss_enable >> mss_num) & 0x1)) ++ continue; ++ } ++ ++ /* Create sysfs directories only for enabled LLTs */ ++ if (strstr(pmc->block_name[i], "llt_miss")) { ++ int llt_num; ++ ++ ret = sscanf(pmc->block_name[i], "llt_miss%d", &llt_num); ++ if (ret < 0) { ++ err = -EINVAL; ++ goto error; ++ } ++ if (!((pmc->llt_enable >> llt_num) & 0x1)) ++ continue; ++ } else if (strstr(pmc->block_name[i], "llt")) { ++ int llt_num; ++ ++ ret = sscanf(pmc->block_name[i], "llt%d", &llt_num); ++ if (ret < 0) { ++ err = -EINVAL; ++ goto error; ++ } ++ if (!((pmc->llt_enable >> llt_num) & 0x1)) ++ continue; ++ } ++ + err = device_property_read_u64_array(dev, pmc->block_name[i], + info, 4); + if (err) { +@@ -1215,6 +1404,7 @@ static int mlxbf_pmc_remove(struct platform_device *pdev) + static const struct acpi_device_id pmc_acpi_ids[] = { + {"MLNXBFD0", 0}, + {"MLNXBFD1", 0}, ++ {"MLNXBFD2", 0}, + {}, + }; + +diff --git a/drivers/platform/mellanox/mlxbf-pmc.h b/drivers/platform/mellanox/mlxbf-pmc.h +index a6f7aade4..fe2516616 100644 +--- a/drivers/platform/mellanox/mlxbf-pmc.h ++++ b/drivers/platform/mellanox/mlxbf-pmc.h +@@ -16,6 +16,7 @@ + + #define MLNX_EVENT_SET_BF1 0 + #define MLNX_EVENT_SET_BF2 1 ++#define MLNX_EVENT_SET_BF3 2 + + #define MLNX_PMC_SVC_REQ_MAJOR 0 + #define MLNX_PMC_SVC_MIN_MINOR 3 +@@ -55,6 +56,8 @@ struct mlxbf_pmc_block_info { + * @pdev: The kernel structure representing the device + * @total_blocks: Total number of blocks + * @tile_count: Number of tiles in the system ++ * @llt_enable: Info on enabled LLTs ++ * @mss_enable: Info on enabled MSSs + * @hwmon_dev: Hwmon device for bfperf + * @ko: Kobject for bfperf + * @block_name: Block name +@@ -67,6 +70,8 @@ struct mlxbf_pmc_context { + struct platform_device *pdev; + uint32_t total_blocks; + uint32_t tile_count; ++ uint8_t llt_enable; ++ uint8_t mss_enable; + struct device *hwmon_dev; + struct kobject *ko; + const char *block_name[MLXBF_PMC_MAX_BLOCKS]; +@@ -76,16 +81,17 @@ struct mlxbf_pmc_context { + unsigned int event_set; + }; + +-#define MLXBF_PERFTYPE_COUNTER 1 + #define MLXBF_PERFTYPE_REGISTER 0 ++#define MLXBF_PERFTYPE_COUNTER 1 ++#define MLXBF_PERFTYPE_CRSPACE 2 + +-#define MLXBF_PERFCTL 0 +-#define MLXBF_PERFEVT 1 +-#define MLXBF_PERFVALEXT 2 +-#define MLXBF_PERFACC0 4 +-#define MLXBF_PERFACC1 5 +-#define MLXBF_PERFMVAL0 6 +-#define MLXBF_PERFMVAL1 7 ++#define MLXBF_PERFCTL 0 ++#define MLXBF_PERFEVT 1 ++#define MLXBF_PERFVALEXT 2 ++#define MLXBF_PERFACC0 4 ++#define MLXBF_PERFACC1 5 ++#define MLXBF_PERFMVAL0 6 ++#define MLXBF_PERFMVAL1 7 + + #define MLXBF_GEN_PERFMON_CONFIG__WR_R_B BIT(0) + #define MLXBF_GEN_PERFMON_CONFIG__STROBE BIT(1) +@@ -143,6 +149,14 @@ struct mlxbf_pmc_context { + #define MLXBF_L3C_PERF_CNT_LOW__VAL GENMASK(31, 0) + #define MLXBF_L3C_PERF_CNT_HIGH__VAL GENMASK(24, 0) + ++#define MLXBF_CRSPACE_PERFMON_REG0 0x0 ++#define MLXBF_CRSPACE_PERFSEL0 GENMASK(23, 16) ++#define MLXBF_CRSPACE_PERFSEL1 GENMASK(7, 0) ++#define MLXBF_CRSPACE_PERFMON_CTL 0x40 ++#define MLXBF_CRSPACE_PERFMON_EN BIT(30) ++#define MLXBF_CRSPACE_PERFMON_CLR BIT(28) ++#define MLXBF_CRSPACE_PERFMON_VAL0 0x4c ++ + struct mlxbf_pmc_events { + uint32_t evt_num; + char *evt_name; +@@ -431,4 +445,419 @@ struct mlxbf_pmc_events mlxbf_l3cache_events[] = { + {-1, NULL} + }; + ++struct mlxbf_pmc_events mlxbf3_llt_events[] = { ++{0, "HNF0_CYCLES"}, ++{1, "HNF0_REQS_RECEIVED"}, ++{2, "HNF0_REQS_PROCESSED"}, ++{3, "HNF0_DIR_HIT"}, ++{4, "HNF0_DIR_MISS"}, ++{5, "HNF0_DIR_RD_ALLOC"}, ++{6, "HNF0_DIR_WR_ALLOC"}, ++{7, "HNF0_DIR_VICTIM"}, ++{8, "HNF0_CL_HAZARD"}, ++{9, "HNF0_ALL_HAZARD"}, ++{10, "HNF0_PIPE_STALLS"}, ++{11, "HNF0_MEM_READS"}, ++{12, "HNF0_MEM_WRITES"}, ++{13, "HNF0_MEM_ACCESS"}, ++{14, "HNF0_DCL_READ"}, ++{15, "HNF0_DCL_INVAL"}, ++{16, "HNF0_CHI_RXDAT"}, ++{17, "HNF0_CHI_RXRSP"}, ++{18, "HNF0_CHI_TXDAT"}, ++{19, "HNF0_CHI_TXRSP"}, ++{20, "HNF0_CHI_TXSNP"}, ++{21, "HNF0_DCT_SNP"}, ++{22, "HNF0_SNP_FWD_DATA"}, ++{23, "HNF0_SNP_FWD_RSP"}, ++{24, "HNF0_SNP_RSP"}, ++{25, "HNF0_EXCL_FULL"}, ++{26, "HNF0_EXCL_WRITE_F"}, ++{27, "HNF0_EXCL_WRITE_S"}, ++{28, "HNF0_EXCL_WRITE"}, ++{29, "HNF0_EXCL_READ"}, ++{30, "HNF0_REQ_BUF_EMPTY"}, ++{31, "HNF0_ALL_MAFS_BUSY"}, ++{32, "HNF0_TXDAT_NO_LCRD"}, ++{33, "HNF0_TXSNP_NO_LCRD"}, ++{34, "HNF0_TXRSP_NO_LCRD"}, ++{35, "HNF0_TXREQ_NO_LCRD"}, ++{36, "HNF0_WRITE"}, ++{37, "HNF0_READ"}, ++{38, "HNF0_ACCESS"}, ++{39, "HNF0_MAF_N_BUSY"}, ++{40, "HNF0_MAF_N_REQS"}, ++{41, "HNF0_SEL_OPCODE"}, ++{42, "HNF1_CYCLES"}, ++{43, "HNF1_REQS_RECEIVED"}, ++{44, "HNF1_REQS_PROCESSED"}, ++{45, "HNF1_DIR_HIT"}, ++{46, "HNF1_DIR_MISS"}, ++{47, "HNF1_DIR_RD_ALLOC"}, ++{48, "HNF1_DIR_WR_ALLOC"}, ++{49, "HNF1_DIR_VICTIM"}, ++{50, "HNF1_CL_HAZARD"}, ++{51, "HNF1_ALL_HAZARD"}, ++{52, "HNF1_PIPE_STALLS"}, ++{53, "HNF1_MEM_READS"}, ++{54, "HNF1_MEM_WRITES"}, ++{55, "HNF1_MEM_ACCESS"}, ++{56, "HNF1_DCL_READ"}, ++{57, "HNF1_DCL_INVAL"}, ++{58, "HNF1_CHI_RXDAT"}, ++{59, "HNF1_CHI_RXRSP"}, ++{60, "HNF1_CHI_TXDAT"}, ++{61, "HNF1_CHI_TXRSP"}, ++{62, "HNF1_CHI_TXSNP"}, ++{63, "HNF1_DCT_SNP"}, ++{64, "HNF1_SNP_FWD_DATA"}, ++{65, "HNF1_SNP_FWD_RSP"}, ++{66, "HNF1_SNP_RSP"}, ++{67, "HNF1_EXCL_FULL"}, ++{68, "HNF1_EXCL_WRITE_F"}, ++{69, "HNF1_EXCL_WRITE_S"}, ++{70, "HNF1_EXCL_WRITE"}, ++{71, "HNF1_EXCL_READ"}, ++{72, "HNF1_REQ_BUF_EMPTY"}, ++{73, "HNF1_ALL_MAFS_BUSY"}, ++{74, "HNF1_TXDAT_NO_LCRD"}, ++{75, "HNF1_TXSNP_NO_LCRD"}, ++{76, "HNF1_TXRSP_NO_LCRD"}, ++{77, "HNF1_TXREQ_NO_LCRD"}, ++{78, "HNF1_WRITE"}, ++{79, "HNF1_READ"}, ++{80, "HNF1_ACCESS"}, ++{81, "HNF1_MAF_N_BUSY"}, ++{82, "HNF1_MAF_N_REQS"}, ++{83, "HNF1_SEL_OPCODE"}, ++{84, "GDC_BANK0_RD_REQ"}, ++{85, "GDC_BANK0_WR_REQ"}, ++{86, "GDC_BANK0_ALLOCATE"}, ++{87, "GDC_BANK0_HIT"}, ++{88, "GDC_BANK0_MISS"}, ++{89, "GDC_BANK0_INVALIDATE"}, ++{90, "GDC_BANK0_EVICT"}, ++{91, "GDC_BANK0_RD_RESP"}, ++{92, "GDC_BANK0_WR_ACK"}, ++{93, "GDC_BANK0_SNOOP"}, ++{94, "GDC_BANK0_SNOOP_NORMAL"}, ++{95, "GDC_BANK0_SNOOP_FWD"}, ++{96, "GDC_BANK0_SNOOP_STASH"}, ++{97, "GDC_BANK0_SNOOP_STASH_INDPND_RD"}, ++{98, "GDC_BANK0_FOLLOWER"}, ++{99, "GDC_BANK0_FW"}, ++{100, "GDC_BANK0_HIT_DCL_BOTH"}, ++{101, "GDC_BANK0_HIT_DCL_PARTIAL"}, ++{102, "GDC_BANK0_EVICT_DCL"}, ++{103, "GDC_BANK0_G_RSE_PIPE_CACHE_DATA0"}, ++{103, "GDC_BANK0_G_RSE_PIPE_CACHE_DATA1"}, ++{105, "GDC_BANK0_ARB_STRB"}, ++{106, "GDC_BANK0_ARB_WAIT"}, ++{107, "GDC_BANK0_GGA_STRB"}, ++{108, "GDC_BANK0_GGA_WAIT"}, ++{109, "GDC_BANK0_FW_STRB"}, ++{110, "GDC_BANK0_FW_WAIT"}, ++{111, "GDC_BANK0_SNP_STRB"}, ++{112, "GDC_BANK0_SNP_WAIT"}, ++{113, "GDC_BANK0_MISS_INARB_STRB"}, ++{114, "GDC_BANK0_MISS_INARB_WAIT"}, ++{115, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD0"}, ++{116, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD1"}, ++{117, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD2"}, ++{118, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD3"}, ++{119, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR0"}, ++{120, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR1"}, ++{121, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR2"}, ++{122, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR3"}, ++{123, "GDC_BANK1_RD_REQ"}, ++{124, "GDC_BANK1_WR_REQ"}, ++{125, "GDC_BANK1_ALLOCATE"}, ++{126, "GDC_BANK1_HIT"}, ++{127, "GDC_BANK1_MISS"}, ++{128, "GDC_BANK1_INVALIDATE"}, ++{129, "GDC_BANK1_EVICT"}, ++{130, "GDC_BANK1_RD_RESP"}, ++{131, "GDC_BANK1_WR_ACK"}, ++{132, "GDC_BANK1_SNOOP"}, ++{133, "GDC_BANK1_SNOOP_NORMAL"}, ++{134, "GDC_BANK1_SNOOP_FWD"}, ++{135, "GDC_BANK1_SNOOP_STASH"}, ++{136, "GDC_BANK1_SNOOP_STASH_INDPND_RD"}, ++{137, "GDC_BANK1_FOLLOWER"}, ++{138, "GDC_BANK1_FW"}, ++{139, "GDC_BANK1_HIT_DCL_BOTH"}, ++{140, "GDC_BANK1_HIT_DCL_PARTIAL"}, ++{141, "GDC_BANK1_EVICT_DCL"}, ++{142, "GDC_BANK1_G_RSE_PIPE_CACHE_DATA0"}, ++{143, "GDC_BANK1_G_RSE_PIPE_CACHE_DATA1"}, ++{144, "GDC_BANK1_ARB_STRB"}, ++{145, "GDC_BANK1_ARB_WAIT"}, ++{146, "GDC_BANK1_GGA_STRB"}, ++{147, "GDC_BANK1_GGA_WAIT"}, ++{148, "GDC_BANK1_FW_STRB"}, ++{149, "GDC_BANK1_FW_WAIT"}, ++{150, "GDC_BANK1_SNP_STRB"}, ++{151, "GDC_BANK1_SNP_WAIT"}, ++{152, "GDC_BANK1_MISS_INARB_STRB"}, ++{153, "GDC_BANK1_MISS_INARB_WAIT"}, ++{154, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD0"}, ++{155, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD1"}, ++{156, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD2"}, ++{157, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD3"}, ++{158, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR0"}, ++{159, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR1"}, ++{160, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR2"}, ++{161, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR3"}, ++{162, "HISTOGRAM_HISTOGRAM_BIN0"}, ++{163, "HISTOGRAM_HISTOGRAM_BIN1"}, ++{164, "HISTOGRAM_HISTOGRAM_BIN2"}, ++{165, "HISTOGRAM_HISTOGRAM_BIN3"}, ++{166, "HISTOGRAM_HISTOGRAM_BIN4"}, ++{167, "HISTOGRAM_HISTOGRAM_BIN5"}, ++{168, "HISTOGRAM_HISTOGRAM_BIN6"}, ++{169, "HISTOGRAM_HISTOGRAM_BIN7"}, ++{170, "HISTOGRAM_HISTOGRAM_BIN8"}, ++{171, "HISTOGRAM_HISTOGRAM_BIN9"}, ++{-1, NULL} ++}; ++ ++struct mlxbf_pmc_events mlxbf3_llt_miss_events[] = { ++{0, "GDC_MISS_MACHINE_RD_REQ"}, ++{1, "GDC_MISS_MACHINE_WR_REQ"}, ++{2, "GDC_MISS_MACHINE_SNP_REQ"}, ++{3, "GDC_MISS_MACHINE_EVICT_REQ"}, ++{4, "GDC_MISS_MACHINE_FW_REQ"}, ++{5, "GDC_MISS_MACHINE_RD_RESP"}, ++{6, "GDC_MISS_MACHINE_WR_RESP"}, ++{7, "GDC_MISS_MACHINE_SNP_STASH_DATAPULL_DROP"}, ++{8, "GDC_MISS_MACHINE_SNP_STASH_DATAPULL_DROP_TXDAT"}, ++{9, "GDC_MISS_MACHINE_CHI_TXREQ"}, ++{10, "GDC_MISS_MACHINE_CHI_RXRSP"}, ++{11, "GDC_MISS_MACHINE_CHI_TXDAT"}, ++{12, "GDC_MISS_MACHINE_CHI_RXDAT"}, ++{13, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_0"}, ++{14, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_1 "}, ++{15, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_2"}, ++{16, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_3 "}, ++{17, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_0 "}, ++{18, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_1 "}, ++{19, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_2 "}, ++{20, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_3 "}, ++{21, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_0"}, ++{22, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_1"}, ++{23, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_2"}, ++{24, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_3"}, ++{25, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_0 "}, ++{26, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_1"}, ++{27, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_2"}, ++{28, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_3"}, ++{29, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_0"}, ++{30, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_1"}, ++{31, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_2"}, ++{32, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_3"}, ++{33, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_4"}, ++{34, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_5"}, ++{35, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_6"}, ++{36, "GDC_MISS_MACHINE_G_RSE_PIPE_TXREQ_0"}, ++{37, "GDC_MISS_MACHINE_G_RSE_PIPE_TXREQ_1"}, ++{38, "GDC_MISS_MACHINE_G_CREDIT_TXREQ_0"}, ++{39, "GDC_MISS_MACHINE_G_CREDIT_TXREQ_1"}, ++{40, "GDC_MISS_MACHINE_G_RSE_PIPE_TXDAT_0"}, ++{41, "GDC_MISS_MACHINE_G_RSE_PIPE_TXDAT_1"}, ++{42, "GDC_MISS_MACHINE_G_CREDIT_TXDAT_0"}, ++{43, "GDC_MISS_MACHINE_G_CREDIT_TXDAT_1"}, ++{44, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_0"}, ++{45, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_1"}, ++{46, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_2"}, ++{47, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_3"}, ++{48, "GDC_MISS_MACHINE_G_RSE_PIPE_TXRSP_0"}, ++{49, "GDC_MISS_MACHINE_G_RSE_PIPE_TXRSP_1"}, ++{50, "GDC_MISS_MACHINE_G_CREDIT_TXRSP_0"}, ++{51, "GDC_MISS_MACHINE_G_CREDIT_TXRSP_1"}, ++{52, "GDC_MISS_MACHINE_G_RSE_PIPE_INARB_0"}, ++{53, "GDC_MISS_MACHINE_G_RSE_PIPE_INARB_1"}, ++{54, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_0"}, ++{55, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_1"}, ++{56, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_2"}, ++{57, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_3"}, ++{58, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_0"}, ++{59, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_1"}, ++{60, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_2"}, ++{61, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_3"}, ++{62, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_4"}, ++{63, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_5"}, ++{64, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_6"}, ++{65, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_7"}, ++{66, "HISTOGRAM_HISTOGRAM_BIN0"}, ++{67, "HISTOGRAM_HISTOGRAM_BIN1"}, ++{68, "HISTOGRAM_HISTOGRAM_BIN2"}, ++{69, "HISTOGRAM_HISTOGRAM_BIN3"}, ++{70, "HISTOGRAM_HISTOGRAM_BIN4"}, ++{71, "HISTOGRAM_HISTOGRAM_BIN5"}, ++{72, "HISTOGRAM_HISTOGRAM_BIN6"}, ++{73, "HISTOGRAM_HISTOGRAM_BIN7"}, ++{74, "HISTOGRAM_HISTOGRAM_BIN8"}, ++{75, "HISTOGRAM_HISTOGRAM_BIN9"}, ++{-1, NULL} ++}; ++ ++struct mlxbf_pmc_events mlxbf3_mss_events[] = { ++{0, "SKYLIB_CDN_TX_FLITS"}, ++{1, "SKYLIB_DDN_TX_FLITS"}, ++{2, "SKYLIB_NDN_TX_FLITS"}, ++{3, "SKYLIB_SDN_TX_FLITS"}, ++{4, "SKYLIB_UDN_TX_FLITS"}, ++{5, "SKYLIB_CDN_RX_FLITS"}, ++{6, "SKYLIB_DDN_RX_FLITS"}, ++{7, "SKYLIB_NDN_RX_FLITS"}, ++{8, "SKYLIB_SDN_RX_FLITS"}, ++{9, "SKYLIB_UDN_RX_FLITS"}, ++{10, "SKYLIB_CDN_TX_STALL"}, ++{11, "SKYLIB_DDN_TX_STALL"}, ++{12, "SKYLIB_NDN_TX_STALL"}, ++{13, "SKYLIB_SDN_TX_STALL"}, ++{14, "SKYLIB_UDN_TX_STALL"}, ++{15, "SKYLIB_CDN_RX_STALL"}, ++{16, "SKYLIB_DDN_RX_STALL"}, ++{17, "SKYLIB_NDN_RX_STALL"}, ++{18, "SKYLIB_SDN_RX_STALL"}, ++{19, "SKYLIB_UDN_RX_STALL"}, ++{20, "SKYLIB_CHI_REQ0_TX_FLITS"}, ++{21, "SKYLIB_CHI_DATA0_TX_FLITS"}, ++{22, "SKYLIB_CHI_RESP0_TX_FLITS"}, ++{23, "SKYLIB_CHI_SNP0_TX_FLITS"}, ++{24, "SKYLIB_CHI_REQ1_TX_FLITS"}, ++{25, "SKYLIB_CHI_DATA1_TX_FLITS"}, ++{26, "SKYLIB_CHI_RESP1_TX_FLITS"}, ++{27, "SKYLIB_CHI_SNP1_TX_FLITS"}, ++{28, "SKYLIB_CHI_REQ2_TX_FLITS"}, ++{29, "SKYLIB_CHI_DATA2_TX_FLITS"}, ++{30, "SKYLIB_CHI_RESP2_TX_FLITS"}, ++{31, "SKYLIB_CHI_SNP2_TX_FLITS"}, ++{32, "SKYLIB_CHI_REQ3_TX_FLITS"}, ++{33, "SKYLIB_CHI_DATA3_TX_FLITS"}, ++{34, "SKYLIB_CHI_RESP3_TX_FLITS"}, ++{35, "SKYLIB_CHI_SNP3_TX_FLITS"}, ++{36, "SKYLIB_TLP_REQ_TX_FLITS"}, ++{37, "SKYLIB_TLP_RESP_TX_FLITS"}, ++{38, "SKYLIB_TLP_META_TX_FLITS"}, ++{39, "SKYLIB_AXIS_DATA_TX_FLITS"}, ++{40, "SKYLIB_AXIS_CRED_TX_FLITS"}, ++{41, "SKYLIB_APB_TX_FLITS"}, ++{42, "SKYLIB_VW_TX_FLITS"}, ++{43, "SKYLIB_GGA_MSN_W_TX_FLITS"}, ++{44, "SKYLIB_GGA_MSN_N_TX_FLITS"}, ++{45, "SKYLIB_CR_REQ_TX_FLITS"}, ++{46, "SKYLIB_CR_RESP_TX_FLITS"}, ++{47, "SKYLIB_MSN_PRNF_TX_FLITS"}, ++{48, "SKYLIB_DBG_DATA_TX_FLITS"}, ++{49, "SKYLIB_DBG_CRED_TX_FLITS"}, ++{50, "SKYLIB_CHI_REQ0_RX_FLITS"}, ++{51, "SKYLIB_CHI_DATA0_RX_FLITS"}, ++{52, "SKYLIB_CHI_RESP0_RX_FLITS"}, ++{53, "SKYLIB_CHI_SNP0_RX_FLITS"}, ++{54, "SKYLIB_CHI_REQ1_RX_FLITS"}, ++{55, "SKYLIB_CHI_DATA1_RX_FLITS"}, ++{56, "SKYLIB_CHI_RESP1_RX_FLITS"}, ++{57, "SKYLIB_CHI_SNP1_RX_FLITS"}, ++{58, "SKYLIB_CHI_REQ2_RX_FLITS"}, ++{59, "SKYLIB_CHI_DATA2_RX_FLITS"}, ++{60, "SKYLIB_CHI_RESP2_RX_FLITS"}, ++{61, "SKYLIB_CHI_SNP2_RX_FLITS"}, ++{62, "SKYLIB_CHI_REQ3_RX_FLITS"}, ++{63, "SKYLIB_CHI_DATA3_RX_FLITS"}, ++{64, "SKYLIB_CHI_RESP3_RX_FLITS"}, ++{65, "SKYLIB_CHI_SNP3_RX_FLITS"}, ++{66, "SKYLIB_TLP_REQ_RX_FLITS"}, ++{67, "SKYLIB_TLP_RESP_RX_FLITS"}, ++{68, "SKYLIB_TLP_META_RX_FLITS"}, ++{69, "SKYLIB_AXIS_DATA_RX_FLITS"}, ++{70, "SKYLIB_AXIS_CRED_RX_FLITS"}, ++{71, "SKYLIB_APB_RX_FLITS"}, ++{72, "SKYLIB_VW_RX_FLITS"}, ++{73, "SKYLIB_GGA_MSN_W_RX_FLITS"}, ++{74, "SKYLIB_GGA_MSN_N_RX_FLITS"}, ++{75, "SKYLIB_CR_REQ_RX_FLITS"}, ++{76, "SKYLIB_CR_RESP_RX_FLITS"}, ++{77, "SKYLIB_MSN_PRNF_RX_FLITS"}, ++{78, "SKYLIB_DBG_DATA_RX_FLITS"}, ++{79, "SKYLIB_DBG_CRED_RX_FLITS"}, ++{80, "SKYLIB_CHI_REQ0_TX_STALL"}, ++{81, "SKYLIB_CHI_DATA0_TX_STALL"}, ++{82, "SKYLIB_CHI_RESP0_TX_STALL"}, ++{83, "SKYLIB_CHI_SNP0_TX_STALL"}, ++{84, "SKYLIB_CHI_REQ1_TX_STALL"}, ++{85, "SKYLIB_CHI_DATA1_TX_STALL"}, ++{86, "SKYLIB_CHI_RESP1_TX_STALL"}, ++{87, "SKYLIB_CHI_SNP1_TX_STALL"}, ++{88, "SKYLIB_CHI_REQ2_TX_STALL"}, ++{89, "SKYLIB_CHI_DATA2_TX_STALL"}, ++{90, "SKYLIB_CHI_RESP2_TX_STALL"}, ++{91, "SKYLIB_CHI_SNP2_TX_STALL"}, ++{92, "SKYLIB_CHI_REQ3_TX_STALL"}, ++{93, "SKYLIB_CHI_DATA3_TX_STALL"}, ++{94, "SKYLIB_CHI_RESP3_TX_STALL"}, ++{95, "SKYLIB_CHI_SNP3_TX_STALL"}, ++{96, "SKYLIB_TLP_REQ_TX_STALL"}, ++{97, "SKYLIB_TLP_RESP_TX_STALL"}, ++{98, "SKYLIB_TLP_META_TX_STALL"}, ++{99, "SKYLIB_AXIS_DATA_TX_STALL"}, ++{100, "SKYLIB_AXIS_CRED_TX_STALL"}, ++{101, "SKYLIB_APB_TX_STALL"}, ++{102, "SKYLIB_VW_TX_STALL"}, ++{103, "SKYLIB_GGA_MSN_W_TX_STALL"}, ++{104, "SKYLIB_GGA_MSN_N_TX_STALL"}, ++{105, "SKYLIB_CR_REQ_TX_STALL"}, ++{106, "SKYLIB_CR_RESP_TX_STALL"}, ++{107, "SKYLIB_MSN_PRNF_TX_STALL"}, ++{108, "SKYLIB_DBG_DATA_TX_STALL"}, ++{109, "SKYLIB_DBG_CRED_TX_STALL"}, ++{110, "SKYLIB_CHI_REQ0_RX_STALL"}, ++{111, "SKYLIB_CHI_DATA0_RX_STALL"}, ++{112, "SKYLIB_CHI_RESP0_RX_STALL"}, ++{113, "SKYLIB_CHI_SNP0_RX_STALL"}, ++{114, "SKYLIB_CHI_REQ1_RX_STALL"}, ++{115, "SKYLIB_CHI_DATA1_RX_STALL"}, ++{116, "SKYLIB_CHI_RESP1_RX_STALL"}, ++{117, "SKYLIB_CHI_SNP1_RX_STALL"}, ++{118, "SKYLIB_CHI_REQ2_RX_STALL"}, ++{119, "SKYLIB_CHI_DATA2_RX_STALL"}, ++{120, "SKYLIB_CHI_RESP2_RX_STALL"}, ++{121, "SKYLIB_CHI_SNP2_RX_STALL"}, ++{122, "SKYLIB_CHI_REQ3_RX_STALL"}, ++{123, "SKYLIB_CHI_DATA3_RX_STALL"}, ++{124, "SKYLIB_CHI_RESP3_RX_STALL"}, ++{125, "SKYLIB_CHI_SNP3_RX_STALL"}, ++{126, "SKYLIB_TLP_REQ_RX_STALL"}, ++{127, "SKYLIB_TLP_RESP_RX_STALL"}, ++{128, "SKYLIB_TLP_META_RX_STALL"}, ++{129, "SKYLIB_AXIS_DATA_RX_STALL"}, ++{130, "SKYLIB_AXIS_CRED_RX_STALL"}, ++{131, "SKYLIB_APB_RX_STALL"}, ++{132, "SKYLIB_VW_RX_STALL"}, ++{133, "SKYLIB_GGA_MSN_W_RX_STALL"}, ++{134, "SKYLIB_GGA_MSN_N_RX_STALL"}, ++{135, "SKYLIB_CR_REQ_RX_STALL"}, ++{136, "SKYLIB_CR_RESP_RX_STALL"}, ++{137, "SKYLIB_MSN_PRNF_RX_STALL"}, ++{138, "SKYLIB_DBG_DATA_RX_STALL"}, ++{139, "SKYLIB_DBG_CRED_RX_STALL"}, ++{140, "SKYLIB_CDN_LOOPBACK_FLITS"}, ++{141, "SKYLIB_DDN_LOOPBACK_FLITS"}, ++{142, "SKYLIB_NDN_LOOPBACK_FLITS"}, ++{143, "SKYLIB_SDN_LOOPBACK_FLITS"}, ++{144, "SKYLIB_UDN_LOOPBACK_FLITS"}, ++{145, "HISTOGRAM_HISTOGRAM_BIN0"}, ++{146, "HISTOGRAM_HISTOGRAM_BIN1"}, ++{147, "HISTOGRAM_HISTOGRAM_BIN2"}, ++{148, "HISTOGRAM_HISTOGRAM_BIN3"}, ++{149, "HISTOGRAM_HISTOGRAM_BIN4"}, ++{150, "HISTOGRAM_HISTOGRAM_BIN5"}, ++{151, "HISTOGRAM_HISTOGRAM_BIN6"}, ++{152, "HISTOGRAM_HISTOGRAM_BIN7"}, ++{153, "HISTOGRAM_HISTOGRAM_BIN8"}, ++{154, "HISTOGRAM_HISTOGRAM_BIN9"}, ++{-1, NULL} ++}; ++ + #endif /* __MLXBF_PMC_H__ */ +-- +2.20.1 + diff --git a/patch/0264-UBUNTU-SAUCE-platform-mellanox-Add-ctrl-message-and-.patch b/patch/0264-UBUNTU-SAUCE-platform-mellanox-Add-ctrl-message-and-.patch new file mode 100644 index 000000000..14a994128 --- /dev/null +++ b/patch/0264-UBUNTU-SAUCE-platform-mellanox-Add-ctrl-message-and-.patch @@ -0,0 +1,275 @@ +From cafef2e9c3fc7113396fb53f55e0b6dfa6115e6a Mon Sep 17 00:00:00 2001 +From: Liming Sun +Date: Thu, 12 Jan 2023 13:58:47 -0500 +Subject: [PATCH backport 5.10 5/6] UBUNTU: SAUCE: platform/mellanox: Add ctrl + message and MAC configuration + +BugLink: https://bugs.launchpad.net/bugs/2002689 + +This commit adds control message support and MAC configuration +based on the control message. + +Signed-off-by: Liming Sun +Acked-by: Bartlomiej Zolnierkiewicz +Acked-by: Tim Gardner +[bzolnier: use a short URL version for BugLink] +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/platform/mellanox/mlxbf-tmfifo.c | 172 ++++++++++++++++++++--- + 1 file changed, 151 insertions(+), 21 deletions(-) + +diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c +index f401bbbd0..97956c9c9 100644 +--- a/drivers/platform/mellanox/mlxbf-tmfifo.c ++++ b/drivers/platform/mellanox/mlxbf-tmfifo.c +@@ -159,7 +159,9 @@ struct mlxbf_tmfifo_irq_info { + * @timer: background timer + * @vring: Tx/Rx ring + * @spin_lock: Tx/Rx spin lock ++ * @ctrl_mac: MAC address received in control message + * @is_ready: ready flag ++ * @send_ctrl: flag to send control message when ready + */ + struct mlxbf_tmfifo { + struct mlxbf_tmfifo_vdev *vdev[MLXBF_TMFIFO_VDEV_MAX]; +@@ -180,7 +182,16 @@ struct mlxbf_tmfifo { + struct timer_list timer; + struct mlxbf_tmfifo_vring *vring[2]; + spinlock_t spin_lock[2]; /* spin lock */ +- bool is_ready; ++ u8 ctrl_mac[ETH_ALEN]; ++ u32 is_ready : 1; ++ u32 send_ctrl : 1; ++}; ++ ++/* Internal message types defined in reverse order starting from 0xFF. */ ++enum { ++ MLXBF_TMFIFO_MSG_CTRL_REQ = 0xFD, ++ MLXBF_TMFIFO_MSG_MAC_1 = 0xFE, ++ MLXBF_TMFIFO_MSG_MAC_2 = 0xFF + }; + + /** +@@ -190,11 +201,17 @@ struct mlxbf_tmfifo { + * will be read by the other side as data stream in the same byte order. + * The length needs to be encoded into network order so both sides + * could understand it. ++ * @mac: first or second half of the MAC address depending on the type. ++ * @checksum: checksum of the message header (only control message for now). + */ + struct mlxbf_tmfifo_msg_hdr { + u8 type; + __be16 len; +- u8 unused[5]; ++ union { ++ u8 mac[3]; ++ u8 unused[4]; ++ } __packed; ++ u8 checksum; + } __packed __aligned(sizeof(u64)); + + /* +@@ -491,6 +508,8 @@ static int mlxbf_tmfifo_get_rx_avail(struct mlxbf_tmfifo *fifo) + return FIELD_GET(MLXBF_TMFIFO_RX_STS__COUNT_MASK, sts); + } + ++ ++ + /* Get the number of available words in the TmFifo for sending. */ + static int mlxbf_tmfifo_get_tx_avail(struct mlxbf_tmfifo *fifo, int vdev_id) + { +@@ -509,6 +528,127 @@ static int mlxbf_tmfifo_get_tx_avail(struct mlxbf_tmfifo *fifo, int vdev_id) + return fifo->tx_fifo_size - tx_reserve - count; + } + ++/* Read the configured network MAC address from efi variable. */ ++static void mlxbf_tmfifo_get_cfg_mac(u8 *mac) ++{ ++ efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID; ++ unsigned long size = ETH_ALEN; ++ u8 buf[ETH_ALEN]; ++ efi_status_t rc; ++ ++ rc = efi.get_variable(mlxbf_tmfifo_efi_name, &guid, NULL, &size, buf); ++ if (rc == EFI_SUCCESS && size == ETH_ALEN) ++ ether_addr_copy(mac, buf); ++ else ++ ether_addr_copy(mac, mlxbf_tmfifo_net_default_mac); ++} ++ ++/* Set the configured network MAC address into efi variable. */ ++static efi_status_t mlxbf_tmfifo_set_cfg_mac(u8 *mac) ++{ ++ efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID; ++ efi_status_t status = EFI_SUCCESS; ++ u8 old_mac[ETH_ALEN] = {0}; ++ ++ mlxbf_tmfifo_get_cfg_mac(old_mac); ++ ++ if (memcmp(old_mac, mac, ETH_ALEN)) { ++ status = efi.set_variable(mlxbf_tmfifo_efi_name, &guid, ++ EFI_VARIABLE_NON_VOLATILE | ++ EFI_VARIABLE_BOOTSERVICE_ACCESS | ++ EFI_VARIABLE_RUNTIME_ACCESS, ++ ETH_ALEN, mac); ++ } ++ ++ return status; ++} ++ ++/* Just adds up all the bytes of the header. */ ++static u8 mlxbf_tmfifo_ctrl_checksum(struct mlxbf_tmfifo_msg_hdr *hdr) ++{ ++ u8 checksum = 0; ++ int i; ++ ++ for (i = 0; i < sizeof(*hdr); i++) ++ checksum += ((u8 *)hdr)[i]; ++ ++ return checksum; ++} ++ ++static void mlxbf_tmfifo_ctrl_update_checksum(struct mlxbf_tmfifo_msg_hdr *hdr) ++{ ++ u8 checksum; ++ ++ hdr->checksum = 0; ++ checksum = mlxbf_tmfifo_ctrl_checksum(hdr); ++ hdr->checksum = ~checksum + 1; ++} ++ ++static bool mlxbf_tmfifo_ctrl_verify_checksum(struct mlxbf_tmfifo_msg_hdr *hdr) ++{ ++ u8 checksum = mlxbf_tmfifo_ctrl_checksum(hdr); ++ ++ return checksum ? false : true; ++} ++ ++static void mlxbf_tmfifo_ctrl_rx(struct mlxbf_tmfifo *fifo, ++ struct mlxbf_tmfifo_msg_hdr *hdr) ++{ ++ if (!mlxbf_tmfifo_ctrl_verify_checksum(hdr)) ++ return; ++ ++ switch (hdr->type) { ++ case MLXBF_TMFIFO_MSG_CTRL_REQ: ++ /* ++ * Set a flag to send the MAC address later. It can't be sent ++ * here since another packet might be still in the middle of ++ * transmission. ++ */ ++ fifo->send_ctrl = 1; ++ test_and_set_bit(MLXBF_TM_TX_LWM_IRQ, &fifo->pend_events); ++ schedule_work(&fifo->work); ++ break; ++ case MLXBF_TMFIFO_MSG_MAC_1: ++ /* Get the first half of the MAC address. */ ++ memcpy(fifo->ctrl_mac, hdr->mac, sizeof(hdr->mac)); ++ break; ++ case MLXBF_TMFIFO_MSG_MAC_2: ++ /* Get the second half of the MAC address and update. */ ++ memcpy(fifo->ctrl_mac + sizeof(hdr->mac), hdr->mac, ++ sizeof(hdr->mac)); ++ mlxbf_tmfifo_set_cfg_mac(fifo->ctrl_mac); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void mlxbf_tmfifo_ctrl_tx(struct mlxbf_tmfifo *fifo, int *num_avail) ++{ ++ struct mlxbf_tmfifo_msg_hdr hdr; ++ u8 mac[ETH_ALEN] = { 0 }; ++ ++ /* Send the MAC address with two control messages. */ ++ if (fifo->send_ctrl && *num_avail >= 2) { ++ mlxbf_tmfifo_get_cfg_mac(mac); ++ ++ hdr.type = MLXBF_TMFIFO_MSG_MAC_1; ++ hdr.len = 0; ++ memcpy(hdr.mac, mac, sizeof(hdr.mac)); ++ mlxbf_tmfifo_ctrl_update_checksum(&hdr); ++ writeq(*(u64 *)&hdr, fifo->tx_data); ++ (*num_avail)--; ++ ++ hdr.type = MLXBF_TMFIFO_MSG_MAC_2; ++ memcpy(hdr.mac, mac + sizeof(hdr.mac), sizeof(hdr.mac)); ++ mlxbf_tmfifo_ctrl_update_checksum(&hdr); ++ writeq(*(u64 *)&hdr, fifo->tx_data); ++ (*num_avail)--; ++ ++ fifo->send_ctrl = 0; ++ } ++} ++ + /* Console Tx (move data from the output buffer into the TmFifo). */ + static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail) + { +@@ -634,9 +774,11 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring, + /* Drain one word from the FIFO. */ + *(u64 *)&hdr = readq(fifo->rx_data); + +- /* Skip the length 0 packets (keepalive). */ +- if (hdr.len == 0) ++ /* Handle the zero-length packets (control msg). */ ++ if (hdr.len == 0) { ++ mlxbf_tmfifo_ctrl_rx(fifo, &hdr); + return; ++ } + + /* Check packet type. */ + if (hdr.type == VIRTIO_ID_NET) { +@@ -804,6 +946,9 @@ static void mlxbf_tmfifo_rxtx(struct mlxbf_tmfifo_vring *vring, bool is_rx) + + /* Console output always comes from the Tx buffer. */ + if (!is_rx && devid == VIRTIO_ID_CONSOLE) { ++ /* Check if there is any control data to send. */ ++ mlxbf_tmfifo_ctrl_tx(fifo, &avail); ++ + mlxbf_tmfifo_console_tx(fifo, avail); + break; + } +@@ -1149,21 +1294,6 @@ static int mlxbf_tmfifo_delete_vdev(struct mlxbf_tmfifo *fifo, int vdev_id) + return 0; + } + +-/* Read the configured network MAC address from efi variable. */ +-static void mlxbf_tmfifo_get_cfg_mac(u8 *mac) +-{ +- efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID; +- unsigned long size = ETH_ALEN; +- u8 buf[ETH_ALEN]; +- efi_status_t rc; +- +- rc = efi.get_variable(mlxbf_tmfifo_efi_name, &guid, NULL, &size, buf); +- if (rc == EFI_SUCCESS && size == ETH_ALEN) +- ether_addr_copy(mac, buf); +- else +- ether_addr_copy(mac, mlxbf_tmfifo_net_default_mac); +-} +- + /* Set TmFifo thresolds which is used to trigger interrupts. */ + static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo) + { +@@ -1196,7 +1326,7 @@ static void mlxbf_tmfifo_cleanup(struct mlxbf_tmfifo *fifo) + { + int i; + +- fifo->is_ready = false; ++ fifo->is_ready = 0; + del_timer_sync(&fifo->timer); + mlxbf_tmfifo_disable_irqs(fifo); + cancel_work_sync(&fifo->work); +@@ -1296,7 +1426,7 @@ static int mlxbf_tmfifo_probe(struct platform_device *pdev) + + mod_timer(&fifo->timer, jiffies + MLXBF_TMFIFO_TIMER_INTERVAL); + +- fifo->is_ready = true; ++ fifo->is_ready = 1; + return 0; + + fail: +-- +2.20.1 + diff --git a/patch/0265-hwmon-mlxreg-fan-Return-zero-speed-for-broken-fan.patch b/patch/0265-hwmon-mlxreg-fan-Return-zero-speed-for-broken-fan.patch new file mode 100644 index 000000000..cb0440a0f --- /dev/null +++ b/patch/0265-hwmon-mlxreg-fan-Return-zero-speed-for-broken-fan.patch @@ -0,0 +1,40 @@ +From 0bb5bbc78316970c3bde085f091a70799b39b262 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 5 Feb 2023 09:34:20 +0200 +Subject: [PATCH hwmon backport 5.10 1/1] hwmon: (mlxreg-fan) Return zero speed + for broken fan + +Currently for broken fan driver returns value calculated based on error +code (0xFF) in related fan speed register. +Thus, for such fan user gets fan{n}_fault to 1 and fan{n}_input with +misleading value. + +Add check for fan fault prior return speed value and return zero if +fault is detected. + +Fixes: 65afb4c8e7e4 ("hwmon: (mlxreg-fan) Add support for Mellanox FAN driver") +Signed-off-by: Vadim Pasternak +--- + drivers/hwmon/mlxreg-fan.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c +index acba9d688..b999ca648 100644 +--- a/drivers/hwmon/mlxreg-fan.c ++++ b/drivers/hwmon/mlxreg-fan.c +@@ -158,6 +158,12 @@ mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, + if (err) + return err; + ++ if (MLXREG_FAN_GET_FAULT(regval, tacho->mask)) { ++ /* FAN is broken - return zero for FAN speed. */ ++ *val = 0; ++ return 0; ++ } ++ + *val = MLXREG_FAN_GET_RPM(regval, fan->divider, + fan->samples); + break; +-- +2.20.1 + diff --git a/patch/0266-UBUNTU-SAUCE-mlxbf-pmc-Bug-fix-for-BlueField-3-count.patch b/patch/0266-UBUNTU-SAUCE-mlxbf-pmc-Bug-fix-for-BlueField-3-count.patch new file mode 100644 index 000000000..12bd08f7d --- /dev/null +++ b/patch/0266-UBUNTU-SAUCE-mlxbf-pmc-Bug-fix-for-BlueField-3-count.patch @@ -0,0 +1,94 @@ +From 8cceb490410ba87b8f50ecbc5576f8eaab9f31bd Mon Sep 17 00:00:00 2001 +From: Shravan Kumar Ramani +Date: Tue, 31 Jan 2023 03:20:57 -0500 +Subject: [PATCH 11/12] UBUNTU: SAUCE: mlxbf-pmc: Bug fix for BlueField-3 + counter offsets +X-NVConfidentiality: public + +BugLink: https://bugs.launchpad.net/bugs/2004235 + +The performance counter modules inside each HW block are not +identical and are dependent on the number of counters present +in each case. Hence the offsets for the control and data regs +should be calculated accordingly. + +Signed-off-by: Shravan Kumar Ramani +Acked-by: Tim Gardner +Acked-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/platform/mellanox/mlxbf-pmc.c | 12 +++++++----- + drivers/platform/mellanox/mlxbf-pmc.h | 4 ++-- + 2 files changed, 9 insertions(+), 7 deletions(-) + +diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c +index 285b7433e..9be5a2d68 100644 +--- a/drivers/platform/mellanox/mlxbf-pmc.c ++++ b/drivers/platform/mellanox/mlxbf-pmc.c +@@ -427,7 +427,8 @@ int mlxbf_clear_crspace_counter(int blk_num, uint32_t cnt_num) + { + void *addr; + +- addr = pmc->block[blk_num].mmio_base + MLXBF_CRSPACE_PERFMON_VAL0 + ++ addr = pmc->block[blk_num].mmio_base + ++ MLXBF_CRSPACE_PERFMON_VAL0(pmc->block[blk_num].counters) + + (cnt_num * 4); + + return mlxbf_pmc_writel(0x0, addr); +@@ -532,7 +533,8 @@ int mlxbf_read_crspace_counter(int blk_num, uint32_t cnt_num, uint64_t *result) + int status = 0; + + status = mlxbf_pmc_readl(&value, pmc->block[blk_num].mmio_base + +- MLXBF_CRSPACE_PERFMON_VAL0 + (cnt_num * 4)); ++ MLXBF_CRSPACE_PERFMON_VAL0(pmc->block[blk_num].counters) + ++ (cnt_num * 4)); + if (status) + return status; + +@@ -935,7 +937,7 @@ static ssize_t mlxbf_show_counter_state(struct kobject *ko, + + if (pmc->block[blk_num].type == MLXBF_PERFTYPE_CRSPACE) { + err = mlxbf_pmc_readl(&word, pmc->block[blk_num].mmio_base + +- MLXBF_CRSPACE_PERFMON_CTL); ++ MLXBF_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters)); + if (err) + return -EINVAL; + value = FIELD_GET(MLXBF_CRSPACE_PERFMON_EN, word); +@@ -967,7 +969,7 @@ static ssize_t mlxbf_enable_counters(struct kobject *ko, + return err; + if (pmc->block[blk_num].type == MLXBF_PERFTYPE_CRSPACE) { + err = mlxbf_pmc_readl(&word, pmc->block[blk_num].mmio_base + +- MLXBF_CRSPACE_PERFMON_CTL); ++ MLXBF_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters)); + if (err) + return -EINVAL; + word &= ~MLXBF_CRSPACE_PERFMON_EN; +@@ -975,7 +977,7 @@ static ssize_t mlxbf_enable_counters(struct kobject *ko, + if (en) + word |= FIELD_PREP(MLXBF_CRSPACE_PERFMON_CLR, 1); + mlxbf_pmc_writel(word, pmc->block[blk_num].mmio_base + +- MLXBF_CRSPACE_PERFMON_CTL); ++ MLXBF_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters)); + } else { + if (en == 0) { + err = mlxbf_config_l3_counters(blk_num, false, false); +diff --git a/drivers/platform/mellanox/mlxbf-pmc.h b/drivers/platform/mellanox/mlxbf-pmc.h +index fe2516616..2ee7efc3b 100644 +--- a/drivers/platform/mellanox/mlxbf-pmc.h ++++ b/drivers/platform/mellanox/mlxbf-pmc.h +@@ -152,10 +152,10 @@ struct mlxbf_pmc_context { + #define MLXBF_CRSPACE_PERFMON_REG0 0x0 + #define MLXBF_CRSPACE_PERFSEL0 GENMASK(23, 16) + #define MLXBF_CRSPACE_PERFSEL1 GENMASK(7, 0) +-#define MLXBF_CRSPACE_PERFMON_CTL 0x40 ++#define MLXBF_CRSPACE_PERFMON_CTL(n) (n * 2) + #define MLXBF_CRSPACE_PERFMON_EN BIT(30) + #define MLXBF_CRSPACE_PERFMON_CLR BIT(28) +-#define MLXBF_CRSPACE_PERFMON_VAL0 0x4c ++#define MLXBF_CRSPACE_PERFMON_VAL0(n) (MLXBF_CRSPACE_PERFMON_CTL(n) + 0xc) + + struct mlxbf_pmc_events { + uint32_t evt_num; +-- +2.14.1 + diff --git a/patch/0267-UBUNTU-SAUCE-mmc-sdhci-of-dwcmshc-add-the-missing-de.patch b/patch/0267-UBUNTU-SAUCE-mmc-sdhci-of-dwcmshc-add-the-missing-de.patch new file mode 100644 index 000000000..c61486cf2 --- /dev/null +++ b/patch/0267-UBUNTU-SAUCE-mmc-sdhci-of-dwcmshc-add-the-missing-de.patch @@ -0,0 +1,36 @@ +From 51ec31f1bfb39fd87dea8861b4642d03cbd6c887 Mon Sep 17 00:00:00 2001 +From: Liming Sun +Date: Fri, 3 Feb 2023 07:52:18 -0500 +Subject: [PATCH 12/12] UBUNTU: SAUCE: mmc: sdhci-of-dwcmshc: add the missing + device table IDs for acpi +X-NVConfidentiality: public + +BugLink: https://bugs.launchpad.net/bugs/2004645 + +This commit adds the missing MODULE_DEVICE_TABLE for acpi, or else +it won't be loaded automatically when compiled as a kernel module. + +Signed-off-by: Liming Sun +Acked-by: Tim Gardner +Acked-by: Bartlomiej Zolnierkiewicz +[bzolnier: use a short URL version for BugLink] +Signed-off-by: Bartlomiej Zolnierkiewicz +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c +index ea972bd3c..565489ee7 100644 +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -349,6 +349,7 @@ static const struct acpi_device_id sdhci_dwcmshc_acpi_ids[] = { + }, + {} + }; ++MODULE_DEVICE_TABLE(acpi, sdhci_dwcmshc_acpi_ids); + #endif + + static int dwcmshc_probe(struct platform_device *pdev) +-- +2.14.1 + diff --git a/patch/0269-platform-mellanox-Cosmetic-changes.patch b/patch/0269-platform-mellanox-Cosmetic-changes.patch new file mode 100644 index 000000000..18dc177ed --- /dev/null +++ b/patch/0269-platform-mellanox-Cosmetic-changes.patch @@ -0,0 +1,74 @@ +From da7c9365e155de2a038cbc1cded3a56ea9a363aa Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 27 Feb 2023 15:24:43 +0000 +Subject: [PATCH backport 5.10 1/3] platform: mellanox: Cosmetic changes + +Fix routines and labels names by s/topology/topology. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Michael Shych +--- + drivers/platform/mellanox/mlx-platform.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/platform/mellanox/mlx-platform.c b/drivers/platform/mellanox/mlx-platform.c +index 849fdf5de..656056089 100644 +--- a/drivers/platform/mellanox/mlx-platform.c ++++ b/drivers/platform/mellanox/mlx-platform.c +@@ -6876,7 +6876,7 @@ mlxplat_i2c_mux_complition_notify(void *handle, struct i2c_adapter *parent, + return 0; + } + +-static int mlxplat_i2c_mux_topolgy_init(struct mlxplat_priv *priv) ++static int mlxplat_i2c_mux_topology_init(struct mlxplat_priv *priv) + { + int i, err; + +@@ -6921,7 +6921,7 @@ static int mlxplat_i2c_mux_topolgy_init(struct mlxplat_priv *priv) + return err; + } + +-static void mlxplat_i2c_mux_topolgy_exit(struct mlxplat_priv *priv) ++static void mlxplat_i2c_mux_topology_exit(struct mlxplat_priv *priv) + { + int i; + +@@ -6937,7 +6937,7 @@ static int mlxplat_i2c_main_complition_notify(void *handle, int id) + { + struct mlxplat_priv *priv = handle; + +- return mlxplat_i2c_mux_topolgy_init(priv); ++ return mlxplat_i2c_mux_topology_init(priv); + } + + static int mlxplat_i2c_main_init(struct mlxplat_priv *priv) +@@ -6964,14 +6964,14 @@ static int mlxplat_i2c_main_init(struct mlxplat_priv *priv) + } + + if (priv->i2c_main_init_status == MLXPLAT_I2C_MAIN_BUS_NOTIFIED) { +- err = mlxplat_i2c_mux_topolgy_init(priv); ++ err = mlxplat_i2c_mux_topology_init(priv); + if (err) +- goto fail_mlxplat_i2c_mux_topolgy_init; ++ goto fail_mlxplat_i2c_mux_topology_init; + } + + return 0; + +-fail_mlxplat_i2c_mux_topolgy_init: ++fail_mlxplat_i2c_mux_topology_init: + fail_platform_i2c_register: + fail_mlxplat_mlxcpld_verify_bus_topology: + return err; +@@ -6979,7 +6979,7 @@ static int mlxplat_i2c_main_init(struct mlxplat_priv *priv) + + static void mlxplat_i2c_main_exit(struct mlxplat_priv *priv) + { +- mlxplat_i2c_mux_topolgy_exit(priv); ++ mlxplat_i2c_mux_topology_exit(priv); + if (priv->pdev_i2c) + platform_device_unregister(priv->pdev_i2c); + } +-- +2.20.1 + diff --git a/patch/0270-platform-mellanox-Fix-order-in-exit-flow.patch b/patch/0270-platform-mellanox-Fix-order-in-exit-flow.patch new file mode 100644 index 000000000..4bbbe389a --- /dev/null +++ b/patch/0270-platform-mellanox-Fix-order-in-exit-flow.patch @@ -0,0 +1,39 @@ +From 89d0e497e62b90e8faa2b67c298cedeab47b8f8b Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 27 Feb 2023 16:09:17 +0000 +Subject: [PATCH backport 5.10 2/3] platform: mellanox: Fix order in exit flow + +Fix exit flow order: call mlxplat_post_exit() after +mlxplat_i2c_main_exit() in order to unregister main i2c driver before +to "mlxplat" driver. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Michael Shych +--- + drivers/platform/mellanox/mlx-platform.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/platform/mellanox/mlx-platform.c b/drivers/platform/mellanox/mlx-platform.c +index 656056089..42fd7e4e0 100644 +--- a/drivers/platform/mellanox/mlx-platform.c ++++ b/drivers/platform/mellanox/mlx-platform.c +@@ -6929,8 +6929,6 @@ static void mlxplat_i2c_mux_topology_exit(struct mlxplat_priv *priv) + if (priv->pdev_mux[i]) + platform_device_unregister(priv->pdev_mux[i]); + } +- +- mlxplat_post_exit(); + } + + static int mlxplat_i2c_main_complition_notify(void *handle, int id) +@@ -7068,6 +7066,7 @@ static void __exit mlxplat_exit(void) + unregister_reboot_notifier(mlxplat_reboot_nb); + mlxplat_pre_exit(priv); + mlxplat_i2c_main_exit(priv); ++ mlxplat_post_exit(); + } + module_exit(mlxplat_exit); + +-- +2.20.1 + diff --git a/patch/0271-platform-mellanox-Add-new-attributes.patch b/patch/0271-platform-mellanox-Add-new-attributes.patch new file mode 100644 index 000000000..92044c45b --- /dev/null +++ b/patch/0271-platform-mellanox-Add-new-attributes.patch @@ -0,0 +1,49 @@ +From 6cb8f4e432f8209a3775877d690a979a2e786afc Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 27 Feb 2023 18:56:09 +0000 +Subject: [PATCH backport 5.10 3/3] platform: mellanox: Add new attributes + +Add two new attributes: +"lid_open" - to indicate system intrusion detection. +"reset_long_pwr_pb" - to indicate that system has been reset due to +long press of power button. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Michael Shych +--- + drivers/platform/mellanox/mlx-platform.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/platform/mellanox/mlx-platform.c b/drivers/platform/mellanox/mlx-platform.c +index 42fd7e4e0..4eb327720 100644 +--- a/drivers/platform/mellanox/mlx-platform.c ++++ b/drivers/platform/mellanox/mlx-platform.c +@@ -4067,6 +4067,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0444, + }, ++ { ++ .label = "lid_open", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(2), ++ .mode = 0444, ++ }, + { + .label = "clk_brd1_boot_fail", + .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, +@@ -4706,6 +4712,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_chassis_blade_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, ++ { ++ .label = "reset_long_pwr_pb", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(7), ++ .mode = 0444, ++ }, + { + .label = "pwr_cycle", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, +-- +2.20.1 + diff --git a/patch/0272-platform-mellanox-Change-register-offset-addresses.patch b/patch/0272-platform-mellanox-Change-register-offset-addresses.patch new file mode 100644 index 000000000..a5596171c --- /dev/null +++ b/patch/0272-platform-mellanox-Change-register-offset-addresses.patch @@ -0,0 +1,43 @@ +From 020ab13e16f943bb66da221507f83634a7d9ca05 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 1 Mar 2023 17:21:48 +0000 +Subject: [PATCH backport 5.10 4/5] platform: mellanox: Change register offset + addresses + +Move debug register offsets to different location due to hardware changes. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Michael Shych +--- + drivers/platform/mellanox/mlx-platform.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/platform/mellanox/mlx-platform.c b/drivers/platform/mellanox/mlx-platform.c +index 4eb327720..b5d51673f 100644 +--- a/drivers/platform/mellanox/mlx-platform.c ++++ b/drivers/platform/mellanox/mlx-platform.c +@@ -66,10 +66,6 @@ + #define MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET 0x37 + #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a + #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b +-#define MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET 0x3c +-#define MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET 0x3d +-#define MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET 0x3e +-#define MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET 0x3f + #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 + #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 + #define MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET 0x42 +@@ -130,6 +126,10 @@ + #define MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET 0xaa + #define MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET 0xab + #define MLXPLAT_CPLD_LPC_REG_LC_PWR_ON 0xb2 ++#define MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET 0xb6 ++#define MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET 0xb7 ++#define MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET 0xb8 ++#define MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET 0xb9 + #define MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET 0xc2 + #define MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT 0xc3 + #define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET 0xc7 +-- +2.20.1 + diff --git a/patch/0273-platform-mellanox-Add-field-upgrade-capability-regis.patch b/patch/0273-platform-mellanox-Add-field-upgrade-capability-regis.patch new file mode 100644 index 000000000..0e1c1b469 --- /dev/null +++ b/patch/0273-platform-mellanox-Add-field-upgrade-capability-regis.patch @@ -0,0 +1,72 @@ +From 96de5181b880adf2fd65fa85fbc3e0c74f976788 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 1 Mar 2023 17:49:08 +0000 +Subject: [PATCH backport 5.10 5/6] platform: mellanox: Add field upgrade + capability register + +Add new register to indicate the method of FPGA/CPLD field upgrade +supported on the specific system. +Currently two masks are available: +b00 - field upgrade through LPC gateway (new method introduced to + accelerate field upgrade process). +b11 - field upgrade through CPU GPIO pins (old method). + +Signed-off-by: Vadim Pasternak +Reviewed-by: Michael Shych +--- + drivers/platform/mellanox/mlx-platform.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/platform/mellanox/mlx-platform.c b/drivers/platform/mellanox/mlx-platform.c +index b5d51673f..f674d9173 100644 +--- a/drivers/platform/mellanox/mlx-platform.c ++++ b/drivers/platform/mellanox/mlx-platform.c +@@ -66,6 +66,7 @@ + #define MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET 0x37 + #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a + #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b ++#define MLXPLAT_CPLD_LPC_REG_FU_CAP_OFFSET 0x3c + #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 + #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 + #define MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET 0x42 +@@ -241,6 +242,7 @@ + #define MLXPLAT_CPLD_VOLTREG_UPD_MASK GENMASK(5, 4) + #define MLXPLAT_CPLD_GWP_MASK GENMASK(0, 0) + #define MLXPLAT_CPLD_EROT_MASK GENMASK(1, 0) ++#define MLXPLAT_CPLD_FU_CAP_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_PWR_BUTTON_MASK BIT(0) + #define MLXPLAT_CPLD_LATCH_RST_MASK BIT(5) + #define MLXPLAT_CPLD_THERMAL1_PDB_MASK BIT(3) +@@ -3956,6 +3958,13 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0200, + }, ++ { ++ .label = "jtag_cap", ++ .reg = MLXPLAT_CPLD_LPC_REG_FU_CAP_OFFSET, ++ .mask = MLXPLAT_CPLD_FU_CAP_MASK, ++ .bit = 1, ++ .mode = 0444, ++ }, + { + .label = "jtag_enable", + .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, +@@ -5424,6 +5433,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FU_CAP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET: +@@ -5582,6 +5592,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FU_CAP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET: +-- +2.20.1 + diff --git a/patch/0274-platform-mellanox-Modify-reset-causes-description.patch b/patch/0274-platform-mellanox-Modify-reset-causes-description.patch new file mode 100644 index 000000000..d118ede76 --- /dev/null +++ b/patch/0274-platform-mellanox-Modify-reset-causes-description.patch @@ -0,0 +1,51 @@ +From f8a0954053e6e06070ed399e1810bea089ba36bd Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 2 Mar 2023 12:28:11 +0000 +Subject: [PATCH backport v.5.10 4/8] platform: mellanox: Modify reset causes + description + +For system of classes VMOD0005, VMOD0010: +- remove "reset_from_comex", since this cause doesn't define specific + reason. +- add more speicific reason "reset_sw_reset", which is set along with + removed "reset_from_comex". + +Signed-off-by: Vadim Pasternak +Reviewed-by: Michael Shych +--- + drivers/platform/mellanox/mlx-platform.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/platform/mellanox/mlx-platform.c b/drivers/platform/mellanox/mlx-platform.c +index 486a3e8da..67865636e 100644 +--- a/drivers/platform/mellanox/mlx-platform.c ++++ b/drivers/platform/mellanox/mlx-platform.c +@@ -3832,12 +3832,6 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0444, + }, +- { +- .label = "reset_from_comex", +- .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, +- .mask = GENMASK(7, 0) & ~BIT(4), +- .mode = 0444, +- }, + { + .label = "reset_from_asic", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, +@@ -3856,6 +3850,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0444, + }, ++ { ++ .label = "reset_sw_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(0), ++ .mode = 0444, ++ }, + { + .label = "reset_comex_pwr_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, +-- +2.20.1 + diff --git a/patch/0275-mlxsw-Use-u16-for-local_port-field-instead-of-u8.patch b/patch/0275-mlxsw-Use-u16-for-local_port-field-instead-of-u8.patch new file mode 100644 index 000000000..02c1a875e --- /dev/null +++ b/patch/0275-mlxsw-Use-u16-for-local_port-field-instead-of-u8.patch @@ -0,0 +1,61 @@ +From 2aa5016c277751bcc11c6874a58abbe194708f9f Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 9 Mar 2023 22:37:40 +0000 +Subject: [PATCH backport v.5.10 2/3] mlxsw: Use u16 for local_port field + instead of u8 + +Currently, local_port field is saved as u8, which means that maximum 256 +ports can be used. + +As preparation for Spectrum-4, which will support more than 256 ports, +local_port field should be extended. + +Save local_port as u16 to allow use of additional ports. + +Signed-off-by: Amit Cohen +Reviewed-by: Petr Machata +Signed-off-by: Ido Schimmel +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 4 ++-- + drivers/net/ethernet/mellanox/mlxsw/core.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index a26c6d880..9475cd656 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -2842,7 +2842,7 @@ u64 mlxsw_core_res_get(struct mlxsw_core *mlxsw_core, + } + EXPORT_SYMBOL(mlxsw_core_res_get); + +-static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port, ++static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u16 local_port, + enum devlink_port_flavour flavour, + u8 slot_index, u32 port_number, bool split, + u32 split_port_subnumber, +@@ -2892,7 +2892,7 @@ static void __mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port) + memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port)); + } + +-int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port, ++int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u16 local_port, + u8 slot_index, u32 port_number, bool split, + u32 split_port_subnumber, + bool splittable, u32 lanes, +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index b09f9013d..842f365eb 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -213,7 +213,7 @@ void mlxsw_core_lag_mapping_clear(struct mlxsw_core *mlxsw_core, + u16 lag_id, u8 local_port); + + void *mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port); +-int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port, ++int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u16 local_port, + u8 slot_index, u32 port_number, bool split, + u32 split_port_subnumber, + bool splittable, u32 lanes, +-- +2.20.1 + diff --git a/patch/0276-mlxsw-minimal-Change-type-for-local-port.patch b/patch/0276-mlxsw-minimal-Change-type-for-local-port.patch new file mode 100644 index 000000000..0a2b7f618 --- /dev/null +++ b/patch/0276-mlxsw-minimal-Change-type-for-local-port.patch @@ -0,0 +1,41 @@ +From 299ee861fd4b081f0ab5d168048c9696a12de2f5 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 9 Mar 2023 09:05:38 +0000 +Subject: [PATCH backport v.5.10 1/3] mlxsw: minimal: Change type for local + port + +Since maximum port number available on system has been increased from +128 to 258, change relevant types from u8 to u16: +- 'max_ports' field in structure 'mlxsw_m'; +- 'local_port' argument in mlxsw_m_port_mapping_get(). + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 5fd319697..9f74ca704 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -31,7 +31,7 @@ struct mlxsw_m { + struct mlxsw_core *core; + const struct mlxsw_bus_info *bus_info; + u8 base_mac[ETH_ALEN]; +- u8 max_ports; ++ u16 max_ports; + u8 max_module_count; /* Maximum number of modules per-slot. */ + u8 num_of_slots; /* Including the main board. */ + struct mlxsw_m_line_card **line_cards; +@@ -230,7 +230,7 @@ mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port) + + static struct + mlxsw_m_port_mapping *mlxsw_m_port_mapping_get(struct mlxsw_m *mlxsw_m, +- u8 slot_index, u8 local_port) ++ u8 slot_index, u16 local_port) + { + return &mlxsw_m->line_cards[slot_index]->port_mapping[local_port]; + } +-- +2.20.1 + diff --git a/patch/0277-mlxsw-i2c-Fix-chunk-size-setting-in-output-mailbox-b.patch b/patch/0277-mlxsw-i2c-Fix-chunk-size-setting-in-output-mailbox-b.patch new file mode 100644 index 000000000..7f3a51430 --- /dev/null +++ b/patch/0277-mlxsw-i2c-Fix-chunk-size-setting-in-output-mailbox-b.patch @@ -0,0 +1,41 @@ +From b66ec3f67d61b7e380c61a12771cc2fee2f0a10e Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 9 Mar 2023 09:16:33 +0000 +Subject: [PATCH backport v.5.10 3/3] mlxsw: i2c: Fix chunk size setting in + output mailbox buffer + +Set output mailbox buffer size multiple of minimal chunk size (32). + +Full buffer size is 256 bytes, while chunk size, which can be sent to +device on some controllers could be for example 32 + 4, 64 + 4, 128 + +4. Thus, last chunk maybe missed, and transaction tail will be lost. + +For example, if transaction size is 256 bytes and chunk size is 64 + 4, +only 204 (68 * 3) bytes will be read instead of 256. + +With this fix chunk size will be multiple of 2^n (where n could be 5, 6, +7) and last chunk will be handled. + +Fixes: 95b75cbd1bc5 ("mlxsw: i2c: Extend input parameters list of command API") +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/i2c.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +index ba31540f1..e04557afc 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +@@ -466,7 +466,8 @@ 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->block_size; ++ num = reg_size / (mlxsw_i2c->block_size - ++ (mlxsw_i2c->block_size % MLXSW_I2C_BLK_DEF)); + + if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { + dev_err(&client->dev, "Could not acquire lock"); +-- +2.20.1 + diff --git a/patch/0278-platform-mellanox-mlx-platform-Modify-graceful-shutd.patch b/patch/0278-platform-mellanox-mlx-platform-Modify-graceful-shutd.patch new file mode 100644 index 000000000..72e4b19bb --- /dev/null +++ b/patch/0278-platform-mellanox-mlx-platform-Modify-graceful-shutd.patch @@ -0,0 +1,43 @@ +From 8b83fb501ac77d60e1cc30fac63e71f469ba0992 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 10 Mar 2023 09:15:35 +0000 +Subject: [PATCH backport v.5.10 1/1] platform: mellanox: mlx-platform: Modify + graceful shutdown callback and power down mask + +Use kernel_power_off() instead of kernel_halt() to pass through +machine_power_off() -> pm_power_off(), otherwise axillary power does +not go off. + +Change "power down" bitmask. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Michael Shych +--- + drivers/platform/mellanox/mlx-platform.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/mellanox/mlx-platform.c b/drivers/platform/mellanox/mlx-platform.c +index 67865636e..55afb4c90 100644 +--- a/drivers/platform/mellanox/mlx-platform.c ++++ b/drivers/platform/mellanox/mlx-platform.c +@@ -227,7 +227,7 @@ + MLXPLAT_CPLD_AGGR_MASK_LC_SDWN) + #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 + #define MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2 BIT(2) +-#define MLXPLAT_CPLD_LOW_AGGR_MASK_PWR_BUT BIT(4) ++#define MLXPLAT_CPLD_LOW_AGGR_MASK_PWR_BUT GENMASK(5,4) + #define MLXPLAT_CPLD_LOW_AGGR_MASK_I2C BIT(6) + #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) +@@ -2509,7 +2509,7 @@ mlxplat_mlxcpld_l1_switch_pwr_events_handler(void *handle, enum mlxreg_hotplug_k + u8 action) + { + dev_info(&mlxplat_dev->dev, "System shutdown due to short press of power button"); +- kernel_halt(); ++ kernel_power_off(); + return 0; + } + +-- +2.20.1 + diff --git a/patch/0279-platform-mellanox-mlx-platform-Fix-signals-polarity-.patch b/patch/0279-platform-mellanox-mlx-platform-Fix-signals-polarity-.patch new file mode 100644 index 000000000..6cd5cddd1 --- /dev/null +++ b/patch/0279-platform-mellanox-mlx-platform-Fix-signals-polarity-.patch @@ -0,0 +1,59 @@ +From 6720a3b49d3c0bb26d18bfe651bd9101dde34fc8 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 15 Mar 2023 19:23:20 +0000 +Subject: [PATCH backport v.5.10 1/3] platform: mellanox: mlx-platform: Fix + signals polarity and latch mask + +Change polarity of chassis health and power signals and fix latch reset +mask for L1 switch. + +Fixes: dd635e33b5c9 ("platform: mellanox: Introduce support of new Nvidia L1 switch") +Signed-off-by: Vadim Pasternak +Reviewed-by: Michael Shych +--- + drivers/platform/mellanox/mlx-platform.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/platform/mellanox/mlx-platform.c b/drivers/platform/mellanox/mlx-platform.c +index fa2e539b6..2bc3720a4 100644 +--- a/drivers/platform/mellanox/mlx-platform.c ++++ b/drivers/platform/mellanox/mlx-platform.c +@@ -244,7 +244,7 @@ + #define MLXPLAT_CPLD_EROT_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_FU_CAP_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_PWR_BUTTON_MASK BIT(0) +-#define MLXPLAT_CPLD_LATCH_RST_MASK BIT(5) ++#define MLXPLAT_CPLD_LATCH_RST_MASK BIT(6) + #define MLXPLAT_CPLD_THERMAL1_PDB_MASK BIT(3) + #define MLXPLAT_CPLD_THERMAL2_PDB_MASK BIT(4) + #define MLXPLAT_CPLD_INTRUSION_MASK BIT(6) +@@ -2631,7 +2631,7 @@ static struct mlxreg_core_item mlxplat_mlxcpld_l1_switch_events_items[] = { + .reg = MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET, + .mask = MLXPLAT_CPLD_PWR_BUTTON_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_pwr_events_items_data), +- .inversed = 0, ++ .inversed = 1, + .health = false, + }, + { +@@ -2640,7 +2640,7 @@ static struct mlxreg_core_item mlxplat_mlxcpld_l1_switch_events_items[] = { + .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET, + .mask = MLXPLAT_CPLD_L1_CHA_HEALTH_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_health_events_items_data), +- .inversed = 0, ++ .inversed = 1, + .health = false, + .ind = 8, + }, +@@ -3958,7 +3958,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + { + .label = "latch_reset", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, +- .mask = GENMASK(7, 0) & ~BIT(5), ++ .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0200, + }, + { +-- +2.20.1 + diff --git a/patch/0280-platform-mellanox-mlxreg-hotplug-Extend-condition-fo.patch b/patch/0280-platform-mellanox-mlxreg-hotplug-Extend-condition-fo.patch new file mode 100644 index 000000000..68f8a792d --- /dev/null +++ b/patch/0280-platform-mellanox-mlxreg-hotplug-Extend-condition-fo.patch @@ -0,0 +1,33 @@ +From 6531f28d37beb20fb423f4835eab47beaaf002bb Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 19 Mar 2023 15:04:26 +0000 +Subject: [PATCH backport v.5.10 2/3] platform/mellanox: mlxreg-hotplug: Extend + condition for notification callback processing + +Allow processing of notification callback in routine +mlxreg_hotplug_device_create() in case hotplug object is configured +with action "MLXREG_HOTPLUG_DEVICE_NO_ACTION" in case no I2C parent bus +is specified. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Michael Shych +--- + drivers/platform/mellanox/mlxreg-hotplug.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c +index b7dcc64cd..c5abedd35 100644 +--- a/drivers/platform/mellanox/mlxreg-hotplug.c ++++ b/drivers/platform/mellanox/mlxreg-hotplug.c +@@ -113,7 +113,7 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, + * Return if adapter number is negative. It could be in case hotplug + * event is not associated with hotplug device. + */ +- if (data->hpdev.nr < 0) ++ if (data->hpdev.nr < 0 && data->hpdev.action != MLXREG_HOTPLUG_DEVICE_NO_ACTION) + return 0; + + pdata = dev_get_platdata(&priv->pdev->dev); +-- +2.20.1 + diff --git a/patch/0281-platform-mellanox-mlx-platform-Modify-health-and-pow.patch b/patch/0281-platform-mellanox-mlx-platform-Modify-health-and-pow.patch new file mode 100644 index 000000000..f6b38f971 --- /dev/null +++ b/patch/0281-platform-mellanox-mlx-platform-Modify-health-and-pow.patch @@ -0,0 +1,40 @@ +From 718681c7948f3191fe7ab7cc0a5f96b6454c3a0b Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 19 Mar 2023 15:36:19 +0000 +Subject: [PATCH backport v.5.10 3/3] platform: mellanox: mlx-platform: Modify + health and power hotplug action + +Set explicitly hotplug event action for health and power signals for +L1 switch as "MLXREG_HOTPLUG_DEVICE_NO_ACTION" in order to allow +processing of notification callback even I2C parent bus is not +specified. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Michael Shych +--- + drivers/platform/mellanox/mlx-platform.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/platform/mellanox/mlx-platform.c b/drivers/platform/mellanox/mlx-platform.c +index 2bc3720a4..605d57e95 100644 +--- a/drivers/platform/mellanox/mlx-platform.c ++++ b/drivers/platform/mellanox/mlx-platform.c +@@ -2527,6 +2527,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_l1_switch_pwr_events_items_data[] + .reg = MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET, + .mask = MLXPLAT_CPLD_PWR_BUTTON_MASK, + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_l1_switch_pwr_events_notifier, + }, + }; +@@ -2587,6 +2588,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_l1_switch_health_events_items_dat + .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET, + .mask = MLXPLAT_CPLD_INTRUSION_MASK, + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ .hpdev.action = MLXREG_HOTPLUG_DEVICE_NO_ACTION, + .hpdev.notifier = &mlxplat_mlxcpld_l1_switch_intrusion_events_notifier, + }, + { +-- +2.20.1 + diff --git a/patch/0999-Revert-mlxsw-thermal-Fix-out-of-bounds-memory-a.patch b/patch/0999-Revert-mlxsw-thermal-Fix-out-of-bounds-memory-a.patch deleted file mode 100644 index 94f91acb0..000000000 --- a/patch/0999-Revert-mlxsw-thermal-Fix-out-of-bounds-memory-a.patch +++ /dev/null @@ -1,103 +0,0 @@ -From: Alexander Allen -Date: Thu, 31 Mar 2022 17:17:59 +0000 -Subject: 0999 Revert "mlxsw: thermal: Fix out-of-bounds memory - accesses" - -This reverts commit e59d839743b50cb1d3f42a786bea48cc5621d254. - -Commit is reverted until thermal infrastructure is ready for other fan devices used by Nvidia systems. -Usage of `cooling_cur_state` for setting fan speed has been deprecated in kernel 5.17 by thermal maintainers. -New interface for fan speed enforcing should be done from `hwmon`. -After all fan drivers are aligned, commit will be retuned back. ---- - .../ethernet/mellanox/mlxsw/core_thermal.c | 52 +++++++++++++++++-- - 1 file changed, 47 insertions(+), 5 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index e1a760519097..f9c9ebf68fcd 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -24,8 +24,16 @@ - #define MLXSW_THERMAL_ZONE_MAX_NAME 16 - #define MLXSW_THERMAL_TEMP_SCORE_MAX GENMASK(31, 0) - #define MLXSW_THERMAL_MAX_STATE 10 --#define MLXSW_THERMAL_MIN_STATE 2 - #define MLXSW_THERMAL_MAX_DUTY 255 -+/* Minimum and maximum fan allowed speed in percent: from 20% to 100%. Values -+ * MLXSW_THERMAL_MAX_STATE + x, where x is between 2 and 10 are used for -+ * setting fan speed dynamic minimum. For example, if value is set to 14 (40%) -+ * cooling levels vector will be set to 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10 to -+ * introduce PWM speed in percent: 40, 40, 40, 40, 40, 50, 60. 70, 80, 90, 100. -+ */ -+#define MLXSW_THERMAL_SPEED_MIN (MLXSW_THERMAL_MAX_STATE + 2) -+#define MLXSW_THERMAL_SPEED_MAX (MLXSW_THERMAL_MAX_STATE * 2) -+#define MLXSW_THERMAL_SPEED_MIN_LEVEL 2 /* 20% */ - - /* External cooling devices, allowed for binding to mlxsw thermal zones. */ - static char * const mlxsw_thermal_external_allowed_cdev[] = { -@@ -642,16 +650,49 @@ static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev, - struct mlxsw_thermal *thermal = cdev->devdata; - struct device *dev = thermal->bus_info->dev; - char mfsc_pl[MLXSW_REG_MFSC_LEN]; -+ unsigned long cur_state, i; - int idx; -+ u8 duty; - int err; - -- if (state > MLXSW_THERMAL_MAX_STATE) -- return -EINVAL; -- - idx = mlxsw_get_cooling_device_idx(thermal, cdev); - if (idx < 0) - return idx; - -+ /* Verify if this request is for changing allowed fan dynamical -+ * minimum. If it is - update cooling levels accordingly and update -+ * state, if current state is below the newly requested minimum state. -+ * For example, if current state is 5, and minimal state is to be -+ * changed from 4 to 6, thermal->cooling_levels[0 to 5] will be changed -+ * all from 4 to 6. And state 5 (thermal->cooling_levels[4]) should be -+ * overwritten. -+ */ -+ if (state >= MLXSW_THERMAL_SPEED_MIN && -+ state <= MLXSW_THERMAL_SPEED_MAX) { -+ state -= MLXSW_THERMAL_MAX_STATE; -+ for (i = 0; i <= MLXSW_THERMAL_MAX_STATE; i++) -+ thermal->cooling_levels[i] = max(state, i); -+ -+ mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0); -+ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl); -+ if (err) -+ return err; -+ -+ duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl); -+ cur_state = mlxsw_duty_to_state(duty); -+ -+ /* If current fan state is lower than requested dynamical -+ * minimum, increase fan speed up to dynamical minimum. -+ */ -+ if (state < cur_state) -+ return 0; -+ -+ state = cur_state; -+ } -+ -+ if (state > MLXSW_THERMAL_MAX_STATE) -+ return -EINVAL; -+ - /* Normalize the state to the valid speed range. */ - state = thermal->cooling_levels[state]; - mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state)); -@@ -961,7 +1002,8 @@ int mlxsw_thermal_init(struct mlxsw_core *core, - - /* Initialize cooling levels per PWM state. */ - for (i = 0; i < MLXSW_THERMAL_MAX_STATE; i++) -- thermal->cooling_levels[i] = max(MLXSW_THERMAL_MIN_STATE, i); -+ thermal->cooling_levels[i] = max(MLXSW_THERMAL_SPEED_MIN_LEVEL, -+ i); - - thermal->polling_delay = bus_info->low_frequency ? - MLXSW_THERMAL_SLOW_POLL_INT : --- -2.17.1 - diff --git a/patch/kconfig-exclusions b/patch/kconfig-exclusions index 6d4f0e622..b166ea04e 100644 --- a/patch/kconfig-exclusions +++ b/patch/kconfig-exclusions @@ -11,7 +11,6 @@ CONFIG_CGROUP_NET_PRIO # Unset X86_PAT according to Broadcom's requirement CONFIG_X86_PAT CONFIG_MLXSW_PCI -CONFIG_THERMAL_STATISTICS [arm64] diff --git a/patch/kconfig-inclusions b/patch/kconfig-inclusions index a4dbe48d1..291f58645 100644 --- a/patch/kconfig-inclusions +++ b/patch/kconfig-inclusions @@ -47,7 +47,6 @@ CONFIG_DW_DMAC_PCI=y CONFIG_MLXSW_CORE=m CONFIG_MLXSW_CORE_HWMON=y CONFIG_MLXSW_CORE_THERMAL=y -# CONFIG_MLXSW_CORE_QSFP=y # TODO: enable once 0001-Mellanox-platform-Backport-patches-for-new-Mellanox-.patch is enabled CONFIG_MLXSW_I2C=m CONFIG_MLXSW_MINIMAL=m CONFIG_MFD_INTEL_LPSS=y @@ -79,7 +78,7 @@ CONFIG_SENSORS_DRIVETEMP=m CONFIG_TI_ADS1015=m CONFIG_GPIO_PCA953X=m CONFIG_SERIAL_8250_DETECT_IRQ=y -CONFIG_MLX_WDT=y +CONFIG_MLX_WDT=m CONFIG_LEDS_MLXREG=m CONFIG_MLX_PLATFORM=m CONFIG_MELLANOX_PLATFORM=y @@ -88,12 +87,57 @@ CONFIG_MLXREG_IO=m CONFIG_MAX1363=m CONFIG_THERMAL_NETLINK=y CONFIG_THERMAL_STATISTICS=n - CONFIG_NVSW_SN2201=m CONFIG_TI_ADS1015=m CONFIG_SENSORS_EMC2305=m CONFIG_SENSORS_JC42=m CONFIG_SENSORS_POWR1220=m +CONFIG_NET_VENDOR_MELLANOX=y +CONFIG_NET_DEVLINK=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_MUX=m +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=m +CONFIG_SYSFS=y +CONFIG_DMI_SYSFS=y +CONFIG_GPIO_SYSFS=y +CONFIG_WATCHDOG_SYSFS=y +CONFIG_NVMEM_SYSFS=y +CONFIG_MLXREG_LC=m +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_PMBUS=m +CONFIG_SENSORS_PMBUS=m +CONFIG_HWMON=y +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_TMP102=m +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_EEPROM_AT24=m +CONFIG_GPIOLIB=y +CONFIG_GPIO_GENERIC=m +CONFIG_GPIO_ICH=m +CONFIG_LPC_ICH=m +CONFIG_X86_PKG_TEMP_THERMAL=m +CONFIG_SENSORS_CORETEMP=m +CONFIG_INTEL_PCH_THERMAL=m +CONFIG_IGB=y +CONFIG_IGB_HWMON=y +CONFIG_INOTIFY_USER=y +CONFIG_MFD_CORE=y +CONFIG_SERIAL_8250_DW=y +CONFIG_I2C_SMBUS=m +CONFIG_I2C_I801=m +CONFIG_PINCTRL=y +CONFIG_PINCTRL_INTEL=y +CONFIG_SPI_PXA2XX=m ###-> mellanox-end # For Cisco 8000 diff --git a/patch/series b/patch/series index d5c39c476..93ed733fc 100755 --- a/patch/series +++ b/patch/series @@ -68,107 +68,266 @@ kernel-compat-always-include-linux-compat.h-from-net-compat.patch ###-> mellanox_hw_mgmt-start 0001-i2c-mlxcpld-Update-module-license.patch -0002-i2c-mlxcpld-Decrease-polling-time-for-performan.patch -0003-i2c-mlxcpld-Add-support-for-I2C-bus-frequency-s.patch +0002-i2c-mlxcpld-Decrease-polling-time-for-performance-im.patch +0003-i2c-mlxcpld-Add-support-for-I2C-bus-frequency-settin.patch 0004-i2c-mux-mlxcpld-Update-module-license.patch -0005-i2c-mux-mlxcpld-Move-header-file-out-of-x86-rea.patch -0006-i2c-mux-mlxcpld-Convert-driver-to-platform-driv.patch -0007-i2c-mux-mlxcpld-Prepare-mux-selection-infrastru.patch -0008-i2c-mux-mlxcpld-Get-rid-of-adapter-numbers-enfo.patch -0009-i2c-mux-mlxcpld-Extend-driver-to-support-word-a.patch +0005-i2c-mux-mlxcpld-Move-header-file-out-of-x86-realm.patch +0006-i2c-mux-mlxcpld-Convert-driver-to-platform-driver.patch +0007-i2c-mux-mlxcpld-Prepare-mux-selection-infrastructure.patch +0008-i2c-mux-mlxcpld-Get-rid-of-adapter-numbers-enforceme.patch +0009-i2c-mux-mlxcpld-Extend-driver-to-support-word-addres.patch 0010-i2c-mux-mlxcpld-Extend-supported-mux-number.patch -0011-i2c-mux-mlxcpld-Add-callback-to-notify-mux-crea.patch -0012-hwmon-mlxreg-fan-Add-support-for-fan-drawers-ca.patch -0013-hwmon-pmbus-shrink-code-and-remove-pmbus_do_rem.patch -0015-mlxsw-core-Remove-critical-trip-points-from-the.patch +0011-i2c-mux-mlxcpld-Add-callback-to-notify-mux-creation-.patch +0012-hwmon-mlxreg-fan-Add-support-for-fan-drawers-capabil.patch +0013-hwmon-pmbus-shrink-code-and-remove-pmbus_do_remove.patch +0015-mlxsw-core-Remove-critical-trip-points-from-thermal-.patch 0016-net-don-t-include-ethtool.h-from-netdevice.h.patch -0017-mlxsw-reg-Extend-MTMP-register-with-new-thresho.patch -0018-mlxsw-thermal-Add-function-for-reading-module-t.patch -0019-mlxsw-thermal-Read-module-temperature-threshold.patch -0020-mlxsw-thermal-Fix-null-dereference-of-NULL-temp.patch +0017-mlxsw-reg-Extend-MTMP-register-with-new-threshold-fi.patch +0018-mlxsw-thermal-Add-function-for-reading-module-temper.patch +0019-mlxsw-thermal-Read-module-temperature-thresholds-usi.patch +0020-mlxsw-thermal-Fix-null-dereference-of-NULL-temperatu.patch 0021-mlxsw-reg-Add-bank-number-to-MCIA-register.patch 0022-mlxsw-reg-Document-possible-MCIA-status-values.patch -0023-ethtool-Allow-network-drivers-to-dump-arbitrary.patch -0024-net-ethtool-Export-helpers-for-getting-EEPROM-i.patch -0025-ethtool-Add-fallback-to-get_module_eeprom-from-.patch -0026-mlxsw-core-Add-support-for-module-EEPROM-read-b.patch -0027-ethtool-Decrease-size-of-module-EEPROM-get-poli.patch -0028-ethtool-Use-kernel-data-types-for-internal-EEPR.patch -0029-ethtool-Validate-module-EEPROM-length-as-part-o.patch -0030-ethtool-Validate-module-EEPROM-offset-as-part-o.patch -0031-mlxsw-core_env-Read-module-temperature-threshol.patch +0023-ethtool-Allow-network-drivers-to-dump-arbitrary-EEPR.patch +0024-net-ethtool-Export-helpers-for-getting-EEPROM-info.patch +0025-ethtool-Add-fallback-to-get_module_eeprom-from-netli.patch +0026-mlxsw-core-Add-support-for-module-EEPROM-read-by-pag.patch +0027-ethtool-Decrease-size-of-module-EEPROM-get-policy-ar.patch +0028-ethtool-Use-kernel-data-types-for-internal-EEPROM-st.patch +0029-ethtool-Validate-module-EEPROM-length-as-part-of-pol.patch +0030-ethtool-Validate-module-EEPROM-offset-as-part-of-pol.patch +0031-mlxsw-core_env-Read-module-temperature-thresholds-us.patch 0032-mlxsw-core_env-Avoid-unnecessary-memcpy-s.patch -0035-hwmon-pmbus-Increase-maximum-number-of-phases-p.patch -0036-hwmon-pmbus-Add-support-for-MPS-Multi-phase-mp2.patch +0035-hwmon-pmbus-Increase-maximum-number-of-phases-per-pa.patch +0036-hwmon-pmbus-Add-support-for-MPS-Multi-phase-mp2888-c.patch 0037-dt-bindings-Add-MP2888-voltage-regulator-device.patch 0038-ethtool-wire-in-generic-SFP-module-access.patch -0039-ethtool-Fix-NULL-pointer-dereference-during-mod.patch -0040-phy-sfp-add-netlink-SFP-support-to-generic-SFP-.patch +0039-ethtool-Fix-NULL-pointer-dereference-during-module-E.patch +0040-phy-sfp-add-netlink-SFP-support-to-generic-SFP-code.patch 0042-ethtool-support-FEC-settings-over-netlink.patch 0045-i2c-mlxcpld-Fix-criteria-for-frequency-setting.patch -0046-i2c-mlxcpld-Reduce-polling-time-for-performance.patch -0047-i2c-mlxcpld-Allow-flexible-polling-time-setting.patch -0052-hwmon-mlxreg-fan-Return-non-zero-value-when-fan.patch -0053-mlxsw-core-Avoid-creation-virtual-hwmon-objects.patch -0054-mlxsw-minimal-Simplify-method-of-modules-number.patch -0055-platform_data-mlxreg-Add-new-type-to-support-mo.patch -0056-platform-x86-mlx-platform-Add-initial-support-f.patch -0057-platform-mellanox-mlxreg-hotplug-Extend-logic-f.patch -0058-platform-x86-mlx-platform-Configure-notifier-ca.patch -0059-platform-mellanox-mlxreg-io-Extend-number-of-hw.patch -0060-platform_data-mlxreg-Add-new-field-for-secured-.patch -0061-platform-mellanox-mlxreg-lc-Add-initial-support.patch -0062-Documentation-ABI-Add-new-attributes-for-mlxreg.patch -0063-Documentation-ABI-Add-new-line-card-attributes-.patch -0064-hwmon-mlxreg-fan-Extend-the-maximum-number-of-t.patch -0065-platform-x86-mlx-platform-Extend-FAN-and-LED-co.patch -0066-platform-x86-mlx-platform-Add-new-attributes-fo.patch +0046-i2c-mlxcpld-Reduce-polling-time-for-performance-impr.patch +0047-i2c-mlxcpld-Allow-flexible-polling-time-setting-for-.patch +0053-mlxsw-core-Avoid-creation-virtual-hwmon-objects-by-t.patch +0054-mlxsw-minimal-Simplify-method-of-modules-number-dete.patch +0055-platform_data-mlxreg-Add-new-type-to-support-modular.patch +0056-platform-x86-mlx-platform-Add-initial-support-for-ne.patch +0057-platform-mellanox-mlxreg-hotplug-Extend-logic-for-ho.patch +0058-platform-x86-mlx-platform-Configure-notifier-callbac.patch +0059-platform-mellanox-mlxreg-io-Extend-number-of-hwmon-a.patch +0060-platform_data-mlxreg-Add-new-field-for-secured-acces.patch +0061-platform-mellanox-mlxreg-lc-Add-initial-support-for-.patch +0062-Documentation-ABI-Add-new-attributes-for-mlxreg-io-s.patch +0063-Documentation-ABI-Add-new-line-card-attributes-for-m.patch +0064-hwmon-mlxreg-fan-Extend-the-maximum-number-of-tachom.patch +0065-platform-x86-mlx-platform-Extend-FAN-and-LED-config-.patch +0066-platform-x86-mlx-platform-Add-new-attributes-for-Cof.patch +0067-platform-mellanox-Add-dedicated-match-for-system-typ.patch 0068-mlxsw-core-Initialize-switch-driver-last.patch 0069-mlxsw-core-Remove-mlxsw_core_is_initialized.patch -0070-mlxsw-core_env-Defer-handling-of-module-tempera.patch -0071-mlxsw-core_env-Convert-module_info_lock-to-a-mu.patch +0070-mlxsw-core_env-Defer-handling-of-module-temperature-.patch +0071-mlxsw-core_env-Convert-module_info_lock-to-a-mutex.patch 0072-mlxsw-Track-per-module-port-status.patch 0073-mlxsw-reg-Add-fields-to-PMAOS-register.patch 0074-mlxsw-Make-PMAOS-pack-function-more-generic.patch 0075-mlxsw-Add-support-for-transceiver-modules-reset.patch -0076-ethtool-Add-ability-to-control-transceiver-modu.patch -0077-mlxsw-reg-Add-Port-Module-Memory-Map-Properties.patch -0078-mlxsw-reg-Add-Management-Cable-IO-and-Notificat.patch -0079-mlxsw-Add-ability-to-control-transceiver-module.patch +0076-ethtool-Add-ability-to-control-transceiver-modules-p.patch +0077-mlxsw-reg-Add-Port-Module-Memory-Map-Properties-regi.patch +0078-mlxsw-reg-Add-Management-Cable-IO-and-Notifications-.patch +0079-mlxsw-Add-ability-to-control-transceiver-modules-pow.patch 0080-ethtool-Add-transceiver-module-extended-states.patch -0081-platform-x86-mlx-platform-Add-support-for-multi.patch -0082-mlxsw-core-Extend-external-cooling-device-whitelist-.patch -0083-platform_data-mlxreg-Add-field-for-notification-call.patch -0084-i2c-mlxcpld-Add-callback-to-notify-probing-completio.patch -0085-hwmon-powr1220-Upgrade-driver-to-support-hwmon-info-.patch -0086-hwmon-powr1220-Add-support-for-Lattice-s-POWR1014-po.patch -0087-hwmon-Add-support-for-EMC2305-RPM-based-PWM-Fan-Spee.patch -0088-dt-bindings-Add-description-for-EMC2305-for-RPM-base.patch -0089-platform-mellanox-Add-support-for-new-SN2201-system.patch -0090-Documentation-ABI-Add-new-attributes-for-mlxreg-io-s.patch -0091-platform-x86-mlx-platform-Add-support-for-new-s.patch -0092-platform-mellanox-mlxreg-lc-fix-error-code-in-m.patch -0093-hwmon-mlxreg-fan-Extend-driver-to-support-multi.patch -0094-hwmon-mlxreg-fan-Extend-driver-to-support-multi.patch -0095-hwmon-mlxreg-fan-Fix-out-of-bounds-read-on-arra.patch -0096-hwmon-mlxreg-fan-Modify-PWM-connectivity-valida.patch -0097-hwmon-mlxreg-fan-Support-distinctive-names-per-.patch -0999-Revert-mlxsw-thermal-Fix-out-of-bounds-memory-a.patch -0098-mlxsw-i2c-Prevent-transaction-execution-for.patch +0081-platform-x86-mlx-platform-Add-support-for-multiply-c.patch +0082-mlxsw-core-Extend-external-cooling-device-whitelist-.patch +0083-platform_data-mlxreg-Add-field-for-notification-call.patch +0084-i2c-mlxcpld-Add-callback-to-notify-probing-completio.patch +0085-hwmon-powr1220-Upgrade-driver-to-support-hwmon-info-.patch +0086-hwmon-powr1220-Add-support-for-Lattice-s-POWR1014-po.patch +0087-hwmon-Add-support-for-EMC2305-RPM-based-PWM-Fan-Spee.patch +0089-platform-mellanox-Add-support-for-new-SN2201-system.patch +0090-Documentation-ABI-Add-new-attributes-for-mlxreg-io-s.patch +0091-platform-x86-mlx-platform-Add-support-for-new-system.patch +0092-platform-mellanox-mlxreg-lc-fix-error-code-in-mlxreg.patch +0093-hwmon-mlxreg-fan-Extend-driver-to-support-multiply-P.patch +0094-hwmon-mlxreg-fan-Extend-driver-to-support-multiply-c.patch +0095-hwmon-mlxreg-fan-Fix-out-of-bounds-read-on-array-fan.patch +0096-hwmon-mlxreg-fan-Modify-PWM-connectivity-validation.patch +0097-hwmon-mlxreg-fan-Support-distinctive-names-per-diffe.patch +0099-mlxsw-core_hwmon-Fix-variable-names-for-hwmon-attrib.patch +0100-mlxsw-core_thermal-Rename-labels-according-to-naming.patch +0101-mlxsw-core_thermal-Remove-obsolete-API-for-query-res.patch +0102-mlxsw-reg-Add-mgpir_-prefix-to-MGPIR-fields-comments.patch +0103-mlxsw-core-Remove-unnecessary-asserts.patch +0104-mlxsw-reg-Extend-MTMP-register-with-new-slot-number-.patch +0105-mlxsw-reg-Extend-MTBR-register-with-new-slot-number-.patch +0106-mlxsw-reg-Extend-MCIA-register-with-new-slot-number-.patch +0107-mlxsw-reg-Extend-MCION-register-with-new-slot-number.patch +0108-mlxsw-reg-Extend-PMMP-register-with-new-slot-number-.patch +0109-mlxsw-reg-Extend-MGPIR-register-with-new-slot-fields.patch +0110-mlxsw-core_env-Pass-slot-index-during-PMAOS-register.patch +0111-mlxsw-reg-Add-new-field-to-Management-General-Periph.patch +0112-mlxsw-core-Extend-interfaces-for-cable-info-access-w.patch +0113-mlxsw-core-Extend-port-module-data-structures-for-li.patch +0114-mlxsw-core-Move-port-module-events-enablement-to-a-s.patch +0115-mlxsw-core_hwmon-Split-gearbox-initialization.patch +0116-mlxsw-core_hwmon-Extend-internal-structures-to-suppo.patch +0117-mlxsw-core_hwmon-Introduce-slot-parameter-in-hwmon-i.patch +0118-mlxsw-core_hwmon-Extend-hwmon-device-with-gearbox-ma.patch +0119-mlxsw-core_thermal-Extend-internal-structures-to-sup.patch +0120-mlxsw-core_thermal-Split-gearbox-initialization.patch +0121-mlxsw-core_thermal-Extend-thermal-area-with-gearbox-.patch +0122-mlxsw-core_thermal-Add-line-card-id-prefix-to-line-c.patch +0123-mlxsw-core_thermal-Use-exact-name-of-cooling-devices.patch +0124-mlxsw-core_thermal-Use-common-define-for-thermal-zon.patch +0125-devlink-add-support-to-create-line-card-and-expose-t.patch +0126-devlink-implement-line-card-provisioning.patch +0127-devlink-implement-line-card-active-state.patch +0128-devlink-add-port-to-line-card-relationship-set.patch +0129-devlink-introduce-linecard-info-get-message.patch +0130-devlink-introduce-linecard-info-get-message.patch +0131-mlxsw-reg-Add-Ports-Mapping-event-Configuration-Regi.patch +0132-mlxsw-reg-Add-Management-DownStream-Device-Query-Reg.patch +0133-mlxsw-reg-Add-Management-DownStream-Device-Control-R.patch +0134-mlxsw-reg-Add-Management-Binary-Code-Transfer-Regist.patch +0135-mlxsw-core_linecards-Add-line-card-objects-and-imple.patch +0136-mlxsw-core_linecards-Implement-line-card-activation-.patch +0137-mlxsw-core-Extend-driver-ops-by-remove-selected-port.patch +0138-mlxsw-spectrum-Add-port-to-linecard-mapping.patch +0139-mlxsw-reg-Introduce-Management-Temperature-Extended-.patch +0140-mlxsw-core-Add-APIs-for-thermal-sensor-mapping.patch +0141-mlxsw-reg-Add-Management-DownStream-Device-Tunneling.patch +0142-mlxsw-core_linecards-Probe-devices-for-provisioned-l.patch +0143-mlxsw-core_linecards-Expose-device-FW-version-over-d.patch +0144-mlxsw-core-Introduce-flash-update-components.patch +0145-mlxfw-Get-the-PSID-value-using-op-instead-of-passing.patch +0146-mlxsw-core_linecards-Implement-line-card-device-flas.patch +0147-mlxsw-core_linecards-Introduce-ops-for-linecards-sta.patch +0148-mlxsw-core-Add-interfaces-for-line-card-initializati.patch +0149-mlxsw-core_thermal-Add-interfaces-for-line-card-init.patch +0150-mlxsw-core_hwmon-Add-interfaces-for-line-card-initia.patch +0151-mlxsw-minimal-Prepare-driver-for-modular-system-supp.patch +0152-mlxsw-core-Extend-bus-init-function-with-event-handl.patch +0153-mlxsw-i2c-Add-support-for-system-events-handling.patch +0154-mlxsw-core-Export-line-card-API.patch +0155-mlxsw-minimal-Add-system-event-handler.patch +0156-mlxsw-minimal-Add-interfaces-for-line-card-initializ.patch 0157-platform-x86-mlx-platform-Make-activation-of-some-dr.patch 0158-platform-x86-mlx-platform-Add-cosmetic-changes-for-a.patch 0159-mlx-platform-Add-support-for-systems-equipped-with-t.patch -0160-platform-mellanox-Introduce-support-for-COMe-NVSwitc.patch +0160-platform-mellanox-Introduce-support-for-COMe-managem.patch 0161-platform-x86-mlx-platform-Add-support-for-new-system.patch 0162-platform-mellanox-Add-COME-board-revision-register.patch +0163-platform-mellanox-Introduce-support-for-rack-manager.patch 0164-hwmon-jc42-Add-support-for-Seiko-Instruments-S-34TS0.patch 0165-platform-mellanox-mlxreg-io-Add-locking-for-io-opera.patch -0167-leds-mlxreg-Send-udev-change-event.patch +0166-DS-leds-leds-mlxreg-Send-udev-event-from-leds-mlxreg.patch 0170-i2c-mlxcpld-Fix-register-setting-for-400KHz-frequenc.patch 0171-platform-mellanox-mlxreg-lc-Fix-cleanup-on-failure-a.patch -0173-core-Add-support-for-OSFP-transceiver-modules.patch +0172-DS-platform-mlx-platform-Add-SPI-path-for-rack-switc.patch +0173-mlxsw-core-Add-support-for-OSFP-transceiver-modules.patch 0175-hwmon-pmbus-Add-support-for-Infineon-Digital-Multi-p.patch +0176-platform-mellanox-fix-reset_pwr_converter_fail-attri.patch +0177-Documentation-ABI-fix-description-of-fix-reset_pwr_c.patch +0178-platform-mellanox-Introduce-support-for-next-generat.patch 0180-hwmon-pmbus-Fix-sensors-readouts-for-MPS-Multi-phase.patch +0182-platform-mellanox-Introduce-support-of-new-Nvidia-L1.patch +0183-platform-mellanox-Split-initialization-procedure.patch +0184-platform-mellanox-Split-logic-in-init-and-exit-flow.patch +0185-platform-mellanox-Extend-all-systems-with-I2C-notifi.patch +0186-platform-mellanox-mlxreg-hotplug-Allow-more-flexible.patch +0187-platform_data-mlxreg-Add-field-with-mapped-resource-.patch +0188-i2c-mux-Add-register-map-based-mux-driver.patch +0189-i2c-mlxcpld-Allow-driver-to-run-on-ARM64-architectur.patch +0190-i2c-mlxcpld-Modify-base-address-type.patch +0191-i2c-mlxcpld-Allow-to-configure-base-address-of-regis.patch +0192-i2c-mlxcpld-Add-support-for-extended-transaction-len.patch +0193-platform-mellanox-mlx-platform-Add-mux-selection-reg.patch +0194-platform-mellanox-mlx-platform-Move-bus-shift-assign.patch +0195-platform-mellanox-Add-support-for-dynamic-I2C-channe.patch +0196-platform-mellanox-Relocate-mlx-platform-driver.patch +0197-platform-mellanox-Add-initial-support-for-PCIe-based.patch +0198-platform-mellanox-Introduce-support-for-switches-bas.patch +0199-platform-mellanox-mlx-platform-Add-reset-and-extend-.patch +0200-dt-bindings-i2c-mellanox-i2c-mlxbf-convert-txt-to-YA.patch +0201-i2c-mlxbf-incorrect-base-address-passed-during-io-wr.patch +0202-i2c-mlxbf-prevent-stack-overflow-in-mlxbf_i2c_smbus_.patch +0203-i2c-mlxbf-remove-IRQF_ONESHOT.patch +0204-i2c-mlxbf-Fix-frequency-calculation.patch +0205-i2c-mlxbf-support-lock-mechanism.patch +0206-i2c-mlxbf-add-multi-slave-functionality.patch +0207-i2c-mlxbf-support-BlueField-3-SoC.patch +0208-i2c-mlxbf-remove-device-tree-support.patch +0209-UBUNTU-SAUCE-i2c-mlxbf.c-Add-driver-version.patch +0210-platform-mellanox-Typo-fix-in-the-file-mlxbf-bootctl.patch +0211-UBUNTU-SAUCE-platform-mellanox-Updates-to-mlxbf-boot.patch +0212-platform-mellanox-mlxbf-pmc-Add-Mellanox-BlueField-P.patch +0213-platform-mellanox-mlxbf-pmc-fix-kernel-doc-notation.patch +0214-platform-mellanox-mlxbf-pmc-Fix-an-IS_ERR-vs-NULL-bu.patch +0215-UBUNTU-SAUCE-platform-mellanox-Updates-to-mlxbf-pmc.patch +0216-UBUNTU-SAUCE-mlxbf_pmc-Fix-references-to-sprintf.patch +0217-UBUNTU-SAUCE-mlxbf-pmc-Fix-error-when-reading-unprog.patch +0218-UBUNTU-SAUCE-platform-mellanox-Add-mlx-trio-driver.patch +0219-UBUNTU-SAUCE-platform-mellanox-mlxbf-tmfifo-Add-Blue.patch +0220-UBUNTU-SAUCE-pka-Add-pka-driver.patch +0221-UBUNTU-SAUCE-platform-mellanox-Add-mlxbf-livefish-dr.patch +0222-workqueue-Add-resource-managed-version-of-delayed-wo.patch +0223-devm-helpers-Fix-devm_delayed_work_autocancel-kernel.patch +0224-devm-helpers-Add-resource-managed-version-of-work-in.patch +0225-UBUNTU-SAUCE-Add-support-to-pwr-mlxbf.c-driver.patch +0226-Add-Mellanox-BlueField-Gigabit-Ethernet-driver.patch +0227-mlxbf_gige-clear-valid_polarity-upon-open.patch +0228-net-mellanox-mlxbf_gige-Replace-non-standard-interru.patch +0229-mlxbf_gige-increase-MDIO-polling-rate-to-5us.patch +0230-mlxbf_gige-remove-driver-managed-interrupt-counts.patch +0231-mlxbf_gige-remove-own-module-name-define-and-use-KBU.patch +0232-UBUNTU-SAUCE-mlxbf_gige-add-ethtool-mlxbf_gige_set_r.patch +0233-UBUNTU-SAUCE-Fix-OOB-handling-RX-packets-in-heavy-tr.patch +0234-UBUNTU-SAUCE-mlxbf_gige-add-validation-of-ACPI-table.patch +0235-UBUNTU-SAUCE-mlxbf_gige-set-driver-version-to-1.27.patch +0236-UBUNTU-SAUCE-mlxbf_gige-clear-MDIO-gateway-lock-afte.patch +0237-mlxbf_gige-compute-MDIO-period-based-on-i1clk.patch +0238-net-mlxbf_gige-Fix-an-IS_ERR-vs-NULL-bug-in-mlxbf_gi.patch +0239-UBUNTU-SAUCE-mlxbf_gige-add-MDIO-support-for-BlueFie.patch +0240-UBUNTU-SAUCE-mlxbf_gige-support-10M-100M-1G-speeds-o.patch +0241-UBUNTU-SAUCE-mlxbf_gige-add-BlueField-3-Serdes-confi.patch +0242-UBUNTU-SAUCE-mlxbf_gige-add-BlueField-3-ethtool_ops.patch +0243-UBUNTU-SAUCE-bluefield_edac-Add-SMC-support.patch +0244-UBUNTU-SAUCE-bluefield_edac-Update-license-and-copyr.patch +0245-gpio-mlxbf2-Convert-to-device-PM-ops.patch +0246-gpio-mlxbf2-Drop-wrong-use-of-ACPI_PTR.patch +0247-gpio-mlxbf2-Use-devm_platform_ioremap_resource.patch +0248-gpio-mlxbf2-Use-DEFINE_RES_MEM_NAMED-helper-macro.patch +0249-gpio-mlxbf2-Introduce-IRQ-support.patch +0250-UBUNTU-SAUCE-gpio-mlxbf2.c-support-driver-version.patch +0251-mmc-sdhci-of-dwcmshc-add-rockchip-platform-support.patch +0252-mmc-sdhci-of-dwcmshc-add-ACPI-support-for-BlueField-.patch +0253-mmc-sdhci-of-dwcmshc-fix-error-return-code-in-dwcmsh.patch +0254-mmc-sdhci-of-dwcmshc-set-MMC_CAP_WAIT_WHILE_BUSY.patch +0255-mmc-sdhci-of-dwcmshc-Re-enable-support-for-the-BlueF.patch +0256-UBUNTU-SAUCE-Support-BlueField-3-GPIO-driver.patch +0257-regmap-debugfs-Enable-writing-to-the-regmap-debugfs-.patch +0258-UBUNTU-SAUCE-mlx-bootctl-support-icm-carveout-eeprom.patch +0259-mmc-sdhci-of-dwcmshc-Enable-host-V4-support-for-Blue.patch +0260-UBUNTU-SAUCE-mlxbf-pka-Fix-kernel-crash-with-pka-TRN.patch +0261-mlxbf-ptm-power-and-thermal-management-debugfs-drive.patch +0262-UBUNTU-SAUCE-mlxbf-pmc-Fix-event-string-typo.patch +0263-UBUNTU-SAUCE-mlxbf-pmc-Support-for-BlueField-3-perfo.patch +0264-UBUNTU-SAUCE-platform-mellanox-Add-ctrl-message-and-.patch +0265-hwmon-mlxreg-fan-Return-zero-speed-for-broken-fan.patch +0266-UBUNTU-SAUCE-mlxbf-pmc-Bug-fix-for-BlueField-3-count.patch +0267-UBUNTU-SAUCE-mmc-sdhci-of-dwcmshc-add-the-missing-de.patch +0269-platform-mellanox-Cosmetic-changes.patch +0270-platform-mellanox-Fix-order-in-exit-flow.patch +0271-platform-mellanox-Add-new-attributes.patch +0272-platform-mellanox-Change-register-offset-addresses.patch +0273-platform-mellanox-Add-field-upgrade-capability-regis.patch +0274-platform-mellanox-Modify-reset-causes-description.patch +0275-mlxsw-Use-u16-for-local_port-field-instead-of-u8.patch +0276-mlxsw-minimal-Change-type-for-local-port.patch +0277-mlxsw-i2c-Fix-chunk-size-setting-in-output-mailbox-b.patch +0278-platform-mellanox-mlx-platform-Modify-graceful-shutd.patch +0279-platform-mellanox-mlx-platform-Fix-signals-polarity-.patch +0280-platform-mellanox-mlxreg-hotplug-Extend-condition-fo.patch +0281-platform-mellanox-mlx-platform-Modify-health-and-pow.patch ###-> mellanox_hw_mgmt-end # Cisco patches for 5.10 kernel