From 187bb4aa046c26f2fe508e71dc74c230d316838b Mon Sep 17 00:00:00 2001 From: lguohan Date: Sat, 11 Apr 2020 22:44:42 -0700 Subject: [PATCH] Port kernel patches to 4.19.0-6 kernel (#121) - remove fix_ismt_alignment_issue.patch linux commit id: 5cd5f0bb0d9c32876b3d86b70fb45da10d028be7 - remove 0011-support-Broadcom-54616-Phy-for-Intel-igb-driver.patch linux commit id: eeb0149660a21c61122d4937bd406aa4f334c1e4 - remove driver-l3mdev-cgroup.patch - remove config-l3mdev-cgroup.patch - remove bridge-add-per-port-broadcast-flood-flag.patch linux commit id: 99f906e9ad7b6e79ffeda30f45906a8448b9d6a2 - remove 0025-net-udp_l3mdev_accept-support.patch linux commit id: 63a6fff353d01da5a22b72670c434bf12fa0e3b8 - remove kernel-enable-psample-and-act_sample-drivers.patch - remove mellanox-backport-introduce-psample-a-new-genetlink-channel.patch linux commit id: 6ae0a6286171154661b74f7f550f9441c6008424 - remove mellanox-backport-introduce-tc-sample-action.patch linux commit id: 5c5670fae43027778e84b9d9ff3b9d91a10a8131 - remove 0000-net-Fix-netdev-adjacency-tracking.patch linux commit id: 67b62f98a1de962277b60d77c0c208b76867dbae 0f524a80ff35af8a7664d7661d948107da142e04 f1170fd462c67c4ae2f20734566d94e0f8f62f69 1a3f060c1a47dba4e12ac21ce62b57666b9c4e95 790510d99f39cee7f275d001aa5024032ed9bb48 453d39329ad03f9f6d93ec6d0d57bf7a1e2a20c7 e0e79c8e74b08976d9b45e52b704b9228c6965c7 b3208b2024c9089106df52ae25ebf39068d6f9fc 1cd127fc7d3a6d6a0fc9f9cca47ca3a16ee79679 dd82364c3ab93a96bb1e45d22106a4b1ea4bef39 cf2d67408b2f9a840f27d25a0219070b5b5deec4 - remove 0000-net-ipv6-ll-anycast-mcast-routes-on-dev.patch linux commit id: 4832c30d5458387ff2533ff66fbde26ad8bb5a2d - remove 0001-net-ipv6-Allow-shorthand-delete-of-all-nexthops-in-m.patch linux commit id: 0ae8133586ad1c9be894411aaf8b17bb58c8efe5 - remove linux-4.13-thermal-intel_pch_thermal-Fix-enable-check-on.patch linux commit id: 595536e0b2475a9eac23709cd461143178c12e0e - remove linux-4.16-firmware-dmi-handle-missing-DMI-data-gracefully.patch linux commit id: a81114d03e4a529c4b68293249f75438b3c1783f Signed-off-by: Guohan Lu * [Mellanox] Port the patches to 4.19 (#14) 0001-v4.19-6-Mellanox-platform-Backport-patches-for-new-M.patch 0002-config-mellanox-configuration.patch 0003-mlxsw-minimal-Fix-validation-for-FW-minor-version.patch 0004-mlxsw-core-Add-the-hottest-thermal-zone-detection.patch 0005-hwmon-pmbus-core-Add-support-for-vid-mode-detection-.patch 0006-platform-mellanox-mlxreg-hotplug-Use-capability-r.patch -> Remove files which are no longer used. Co-authored-by: stephens --- Makefile | 24 +- ...00-net-Fix-netdev-adjacency-tracking.patch | 1302 -- ...-ipv6-ll-anycast-mcast-routes-on-dev.patch | 190 - ...d-master-driver-for-Mellanox-systems.patch | 544 - ...horthand-delete-of-all-nexthops-in-m.patch | 140 - ...-platform-Backport-patches-for-new-M.patch | 7736 +++++++++ .../0002-config-mellanox-configuration.patch | 209 + ...cpld-add-driver-for-Mellanox-systems.patch | 317 - ...Fix-validation-for-FW-minor-version.patch} | 13 +- ...x-Introduce-Mellanox-hardware-platfo.patch | 1463 -- ...d-the-hottest-thermal-zone-detection.patch | 166 + ...roduce-support-for-Mellanox-hotplug-.patch | 905 -- ...-Add-support-for-vid-mode-detection-.patch | 418 + ...for-support-Mellanox-regmap-LEDs-for.patch | 398 - ...0006-Mellanox-switch-drivers-changes.patch | 2118 --- ...anox-mlxreg-hotplug-Use-capability-r.patch | 73 + ...-support-for-Intel-VID-protocol-VR13.patch | 30 - ...support-for-Texas-Instruments-tps536.patch | 151 - ...x-introduce-mlxreg-io-driver-and-add.patch | 685 - .../0010-config-mellanox-configuration.patch | 140 - ...adcom-54616-Phy-for-Intel-igb-driver.patch | 61 - ...x-mlxreg-hotplug-driver-add-check-fo.patch | 53 - ...-Support-CPLD-version-reading-based-.patch | 123 - ...-platform-Add-support-for-new-msn201.patch | 83 - ...x-mlxreg-hotplug-add-extra-run-cycle.patch | 71 - ...x-add-new-OEM-system-types-to-mlx-pl.patch | 73 - ...-x86-mlx-platform-fix-module-aliases.patch | 39 - ...-platform-Add-bus-detection-and-diff.patch | 266 - ...sses-Add-capabilities-to-i2c-mlxcpld.patch | 199 - ...ort-patchwork-from-kernels-4.17-4.19.patch | 3063 ---- ...-x86-mlx-platform-backport-from-4.19.patch | 215 - ...-platform-Add-support-for-register-a.patch | 203 - ...24-config-mellanox-fan-configuration.patch | 28 - .../0025-net-udp_l3mdev_accept-support.patch | 306 - ...-Support-extended-port-numbers-for-S.patch | 75 - ...-mlxsw-thermal-monitoring-amendments.patch | 4072 ----- ...-introduce-watchdog-driver-for-Mella.patch | 839 - ...-Support-port-numbers-initialization.patch | 86 - patch/0030-update-kernel-config.patch | 25 - ...1-mlxsw-Align-code-with-kernel-v-5.0.patch | 13374 ---------------- ...sonic-update-kernel-config-mlsxw-pci.patch | 26 - ...driver-info-initialization-in-probe-.patch | 42 - ...mal-disable-highest-zone-calculation.patch | 35 - ...-x86-mlx-platform-Add-CPLD4-register.patch | 63 - ...-kernel-upstream-and-wd-type2-change.patch | 665 - ...7-mlxsw-Align-code-with-kernel-v-5.1.patch | 564 - ...heck-for-split-port-during-thermal-z.patch | 87 - ...nt-reading-unsupported-slave-address.patch | 74 - ...upport-for-Gear-Box-temperatures-in-.patch | 650 - ...ovide-optimization-for-I2C-bus-acces.patch | 668 - ...port-split-entries-in-hwmon-subsyste.patch | 86 - ...m-Backporting-Melanox-drivers-from-v.patch | 1181 -- ...ovide-optimization-for-module-number.patch | 530 - ...inimal-Add-validation-for-FW-version.patch | 109 - ...d-QSFP-EEPROM-supported-size-for-eth.patch | 168 - ...end-with-additional-chipsets-support.patch | 74 - ...thermal-zone-operations-initializati.patch | 101 - ...after-free-when-unregistering-therma.patch | 138 - ...creation-of-thermal-to-hwmon-sysfs-i.patch | 73 - ...thermal-zones-threshold-setting-duri.patch | 34 - ...-platform-Add-more-detention-for-sys.patch | 35 - ...-access-to-the-SKU-ID-string-backpor.patch | 88 - ...-platform-Modify-setting-for-new-sys.patch | 420 - ...-platform-Add-support-for-next-gener.patch | 486 - ...upport-for-new-hardware-device-types.patch | 87 - ...ge-add-per-port-broadcast-flood-flag.patch | 120 - patch/config-arista-7060-cx32s.patch | 6 +- patch/config-arista-dps1900.patch | 16 +- patch/config-cig-cs6436-serail_new.patch | 20 +- patch/config-dell-s6000.patch | 44 +- patch/config-dell-z9100.patch | 12 +- patch/config-ingrasys-s9100.patch | 15 +- patch/config-inventec-d7032.patch | 17 +- patch/config-l3mdev-cgroup.patch | 34 - patch/config-mitac-ly1200.patch | 6 +- patch/config-optoe.patch | 21 +- ...arista-disable-smbus-mux-for-hudson2.patch | 6 +- ...rista-net-tg3-access-regs-indirectly.patch | 20 +- ...et-tg3-disallow-broadcom-default-mac.patch | 10 +- ...ver-arista-net-tg3-dma-mask-4g-sb800.patch | 23 +- patch/driver-hwmon-max6620-fix-rpm-calc.patch | 2 +- patch/driver-hwmon-max6620-update.patch | 2 +- patch/driver-hwmon-max6620.patch | 10 +- ...ver-hwmon-max6658-fix-write-convrate.patch | 24 +- ...n-pmbus-dni_dps460-update-pmbus-core.patch | 2 +- patch/driver-hwmon-pmbus-dni_dps460.patch | 14 +- patch/driver-hwmon-pmbus-dps1900.patch | 23 +- ...r-i2c-bus-intel-ismt-add-delay-param.patch | 8 +- patch/driver-ixgbe-external-phy.patch | 52 +- patch/driver-l3mdev-cgroup.patch | 338 - ...3-add-param-short-preamble-and-reset.patch | 17 +- ...-i2c-mux-force-deselect-on-exit-flag.patch | 8 +- .../driver-sff-8436-use-nvmem-framework.patch | 6 +- ...river-sff-8436-use-nvmem_device_read.patch | 4 +- patch/driver-support-optoe-EOF_fix.patch | 10 +- patch/driver-support-optoe-QSFP_DD.patch | 10 +- ...river-support-optoe-chunk-offset-fix.patch | 6 +- patch/driver-support-optoe.patch | 14 +- ...river-support-sff-8436-eeprom-update.patch | 4 +- patch/driver-support-sff-8436-eeprom.patch | 18 +- ...iver-support-sff-8436-read-write-fix.patch | 9 +- ...er-support-tun-config-carrier-enable.patch | 38 +- patch/fix_ismt_alignment_issue.patch | 141 - patch/kernel-add-kexec-reboot-string.patch | 4 +- ...nable-psample-and-act_sample-drivers.patch | 49 - ...ntel_pch_thermal-Fix-enable-check-on.patch | 46 - ...i-handle-missing-DMI-data-gracefully.patch | 63 - ...duce-psample-a-new-genetlink-channel.patch | 538 - ...-backport-introduce-tc-sample-action.patch | 457 - patch/net-backport-ipv6-missing-route.patch | 15 +- patch/net-psample-fix-skb-over-panic.patch | 9 +- patch/preconfig/series | 2 - patch/series | 106 +- 113 files changed, 8922 insertions(+), 40257 deletions(-) delete mode 100644 patch/0000-net-Fix-netdev-adjacency-tracking.patch delete mode 100644 patch/0000-net-ipv6-ll-anycast-mcast-routes-on-dev.patch delete mode 100644 patch/0001-i2c-mlxcpld-add-master-driver-for-Mellanox-systems.patch delete mode 100644 patch/0001-net-ipv6-Allow-shorthand-delete-of-all-nexthops-in-m.patch create mode 100644 patch/0001-v4.19-6-Mellanox-platform-Backport-patches-for-new-M.patch create mode 100644 patch/0002-config-mellanox-configuration.patch delete mode 100644 patch/0002-i2c-mux-mlxcpld-add-driver-for-Mellanox-systems.patch rename patch/{0057-mlxsw-minimal-Fix-validation-for-FW-minor-version.patch => 0003-mlxsw-minimal-Fix-validation-for-FW-minor-version.patch} (77%) delete mode 100644 patch/0003-platform-mellanox-Introduce-Mellanox-hardware-platfo.patch create mode 100644 patch/0004-mlxsw-core-Add-the-hottest-thermal-zone-detection.patch delete mode 100644 patch/0004-platform-x86-Introduce-support-for-Mellanox-hotplug-.patch create mode 100644 patch/0005-hwmon-pmbus-core-Add-support-for-vid-mode-detection-.patch delete mode 100644 patch/0005-leds-add-driver-for-support-Mellanox-regmap-LEDs-for.patch delete mode 100644 patch/0006-Mellanox-switch-drivers-changes.patch create mode 100644 patch/0006-platform-mellanox-mlxreg-hotplug-Use-capability-r.patch delete mode 100644 patch/0007-hwmon-pmbus-Add-support-for-Intel-VID-protocol-VR13.patch delete mode 100644 patch/0008-hwmon-pmbus-Add-support-for-Texas-Instruments-tps536.patch delete mode 100644 patch/0009-platform-mellonox-introduce-mlxreg-io-driver-and-add.patch delete mode 100644 patch/0010-config-mellanox-configuration.patch delete mode 100644 patch/0011-support-Broadcom-54616-Phy-for-Intel-igb-driver.patch delete mode 100644 patch/0012-platform-mellanox-mlxreg-hotplug-driver-add-check-fo.patch delete mode 100644 patch/0014-mlxsw-qsfp_sysfs-Support-CPLD-version-reading-based-.patch delete mode 100644 patch/0015-platform-x86-mlx-platform-Add-support-for-new-msn201.patch delete mode 100644 patch/0016-platform-mellanox-mlxreg-hotplug-add-extra-run-cycle.patch delete mode 100644 patch/0017-platform-mellanox-add-new-OEM-system-types-to-mlx-pl.patch delete mode 100644 patch/0018-platform-x86-mlx-platform-fix-module-aliases.patch delete mode 100644 patch/0019-platform-x86-mlx-platform-Add-bus-detection-and-diff.patch delete mode 100644 patch/0020-i2c-busses-Add-capabilities-to-i2c-mlxcpld.patch delete mode 100644 patch/0021-Mellanox-backport-patchwork-from-kernels-4.17-4.19.patch delete mode 100644 patch/0022-platform-x86-mlx-platform-backport-from-4.19.patch delete mode 100644 patch/0023-platform-x86-mlx-platform-Add-support-for-register-a.patch delete mode 100644 patch/0024-config-mellanox-fan-configuration.patch delete mode 100644 patch/0025-net-udp_l3mdev_accept-support.patch delete mode 100644 patch/0026-mlxsw-qsfp_sysfs-Support-extended-port-numbers-for-S.patch delete mode 100644 patch/0027-mlxsw-thermal-monitoring-amendments.patch delete mode 100644 patch/0028-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch delete mode 100644 patch/0029-mlxsw-qsfp_sysfs-Support-port-numbers-initialization.patch delete mode 100644 patch/0030-update-kernel-config.patch delete mode 100644 patch/0031-mlxsw-Align-code-with-kernel-v-5.0.patch delete mode 100644 patch/0032-sonic-update-kernel-config-mlsxw-pci.patch delete mode 100644 patch/0033-hwmon-pmbus-Fix-driver-info-initialization-in-probe-.patch delete mode 100644 patch/0034-mlxsw-thermal-disable-highest-zone-calculation.patch delete mode 100644 patch/0035-platform-x86-mlx-platform-Add-CPLD4-register.patch delete mode 100644 patch/0036-watchdog-mlx-wdt-kernel-upstream-and-wd-type2-change.patch delete mode 100644 patch/0037-mlxsw-Align-code-with-kernel-v-5.1.patch delete mode 100644 patch/0038-mlxsw-core-Add-check-for-split-port-during-thermal-z.patch delete mode 100644 patch/0039-mlxsw-core-Prevent-reading-unsupported-slave-address.patch delete mode 100644 patch/0040-mlxsw-core-add-support-for-Gear-Box-temperatures-in-.patch delete mode 100644 patch/0041-mlxsw-minimal-Provide-optimization-for-I2C-bus-acces.patch delete mode 100644 patch/0042-mlxsw-core-Skip-port-split-entries-in-hwmon-subsyste.patch delete mode 100644 patch/0043-mellanox-platform-Backporting-Melanox-drivers-from-v.patch delete mode 100644 patch/0044-mlxsw-minimal-Provide-optimization-for-module-number.patch delete mode 100644 patch/0045-mlxsw-minimal-Add-validation-for-FW-version.patch delete mode 100644 patch/0046-mlxsw-core-Extend-QSFP-EEPROM-supported-size-for-eth.patch delete mode 100644 patch/0047-mfd-lpc-ich-extend-with-additional-chipsets-support.patch delete mode 100644 patch/0048-mlxsw-core-Skip-thermal-zone-operations-initializati.patch delete mode 100644 patch/0049-thermal-Fix-use-after-free-when-unregistering-therma.patch delete mode 100644 patch/0050-mlxsw-core-Drop-creation-of-thermal-to-hwmon-sysfs-i.patch delete mode 100644 patch/0051-mlxsw-core-Skip-thermal-zones-threshold-setting-duri.patch delete mode 100644 patch/0052-platform-x86-mlx-platform-Add-more-detention-for-sys.patch delete mode 100644 patch/0053-firmware-dmi-Add-access-to-the-SKU-ID-string-backpor.patch delete mode 100644 patch/0054-platform-x86-mlx-platform-Modify-setting-for-new-sys.patch delete mode 100644 patch/0055-platform-x86-mlx-platform-Add-support-for-next-gener.patch delete mode 100644 patch/0056-mlxsw-core-Add-support-for-new-hardware-device-types.patch delete mode 100644 patch/bridge-add-per-port-broadcast-flood-flag.patch mode change 100755 => 100644 patch/config-cig-cs6436-serail_new.patch delete mode 100644 patch/config-l3mdev-cgroup.patch mode change 100755 => 100644 patch/driver-ixgbe-external-phy.patch delete mode 100644 patch/driver-l3mdev-cgroup.patch delete mode 100644 patch/fix_ismt_alignment_issue.patch delete mode 100644 patch/kernel-enable-psample-and-act_sample-drivers.patch delete mode 100644 patch/linux-4.13-thermal-intel_pch_thermal-Fix-enable-check-on.patch delete mode 100644 patch/linux-4.16-firmware-dmi-handle-missing-DMI-data-gracefully.patch delete mode 100644 patch/mellanox-backport-introduce-psample-a-new-genetlink-channel.patch delete mode 100644 patch/mellanox-backport-introduce-tc-sample-action.patch diff --git a/Makefile b/Makefile index e1b6363cd176..26de647ec6d0 100644 --- a/Makefile +++ b/Makefile @@ -2,17 +2,17 @@ SHELL = /bin/bash .SHELLFLAGS += -e -KERNEL_ABI_MINOR_VERSION = 2 -KVERSION_SHORT ?= 4.9.0-11-$(KERNEL_ABI_MINOR_VERSION) +KERNEL_ABI_MINOR_VERSION = 0 +KVERSION_SHORT ?= 4.19.0-6-$(KERNEL_ABI_MINOR_VERSION) KVERSION ?= $(KVERSION_SHORT)-amd64 -KERNEL_VERSION ?= 4.9.189 -KERNEL_SUBVERSION ?= 3+deb9u2 +KERNEL_VERSION ?= 4.19.67 +KERNEL_SUBVERSION ?= 2+deb10u2 kernel_procure_method ?= build CONFIGURED_ARCH ?= amd64 LINUX_HEADER_COMMON = linux-headers-$(KVERSION_SHORT)-common_$(KERNEL_VERSION)-$(KERNEL_SUBVERSION)_all.deb LINUX_HEADER_AMD64 = linux-headers-$(KVERSION)_$(KERNEL_VERSION)-$(KERNEL_SUBVERSION)_$(CONFIGURED_ARCH).deb -LINUX_IMAGE = linux-image-$(KVERSION)_$(KERNEL_VERSION)-$(KERNEL_SUBVERSION)_$(CONFIGURED_ARCH).deb +LINUX_IMAGE = linux-image-$(KVERSION)-unsigned_$(KERNEL_VERSION)-$(KERNEL_SUBVERSION)_$(CONFIGURED_ARCH).deb MAIN_TARGET = $(LINUX_HEADER_COMMON) DERIVED_TARGETS = $(LINUX_HEADER_AMD64) $(LINUX_IMAGE) @@ -48,9 +48,9 @@ ORIG_FILE = linux_$(KERNEL_VERSION).orig.tar.xz DEBIAN_FILE = linux_$(KERNEL_VERSION)-$(KERNEL_SUBVERSION).debian.tar.xz BUILD_DIR=linux-$(KERNEL_VERSION) -DSC_FILE_URL = "http://security.debian.org/debian-security/pool/updates/main/l/linux/linux_4.9.189-3+deb9u2.dsc" -DEBIAN_FILE_URL = "http://security.debian.org/debian-security/pool/updates/main/l/linux/linux_4.9.189-3+deb9u2.debian.tar.xz" -ORIG_FILE_URL = "http://security.debian.org/debian-security/pool/updates/main/l/linux/linux_4.9.189.orig.tar.xz" +DSC_FILE_URL = "http://security.debian.org/debian-security/pool/updates/main/l/linux/linux_4.19.67-2+deb10u2.dsc" +DEBIAN_FILE_URL = "http://security.debian.org/debian-security/pool/updates/main/l/linux/linux_4.19.67-2+deb10u2.debian.tar.xz" +ORIG_FILE_URL = "http://security.debian.org/debian-security/pool/updates/main/l/linux/linux_4.19.67.orig.tar.xz" $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : # Obtaining the Debian kernel source @@ -74,13 +74,13 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : debian/bin/gencontrol.py # generate linux build file for amd64_none_amd64 - fakeroot make -f debian/rules.gen setup_armhf_none_armmp - fakeroot make -f debian/rules.gen setup_arm64_none + # fakeroot make -f debian/rules.gen setup_armhf_none_armmp + # fakeroot make -f debian/rules.gen setup_arm64_none fakeroot make -f debian/rules.gen setup_amd64_none_amd64 # Applying patches and configuration changes - git add debian/build/build_armhf_none_armmp/.config -f - git add debian/build/build_arm64_none_arm64/.config -f + # git add debian/build/build_armhf_none_armmp/.config -f + # git add debian/build/build_arm64_none_arm64/.config -f git add debian/build/build_amd64_none_amd64/.config -f git add debian/config.defines.dump -f git add debian/control -f diff --git a/patch/0000-net-Fix-netdev-adjacency-tracking.patch b/patch/0000-net-Fix-netdev-adjacency-tracking.patch deleted file mode 100644 index 3cda8053c351..000000000000 --- a/patch/0000-net-Fix-netdev-adjacency-tracking.patch +++ /dev/null @@ -1,1302 +0,0 @@ -From 962236dd11d64946c9d0c80982b1f75adb1c0780 Mon Sep 17 00:00:00 2001 -From: ps407411 -Date: Wed, 4 Sep 2019 10:22:48 +0000 -Subject: [PATCH] net: Fix netdev adjacency tracking - - -Note: This patch is no longer required in kernel version >=4.10 - -Refer to below patches which have been combined into single patch. - -https://github.com/torvalds/linux/commit/67b62f98a1de962277b60d77c0c208b76867dbae#diff-3ce2f1b11ea5a4b9c88ef0b4159bd481 -https://github.com/torvalds/linux/commit/0f524a80ff35af8a7664d7661d948107da142e04#diff-3ce2f1b11ea5a4b9c88ef0b4159bd481 -https://github.com/torvalds/linux/commit/f1170fd462c67c4ae2f20734566d94e0f8f62f69#diff-3ce2f1b11ea5a4b9c88ef0b4159bd481 -https://github.com/torvalds/linux/commit/1a3f060c1a47dba4e12ac21ce62b57666b9c4e95#diff-3ce2f1b11ea5a4b9c88ef0b4159bd481 -https://github.com/torvalds/linux/commit/790510d99f39cee7f275d001aa5024032ed9bb48#diff-3ce2f1b11ea5a4b9c88ef0b4159bd481 - -https://github.com/torvalds/linux/commit/453d39329ad03f9f6d93ec6d0d57bf7a1e2a20c7#diff-66286e176927fcbf186d37fce71bc94e -https://github.com/torvalds/linux/commit/e0e79c8e74b08976d9b45e52b704b9228c6965c7#diff-598fcd5f9f85a0fea3a53a7022974457 - -https://github.com/torvalds/linux/commit/b3208b2024c9089106df52ae25ebf39068d6f9fc#diff-ce347f03cd1a8602476d0774dd8dde24 - -https://github.com/torvalds/linux/commit/1cd127fc7d3a6d6a0fc9f9cca47ca3a16ee79679#diff-69464fa7779eabc57449a324cd70bbcb - -https://github.com/torvalds/linux/commit/dd82364c3ab93a96bb1e45d22106a4b1ea4bef39#diff-5a740fc1e7dea601fffed2ecbbb8e7c8 - -https://github.com/torvalds/linux/commit/cf2d67408b2f9a840f27d25a0219070b5b5deec4#diff-c0c1e518eebaabb2ad27194986805291 - -Signed-off-by: Preetham Singh ---- - drivers/infiniband/core/core_priv.h | 9 +- - drivers/infiniband/core/roce_gid_mgmt.c | 42 ++- - drivers/infiniband/ulp/ipoib/ipoib_main.c | 37 +- - drivers/net/bonding/bond_alb.c | 81 ++-- - drivers/net/bonding/bond_main.c | 18 +- - drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 132 ++++--- - .../net/ethernet/mellanox/mlxsw/spectrum.c | 37 +- - drivers/net/ethernet/rocker/rocker_main.c | 32 +- - include/linux/netdevice.h | 40 +- - net/core/dev.c | 349 +++++++++--------- - 10 files changed, 423 insertions(+), 354 deletions(-) - -diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h -index 19d499d..0c0bea0 100644 ---- a/drivers/infiniband/core/core_priv.h -+++ b/drivers/infiniband/core/core_priv.h -@@ -127,14 +127,7 @@ void ib_cache_release_one(struct ib_device *device); - static inline bool rdma_is_upper_dev_rcu(struct net_device *dev, - struct net_device *upper) - { -- struct net_device *_upper = NULL; -- struct list_head *iter; -- -- netdev_for_each_all_upper_dev_rcu(dev, _upper, iter) -- if (_upper == upper) -- break; -- -- return _upper == upper; -+ return netdev_has_upper_dev_all_rcu(dev, upper); - } - - int addr_init(void); -diff --git a/drivers/infiniband/core/roce_gid_mgmt.c b/drivers/infiniband/core/roce_gid_mgmt.c -index 06556c3..3a64a08 100644 ---- a/drivers/infiniband/core/roce_gid_mgmt.c -+++ b/drivers/infiniband/core/roce_gid_mgmt.c -@@ -437,6 +437,28 @@ static void callback_for_addr_gid_device_scan(struct ib_device *device, - &parsed->gid_attr); - } - -+struct upper_list { -+ struct list_head list; -+ struct net_device *upper; -+}; -+ -+static int netdev_upper_walk(struct net_device *upper, void *data) -+{ -+ struct upper_list *entry = kmalloc(sizeof(*entry), GFP_ATOMIC); -+ struct list_head *upper_list = data; -+ -+ if (!entry) { -+ pr_info("roce_gid_mgmt: couldn't allocate entry to delete ndev\n"); -+ return 0; -+ } -+ -+ list_add_tail(&entry->list, upper_list); -+ dev_hold(upper); -+ entry->upper = upper; -+ -+ return 0; -+} -+ - static void handle_netdev_upper(struct ib_device *ib_dev, u8 port, - void *cookie, - void (*handle_netdev)(struct ib_device *ib_dev, -@@ -444,30 +466,12 @@ static void handle_netdev_upper(struct ib_device *ib_dev, u8 port, - struct net_device *ndev)) - { - struct net_device *ndev = (struct net_device *)cookie; -- struct upper_list { -- struct list_head list; -- struct net_device *upper; -- }; -- struct net_device *upper; -- struct list_head *iter; - struct upper_list *upper_iter; - struct upper_list *upper_temp; - LIST_HEAD(upper_list); - - rcu_read_lock(); -- netdev_for_each_all_upper_dev_rcu(ndev, upper, iter) { -- struct upper_list *entry = kmalloc(sizeof(*entry), -- GFP_ATOMIC); -- -- if (!entry) { -- pr_info("roce_gid_mgmt: couldn't allocate entry to delete ndev\n"); -- continue; -- } -- -- list_add_tail(&entry->list, &upper_list); -- dev_hold(upper); -- entry->upper = upper; -- } -+ netdev_walk_all_upper_dev_rcu(ndev, netdev_upper_walk, &upper_list); - rcu_read_unlock(); - - handle_netdev(ib_dev, port, ndev); -diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c -index 17c5bc7..166d41d 100644 ---- a/drivers/infiniband/ulp/ipoib/ipoib_main.c -+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c -@@ -319,6 +319,25 @@ static struct net_device *ipoib_get_master_net_dev(struct net_device *dev) - return dev; - } - -+struct ipoib_walk_data { -+ const struct sockaddr *addr; -+ struct net_device *result; -+}; -+ -+static int ipoib_upper_walk(struct net_device *upper, void *_data) -+{ -+ struct ipoib_walk_data *data = _data; -+ int ret = 0; -+ -+ if (ipoib_is_dev_match_addr_rcu(data->addr, upper)) { -+ dev_hold(upper); -+ data->result = upper; -+ ret = 1; -+ } -+ -+ return ret; -+} -+ - /** - * Find a net_device matching the given address, which is an upper device of - * the given net_device. -@@ -331,27 +350,21 @@ static struct net_device *ipoib_get_master_net_dev(struct net_device *dev) - static struct net_device *ipoib_get_net_dev_match_addr( - const struct sockaddr *addr, struct net_device *dev) - { -- struct net_device *upper, -- *result = NULL; -- struct list_head *iter; -+ struct ipoib_walk_data data = { -+ .addr = addr, -+ }; - - rcu_read_lock(); - if (ipoib_is_dev_match_addr_rcu(addr, dev)) { - dev_hold(dev); -- result = dev; -+ data.result = dev; - goto out; - } -+ netdev_walk_all_upper_dev_rcu(dev, ipoib_upper_walk, &data); - -- netdev_for_each_all_upper_dev_rcu(dev, upper, iter) { -- if (ipoib_is_dev_match_addr_rcu(addr, upper)) { -- dev_hold(upper); -- result = upper; -- break; -- } -- } - out: - rcu_read_unlock(); -- return result; -+ return data.result; - } - - /* returns the number of IPoIB netdevs on top a given ipoib device matching a -diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c -index 91d8a48..b49f1e9 100644 ---- a/drivers/net/bonding/bond_alb.c -+++ b/drivers/net/bonding/bond_alb.c -@@ -954,13 +954,61 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[], - dev_queue_xmit(skb); - } - -+struct alb_walk_data { -+ struct bonding *bond; -+ struct slave *slave; -+ u8 *mac_addr; -+ bool strict_match; -+}; -+ -+static int alb_upper_dev_walk(struct net_device *upper, void *_data) -+{ -+ struct alb_walk_data *data = _data; -+ bool strict_match = data->strict_match; -+ struct bonding *bond = data->bond; -+ struct slave *slave = data->slave; -+ u8 *mac_addr = data->mac_addr; -+ struct bond_vlan_tag *tags; -+ -+ if (is_vlan_dev(upper) && vlan_get_encap_level(upper) == 0) { -+ if (strict_match && -+ ether_addr_equal_64bits(mac_addr, -+ upper->dev_addr)) { -+ alb_send_lp_vid(slave, mac_addr, -+ vlan_dev_vlan_proto(upper), -+ vlan_dev_vlan_id(upper)); -+ } else if (!strict_match) { -+ alb_send_lp_vid(slave, upper->dev_addr, -+ vlan_dev_vlan_proto(upper), -+ vlan_dev_vlan_id(upper)); -+ } -+ } -+ -+ /* If this is a macvlan device, then only send updates -+ * when strict_match is turned off. -+ */ -+ if (netif_is_macvlan(upper) && !strict_match) { -+ tags = bond_verify_device_path(bond->dev, upper, 0); -+ if (IS_ERR_OR_NULL(tags)) -+ BUG(); -+ alb_send_lp_vid(slave, upper->dev_addr, -+ tags[0].vlan_proto, tags[0].vlan_id); -+ kfree(tags); -+ } -+ -+ return 0; -+} -+ - static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[], - bool strict_match) - { - struct bonding *bond = bond_get_bond_by_slave(slave); -- struct net_device *upper; -- struct list_head *iter; -- struct bond_vlan_tag *tags; -+ struct alb_walk_data data = { -+ .strict_match = strict_match, -+ .mac_addr = mac_addr, -+ .slave = slave, -+ .bond = bond, -+ }; - - /* send untagged */ - alb_send_lp_vid(slave, mac_addr, 0, 0); -@@ -969,32 +1017,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[], - * for that device. - */ - rcu_read_lock(); -- netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) { -- if (is_vlan_dev(upper) && -- bond->nest_level == vlan_get_encap_level(upper) - 1) { -- if (upper->addr_assign_type == NET_ADDR_STOLEN) { -- alb_send_lp_vid(slave, mac_addr, -- vlan_dev_vlan_proto(upper), -- vlan_dev_vlan_id(upper)); -- } else { -- alb_send_lp_vid(slave, upper->dev_addr, -- vlan_dev_vlan_proto(upper), -- vlan_dev_vlan_id(upper)); -- } -- } -- -- /* If this is a macvlan device, then only send updates -- * when strict_match is turned off. -- */ -- if (netif_is_macvlan(upper) && !strict_match) { -- tags = bond_verify_device_path(bond->dev, upper, 0); -- if (IS_ERR_OR_NULL(tags)) -- BUG(); -- alb_send_lp_vid(slave, upper->dev_addr, -- tags[0].vlan_proto, tags[0].vlan_id); -- kfree(tags); -- } -- } -+ netdev_walk_all_upper_dev_rcu(bond->dev, alb_upper_dev_walk, &data); - rcu_read_unlock(); - } - -diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c -index 24a3433..2bd9371 100644 ---- a/drivers/net/bonding/bond_main.c -+++ b/drivers/net/bonding/bond_main.c -@@ -2277,22 +2277,24 @@ static void bond_mii_monitor(struct work_struct *work) - } - } - -+static int bond_upper_dev_walk(struct net_device *upper, void *data) -+{ -+ __be32 ip = *((__be32 *)data); -+ -+ return ip == bond_confirm_addr(upper, 0, ip); -+} -+ - static bool bond_has_this_ip(struct bonding *bond, __be32 ip) - { -- struct net_device *upper; -- struct list_head *iter; - bool ret = false; - - if (ip == bond_confirm_addr(bond->dev, 0, ip)) - return true; - - rcu_read_lock(); -- netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) { -- if (ip == bond_confirm_addr(upper, 0, ip)) { -- ret = true; -- break; -- } -- } -+ if (netdev_walk_all_upper_dev_rcu(bond->dev, bond_upper_dev_walk, &ip)) -+ ret = true; -+ - rcu_read_unlock(); - - return ret; -diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c -index a5428b6..187c38e 100644 ---- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c -+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c -@@ -5012,24 +5012,23 @@ static int ixgbe_fwd_ring_up(struct net_device *vdev, - return err; - } - --static void ixgbe_configure_dfwd(struct ixgbe_adapter *adapter) -+static int ixgbe_upper_dev_walk(struct net_device *upper, void *data) - { -- struct net_device *upper; -- struct list_head *iter; -- int err; -+ if (netif_is_macvlan(upper)) { -+ struct macvlan_dev *dfwd = netdev_priv(upper); -+ struct ixgbe_fwd_adapter *vadapter = dfwd->fwd_priv; -+ -+ if (dfwd->fwd_priv) -+ ixgbe_fwd_ring_up(upper, vadapter); -+ } - -- netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) { -- if (netif_is_macvlan(upper)) { -- struct macvlan_dev *dfwd = netdev_priv(upper); -- struct ixgbe_fwd_adapter *vadapter = dfwd->fwd_priv; -+ return 0; -+} - -- if (dfwd->fwd_priv) { -- err = ixgbe_fwd_ring_up(upper, vadapter); -- if (err) -- continue; -- } -- } -- } -+static void ixgbe_configure_dfwd(struct ixgbe_adapter *adapter) -+{ -+ netdev_walk_all_upper_dev_rcu(adapter->netdev, -+ ixgbe_upper_dev_walk, NULL); - } - - static void ixgbe_configure(struct ixgbe_adapter *adapter) -@@ -5448,12 +5447,25 @@ static void ixgbe_fdir_filter_exit(struct ixgbe_adapter *adapter) - spin_unlock(&adapter->fdir_perfect_lock); - } - -+static int ixgbe_disable_macvlan(struct net_device *upper, void *data) -+{ -+ if (netif_is_macvlan(upper)) { -+ struct macvlan_dev *vlan = netdev_priv(upper); -+ -+ if (vlan->fwd_priv) { -+ netif_tx_stop_all_queues(upper); -+ netif_carrier_off(upper); -+ netif_tx_disable(upper); -+ } -+ } -+ -+ return 0; -+} -+ - void ixgbe_down(struct ixgbe_adapter *adapter) - { - struct net_device *netdev = adapter->netdev; - struct ixgbe_hw *hw = &adapter->hw; -- struct net_device *upper; -- struct list_head *iter; - int i; - - /* signal that we are down to the interrupt handler */ -@@ -5477,17 +5489,8 @@ void ixgbe_down(struct ixgbe_adapter *adapter) - netif_tx_disable(netdev); - - /* disable any upper devices */ -- netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) { -- if (netif_is_macvlan(upper)) { -- struct macvlan_dev *vlan = netdev_priv(upper); -- -- if (vlan->fwd_priv) { -- netif_tx_stop_all_queues(upper); -- netif_carrier_off(upper); -- netif_tx_disable(upper); -- } -- } -- } -+ netdev_walk_all_upper_dev_rcu(adapter->netdev, -+ ixgbe_disable_macvlan, NULL); - - ixgbe_irq_disable(adapter); - -@@ -6727,6 +6730,18 @@ static void ixgbe_update_default_up(struct ixgbe_adapter *adapter) - #endif - } - -+static int ixgbe_enable_macvlan(struct net_device *upper, void *data) -+{ -+ if (netif_is_macvlan(upper)) { -+ struct macvlan_dev *vlan = netdev_priv(upper); -+ -+ if (vlan->fwd_priv) -+ netif_tx_wake_all_queues(upper); -+ } -+ -+ return 0; -+} -+ - /** - * ixgbe_watchdog_link_is_up - update netif_carrier status and - * print link up message -@@ -6736,8 +6751,6 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter) - { - struct net_device *netdev = adapter->netdev; - struct ixgbe_hw *hw = &adapter->hw; -- struct net_device *upper; -- struct list_head *iter; - u32 link_speed = adapter->link_speed; - const char *speed_str; - bool flow_rx, flow_tx; -@@ -6808,14 +6821,8 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter) - - /* enable any upper devices */ - rtnl_lock(); -- netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) { -- if (netif_is_macvlan(upper)) { -- struct macvlan_dev *vlan = netdev_priv(upper); -- -- if (vlan->fwd_priv) -- netif_tx_wake_all_queues(upper); -- } -- } -+ netdev_walk_all_upper_dev_rcu(adapter->netdev, -+ ixgbe_enable_macvlan, NULL); - rtnl_unlock(); - - /* update the default user priority for VFs */ -@@ -8353,12 +8360,38 @@ static int ixgbe_configure_clsu32_del_hnode(struct ixgbe_adapter *adapter, - } - - #ifdef CONFIG_NET_CLS_ACT -+struct upper_walk_data { -+ struct ixgbe_adapter *adapter; -+ u64 action; -+ int ifindex; -+ u8 queue; -+}; -+ -+static int get_macvlan_queue(struct net_device *upper, void *_data) -+{ -+ if (netif_is_macvlan(upper)) { -+ struct macvlan_dev *dfwd = netdev_priv(upper); -+ struct ixgbe_fwd_adapter *vadapter = dfwd->fwd_priv; -+ struct upper_walk_data *data = _data; -+ struct ixgbe_adapter *adapter = data->adapter; -+ int ifindex = data->ifindex; -+ -+ if (vadapter && vadapter->netdev->ifindex == ifindex) { -+ data->queue = adapter->rx_ring[vadapter->rx_base_queue]->reg_idx; -+ data->action = data->queue; -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ - static int handle_redirect_action(struct ixgbe_adapter *adapter, int ifindex, - u8 *queue, u64 *action) - { - unsigned int num_vfs = adapter->num_vfs, vf; -+ struct upper_walk_data data; - struct net_device *upper; -- struct list_head *iter; - - /* redirect to a SRIOV VF */ - for (vf = 0; vf < num_vfs; ++vf) { -@@ -8376,17 +8409,16 @@ static int handle_redirect_action(struct ixgbe_adapter *adapter, int ifindex, - } - - /* redirect to a offloaded macvlan netdev */ -- netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) { -- if (netif_is_macvlan(upper)) { -- struct macvlan_dev *dfwd = netdev_priv(upper); -- struct ixgbe_fwd_adapter *vadapter = dfwd->fwd_priv; -- -- if (vadapter && vadapter->netdev->ifindex == ifindex) { -- *queue = adapter->rx_ring[vadapter->rx_base_queue]->reg_idx; -- *action = *queue; -- return 0; -- } -- } -+ data.adapter = adapter; -+ data.ifindex = ifindex; -+ data.action = 0; -+ data.queue = 0; -+ if (netdev_walk_all_upper_dev_rcu(adapter->netdev, -+ get_macvlan_queue, &data)) { -+ *action = data.action; -+ *queue = data.queue; -+ -+ return 0; - } - - return -EINVAL; -diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c -index cc847e0..11cc608 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c -@@ -3093,19 +3093,30 @@ static bool mlxsw_sp_port_dev_check(const struct net_device *dev) - return dev->netdev_ops == &mlxsw_sp_port_netdev_ops; - } - -+static int mlxsw_lower_dev_walk(struct net_device *lower_dev, void *data) -+{ -+ struct mlxsw_sp_port **port = data; -+ int ret = 0; -+ -+ if (mlxsw_sp_port_dev_check(lower_dev)) { -+ *port = netdev_priv(lower_dev); -+ ret = 1; -+ } -+ -+ return ret; -+} -+ - static struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev) - { -- struct net_device *lower_dev; -- struct list_head *iter; -+ struct mlxsw_sp_port *port; - - if (mlxsw_sp_port_dev_check(dev)) - return netdev_priv(dev); - -- netdev_for_each_all_lower_dev(dev, lower_dev, iter) { -- if (mlxsw_sp_port_dev_check(lower_dev)) -- return netdev_priv(lower_dev); -- } -- return NULL; -+ port = NULL; -+ netdev_walk_all_lower_dev(dev, mlxsw_lower_dev_walk, &port); -+ -+ return port; - } - - static struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev) -@@ -3118,17 +3129,15 @@ static struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev) - - static struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev) - { -- struct net_device *lower_dev; -- struct list_head *iter; -+ struct mlxsw_sp_port *port; - - if (mlxsw_sp_port_dev_check(dev)) - return netdev_priv(dev); - -- netdev_for_each_all_lower_dev_rcu(dev, lower_dev, iter) { -- if (mlxsw_sp_port_dev_check(lower_dev)) -- return netdev_priv(lower_dev); -- } -- return NULL; -+ port = NULL; -+ netdev_walk_all_lower_dev_rcu(dev, mlxsw_lower_dev_walk, &port); -+ -+ return port; - } - - struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev) -diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c -index 24b7464..c6cccfb 100644 ---- a/drivers/net/ethernet/rocker/rocker_main.c -+++ b/drivers/net/ethernet/rocker/rocker_main.c -@@ -2839,20 +2839,38 @@ static bool rocker_port_dev_check_under(const struct net_device *dev, - return true; - } - -+struct rocker_walk_data { -+ struct rocker *rocker; -+ struct rocker_port *port; -+}; -+ -+static int rocker_lower_dev_walk(struct net_device *lower_dev, void *_data) -+{ -+ struct rocker_walk_data *data = _data; -+ int ret = 0; -+ -+ if (rocker_port_dev_check_under(lower_dev, data->rocker)) { -+ data->port = netdev_priv(lower_dev); -+ ret = 1; -+ } -+ -+ return ret; -+} -+ - struct rocker_port *rocker_port_dev_lower_find(struct net_device *dev, - struct rocker *rocker) - { -- struct net_device *lower_dev; -- struct list_head *iter; -+ struct rocker_walk_data data; - - if (rocker_port_dev_check_under(dev, rocker)) - return netdev_priv(dev); - -- netdev_for_each_all_lower_dev(dev, lower_dev, iter) { -- if (rocker_port_dev_check_under(lower_dev, rocker)) -- return netdev_priv(lower_dev); -- } -- return NULL; -+ data.rocker = rocker; -+ data.port = NULL; -+ netdev_walk_all_lower_dev(dev, rocker_lower_dev_walk, &data); -+ -+ return data.port; -+ - } - - static int rocker_netdevice_event(struct notifier_block *unused, -diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h -index 2ecf0f3..feb5d4c 100644 ---- a/include/linux/netdevice.h -+++ b/include/linux/netdevice.h -@@ -1460,7 +1460,6 @@ enum netdev_priv_flags { - * @ptype_specific: Device-specific, protocol-specific packet handlers - * - * @adj_list: Directly linked devices, like slaves for bonding -- * @all_adj_list: All linked devices, *including* neighbours - * @features: Currently active device features - * @hw_features: User-changeable features - * -@@ -1678,11 +1677,6 @@ struct net_device { - struct list_head lower; - } adj_list; - -- struct { -- struct list_head upper; -- struct list_head lower; -- } all_adj_list; -- - netdev_features_t features; - netdev_features_t hw_features; - netdev_features_t wanted_features; -@@ -3907,15 +3901,16 @@ struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev, - updev; \ - updev = netdev_upper_get_next_dev_rcu(dev, &(iter))) - --/* iterate through upper list, must be called under RCU read lock */ --#define netdev_for_each_all_upper_dev_rcu(dev, updev, iter) \ -- for (iter = &(dev)->all_adj_list.upper, \ -- updev = netdev_all_upper_get_next_dev_rcu(dev, &(iter)); \ -- updev; \ -- updev = netdev_all_upper_get_next_dev_rcu(dev, &(iter))) -- - bool netdev_has_any_upper_dev(struct net_device *dev); - -+int netdev_walk_all_upper_dev_rcu(struct net_device *dev, -+ int (*fn)(struct net_device *upper_dev, -+ void *data), -+ void *data); -+ -+bool netdev_has_upper_dev_all_rcu(struct net_device *dev, -+ struct net_device *upper_dev); -+ - void *netdev_lower_get_next_private(struct net_device *dev, - struct list_head **iter); - void *netdev_lower_get_next_private_rcu(struct net_device *dev, -@@ -3947,17 +3942,14 @@ struct net_device *netdev_all_lower_get_next(struct net_device *dev, - struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev, - struct list_head **iter); - --#define netdev_for_each_all_lower_dev(dev, ldev, iter) \ -- for (iter = (dev)->all_adj_list.lower.next, \ -- ldev = netdev_all_lower_get_next(dev, &(iter)); \ -- ldev; \ -- ldev = netdev_all_lower_get_next(dev, &(iter))) -- --#define netdev_for_each_all_lower_dev_rcu(dev, ldev, iter) \ -- for (iter = &(dev)->all_adj_list.lower, \ -- ldev = netdev_all_lower_get_next_rcu(dev, &(iter)); \ -- ldev; \ -- ldev = netdev_all_lower_get_next_rcu(dev, &(iter))) -+int netdev_walk_all_lower_dev(struct net_device *dev, -+ int (*fn)(struct net_device *lower_dev, -+ void *data), -+ void *data); -+int netdev_walk_all_lower_dev_rcu(struct net_device *dev, -+ int (*fn)(struct net_device *lower_dev, -+ void *data), -+ void *data); - - void *netdev_adjacent_get_private(struct list_head *adj_list); - void *netdev_lower_get_first_private_rcu(struct net_device *dev); -diff --git a/net/core/dev.c b/net/core/dev.c -index b48a741..257d982 100644 ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -5368,6 +5368,13 @@ static struct netdev_adjacent *__netdev_find_adj(struct net_device *adj_dev, - return NULL; - } - -+static int __netdev_has_upper_dev(struct net_device *upper_dev, void *data) -+{ -+ struct net_device *dev = data; -+ -+ return upper_dev == dev; -+} -+ - /** - * netdev_has_upper_dev - Check if device is linked to an upper device - * @dev: device -@@ -5382,10 +5389,30 @@ bool netdev_has_upper_dev(struct net_device *dev, - { - ASSERT_RTNL(); - -- return __netdev_find_adj(upper_dev, &dev->all_adj_list.upper); -+ return netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev, -+ upper_dev); - } - EXPORT_SYMBOL(netdev_has_upper_dev); - -+/** -+ * netdev_has_upper_dev_all - Check if device is linked to an upper device -+ * @dev: device -+ * @upper_dev: upper device to check -+ * -+ * Find out if a device is linked to specified upper device and return true -+ * in case it is. Note that this checks the entire upper device chain. -+ * The caller must hold rcu lock. -+ */ -+ -+bool netdev_has_upper_dev_all_rcu(struct net_device *dev, -+ struct net_device *upper_dev) -+{ -+ return !!netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev, -+ upper_dev); -+} -+EXPORT_SYMBOL(netdev_has_upper_dev_all_rcu); -+ -+ - /** - * netdev_has_any_upper_dev - Check if device is linked to some device - * @dev: device -@@ -5397,7 +5424,7 @@ bool netdev_has_any_upper_dev(struct net_device *dev) - { - ASSERT_RTNL(); - -- return !list_empty(&dev->all_adj_list.upper); -+ return !list_empty(&dev->adj_list.upper); - } - EXPORT_SYMBOL(netdev_has_any_upper_dev); - -@@ -5425,6 +5452,20 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev) - } - EXPORT_SYMBOL(netdev_master_upper_dev_get); - -+/** -+ * netdev_has_any_lower_dev - Check if device is linked to some device -+ * @dev: device -+ * -+ * Find out if a device is linked to a lower device and return true in case -+ * it is. The caller must hold the RTNL lock. -+ */ -+static bool netdev_has_any_lower_dev(struct net_device *dev) -+{ -+ ASSERT_RTNL(); -+ -+ return !list_empty(&dev->adj_list.lower); -+} -+ - void *netdev_adjacent_get_private(struct list_head *adj_list) - { - struct netdev_adjacent *adj; -@@ -5461,16 +5502,8 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, - } - EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu); - --/** -- * netdev_all_upper_get_next_dev_rcu - Get the next dev from upper list -- * @dev: device -- * @iter: list_head ** of the current position -- * -- * Gets the next device from the dev's upper list, starting from iter -- * position. The caller must hold RCU read lock. -- */ --struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev, -- struct list_head **iter) -+static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev, -+ struct list_head **iter) - { - struct netdev_adjacent *upper; - -@@ -5478,15 +5511,41 @@ struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev, - - upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); - -- if (&upper->list == &dev->all_adj_list.upper) -+ if (&upper->list == &dev->adj_list.upper) - return NULL; - - *iter = &upper->list; - - return upper->dev; - } --EXPORT_SYMBOL(netdev_all_upper_get_next_dev_rcu); - -+int netdev_walk_all_upper_dev_rcu(struct net_device *dev, -+ int (*fn)(struct net_device *dev, -+ void *data), -+ void *data) -+{ -+ struct net_device *udev; -+ struct list_head *iter; -+ int ret; -+ -+ for (iter = &dev->adj_list.upper, -+ udev = netdev_next_upper_dev_rcu(dev, &iter); -+ udev; -+ udev = netdev_next_upper_dev_rcu(dev, &iter)) { -+ /* first is the upper device itself */ -+ ret = fn(udev, data); -+ if (ret) -+ return ret; -+ -+ /* then look at all of its upper devices */ -+ ret = netdev_walk_all_upper_dev_rcu(udev, fn, data); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(netdev_walk_all_upper_dev_rcu); - /** - * netdev_lower_get_next_private - Get the next ->private from the - * lower neighbour list -@@ -5568,55 +5627,91 @@ void *netdev_lower_get_next(struct net_device *dev, struct list_head **iter) - } - EXPORT_SYMBOL(netdev_lower_get_next); - --/** -- * netdev_all_lower_get_next - Get the next device from all lower neighbour list -- * @dev: device -- * @iter: list_head ** of the current position -- * -- * Gets the next netdev_adjacent from the dev's all lower neighbour -- * list, starting from iter position. The caller must hold RTNL lock or -- * its own locking that guarantees that the neighbour all lower -- * list will remain unchanged. -- */ --struct net_device *netdev_all_lower_get_next(struct net_device *dev, struct list_head **iter) -+static struct net_device *netdev_next_lower_dev(struct net_device *dev, -+ struct list_head **iter) - { - struct netdev_adjacent *lower; - - lower = list_entry(*iter, struct netdev_adjacent, list); - -- if (&lower->list == &dev->all_adj_list.lower) -+ if (&lower->list == &dev->adj_list.lower) - return NULL; - - *iter = lower->list.next; - - return lower->dev; - } --EXPORT_SYMBOL(netdev_all_lower_get_next); - --/** -- * netdev_all_lower_get_next_rcu - Get the next device from all -- * lower neighbour list, RCU variant -- * @dev: device -- * @iter: list_head ** of the current position -- * -- * Gets the next netdev_adjacent from the dev's all lower neighbour -- * list, starting from iter position. The caller must hold RCU read lock. -- */ --struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev, -- struct list_head **iter) -+int netdev_walk_all_lower_dev(struct net_device *dev, -+ int (*fn)(struct net_device *dev, -+ void *data), -+ void *data) -+{ -+ struct net_device *ldev; -+ struct list_head *iter; -+ int ret; -+ -+ for (iter = &dev->adj_list.lower, -+ ldev = netdev_next_lower_dev(dev, &iter); -+ ldev; -+ ldev = netdev_next_lower_dev(dev, &iter)) { -+ /* first is the lower device itself */ -+ ret = fn(ldev, data); -+ if (ret) -+ return ret; -+ -+ /* then look at all of its lower devices */ -+ ret = netdev_walk_all_lower_dev(ldev, fn, data); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev); -+ -+static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev, -+ struct list_head **iter) - { - struct netdev_adjacent *lower; - - lower = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); - -- if (&lower->list == &dev->all_adj_list.lower) -+ if (&lower->list == &dev->adj_list.lower) - return NULL; - - *iter = &lower->list; - - return lower->dev; - } --EXPORT_SYMBOL(netdev_all_lower_get_next_rcu); -+ -+int netdev_walk_all_lower_dev_rcu(struct net_device *dev, -+ int (*fn)(struct net_device *dev, -+ void *data), -+ void *data) -+{ -+ struct net_device *ldev; -+ struct list_head *iter; -+ int ret; -+ -+ for (iter = &dev->adj_list.lower, -+ ldev = netdev_next_lower_dev_rcu(dev, &iter); -+ ldev; -+ ldev = netdev_next_lower_dev_rcu(dev, &iter)) { -+ /* first is the lower device itself */ -+ ret = fn(ldev, data); -+ if (ret) -+ return ret; -+ -+ /* then look at all of its lower devices */ -+ ret = netdev_walk_all_lower_dev_rcu(ldev, fn, data); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev_rcu); - - /** - * netdev_lower_get_first_private_rcu - Get the first ->private from the -@@ -5689,7 +5784,6 @@ static inline bool netdev_adjacent_is_neigh_list(struct net_device *dev, - - static int __netdev_adjacent_dev_insert(struct net_device *dev, - struct net_device *adj_dev, -- u16 ref_nr, - struct list_head *dev_list, - void *private, bool master) - { -@@ -5699,7 +5793,9 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, - adj = __netdev_find_adj(adj_dev, dev_list); - - if (adj) { -- adj->ref_nr += ref_nr; -+ adj->ref_nr += 1; -+ pr_debug("Insert adjacency: dev %s adj_dev %s adj->ref_nr %d\n", -+ dev->name, adj_dev->name, adj->ref_nr); - return 0; - } - -@@ -5709,12 +5805,12 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, - - adj->dev = adj_dev; - adj->master = master; -- adj->ref_nr = ref_nr; -+ adj->ref_nr = 1; - adj->private = private; - dev_hold(adj_dev); - -- pr_debug("dev_hold for %s, because of link added from %s to %s\n", -- adj_dev->name, dev->name, adj_dev->name); -+ pr_debug("Insert adjacency: dev %s adj_dev %s adj->ref_nr %d; dev_hold on %s\n", -+ dev->name, adj_dev->name, adj->ref_nr, adj_dev->name); - - if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list)) { - ret = netdev_adjacent_sysfs_add(dev, adj_dev, dev_list); -@@ -5753,6 +5849,9 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev, - { - struct netdev_adjacent *adj; - -+ pr_debug("Remove adjacency: dev %s adj_dev %s ref_nr %d\n", -+ dev->name, adj_dev->name, ref_nr); -+ - adj = __netdev_find_adj(adj_dev, dev_list); - - if (!adj) { -@@ -5763,8 +5862,9 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev, - } - - if (adj->ref_nr > ref_nr) { -- pr_debug("%s to %s ref_nr-%d = %d\n", dev->name, adj_dev->name, -- ref_nr, adj->ref_nr-ref_nr); -+ pr_debug("adjacency: %s to %s ref_nr - %d = %d\n", -+ dev->name, adj_dev->name, ref_nr, -+ adj->ref_nr - ref_nr); - adj->ref_nr -= ref_nr; - return; - } -@@ -5776,7 +5876,7 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev, - netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); - - list_del_rcu(&adj->list); -- pr_debug("dev_put for %s, because link removed from %s to %s\n", -+ pr_debug("adjacency: dev_put for %s, because link removed from %s to %s\n", - adj_dev->name, dev->name, adj_dev->name); - dev_put(adj_dev); - kfree_rcu(adj, rcu); -@@ -5784,82 +5884,50 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev, - - static int __netdev_adjacent_dev_link_lists(struct net_device *dev, - struct net_device *upper_dev, -- u16 ref_nr, - struct list_head *up_list, - struct list_head *down_list, - void *private, bool master) - { - int ret; - -- ret = __netdev_adjacent_dev_insert(dev, upper_dev, ref_nr, up_list, -+ ret = __netdev_adjacent_dev_insert(dev, upper_dev, up_list, - private, master); - if (ret) - return ret; - -- ret = __netdev_adjacent_dev_insert(upper_dev, dev, ref_nr, down_list, -+ ret = __netdev_adjacent_dev_insert(upper_dev, dev, down_list, - private, false); - if (ret) { -- __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list); -+ __netdev_adjacent_dev_remove(dev, upper_dev, 1, up_list); - return ret; - } - - return 0; - } - --static int __netdev_adjacent_dev_link(struct net_device *dev, -- struct net_device *upper_dev, -- u16 ref_nr) --{ -- return __netdev_adjacent_dev_link_lists(dev, upper_dev, ref_nr, -- &dev->all_adj_list.upper, -- &upper_dev->all_adj_list.lower, -- NULL, false); --} -- - static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev, -- struct net_device *upper_dev, -- u16 ref_nr, -- struct list_head *up_list, -- struct list_head *down_list) --{ -- __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list); -- __netdev_adjacent_dev_remove(upper_dev, dev, ref_nr, down_list); --} -- --static void __netdev_adjacent_dev_unlink(struct net_device *dev, -- struct net_device *upper_dev, -- u16 ref_nr) -+ struct net_device *upper_dev, -+ u16 ref_nr, -+ struct list_head *up_list, -+ struct list_head *down_list) - { -- __netdev_adjacent_dev_unlink_lists(dev, upper_dev, ref_nr, -- &dev->all_adj_list.upper, -- &upper_dev->all_adj_list.lower); -+ __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list); -+ __netdev_adjacent_dev_remove(upper_dev, dev, ref_nr, down_list); - } - - static int __netdev_adjacent_dev_link_neighbour(struct net_device *dev, - struct net_device *upper_dev, - void *private, bool master) - { -- int ret = __netdev_adjacent_dev_link(dev, upper_dev, 1); -- -- if (ret) -- return ret; -- -- ret = __netdev_adjacent_dev_link_lists(dev, upper_dev, 1, -- &dev->adj_list.upper, -- &upper_dev->adj_list.lower, -- private, master); -- if (ret) { -- __netdev_adjacent_dev_unlink(dev, upper_dev, 1); -- return ret; -- } -- -- return 0; -+ return __netdev_adjacent_dev_link_lists(dev, upper_dev, -+ &dev->adj_list.upper, -+ &upper_dev->adj_list.lower, -+ private, master); - } - - static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev, - struct net_device *upper_dev) - { -- __netdev_adjacent_dev_unlink(dev, upper_dev, 1); - __netdev_adjacent_dev_unlink_lists(dev, upper_dev, 1, - &dev->adj_list.upper, - &upper_dev->adj_list.lower); -@@ -5870,7 +5938,6 @@ static int __netdev_upper_dev_link(struct net_device *dev, - void *upper_priv, void *upper_info) - { - struct netdev_notifier_changeupper_info changeupper_info; -- struct netdev_adjacent *i, *j, *to_i, *to_j; - int ret = 0; - - ASSERT_RTNL(); -@@ -5879,10 +5946,10 @@ static int __netdev_upper_dev_link(struct net_device *dev, - return -EBUSY; - - /* To prevent loops, check if dev is not upper device to upper_dev. */ -- if (__netdev_find_adj(dev, &upper_dev->all_adj_list.upper)) -+ if (netdev_has_upper_dev(upper_dev, dev)) - return -EBUSY; - -- if (__netdev_find_adj(upper_dev, &dev->adj_list.upper)) -+ if (netdev_has_upper_dev(dev, upper_dev)) - return -EEXIST; - - if (master && netdev_master_upper_dev_get(dev)) -@@ -5904,80 +5971,15 @@ static int __netdev_upper_dev_link(struct net_device *dev, - if (ret) - return ret; - -- /* Now that we linked these devs, make all the upper_dev's -- * all_adj_list.upper visible to every dev's all_adj_list.lower an -- * versa, and don't forget the devices itself. All of these -- * links are non-neighbours. -- */ -- list_for_each_entry(i, &dev->all_adj_list.lower, list) { -- list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) { -- pr_debug("Interlinking %s with %s, non-neighbour\n", -- i->dev->name, j->dev->name); -- ret = __netdev_adjacent_dev_link(i->dev, j->dev, i->ref_nr); -- if (ret) -- goto rollback_mesh; -- } -- } -- -- /* add dev to every upper_dev's upper device */ -- list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) { -- pr_debug("linking %s's upper device %s with %s\n", -- upper_dev->name, i->dev->name, dev->name); -- ret = __netdev_adjacent_dev_link(dev, i->dev, i->ref_nr); -- if (ret) -- goto rollback_upper_mesh; -- } -- -- /* add upper_dev to every dev's lower device */ -- list_for_each_entry(i, &dev->all_adj_list.lower, list) { -- pr_debug("linking %s's lower device %s with %s\n", dev->name, -- i->dev->name, upper_dev->name); -- ret = __netdev_adjacent_dev_link(i->dev, upper_dev, i->ref_nr); -- if (ret) -- goto rollback_lower_mesh; -- } -- - ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev, - &changeupper_info.info); - ret = notifier_to_errno(ret); - if (ret) -- goto rollback_lower_mesh; -+ goto rollback; - - return 0; - --rollback_lower_mesh: -- to_i = i; -- list_for_each_entry(i, &dev->all_adj_list.lower, list) { -- if (i == to_i) -- break; -- __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr); -- } -- -- i = NULL; -- --rollback_upper_mesh: -- to_i = i; -- list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) { -- if (i == to_i) -- break; -- __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr); -- } -- -- i = j = NULL; -- --rollback_mesh: -- to_i = i; -- to_j = j; -- list_for_each_entry(i, &dev->all_adj_list.lower, list) { -- list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) { -- if (i == to_i && j == to_j) -- break; -- __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr); -- } -- if (i == to_i) -- break; -- } -- -+rollback: - __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); - - return ret; -@@ -6034,7 +6036,6 @@ void netdev_upper_dev_unlink(struct net_device *dev, - struct net_device *upper_dev) - { - struct netdev_notifier_changeupper_info changeupper_info; -- struct netdev_adjacent *i, *j; - ASSERT_RTNL(); - - changeupper_info.upper_dev = upper_dev; -@@ -6046,23 +6047,6 @@ void netdev_upper_dev_unlink(struct net_device *dev, - - __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); - -- /* Here is the tricky part. We must remove all dev's lower -- * devices from all upper_dev's upper devices and vice -- * versa, to maintain the graph relationship. -- */ -- list_for_each_entry(i, &dev->all_adj_list.lower, list) -- list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) -- __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr); -- -- /* remove also the devices itself from lower/upper device -- * list -- */ -- list_for_each_entry(i, &dev->all_adj_list.lower, list) -- __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr); -- -- list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) -- __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr); -- - call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev, - &changeupper_info.info); - } -@@ -6879,6 +6863,7 @@ static void rollback_registered_many(struct list_head *head) - - /* Notifier chain MUST detach us all upper devices. */ - WARN_ON(netdev_has_any_upper_dev(dev)); -+ WARN_ON(netdev_has_any_lower_dev(dev)); - - /* Remove entries from kobject tree */ - netdev_unregister_kobject(dev); -@@ -7757,8 +7742,6 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, - INIT_LIST_HEAD(&dev->link_watch_list); - INIT_LIST_HEAD(&dev->adj_list.upper); - INIT_LIST_HEAD(&dev->adj_list.lower); -- INIT_LIST_HEAD(&dev->all_adj_list.upper); -- INIT_LIST_HEAD(&dev->all_adj_list.lower); - INIT_LIST_HEAD(&dev->ptype_all); - INIT_LIST_HEAD(&dev->ptype_specific); - #ifdef CONFIG_NET_SCHED --- -2.18.0 - diff --git a/patch/0000-net-ipv6-ll-anycast-mcast-routes-on-dev.patch b/patch/0000-net-ipv6-ll-anycast-mcast-routes-on-dev.patch deleted file mode 100644 index f4eeeb475df9..000000000000 --- a/patch/0000-net-ipv6-ll-anycast-mcast-routes-on-dev.patch +++ /dev/null @@ -1,190 +0,0 @@ -From 90df429b3fdfac074351327ca8681f940480229a Mon Sep 17 00:00:00 2001 -From: Preetham Singh -Date: Sun, 8 Sep 2019 09:47:17 +0000 -Subject: [PATCH] From 0b4074c953a707e8b3103fefeeaa5b439f869b3b Mon Sep 17 - 00:00:00 2001 Subject: [PATCH]net: IPv6 anycast, mcast routes with nhop - interface - -All auto generated IPv6 LL, anycast and multicast routes are installed -with nhop as l3mdev instead of interface. - -Signed-off-by: Preetham Singh ---- - net/ipv6/addrconf.c | 41 ----------------------------------------- - net/ipv6/icmp.c | 15 +++++++++++++-- - net/ipv6/route.c | 45 +++++++++++++++++++++++++++++++++++---------- - 3 files changed, 48 insertions(+), 53 deletions(-) - -diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c -index 4a5d3bbf..a8bd7807 100644 ---- a/net/ipv6/addrconf.c -+++ b/net/ipv6/addrconf.c -@@ -2969,9 +2969,6 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) - static void init_loopback(struct net_device *dev) - { - struct inet6_dev *idev; -- struct net_device *sp_dev; -- struct inet6_ifaddr *sp_ifa; -- struct rt6_info *sp_rt; - - /* ::1 */ - -@@ -2985,44 +2982,6 @@ static void init_loopback(struct net_device *dev) - - add_addr(idev, &in6addr_loopback, 128, IFA_HOST); - -- /* Add routes to other interface's IPv6 addresses */ -- for_each_netdev(dev_net(dev), sp_dev) { -- if (!strcmp(sp_dev->name, dev->name)) -- continue; -- -- idev = __in6_dev_get(sp_dev); -- if (!idev) -- continue; -- -- read_lock_bh(&idev->lock); -- list_for_each_entry(sp_ifa, &idev->addr_list, if_list) { -- -- if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE)) -- continue; -- -- if (sp_ifa->rt) { -- /* This dst has been added to garbage list when -- * lo device down, release this obsolete dst and -- * reallocate a new router for ifa. -- */ -- if (!atomic_read(&sp_ifa->rt->rt6i_ref)) { -- ip6_rt_put(sp_ifa->rt); -- sp_ifa->rt = NULL; -- } else { -- continue; -- } -- } -- -- sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, false); -- -- /* Failure cases are ignored */ -- if (!IS_ERR(sp_rt)) { -- sp_ifa->rt = sp_rt; -- ip6_ins_rt(sp_rt); -- } -- } -- read_unlock_bh(&idev->lock); -- } - } - - void addrconf_add_linklocal(struct inet6_dev *idev, -diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c -index 2772004b..f18128fb 100644 ---- a/net/ipv6/icmp.c -+++ b/net/ipv6/icmp.c -@@ -445,9 +445,20 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, - * Source addr check - */ - -- if (__ipv6_addr_needs_scope_id(addr_type)) -+ if (__ipv6_addr_needs_scope_id(addr_type)) { - iif = skb->dev->ifindex; -- else { -+ -+ /* for local packets, get the real device index */ -+ if (iif == LOOPBACK_IFINDEX) { -+ dst = skb_dst(skb); -+ if (dst) { -+ struct rt6_info *rt; -+ -+ rt = container_of(dst, struct rt6_info, dst); -+ iif = rt->rt6i_idev->dev->ifindex; -+ } -+ } -+ } else { - dst = skb_dst(skb); - iif = l3mdev_master_ifindex(dst ? dst->dev : skb->dev); - } -diff --git a/net/ipv6/route.c b/net/ipv6/route.c -index cbc066d2..7dcd34f5 100644 ---- a/net/ipv6/route.c -+++ b/net/ipv6/route.c -@@ -940,10 +940,35 @@ int ip6_ins_rt(struct rt6_info *rt) - return __ip6_ins_rt(rt, &info, &mxc); - } - -+/* called with rcu_lock held */ -+static struct net_device *ip6_rt_get_dev_rcu(struct rt6_info *rt) -+{ -+ struct net_device *dev = rt->dst.dev; -+ -+ if (rt->rt6i_flags & RTF_LOCAL) { -+ /* for copies of local routes, dst->dev needs to be the -+ * device if it is a master device, the master device if -+ * device is enslaved, and the loopback as the default -+ */ -+ if (netif_is_l3_slave(dev) && -+ !rt6_need_strict(&rt->rt6i_dst.addr)) -+ dev = l3mdev_master_dev_rcu(dev); -+ else if (!netif_is_l3_master(dev)) -+ dev = dev_net(dev)->loopback_dev; -+ /* last case is netif_is_l3_master(dev) is true in which -+ * case we want dev returned to be dev -+ */ -+ } -+ -+ return dev; -+} -+ -+ - static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort, - const struct in6_addr *daddr, - const struct in6_addr *saddr) - { -+ struct net_device *dev; - struct rt6_info *rt; - - /* -@@ -953,7 +978,10 @@ static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort, - if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)) - ort = (struct rt6_info *)ort->dst.from; - -- rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, 0); -+ rcu_read_lock(); -+ dev = ip6_rt_get_dev_rcu(ort); -+ rt = __ip6_dst_alloc(dev_net(dev), dev, 0); -+ rcu_read_unlock(); - - if (!rt) - return NULL; -@@ -983,9 +1011,12 @@ static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort, - static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt) - { - struct rt6_info *pcpu_rt; -+ struct net_device *dev; - -- pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev), -- rt->dst.dev, rt->dst.flags); -+ rcu_read_lock(); -+ dev = ip6_rt_get_dev_rcu(rt); -+ pcpu_rt = __ip6_dst_alloc(dev_net(dev), dev, rt->dst.flags); -+ rcu_read_unlock(); - - if (!pcpu_rt) - return NULL; -@@ -2623,15 +2654,9 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, - { - u32 tb_id; - struct net *net = dev_net(idev->dev); -- struct net_device *dev = net->loopback_dev; -+ struct net_device *dev = idev->dev; - struct rt6_info *rt; - -- /* use L3 Master device as loopback for host routes if device -- * is enslaved and address is not link local or multicast -- */ -- if (!rt6_need_strict(addr)) -- dev = l3mdev_master_dev_rcu(idev->dev) ? : dev; -- - rt = ip6_dst_alloc(net, dev, DST_NOCOUNT); - if (!rt) - return ERR_PTR(-ENOMEM); --- -2.18.0 - diff --git a/patch/0001-i2c-mlxcpld-add-master-driver-for-Mellanox-systems.patch b/patch/0001-i2c-mlxcpld-add-master-driver-for-Mellanox-systems.patch deleted file mode 100644 index 54431bcc5437..000000000000 --- a/patch/0001-i2c-mlxcpld-add-master-driver-for-Mellanox-systems.patch +++ /dev/null @@ -1,544 +0,0 @@ -Linux backport patch. Includes following commits: -899e11216e1c215b97f2f8f92c7b010a4e88f38e - - -diff -Nur a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig ---- a/drivers/i2c/busses/Kconfig 2017-11-12 08:08:32.136039784 +0000 -+++ b/drivers/i2c/busses/Kconfig 2017-11-12 08:08:40.776039899 +0000 -@@ -1150,6 +1150,17 @@ - This support is also available as a module. If so, the module - will be called i2c-elektor. - -+config I2C_MLXCPLD -+ tristate "Mellanox I2C driver" -+ depends on X86_64 -+ help -+ This exposes the Mellanox platform I2C busses to the linux I2C layer -+ for X86 based systems. -+ Controller is implemented as CPLD logic. -+ -+ This driver can also be built as a module. If so, the module will be -+ called as i2c-mlxcpld. -+ - config I2C_PCA_ISA - tristate "PCA9564/PCA9665 on an ISA bus" - depends on ISA -diff -Nur a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile ---- a/drivers/i2c/busses/Makefile 2017-11-12 08:08:32.140039784 +0000 -+++ b/drivers/i2c/busses/Makefile 2017-11-12 08:08:40.780039899 +0000 -@@ -116,6 +116,7 @@ - obj-$(CONFIG_I2C_BRCMSTB) += i2c-brcmstb.o - obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o - obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o -+obj-$(CONFIG_I2C_MLXCPLD) += i2c-mlxcpld.o - obj-$(CONFIG_I2C_OPAL) += i2c-opal.o - obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o - obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o -diff -Nur a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c ---- a/drivers/i2c/busses/i2c-mlxcpld.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/i2c/busses/i2c-mlxcpld.c 2017-11-12 08:08:40.780039899 +0000 -@@ -0,0 +1,504 @@ -+/* -+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2016 Michael Shych -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. 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. -+ * 3. Neither the names of the copyright holders nor the names of its -+ * contributors may be used to endorse or promote products derived from -+ * this software without specific prior written permission. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2 as published by the Free -+ * Software Foundation. -+ * -+ * 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 -+ -+/* General defines */ -+#define MLXPLAT_CPLD_LPC_I2C_BASE_ADDR 0x2000 -+#define MLXCPLD_I2C_DEVICE_NAME "i2c_mlxcpld" -+#define MLXCPLD_I2C_VALID_FLAG (I2C_M_RECV_LEN | I2C_M_RD) -+#define MLXCPLD_I2C_BUS_NUM 1 -+#define MLXCPLD_I2C_DATA_REG_SZ 36 -+#define MLXCPLD_I2C_MAX_ADDR_LEN 4 -+#define MLXCPLD_I2C_RETR_NUM 2 -+#define MLXCPLD_I2C_XFER_TO 500000 /* usec */ -+#define MLXCPLD_I2C_POLL_TIME 2000 /* usec */ -+ -+/* LPC I2C registers */ -+#define MLXCPLD_LPCI2C_LPF_REG 0x0 -+#define MLXCPLD_LPCI2C_CTRL_REG 0x1 -+#define MLXCPLD_LPCI2C_HALF_CYC_REG 0x4 -+#define MLXCPLD_LPCI2C_I2C_HOLD_REG 0x5 -+#define MLXCPLD_LPCI2C_CMD_REG 0x6 -+#define MLXCPLD_LPCI2C_NUM_DAT_REG 0x7 -+#define MLXCPLD_LPCI2C_NUM_ADDR_REG 0x8 -+#define MLXCPLD_LPCI2C_STATUS_REG 0x9 -+#define MLXCPLD_LPCI2C_DATA_REG 0xa -+ -+/* LPC I2C masks and parametres */ -+#define MLXCPLD_LPCI2C_RST_SEL_MASK 0x1 -+#define MLXCPLD_LPCI2C_TRANS_END 0x1 -+#define MLXCPLD_LPCI2C_STATUS_NACK 0x10 -+#define MLXCPLD_LPCI2C_NO_IND 0 -+#define MLXCPLD_LPCI2C_ACK_IND 1 -+#define MLXCPLD_LPCI2C_NACK_IND 2 -+ -+struct mlxcpld_i2c_curr_xfer { -+ u8 cmd; -+ u8 addr_width; -+ u8 data_len; -+ u8 msg_num; -+ struct i2c_msg *msg; -+}; -+ -+struct mlxcpld_i2c_priv { -+ struct i2c_adapter adap; -+ u32 base_addr; -+ struct mutex lock; -+ struct mlxcpld_i2c_curr_xfer xfer; -+ struct device *dev; -+}; -+ -+static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr) -+{ -+ int i; -+ -+ for (i = 0; i < len - len % 4; i += 4) -+ outl(*(u32 *)(data + i), addr + i); -+ for (; i < len; ++i) -+ outb(*(data + i), addr + i); -+} -+ -+static void mlxcpld_i2c_lpc_read_buf(u8 *data, u8 len, u32 addr) -+{ -+ int i; -+ -+ for (i = 0; i < len - len % 4; i += 4) -+ *(u32 *)(data + i) = inl(addr + i); -+ for (; i < len; ++i) -+ *(data + i) = inb(addr + i); -+} -+ -+static void mlxcpld_i2c_read_comm(struct mlxcpld_i2c_priv *priv, u8 offs, -+ u8 *data, u8 datalen) -+{ -+ u32 addr = priv->base_addr + offs; -+ -+ switch (datalen) { -+ case 1: -+ *(data) = inb(addr); -+ break; -+ case 2: -+ *((u16 *)data) = inw(addr); -+ break; -+ case 3: -+ *((u16 *)data) = inw(addr); -+ *(data + 2) = inb(addr + 2); -+ break; -+ case 4: -+ *((u32 *)data) = inl(addr); -+ break; -+ default: -+ mlxcpld_i2c_lpc_read_buf(data, datalen, addr); -+ break; -+ } -+} -+ -+static void mlxcpld_i2c_write_comm(struct mlxcpld_i2c_priv *priv, u8 offs, -+ u8 *data, u8 datalen) -+{ -+ u32 addr = priv->base_addr + offs; -+ -+ switch (datalen) { -+ case 1: -+ outb(*(data), addr); -+ break; -+ case 2: -+ outw(*((u16 *)data), addr); -+ break; -+ case 3: -+ outw(*((u16 *)data), addr); -+ outb(*(data + 2), addr + 2); -+ break; -+ case 4: -+ outl(*((u32 *)data), addr); -+ break; -+ default: -+ mlxcpld_i2c_lpc_write_buf(data, datalen, addr); -+ break; -+ } -+} -+ -+/* -+ * Check validity of received i2c messages parameters. -+ * Returns 0 if OK, other - in case of invalid parameters. -+ */ -+static int mlxcpld_i2c_check_msg_params(struct mlxcpld_i2c_priv *priv, -+ struct i2c_msg *msgs, int num) -+{ -+ int i; -+ -+ if (!num) { -+ dev_err(priv->dev, "Incorrect 0 num of messages\n"); -+ return -EINVAL; -+ } -+ -+ if (unlikely(msgs[0].addr > 0x7f)) { -+ dev_err(priv->dev, "Invalid address 0x%03x\n", -+ msgs[0].addr); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < num; ++i) { -+ if (unlikely(!msgs[i].buf)) { -+ dev_err(priv->dev, "Invalid buf in msg[%d]\n", -+ i); -+ return -EINVAL; -+ } -+ if (unlikely(msgs[0].addr != msgs[i].addr)) { -+ dev_err(priv->dev, "Invalid addr in msg[%d]\n", -+ i); -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+/* -+ * Check if transfer is completed and status of operation. -+ * Returns 0 - transfer completed (both ACK or NACK), -+ * negative - transfer isn't finished. -+ */ -+static int mlxcpld_i2c_check_status(struct mlxcpld_i2c_priv *priv, int *status) -+{ -+ u8 val; -+ -+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_STATUS_REG, &val, 1); -+ -+ if (val & MLXCPLD_LPCI2C_TRANS_END) { -+ if (val & MLXCPLD_LPCI2C_STATUS_NACK) -+ /* -+ * The slave is unable to accept the data. No such -+ * slave, command not understood, or unable to accept -+ * any more data. -+ */ -+ *status = MLXCPLD_LPCI2C_NACK_IND; -+ else -+ *status = MLXCPLD_LPCI2C_ACK_IND; -+ return 0; -+ } -+ *status = MLXCPLD_LPCI2C_NO_IND; -+ -+ return -EIO; -+} -+ -+static void mlxcpld_i2c_set_transf_data(struct mlxcpld_i2c_priv *priv, -+ struct i2c_msg *msgs, int num, -+ u8 comm_len) -+{ -+ priv->xfer.msg = msgs; -+ priv->xfer.msg_num = num; -+ -+ /* -+ * All upper layers currently are never use transfer with more than -+ * 2 messages. Actually, it's also not so relevant in Mellanox systems -+ * because of HW limitation. Max size of transfer is not more than 32 -+ * bytes in the current x86 LPCI2C bridge. -+ */ -+ priv->xfer.cmd = msgs[num - 1].flags & I2C_M_RD; -+ -+ if (priv->xfer.cmd == I2C_M_RD && comm_len != msgs[0].len) { -+ priv->xfer.addr_width = msgs[0].len; -+ priv->xfer.data_len = comm_len - priv->xfer.addr_width; -+ } else { -+ priv->xfer.addr_width = 0; -+ priv->xfer.data_len = comm_len; -+ } -+} -+ -+/* Reset CPLD LPCI2C block */ -+static void mlxcpld_i2c_reset(struct mlxcpld_i2c_priv *priv) -+{ -+ u8 val; -+ -+ mutex_lock(&priv->lock); -+ -+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CTRL_REG, &val, 1); -+ val &= ~MLXCPLD_LPCI2C_RST_SEL_MASK; -+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_CTRL_REG, &val, 1); -+ -+ mutex_unlock(&priv->lock); -+} -+ -+/* Make sure the CPLD is ready to start transmitting. */ -+static int mlxcpld_i2c_check_busy(struct mlxcpld_i2c_priv *priv) -+{ -+ u8 val; -+ -+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_STATUS_REG, &val, 1); -+ -+ if (val & MLXCPLD_LPCI2C_TRANS_END) -+ return 0; -+ -+ return -EIO; -+} -+ -+static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv) -+{ -+ int timeout = 0; -+ -+ do { -+ if (!mlxcpld_i2c_check_busy(priv)) -+ break; -+ usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME); -+ timeout += MLXCPLD_I2C_POLL_TIME; -+ } while (timeout <= MLXCPLD_I2C_XFER_TO); -+ -+ if (timeout > MLXCPLD_I2C_XFER_TO) -+ return -ETIMEDOUT; -+ -+ return 0; -+} -+ -+/* -+ * Wait for master transfer to complete. -+ * It puts current process to sleep until we get interrupt or timeout expires. -+ * Returns the number of transferred or read bytes or error (<0). -+ */ -+static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) -+{ -+ int status, i, timeout = 0; -+ u8 datalen; -+ -+ do { -+ usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME); -+ if (!mlxcpld_i2c_check_status(priv, &status)) -+ break; -+ timeout += MLXCPLD_I2C_POLL_TIME; -+ } while (status == 0 && timeout < MLXCPLD_I2C_XFER_TO); -+ -+ switch (status) { -+ case MLXCPLD_LPCI2C_NO_IND: -+ return -ETIMEDOUT; -+ -+ case MLXCPLD_LPCI2C_ACK_IND: -+ if (priv->xfer.cmd != I2C_M_RD) -+ return (priv->xfer.addr_width + priv->xfer.data_len); -+ -+ if (priv->xfer.msg_num == 1) -+ i = 0; -+ else -+ i = 1; -+ -+ if (!priv->xfer.msg[i].buf) -+ return -EINVAL; -+ -+ /* -+ * Actual read data len will be always the same as -+ * requested len. 0xff (line pull-up) will be returned -+ * if slave has no data to return. Thus don't read -+ * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. -+ */ -+ datalen = priv->xfer.data_len; -+ -+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG, -+ priv->xfer.msg[i].buf, datalen); -+ -+ return datalen; -+ -+ case MLXCPLD_LPCI2C_NACK_IND: -+ return -ENXIO; -+ -+ default: -+ return -EINVAL; -+ } -+} -+ -+static void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv) -+{ -+ int i, len = 0; -+ u8 cmd; -+ -+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG, -+ &priv->xfer.data_len, 1); -+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, -+ &priv->xfer.addr_width, 1); -+ -+ for (i = 0; i < priv->xfer.msg_num; i++) { -+ if ((priv->xfer.msg[i].flags & I2C_M_RD) != I2C_M_RD) { -+ /* Don't write to CPLD buffer in read transaction */ -+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_DATA_REG + -+ len, priv->xfer.msg[i].buf, -+ priv->xfer.msg[i].len); -+ len += priv->xfer.msg[i].len; -+ } -+ } -+ -+ /* -+ * Set target slave address with command for master transfer. -+ * It should be latest executed function before CPLD transaction. -+ */ -+ cmd = (priv->xfer.msg[0].addr << 1) | priv->xfer.cmd; -+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_CMD_REG, &cmd, 1); -+} -+ -+/* -+ * Generic lpc-i2c transfer. -+ * Returns the number of processed messages or error (<0). -+ */ -+static int mlxcpld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, -+ int num) -+{ -+ struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap); -+ u8 comm_len = 0; -+ int i, err; -+ -+ err = mlxcpld_i2c_check_msg_params(priv, msgs, num); -+ if (err) { -+ dev_err(priv->dev, "Incorrect message\n"); -+ return err; -+ } -+ -+ for (i = 0; i < num; ++i) -+ comm_len += msgs[i].len; -+ -+ /* Check bus state */ -+ if (mlxcpld_i2c_wait_for_free(priv)) { -+ dev_err(priv->dev, "LPCI2C bridge is busy\n"); -+ -+ /* -+ * Usually it means something serious has happened. -+ * We can not have unfinished previous transfer -+ * so it doesn't make any sense to try to stop it. -+ * Probably we were not able to recover from the -+ * previous error. -+ * The only reasonable thing - is soft reset. -+ */ -+ mlxcpld_i2c_reset(priv); -+ if (mlxcpld_i2c_check_busy(priv)) { -+ dev_err(priv->dev, "LPCI2C bridge is busy after reset\n"); -+ return -EIO; -+ } -+ } -+ -+ mlxcpld_i2c_set_transf_data(priv, msgs, num, comm_len); -+ -+ mutex_lock(&priv->lock); -+ -+ /* Do real transfer. Can't fail */ -+ mlxcpld_i2c_xfer_msg(priv); -+ -+ /* Wait for transaction complete */ -+ err = mlxcpld_i2c_wait_for_tc(priv); -+ -+ mutex_unlock(&priv->lock); -+ -+ return err < 0 ? err : num; -+} -+ -+static u32 mlxcpld_i2c_func(struct i2c_adapter *adap) -+{ -+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; -+} -+ -+static const struct i2c_algorithm mlxcpld_i2c_algo = { -+ .master_xfer = mlxcpld_i2c_xfer, -+ .functionality = mlxcpld_i2c_func -+}; -+ -+static struct i2c_adapter_quirks mlxcpld_i2c_quirks = { -+ .flags = I2C_AQ_COMB_WRITE_THEN_READ, -+ .max_read_len = MLXCPLD_I2C_DATA_REG_SZ - MLXCPLD_I2C_MAX_ADDR_LEN, -+ .max_write_len = MLXCPLD_I2C_DATA_REG_SZ, -+ .max_comb_1st_msg_len = 4, -+}; -+ -+static struct i2c_adapter mlxcpld_i2c_adapter = { -+ .owner = THIS_MODULE, -+ .name = "i2c-mlxcpld", -+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, -+ .algo = &mlxcpld_i2c_algo, -+ .quirks = &mlxcpld_i2c_quirks, -+ .retries = MLXCPLD_I2C_RETR_NUM, -+ .nr = MLXCPLD_I2C_BUS_NUM, -+}; -+ -+static int mlxcpld_i2c_probe(struct platform_device *pdev) -+{ -+ struct mlxcpld_i2c_priv *priv; -+ int err; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ mutex_init(&priv->lock); -+ platform_set_drvdata(pdev, priv); -+ -+ priv->dev = &pdev->dev; -+ -+ /* Register with i2c layer */ -+ mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO); -+ priv->adap = mlxcpld_i2c_adapter; -+ priv->adap.dev.parent = &pdev->dev; -+ priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; -+ i2c_set_adapdata(&priv->adap, priv); -+ -+ err = i2c_add_numbered_adapter(&priv->adap); -+ if (err) -+ mutex_destroy(&priv->lock); -+ -+ return err; -+} -+ -+static int mlxcpld_i2c_remove(struct platform_device *pdev) -+{ -+ struct mlxcpld_i2c_priv *priv = platform_get_drvdata(pdev); -+ -+ i2c_del_adapter(&priv->adap); -+ mutex_destroy(&priv->lock); -+ -+ return 0; -+} -+ -+static struct platform_driver mlxcpld_i2c_driver = { -+ .probe = mlxcpld_i2c_probe, -+ .remove = mlxcpld_i2c_remove, -+ .driver = { -+ .name = MLXCPLD_I2C_DEVICE_NAME, -+ }, -+}; -+ -+module_platform_driver(mlxcpld_i2c_driver); -+ -+MODULE_AUTHOR("Michael Shych "); -+MODULE_DESCRIPTION("Mellanox I2C-CPLD controller driver"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_ALIAS("platform:i2c-mlxcpld"); diff --git a/patch/0001-net-ipv6-Allow-shorthand-delete-of-all-nexthops-in-m.patch b/patch/0001-net-ipv6-Allow-shorthand-delete-of-all-nexthops-in-m.patch deleted file mode 100644 index 084464636813..000000000000 --- a/patch/0001-net-ipv6-Allow-shorthand-delete-of-all-nexthops-in-m.patch +++ /dev/null @@ -1,140 +0,0 @@ -From 055d25a3f712c2fcb16a171786e487739953d471 Mon Sep 17 00:00:00 2001 -From: Preetham Singh -Date: Wed, 18 Sep 2019 02:54:13 -0700 -Subject: [PATCH] net: ipv6: Allow shorthand delete of all - nexthops in multipath route - -This was already supported by IPv4 but missing for IPv6. This commit -brings shorthand delete of IPv6 multipath routes in kernel. - -Successive delete of multi-path routes(32 paths) was not clearing all routes in kernel though frr was sending RTM_DELROUTE when last nexthop was getting deleted. Reason being For IPv6 delete route in kernel, expects all nhops to be sent. On counter part, IPv4 route delete in kernel does NOT expect all nhops to be sent. FRR currently doesnt send any nhops when operation is RTM_DELROUTE for both IPv4 & IPv6. - -back porting below changes from newer version of kernel -https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/net/ipv6/route.c?h=v4.14.144&id=0ae8133586ad1c9be894411aaf8b17bb58c8efe5 - -After importing above patch, there were no stale IPv6 routes in kernel. - -Signed-off-by: Preetham Singh ---- - include/net/ip6_fib.h | 4 ++- - net/ipv6/route.c | 67 +++++++++++++++++++++++++++++++++++++++++-- - 2 files changed, 68 insertions(+), 3 deletions(-) - -diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h -index a6bcb18..82ef4ba 100644 ---- a/include/net/ip6_fib.h -+++ b/include/net/ip6_fib.h -@@ -37,7 +37,9 @@ struct fib6_config { - int fc_ifindex; - u32 fc_flags; - u32 fc_protocol; -- u32 fc_type; /* only 8 bits are used */ -+ u16 fc_type; /* only 8 bits are used */ -+ u16 fc_delete_all_nh : 1, -+ __unused : 15; - - struct in6_addr fc_dst; - struct in6_addr fc_src; -diff --git a/net/ipv6/route.c b/net/ipv6/route.c -index 7dcd34f..9743662 100644 ---- a/net/ipv6/route.c -+++ b/net/ipv6/route.c -@@ -98,6 +98,12 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb); - static void rt6_dst_from_metrics_check(struct rt6_info *rt); - static int rt6_score_route(struct rt6_info *rt, int oif, int strict); -+static size_t rt6_nlmsg_size(struct rt6_info *rt); -+static int rt6_fill_node(struct net *net, -+ struct sk_buff *skb, struct rt6_info *rt, -+ struct in6_addr *dst, struct in6_addr *src, -+ int iif, int type, u32 portid, u32 seq, -+ int prefix, int nowait, unsigned int flags); - - #ifdef CONFIG_IPV6_ROUTE_INFO - static struct rt6_info *rt6_add_route_info(struct net *net, -@@ -2183,6 +2189,57 @@ int ip6_del_rt(struct rt6_info *rt) - return __ip6_del_rt(rt, &info); - } - -+static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg) -+{ -+ struct nl_info *info = &cfg->fc_nlinfo; -+ struct net *net = info->nl_net; -+ struct sk_buff *skb = NULL; -+ struct fib6_table *table; -+ int err = -ENOENT; -+ -+ if (rt == net->ipv6.ip6_null_entry) -+ goto out_put; -+ table = rt->rt6i_table; -+ write_lock_bh(&table->tb6_lock); -+ -+ if (rt->rt6i_nsiblings && cfg->fc_delete_all_nh) { -+ struct rt6_info *sibling, *next_sibling; -+ -+ /* prefer to send a single notification with all hops */ -+ skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any()); -+ if (skb) { -+ u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; -+ -+ if (rt6_fill_node(net, skb, rt, -+ NULL, NULL, 0, RTM_DELROUTE, -+ info->portid, seq, 0, 0, 0) < 0) { -+ kfree_skb(skb); -+ skb = NULL; -+ } -+ } -+ -+ list_for_each_entry_safe(sibling, next_sibling, -+ &rt->rt6i_siblings, -+ rt6i_siblings) { -+ err = fib6_del(sibling, info); -+ if (err) -+ goto out_unlock; -+ } -+ } -+ -+ err = fib6_del(rt, info); -+out_unlock: -+ write_unlock_bh(&table->tb6_lock); -+out_put: -+ ip6_rt_put(rt); -+ -+ if (skb) { -+ rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE, -+ info->nlh, gfp_any()); -+ } -+ return err; -+} -+ - static int ip6_route_del(struct fib6_config *cfg) - { - struct fib6_table *table; -@@ -2219,7 +2276,11 @@ static int ip6_route_del(struct fib6_config *cfg) - dst_hold(&rt->dst); - read_unlock_bh(&table->tb6_lock); - -- return __ip6_del_rt(rt, &cfg->fc_nlinfo); -+ /* if gateway was specified only delete the one hop */ -+ if (cfg->fc_flags & RTF_GATEWAY) -+ return __ip6_del_rt(rt, &cfg->fc_nlinfo); -+ -+ return __ip6_del_rt_siblings(rt, cfg); - } - } - read_unlock_bh(&table->tb6_lock); -@@ -3167,8 +3228,10 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh) - - if (cfg.fc_mp) - return ip6_route_multipath_del(&cfg); -- else -+ else { -+ cfg.fc_delete_all_nh = 1; - return ip6_route_del(&cfg); -+ } - } - - static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) --- -2.18.0 - diff --git a/patch/0001-v4.19-6-Mellanox-platform-Backport-patches-for-new-M.patch b/patch/0001-v4.19-6-Mellanox-platform-Backport-patches-for-new-M.patch new file mode 100644 index 000000000000..829e894c7c0a --- /dev/null +++ b/patch/0001-v4.19-6-Mellanox-platform-Backport-patches-for-new-M.patch @@ -0,0 +1,7736 @@ +From 94c3405f5b95f3f699ad8167630b4fbf9a788dce Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 4 Feb 2020 23:30:59 +0200 +Subject: [PATCH 1/2] v4.19-6: Mellanox platform: Backport patches for new + Mellanox systems + +It contains backport patches from v4.20 - v5.5 and below bug fixes and +optimizations. + +Fix wrong order in probe error flow, in case the firmware version is +incompatible with the driver. +Validation of firmware version should be provided at early stage, prior +of initialization of different driver components. + +Decrease i2c controller polling time from 2000usec to 200usec +for the performance improvement. + +Skip thermal zones setting for modules to reduce probing time. +It is to be read anyway during thermal zone operations. +Skip thermal zone setting and reading during initialization. + +Drop creation of "hwmon" interfaces from "thermal". These interfaces +are redundant, since they are created by "core_hwmon" component. +Creation of those interface from "thermal" just causes each temperature +input entry to by created twice in "hwmon" +Add thermal zone platform parameters definition with the field +"no_hwmon" set to true. Use it in thermal_zone_device_register(). +It will indicate that the "thermal" to "hwmon" sysfs interface is not + +Signed-off-by: Vadim Pasternak +Signed-off-by: Stephen Sun + +v4.19-6: Mellanox platform: Additional backport for new Mellanox systems + +It contains backport patches from v5.* kernels: +- Adding module for ethtool support. +- Changing Mellanox i2c bus poling time frequency. +- Watchdog Mellanox driver. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Stephen Sun +--- + drivers/hwmon/mlxreg-fan.c | 90 +- + drivers/hwmon/pmbus/tps53679.c | 10 +- + drivers/i2c/busses/i2c-mlxcpld.c | 2 +- + drivers/leds/leds-mlxreg.c | 23 +- + drivers/net/ethernet/mellanox/mlxsw/Kconfig | 9 + + drivers/net/ethernet/mellanox/mlxsw/Makefile | 3 +- + drivers/net/ethernet/mellanox/mlxsw/core.c | 82 +- + drivers/net/ethernet/mellanox/mlxsw/core.h | 36 + + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 256 ++++ + drivers/net/ethernet/mellanox/mlxsw/core_env.h | 17 + + drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 361 +++++- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 696 +++++++++- + drivers/net/ethernet/mellanox/mlxsw/i2c.c | 212 +++- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 328 ++++- + drivers/net/ethernet/mellanox/mlxsw/pci.c | 49 +- + drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c | 454 +++++++ + drivers/net/ethernet/mellanox/mlxsw/reg.h | 1243 +++++++++++++++++- + drivers/net/ethernet/mellanox/mlxsw/resources.h | 6 + + drivers/platform/mellanox/mlxreg-hotplug.c | 42 +- + drivers/platform/x86/mlx-platform.c | 1332 +++++++++++++++++--- + drivers/watchdog/Kconfig | 16 + + drivers/watchdog/Makefile | 1 + + drivers/watchdog/mlx_wdt.c | 289 +++++ + include/linux/platform_data/mlxreg.h | 27 +- + include/uapi/linux/ethtool.h | 3 + + 25 files changed, 5247 insertions(+), 340 deletions(-) + create mode 100644 drivers/net/ethernet/mellanox/mlxsw/core_env.c + create mode 100644 drivers/net/ethernet/mellanox/mlxsw/core_env.h + create mode 100644 drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c + create mode 100644 drivers/watchdog/mlx_wdt.c + +diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c +index d8fa4be..7028a4f 100644 +--- a/drivers/hwmon/mlxreg-fan.c ++++ b/drivers/hwmon/mlxreg-fan.c +@@ -27,7 +27,9 @@ + #define MLXREG_FAN_SPEED_MAX (MLXREG_FAN_MAX_STATE * 2) + #define MLXREG_FAN_SPEED_MIN_LEVEL 2 /* 20 percent */ + #define MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF 44 +-#define MLXREG_FAN_TACHO_DIVIDER_DEF 1132 ++#define MLXREG_FAN_TACHO_DIV_MIN 283 ++#define MLXREG_FAN_TACHO_DIV_DEF (MLXREG_FAN_TACHO_DIV_MIN * 4) ++#define MLXREG_FAN_TACHO_DIV_SCALE_MAX 64 + /* + * FAN datasheet defines the formula for RPM calculations as RPM = 15/t-high. + * The logic in a programmable device measures the time t-high by sampling the +@@ -51,7 +53,7 @@ + */ + #define MLXREG_FAN_GET_RPM(rval, d, s) (DIV_ROUND_CLOSEST(15000000 * 100, \ + ((rval) + (s)) * (d))) +-#define MLXREG_FAN_GET_FAULT(val, mask) (!((val) ^ (mask))) ++#define MLXREG_FAN_GET_FAULT(val, mask) ((val) == (mask)) + #define MLXREG_FAN_PWM_DUTY2STATE(duty) (DIV_ROUND_CLOSEST((duty) * \ + MLXREG_FAN_MAX_STATE, \ + MLXREG_FAN_MAX_DUTY)) +@@ -360,15 +362,57 @@ static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev, + .set_cur_state = mlxreg_fan_set_cur_state, + }; + ++static int mlxreg_fan_connect_verify(struct mlxreg_fan *fan, ++ struct mlxreg_core_data *data) ++{ ++ u32 regval; ++ int err; ++ ++ err = regmap_read(fan->regmap, data->capability, ®val); ++ if (err) { ++ dev_err(fan->dev, "Failed to query capability register 0x%08x\n", ++ data->capability); ++ return err; ++ } ++ ++ return !!(regval & data->bit); ++} ++ ++static int mlxreg_fan_speed_divider_get(struct mlxreg_fan *fan, ++ struct mlxreg_core_data *data) ++{ ++ u32 regval; ++ int err; ++ ++ err = regmap_read(fan->regmap, data->capability, ®val); ++ if (err) { ++ dev_err(fan->dev, "Failed to query capability register 0x%08x\n", ++ data->capability); ++ return err; ++ } ++ ++ /* ++ * Set divider value according to the capability register, in case it ++ * contains valid value. Otherwise use default value. The purpose of ++ * this validation is to protect against the old hardware, in which ++ * this register can return zero. ++ */ ++ if (regval > 0 && regval <= MLXREG_FAN_TACHO_DIV_SCALE_MAX) ++ fan->divider = regval * MLXREG_FAN_TACHO_DIV_MIN; ++ ++ return 0; ++} ++ + static int mlxreg_fan_config(struct mlxreg_fan *fan, + struct mlxreg_core_platform_data *pdata) + { + struct mlxreg_core_data *data = pdata->data; + bool configured = false; + int tacho_num = 0, i; ++ int err; + + fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF; +- fan->divider = MLXREG_FAN_TACHO_DIVIDER_DEF; ++ fan->divider = MLXREG_FAN_TACHO_DIV_DEF; + for (i = 0; i < pdata->counter; i++, data++) { + if (strnstr(data->label, "tacho", sizeof(data->label))) { + if (tacho_num == MLXREG_FAN_MAX_TACHO) { +@@ -376,6 +420,17 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, + data->label); + return -EINVAL; + } ++ ++ if (data->capability) { ++ err = mlxreg_fan_connect_verify(fan, data); ++ if (err < 0) ++ return err; ++ else if (!err) { ++ tacho_num++; ++ continue; ++ } ++ } ++ + fan->tacho[tacho_num].reg = data->reg; + fan->tacho[tacho_num].mask = data->mask; + fan->tacho[tacho_num++].connected = true; +@@ -394,13 +449,21 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, + return -EINVAL; + } + /* Validate that conf parameters are not zeros. */ +- if (!data->mask || !data->bit) { ++ if (!data->mask && !data->bit && !data->capability) { + dev_err(fan->dev, "invalid conf entry params: %s\n", + data->label); + return -EINVAL; + } +- fan->samples = data->mask; +- fan->divider = data->bit; ++ if (data->capability) { ++ err = mlxreg_fan_speed_divider_get(fan, data); ++ if (err) ++ return err; ++ } else { ++ if (data->mask) ++ fan->samples = data->mask; ++ if (data->bit) ++ fan->divider = data->bit; ++ } + configured = true; + } else { + dev_err(fan->dev, "invalid label: %s\n", data->label); +@@ -420,21 +483,22 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, + static int mlxreg_fan_probe(struct platform_device *pdev) + { + struct mlxreg_core_platform_data *pdata; ++ struct device *dev = &pdev->dev; + struct mlxreg_fan *fan; + struct device *hwm; + int err; + +- pdata = dev_get_platdata(&pdev->dev); ++ pdata = dev_get_platdata(dev); + if (!pdata) { +- dev_err(&pdev->dev, "Failed to get platform data.\n"); ++ dev_err(dev, "Failed to get platform data.\n"); + return -EINVAL; + } + +- fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL); ++ fan = devm_kzalloc(dev, sizeof(*fan), GFP_KERNEL); + if (!fan) + return -ENOMEM; + +- fan->dev = &pdev->dev; ++ fan->dev = dev; + fan->regmap = pdata->regmap; + platform_set_drvdata(pdev, fan); + +@@ -442,12 +506,12 @@ static int mlxreg_fan_probe(struct platform_device *pdev) + if (err) + return err; + +- hwm = devm_hwmon_device_register_with_info(&pdev->dev, "mlxreg_fan", ++ hwm = devm_hwmon_device_register_with_info(dev, "mlxreg_fan", + fan, + &mlxreg_fan_hwmon_chip_info, + NULL); + if (IS_ERR(hwm)) { +- dev_err(&pdev->dev, "Failed to register hwmon device\n"); ++ dev_err(dev, "Failed to register hwmon device\n"); + return PTR_ERR(hwm); + } + +@@ -455,7 +519,7 @@ static int mlxreg_fan_probe(struct platform_device *pdev) + fan->cdev = thermal_cooling_device_register("mlxreg_fan", fan, + &mlxreg_fan_cooling_ops); + if (IS_ERR(fan->cdev)) { +- dev_err(&pdev->dev, "Failed to register cooling device\n"); ++ dev_err(dev, "Failed to register cooling device\n"); + return PTR_ERR(fan->cdev); + } + } +diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c +index 85b515c..45eacc5 100644 +--- a/drivers/hwmon/pmbus/tps53679.c ++++ b/drivers/hwmon/pmbus/tps53679.c +@@ -80,7 +80,15 @@ static int tps53679_identify(struct i2c_client *client, + static int tps53679_probe(struct i2c_client *client, + const struct i2c_device_id *id) + { +- return pmbus_do_probe(client, id, &tps53679_info); ++ struct pmbus_driver_info *info; ++ ++ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ memcpy(info, &tps53679_info, sizeof(*info)); ++ ++ return pmbus_do_probe(client, id, info); + } + + static const struct i2c_device_id tps53679_id[] = { +diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c +index 2fd717d..6da4b58 100644 +--- a/drivers/i2c/busses/i2c-mlxcpld.c ++++ b/drivers/i2c/busses/i2c-mlxcpld.c +@@ -51,7 +51,7 @@ + #define MLXCPLD_I2C_MAX_ADDR_LEN 4 + #define MLXCPLD_I2C_RETR_NUM 2 + #define MLXCPLD_I2C_XFER_TO 500000 /* usec */ +-#define MLXCPLD_I2C_POLL_TIME 2000 /* usec */ ++#define MLXCPLD_I2C_POLL_TIME 400 /* usec */ + + /* LPC I2C registers */ + #define MLXCPLD_LPCI2C_CPBLTY_REG 0x0 +diff --git a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c +index 1ee48cb..0c14a74 100644 +--- a/drivers/leds/leds-mlxreg.c ++++ b/drivers/leds/leds-mlxreg.c +@@ -22,6 +22,7 @@ + #define MLXREG_LED_AMBER_SOLID 0x09 /* Solid amber */ + #define MLXREG_LED_BLINK_3HZ 167 /* ~167 msec off/on - HW support */ + #define MLXREG_LED_BLINK_6HZ 83 /* ~83 msec off/on - HW support */ ++#define MLXREG_LED_CAPABILITY_CLEAR GENMASK(31, 8) /* Clear mask */ + + /** + * struct mlxreg_led_data - led control data: +@@ -186,7 +187,8 @@ static int mlxreg_led_config(struct mlxreg_led_priv_data *priv) + struct mlxreg_core_data *data = led_pdata->data; + struct mlxreg_led_data *led_data; + struct led_classdev *led_cdev; +- enum led_brightness brightness; ++ int brightness; ++ u32 regval; + int i; + int err; + +@@ -196,6 +198,23 @@ static int mlxreg_led_config(struct mlxreg_led_priv_data *priv) + if (!led_data) + return -ENOMEM; + ++ if (data->capability) { ++ err = regmap_read(led_pdata->regmap, data->capability, ++ ®val); ++ if (err) { ++ dev_err(&priv->pdev->dev, "Failed to query capability register\n"); ++ return err; ++ } ++ if (!(regval & data->bit)) ++ continue; ++ /* ++ * Field "bit" can contain one capability bit in 0 byte ++ * and offset bit in 1-3 bytes. Clear capability bit and ++ * keep only offset bit. ++ */ ++ data->bit &= MLXREG_LED_CAPABILITY_CLEAR; ++ } ++ + led_cdev = &led_data->led_cdev; + led_data->data_parent = priv; + if (strstr(data->label, "red") || +@@ -213,7 +232,7 @@ static int mlxreg_led_config(struct mlxreg_led_priv_data *priv) + data->label); + led_cdev->name = led_data->led_cdev_name; + led_cdev->brightness = brightness; +- led_cdev->max_brightness = LED_ON; ++ led_cdev->max_brightness = 1; + led_cdev->brightness_set_blocking = + mlxreg_led_brightness_set; + led_cdev->brightness_get = mlxreg_led_brightness_get; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig +index 8a291eb..51e485b 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig ++++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig +@@ -28,6 +28,15 @@ config MLXSW_CORE_THERMAL + Say Y here if you want to automatically control fans speed according + ambient temperature reported by ASIC. + ++config MLXSW_CORE_QSFP ++ bool "QSFP support for Mellanox Technologies Switch ASICs" ++ depends on MLXSW_CORE && HWMON ++ depends on !(MLXSW_CORE=y && HWMON=m) ++ default y ++ ---help--- ++ Say Y here if you want to expose sysfs QSFP interface on mlxsw ++ devices. ++ + config MLXSW_PCI + tristate "PCI bus implementation for Mellanox Technologies Switch ASICs" + depends on PCI && HAS_IOMEM && MLXSW_CORE +diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile +index 68fa44a..da75f61 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/Makefile ++++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile +@@ -1,9 +1,10 @@ + # 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_acl_flex_actions.o core_env.o + mlxsw_core-$(CONFIG_MLXSW_CORE_HWMON) += core_hwmon.o + mlxsw_core-$(CONFIG_MLXSW_CORE_THERMAL) += core_thermal.o ++mlxsw_core-$(CONFIG_MLXSW_CORE_QSFP) += qsfp_sysfs.o + obj-$(CONFIG_MLXSW_PCI) += mlxsw_pci.o + mlxsw_pci-objs := pci.o + obj-$(CONFIG_MLXSW_I2C) += mlxsw_i2c.o +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 2e6df58..c38c1c5 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -78,6 +78,7 @@ struct mlxsw_core { + struct mlxsw_res res; + struct mlxsw_hwmon *hwmon; + struct mlxsw_thermal *thermal; ++ struct mlxsw_qsfp *qsfp; + struct mlxsw_core_port *ports; + unsigned int max_ports; + bool reload_fail; +@@ -122,6 +123,12 @@ void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core) + } + EXPORT_SYMBOL(mlxsw_core_driver_priv); + ++bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core) ++{ ++ return mlxsw_core->driver->res_query_enabled; ++} ++EXPORT_SYMBOL(mlxsw_core_res_query_enabled); ++ + struct mlxsw_rx_listener_item { + struct list_head list; + struct mlxsw_rx_listener rxl; +@@ -971,9 +978,9 @@ static int mlxsw_devlink_core_bus_device_reload(struct devlink *devlink, + }; + + 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, +- struct devlink *devlink) ++ const struct mlxsw_bus *mlxsw_bus, ++ void *bus_priv, bool reload, ++ struct devlink *devlink) + { + const char *device_kind = mlxsw_bus_info->device_kind; + struct mlxsw_core *mlxsw_core; +@@ -1040,6 +1047,18 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + goto err_devlink_register; + } + ++ if (mlxsw_driver->init) { ++ err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info); ++ if (err) ++ goto err_driver_init; ++ } ++ ++ if (mlxsw_driver->params_register && !reload) { ++ err = mlxsw_driver->params_register(mlxsw_core); ++ if (err) ++ goto err_register_params; ++ } ++ + err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon); + if (err) + goto err_hwmon_init; +@@ -1049,19 +1068,22 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + if (err) + goto err_thermal_init; + +- if (mlxsw_driver->init) { +- err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info); +- if (err) +- goto err_driver_init; +- } ++ err = mlxsw_qsfp_init(mlxsw_core, mlxsw_bus_info, ++ &mlxsw_core->qsfp); ++ if (err) ++ goto err_qsfp_init; + + return 0; + +-err_driver_init: ++err_qsfp_init: + mlxsw_thermal_fini(mlxsw_core->thermal); + err_thermal_init: + mlxsw_hwmon_fini(mlxsw_core->hwmon); + err_hwmon_init: ++ if (mlxsw_driver->params_unregister && !reload) ++ mlxsw_driver->params_unregister(mlxsw_core); ++err_register_params: ++err_driver_init: + if (!reload) + devlink_unregister(devlink); + err_devlink_register: +@@ -1100,8 +1122,11 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, + + if (mlxsw_core->driver->fini) + mlxsw_core->driver->fini(mlxsw_core); ++ mlxsw_qsfp_fini(mlxsw_core->qsfp); + mlxsw_thermal_fini(mlxsw_core->thermal); + mlxsw_hwmon_fini(mlxsw_core->hwmon); ++ if (mlxsw_core->driver->params_unregister && !reload) ++ mlxsw_core->driver->params_unregister(mlxsw_core); + if (!reload) + devlink_unregister(devlink); + mlxsw_emad_fini(mlxsw_core); +@@ -1114,6 +1139,8 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, + return; + + reload_fail_deinit: ++ if (mlxsw_core->driver->params_unregister) ++ mlxsw_core->driver->params_unregister(mlxsw_core); + devlink_unregister(devlink); + devlink_resources_unregister(devlink, NULL); + devlink_free(devlink); +@@ -1871,6 +1898,43 @@ void mlxsw_core_fw_flash_end(struct mlxsw_core *mlxsw_core) + } + EXPORT_SYMBOL(mlxsw_core_fw_flash_end); + ++int mlxsw_core_resources_query(struct mlxsw_core *mlxsw_core, char *mbox, ++ struct mlxsw_res *res) ++{ ++ int index, i; ++ u64 data; ++ u16 id; ++ int err; ++ ++ if (!res) ++ return 0; ++ ++ mlxsw_cmd_mbox_zero(mbox); ++ ++ for (index = 0; index < MLXSW_CMD_QUERY_RESOURCES_MAX_QUERIES; ++ index++) { ++ err = mlxsw_cmd_query_resources(mlxsw_core, mbox, index); ++ if (err) ++ return err; ++ ++ for (i = 0; i < MLXSW_CMD_QUERY_RESOURCES_PER_QUERY; i++) { ++ id = mlxsw_cmd_mbox_query_resource_id_get(mbox, i); ++ data = mlxsw_cmd_mbox_query_resource_data_get(mbox, i); ++ ++ if (id == MLXSW_CMD_QUERY_RESOURCES_TABLE_END_ID) ++ return 0; ++ ++ mlxsw_res_parse(res, id, data); ++ } ++ } ++ ++ /* If after MLXSW_RESOURCES_QUERY_MAX_QUERIES we still didn't get ++ * MLXSW_RESOURCES_TABLE_END_ID, something went bad in the FW. ++ */ ++ return -EIO; ++} ++EXPORT_SYMBOL(mlxsw_core_resources_query); ++ + static int __init mlxsw_core_module_init(void) + { + int err; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index c4e4971..3fb3a75 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -28,6 +28,8 @@ + + void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core); + ++bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core); ++ + int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver); + void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver); + +@@ -182,6 +184,8 @@ int mlxsw_core_port_get_phys_port_name(struct mlxsw_core *mlxsw_core, + int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay); + bool mlxsw_core_schedule_work(struct work_struct *work); + void mlxsw_core_flush_owq(void); ++int mlxsw_core_resources_query(struct mlxsw_core *mlxsw_core, char *mbox, ++ struct mlxsw_res *res); + + #define MLXSW_CONFIG_PROFILE_SWID_COUNT 8 + +@@ -282,6 +286,8 @@ struct mlxsw_driver { + const struct mlxsw_config_profile *profile, + u64 *p_single_size, u64 *p_double_size, + u64 *p_linear_size); ++ int (*params_register)(struct mlxsw_core *mlxsw_core); ++ void (*params_unregister)(struct mlxsw_core *mlxsw_core); + u8 txhdr_len; + const struct mlxsw_config_profile *profile; + bool res_query_enabled; +@@ -342,6 +348,7 @@ struct mlxsw_bus_info { + struct mlxsw_fw_rev fw_rev; + u8 vsd[MLXSW_CMD_BOARDINFO_VSD_LEN]; + u8 psid[MLXSW_CMD_BOARDINFO_PSID_LEN]; ++ u8 low_frequency; + }; + + struct mlxsw_hwmon; +@@ -392,4 +399,33 @@ static inline void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) + + #endif + ++enum mlxsw_devlink_param_id { ++ MLXSW_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, ++ MLXSW_DEVLINK_PARAM_ID_ACL_REGION_REHASH_INTERVAL, ++}; ++ ++struct mlxsw_qsfp; ++ ++#ifdef CONFIG_MLXSW_CORE_QSFP ++ ++int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, ++ const struct mlxsw_bus_info *mlxsw_bus_info, ++ struct mlxsw_qsfp **p_qsfp); ++void mlxsw_qsfp_fini(struct mlxsw_qsfp *qsfp); ++ ++#else ++ ++static inline int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, ++ const struct mlxsw_bus_info *mlxsw_bus_info, ++ struct mlxsw_qsfp **p_qsfp) ++{ ++ return 0; ++} ++ ++static inline void mlxsw_qsfp_fini(struct mlxsw_qsfp *qsfp) ++{ ++} ++ ++#endif ++ + #endif +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +new file mode 100644 +index 0000000..03eae1e +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -0,0 +1,256 @@ ++// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 ++/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ ++ ++#include ++#include ++#include ++ ++#include "core.h" ++#include "core_env.h" ++#include "item.h" ++#include "reg.h" ++ ++static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id, ++ bool *qsfp) ++{ ++ char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE]; ++ char mcia_pl[MLXSW_REG_MCIA_LEN]; ++ 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); ++ err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); ++ if (err) ++ return err; ++ mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp); ++ ident = eeprom_tmp[0]; ++ switch (ident) { ++ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: ++ *qsfp = false; ++ break; ++ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: /* fall-through */ ++ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */ ++ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: /* fall-through */ ++ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD: /* fall-through */ ++ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP_DD: /* fall-through */ ++ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS_CMIS: ++ *qsfp = true; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, ++ u16 offset, u16 size, bool qsfp, void *data, ++ unsigned int *p_read_size) ++{ ++ char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE]; ++ char mcia_pl[MLXSW_REG_MCIA_LEN]; ++ u16 i2c_addr; ++ u8 page = 0; ++ int status; ++ int err; ++ ++ size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE); ++ ++ if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH && ++ offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) ++ /* Cross pages read, read until offset 256 in low page */ ++ size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset; ++ ++ i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW; ++ if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) { ++ if (qsfp) { ++ page = MLXSW_REG_MCIA_PAGE_GET(offset); ++ offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page; ++ if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) ++ size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - ++ offset; ++ } else { ++ i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH; ++ offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH; ++ } ++ } ++ ++ mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, offset, size, i2c_addr); ++ ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); ++ if (err) ++ return err; ++ ++ status = mlxsw_reg_mcia_status_get(mcia_pl); ++ if (status) ++ return -EIO; ++ ++ mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp); ++ memcpy(data, eeprom_tmp, size); ++ *p_read_size = size; ++ ++ return 0; ++} ++ ++int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, ++ int off, int *temp) ++{ ++ char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE]; ++ union { ++ u8 buf[MLXSW_REG_MCIA_TH_ITEM_SIZE]; ++ u16 temp; ++ } temp_thresh; ++ char mcia_pl[MLXSW_REG_MCIA_LEN] = {0}; ++ char mtmp_pl[MLXSW_REG_MTMP_LEN]; ++ unsigned int module_temp; ++ bool qsfp; ++ int err; ++ ++ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, ++ false, false); ++ err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); ++ if (err) ++ return err; ++ mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, NULL); ++ if (!module_temp) { ++ *temp = 0; ++ return 0; ++ } ++ ++ /* Read Free Side Device Temperature Thresholds from page 03h ++ * (MSB at lower byte address). ++ * Bytes: ++ * 128-129 - Temp High Alarm (SFP_TEMP_HIGH_ALARM); ++ * 130-131 - Temp Low Alarm (SFP_TEMP_LOW_ALARM); ++ * 132-133 - Temp High Warning (SFP_TEMP_HIGH_WARN); ++ * 134-135 - Temp Low Warning (SFP_TEMP_LOW_WARN); ++ */ ++ ++ /* Validate module identifier value. */ ++ err = mlxsw_env_validate_cable_ident(core, module, &qsfp); ++ if (err) ++ return err; ++ ++ if (qsfp) ++ mlxsw_reg_mcia_pack(mcia_pl, module, 0, ++ MLXSW_REG_MCIA_TH_PAGE_NUM, ++ 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_PAGE0_LO, ++ off, MLXSW_REG_MCIA_TH_ITEM_SIZE, ++ MLXSW_REG_MCIA_I2C_ADDR_HIGH); ++ ++ err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp); ++ memcpy(temp_thresh.buf, eeprom_tmp, MLXSW_REG_MCIA_TH_ITEM_SIZE); ++ *temp = temp_thresh.temp * 1000; ++ ++ return 0; ++} ++ ++int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, 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; ++ u8 module_rev_id, module_id, diag_mon; ++ unsigned int read_size; ++ int err; ++ ++ err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset, ++ false, module_info, &read_size); ++ if (err) ++ return err; ++ ++ if (read_size < offset) ++ return -EIO; ++ ++ module_rev_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID]; ++ module_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID]; ++ ++ switch (module_id) { ++ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: ++ modinfo->type = ETH_MODULE_SFF_8436; ++ modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; ++ break; ++ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */ ++ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: ++ if (module_id == MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 || ++ module_rev_id >= ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) { ++ modinfo->type = ETH_MODULE_SFF_8636; ++ modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; ++ } else { ++ modinfo->type = ETH_MODULE_SFF_8436; ++ modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; ++ } ++ 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, false, ++ &diag_mon, &read_size); ++ if (err) ++ return err; ++ ++ if (read_size < 1) ++ return -EIO; ++ ++ modinfo->type = ETH_MODULE_SFF_8472; ++ if (diag_mon) ++ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; ++ else ++ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++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) ++{ ++ int offset = ee->offset; ++ unsigned int read_size; ++ bool qsfp; ++ int i = 0; ++ int err; ++ ++ if (!ee->len) ++ return -EINVAL; ++ ++ memset(data, 0, ee->len); ++ ++ /* Validate module identifier type. */ ++ err = mlxsw_env_validate_cable_ident(mlxsw_core, module, &qsfp); ++ if (err) ++ return err; ++ ++ while (i < ee->len) { ++ err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset, ++ ee->len - i, qsfp, ++ data + i, &read_size); ++ if (err) { ++ netdev_err(netdev, "Eeprom query failed\n"); ++ return err; ++ } ++ ++ i += read_size; ++ offset += read_size; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(mlxsw_env_get_module_eeprom); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.h b/drivers/net/ethernet/mellanox/mlxsw/core_env.h +new file mode 100644 +index 0000000..064d0e7 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ ++/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ ++ ++#ifndef _MLXSW_CORE_ENV_H ++#define _MLXSW_CORE_ENV_H ++ ++int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, 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_eeprom(struct net_device *netdev, ++ struct mlxsw_core *mlxsw_core, int module, ++ struct ethtool_eeprom *ee, u8 *data); ++ ++#endif +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index e04e816..3fe878d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -7,8 +7,10 @@ + #include + #include + #include ++#include + + #include "core.h" ++#include "core_env.h" + + #define MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT 127 + #define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT * 4 + \ +@@ -21,6 +23,14 @@ struct mlxsw_hwmon_attr { + char name[32]; + }; + ++static int mlxsw_hwmon_get_attr_index(int index, int count) ++{ ++ if (index >= count) ++ return index % count + MLXSW_REG_MTMP_GBOX_INDEX_MIN; ++ ++ return index; ++} ++ + struct mlxsw_hwmon { + struct mlxsw_core *core; + const struct mlxsw_bus_info *bus_info; +@@ -30,6 +40,8 @@ struct mlxsw_hwmon { + struct attribute *attrs[MLXSW_HWMON_ATTR_COUNT + 1]; + struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT]; + unsigned int attrs_count; ++ u8 sensor_count; ++ u8 module_sensor_max; + }; + + static ssize_t mlxsw_hwmon_temp_show(struct device *dev, +@@ -40,18 +52,19 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); + struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; +- unsigned int temp; ++ int temp, index; + int err; + +- mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index, +- false, false); ++ index = mlxsw_hwmon_get_attr_index(mlwsw_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); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); + return err; + } + mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); +- return sprintf(buf, "%u\n", temp); ++ return sprintf(buf, "%d\n", temp); + } + + static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, +@@ -62,18 +75,19 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); + struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; +- unsigned int temp_max; ++ int temp_max, index; + int err; + +- mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index, +- false, false); ++ index = mlxsw_hwmon_get_attr_index(mlwsw_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); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); + return err; + } + mlxsw_reg_mtmp_unpack(mtmp_pl, NULL, &temp_max, NULL); +- return sprintf(buf, "%u\n", temp_max); ++ return sprintf(buf, "%d\n", temp_max); + } + + static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, +@@ -85,6 +99,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + unsigned long val; ++ int index; + int err; + + err = kstrtoul(buf, 10, &val); +@@ -93,7 +108,9 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + if (val != 1) + return -EINVAL; + +- mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index, true, true); ++ index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, ++ mlxsw_hwmon->module_sensor_max); ++ mlxsw_reg_mtmp_pack(mtmp_pl, index, true, true); + err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to reset temp sensor history\n"); +@@ -121,6 +138,27 @@ static ssize_t mlxsw_hwmon_fan_rpm_show(struct device *dev, + return sprintf(buf, "%u\n", mlxsw_reg_mfsm_rpm_get(mfsm_pl)); + } + ++static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); ++ struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ char fore_pl[MLXSW_REG_FORE_LEN]; ++ bool fault; ++ int err; ++ ++ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(fore), fore_pl); ++ if (err) { ++ 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); ++ ++ return sprintf(buf, "%u\n", fault); ++} ++ + static ssize_t mlxsw_hwmon_pwm_show(struct device *dev, + struct device_attribute *attr, + char *buf) +@@ -167,12 +205,155 @@ static ssize_t mlxsw_hwmon_pwm_store(struct device *dev, + return len; + } + ++static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); ++ struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ char mtmp_pl[MLXSW_REG_MTMP_LEN]; ++ u8 module; ++ int temp; ++ int err; ++ ++ module = mlwsw_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); ++ if (err) ++ return err; ++ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); ++ ++ return sprintf(buf, "%d\n", temp); ++} ++ ++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 = ++ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); ++ struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; ++ u8 module, fault; ++ u16 temp; ++ int err; ++ ++ module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, ++ 1); ++ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); ++ if (err) { ++ dev_err(dev, "Failed to query module temperature sensor\n"); ++ return err; ++ } ++ ++ mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); ++ ++ /* Update status and temperature cache. */ ++ switch (temp) { ++ case MLXSW_REG_MTBR_BAD_SENS_INFO: ++ /* Untrusted cable is connected. Reading temperature from its ++ * sensor is faulty. ++ */ ++ fault = 1; ++ break; ++ case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ ++ case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ ++ case MLXSW_REG_MTBR_INDEX_NA: ++ default: ++ fault = 0; ++ break; ++ } ++ ++ return sprintf(buf, "%u\n", fault); ++} ++ ++static ssize_t ++mlxsw_hwmon_module_temp_critical_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); ++ struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ int temp; ++ u8 module; ++ int err; ++ ++ module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, ++ SFP_TEMP_HIGH_WARN, &temp); ++ if (err) { ++ dev_err(dev, "Failed to query module temperature thresholds\n"); ++ return err; ++ } ++ ++ return sprintf(buf, "%u\n", temp); ++} ++ ++static ssize_t ++mlxsw_hwmon_module_temp_emergency_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); ++ struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ u8 module; ++ int temp; ++ int err; ++ ++ module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, ++ SFP_TEMP_HIGH_ALARM, &temp); ++ if (err) { ++ dev_err(dev, "Failed to query module temperature thresholds\n"); ++ return err; ++ } ++ ++ return sprintf(buf, "%u\n", temp); ++} ++ ++static ssize_t ++mlxsw_hwmon_module_temp_label_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); ++ ++ return sprintf(buf, "front panel %03u\n", ++ mlwsw_hwmon_attr->type_index); ++} ++ ++static ssize_t ++mlxsw_hwmon_gbox_temp_label_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); ++ struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ int index = mlwsw_hwmon_attr->type_index - ++ mlxsw_hwmon->module_sensor_max + 1; ++ ++ return sprintf(buf, "gearbox %03u\n", index); ++} ++ + enum mlxsw_hwmon_attr_type { + MLXSW_HWMON_ATTR_TYPE_TEMP, + MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, + MLXSW_HWMON_ATTR_TYPE_TEMP_RST, + MLXSW_HWMON_ATTR_TYPE_FAN_RPM, ++ MLXSW_HWMON_ATTR_TYPE_FAN_FAULT, + MLXSW_HWMON_ATTR_TYPE_PWM, ++ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, ++ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT, ++ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, ++ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG, ++ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL, ++ MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL, + }; + + static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon, +@@ -209,6 +390,12 @@ static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon, + snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), + "fan%u_input", num + 1); + break; ++ case MLXSW_HWMON_ATTR_TYPE_FAN_FAULT: ++ mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_fan_fault_show; ++ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; ++ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), ++ "fan%u_fault", num + 1); ++ break; + case MLXSW_HWMON_ATTR_TYPE_PWM: + mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_pwm_show; + mlxsw_hwmon_attr->dev_attr.store = mlxsw_hwmon_pwm_store; +@@ -216,6 +403,47 @@ static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon, + snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), + "pwm%u", num + 1); + break; ++ case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE: ++ mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_module_temp_show; ++ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; ++ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), ++ "temp%u_input", num + 1); ++ break; ++ case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT: ++ mlxsw_hwmon_attr->dev_attr.show = ++ mlxsw_hwmon_module_temp_fault_show; ++ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; ++ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), ++ "temp%u_fault", num + 1); ++ break; ++ case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT: ++ mlxsw_hwmon_attr->dev_attr.show = ++ mlxsw_hwmon_module_temp_critical_show; ++ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; ++ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), ++ "temp%u_crit", num + 1); ++ break; ++ case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG: ++ mlxsw_hwmon_attr->dev_attr.show = ++ mlxsw_hwmon_module_temp_emergency_show; ++ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; ++ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), ++ "temp%u_emergency", num + 1); ++ break; ++ case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL: ++ mlxsw_hwmon_attr->dev_attr.show = ++ mlxsw_hwmon_module_temp_label_show; ++ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; ++ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), ++ "temp%u_label", num + 1); ++ break; ++ case MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL: ++ mlxsw_hwmon_attr->dev_attr.show = ++ mlxsw_hwmon_gbox_temp_label_show; ++ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; ++ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), ++ "temp%u_label", num + 1); ++ break; + default: + WARN_ON(1); + } +@@ -233,7 +461,6 @@ static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon) + { + char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0}; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; +- u8 sensor_count; + int i; + int err; + +@@ -242,8 +469,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; + } +- sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl); +- for (i = 0; i < sensor_count; i++) { ++ mlxsw_hwmon->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl); ++ for (i = 0; i < mlxsw_hwmon->sensor_count; i++) { + mlxsw_reg_mtmp_pack(mtmp_pl, i, true, true); + err = mlxsw_reg_write(mlxsw_hwmon->core, + MLXSW_REG(mtmp), mtmp_pl); +@@ -280,10 +507,14 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) + mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active); + num = 0; + for (type_index = 0; type_index < MLXSW_MFCR_TACHOS_MAX; type_index++) { +- if (tacho_active & BIT(type_index)) ++ if (tacho_active & BIT(type_index)) { + mlxsw_hwmon_attr_add(mlxsw_hwmon, + MLXSW_HWMON_ATTR_TYPE_FAN_RPM, ++ type_index, num); ++ mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ MLXSW_HWMON_ATTR_TYPE_FAN_FAULT, + type_index, num++); ++ } + } + num = 0; + for (type_index = 0; type_index < MLXSW_MFCR_PWMS_MAX; type_index++) { +@@ -295,6 +526,100 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) + return 0; + } + ++static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) ++{ ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; ++ 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) ++ return err; ++ ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, ++ &module_sensor_max); ++ ++ /* Add extra attributes for module temperature. Sensor index is ++ * assigned to sensor_count value, while all indexed before ++ * sensor_count are already utilized by the sensors connected through ++ * 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_ATTR_TYPE_TEMP_MODULE, i, i); ++ mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT, ++ i, i); ++ mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, i, ++ i); ++ mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG, ++ i, i); ++ mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL, ++ i, i); ++ } ++ ++ return 0; ++} ++ ++static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) ++{ ++ 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); ++ 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); ++ if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || ++ !gbox_num) ++ return 0; ++ ++ index = mlxsw_hwmon->module_sensor_max; ++ max_index = mlxsw_hwmon->module_sensor_max + gbox_num; ++ 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); ++ err = mlxsw_reg_write(mlxsw_hwmon->core, ++ MLXSW_REG(mtmp), mtmp_pl); ++ if (err) { ++ dev_err(mlxsw_hwmon->bus_info->dev, "Failed to setup temp sensor number %d\n", ++ sensor_index); ++ return err; ++ } ++ mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP, ++ index, index); ++ mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, index, ++ index); ++ mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ MLXSW_HWMON_ATTR_TYPE_TEMP_RST, index, ++ index); ++ mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL, ++ index, index); ++ index++; ++ } ++ ++ return 0; ++} ++ + int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + const struct mlxsw_bus_info *mlxsw_bus_info, + struct mlxsw_hwmon **p_hwmon) +@@ -317,6 +642,14 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + if (err) + goto err_fans_init; + ++ err = mlxsw_hwmon_module_init(mlxsw_hwmon); ++ if (err) ++ goto err_temp_module_init; ++ ++ err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon); ++ if (err) ++ goto err_temp_gearbox_init; ++ + mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group; + mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs; + +@@ -333,6 +666,8 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + return 0; + + err_hwmon_register: ++err_temp_gearbox_init: ++err_temp_module_init: + err_fans_init: + err_temp_init: + kfree(mlxsw_hwmon); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 6d29dc4..b753729 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -9,17 +9,48 @@ + #include + #include + #include ++#include + + #include "core.h" ++#include "core_env.h" + + #define MLXSW_THERMAL_POLL_INT 1000 /* ms */ +-#define MLXSW_THERMAL_MAX_TEMP 110000 /* 110C */ ++#define MLXSW_THERMAL_SLOW_POLL_INT 20000 /* ms */ ++#define MLXSW_THERMAL_ASIC_TEMP_NORM 75000 /* 75C */ ++#define MLXSW_THERMAL_ASIC_TEMP_HIGH 85000 /* 85C */ ++#define MLXSW_THERMAL_ASIC_TEMP_HOT 105000 /* 105C */ ++#define MLXSW_THERMAL_ASIC_TEMP_CRIT 110000 /* 110C */ ++#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_MAX_STATE 10 + #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[] = { ++ "mlxreg_fan", ++}; ++ ++enum mlxsw_thermal_trips { ++ MLXSW_THERMAL_TEMP_TRIP_NORM, ++ MLXSW_THERMAL_TEMP_TRIP_HIGH, ++ MLXSW_THERMAL_TEMP_TRIP_HOT, ++ MLXSW_THERMAL_TEMP_TRIP_CRIT, ++}; + + struct mlxsw_thermal_trip { + int type; + int temp; ++ int hyst; + int min_state; + int max_state; + }; +@@ -27,32 +58,29 @@ struct mlxsw_thermal_trip { + static const struct mlxsw_thermal_trip default_thermal_trips[] = { + { /* In range - 0-40% PWM */ + .type = THERMAL_TRIP_ACTIVE, +- .temp = 75000, ++ .temp = MLXSW_THERMAL_ASIC_TEMP_NORM, ++ .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP, + .min_state = 0, + .max_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10, + }, +- { /* High - 40-100% PWM */ +- .type = THERMAL_TRIP_ACTIVE, +- .temp = 80000, +- .min_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10, +- .max_state = MLXSW_THERMAL_MAX_STATE, +- }, + { +- /* Very high - 100% PWM */ ++ /* In range - 40-100% PWM */ + .type = THERMAL_TRIP_ACTIVE, +- .temp = 85000, +- .min_state = MLXSW_THERMAL_MAX_STATE, ++ .temp = MLXSW_THERMAL_ASIC_TEMP_HIGH, ++ .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP, ++ .min_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10, + .max_state = MLXSW_THERMAL_MAX_STATE, + }, + { /* Warning */ + .type = THERMAL_TRIP_HOT, +- .temp = 105000, ++ .temp = MLXSW_THERMAL_ASIC_TEMP_HOT, ++ .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP, + .min_state = MLXSW_THERMAL_MAX_STATE, + .max_state = MLXSW_THERMAL_MAX_STATE, + }, + { /* Critical - soft poweroff */ + .type = THERMAL_TRIP_CRITICAL, +- .temp = MLXSW_THERMAL_MAX_TEMP, ++ .temp = MLXSW_THERMAL_ASIC_TEMP_CRIT, + .min_state = MLXSW_THERMAL_MAX_STATE, + .max_state = MLXSW_THERMAL_MAX_STATE, + } +@@ -63,13 +91,32 @@ struct mlxsw_thermal_trip { + /* Make sure all trips are writable */ + #define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1) + ++struct mlxsw_thermal; ++ ++struct mlxsw_thermal_module { ++ struct mlxsw_thermal *parent; ++ struct thermal_zone_device *tzdev; ++ struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; ++ enum thermal_device_mode mode; ++ int module; /* Module or gearbox number */ ++}; ++ + struct mlxsw_thermal { + struct mlxsw_core *core; + const struct mlxsw_bus_info *bus_info; + struct thermal_zone_device *tzdev; ++ int polling_delay; + 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]; + enum thermal_device_mode mode; ++ struct mlxsw_thermal_module *tz_module_arr; ++ u8 tz_module_num; ++ struct mlxsw_thermal_module *tz_gearbox_arr; ++ u8 tz_gearbox_num; ++ unsigned int tz_highest_score; ++ struct thermal_zone_device *tz_highest_dev; ++ bool initializing; /* Driver is in initialization stage */ + }; + + static inline u8 mlxsw_state_to_duty(int state) +@@ -93,9 +140,67 @@ static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal, + if (thermal->cdevs[i] == cdev) + return i; + ++ /* 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], ++ sizeof(cdev->type))) ++ return 0; ++ } ++ + return -ENODEV; + } + ++static void ++mlxsw_thermal_module_trips_reset(struct mlxsw_thermal_module *tz) ++{ ++ tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = 0; ++ tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = 0; ++ tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = 0; ++ tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = 0; ++} ++ ++static int ++mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core, ++ struct mlxsw_thermal_module *tz) ++{ ++ int crit_temp, emerg_temp; ++ int err; ++ ++ err = mlxsw_env_module_temp_thresholds_get(core, tz->module, ++ SFP_TEMP_HIGH_WARN, ++ &crit_temp); ++ if (err) ++ return err; ++ ++ err = mlxsw_env_module_temp_thresholds_get(core, tz->module, ++ SFP_TEMP_HIGH_ALARM, ++ &emerg_temp); ++ if (err) ++ return err; ++ ++ /* According to the system thermal requirements, the thermal zones are ++ * defined with four trip points. The critical and emergency ++ * temperature thresholds, provided by QSFP module are set as "active" ++ * and "hot" trip points, "normal" and "critical" trip points are ++ * derived from "active" and "hot" by subtracting or adding double ++ * hysteresis value. ++ */ ++ if (crit_temp >= MLXSW_THERMAL_MODULE_TEMP_SHIFT) ++ tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp - ++ MLXSW_THERMAL_MODULE_TEMP_SHIFT; ++ else ++ tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp; ++ tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = crit_temp; ++ tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = emerg_temp; ++ if (emerg_temp > crit_temp) ++ tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = emerg_temp + ++ MLXSW_THERMAL_MODULE_TEMP_SHIFT; ++ else ++ tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = emerg_temp; ++ ++ return 0; ++} ++ + static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev, + struct thermal_cooling_device *cdev) + { +@@ -162,7 +267,7 @@ static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev, + mutex_lock(&tzdev->lock); + + if (mode == THERMAL_DEVICE_ENABLED) +- tzdev->polling_delay = MLXSW_THERMAL_POLL_INT; ++ tzdev->polling_delay = thermal->polling_delay; + else + tzdev->polling_delay = 0; + +@@ -180,9 +285,15 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, + struct mlxsw_thermal *thermal = tzdev->devdata; + struct device *dev = thermal->bus_info->dev; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; +- unsigned int temp; ++ int temp; + int err; + ++ /* Do not read temperature in initialization stage. */ ++ if (thermal->initializing) { ++ *p_temp = 0; ++ return 0; ++ } ++ + mlxsw_reg_mtmp_pack(mtmp_pl, 0, false, false); + + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -192,7 +303,7 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, + } + mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); + +- *p_temp = (int) temp; ++ *p_temp = temp; + return 0; + } + +@@ -227,13 +338,35 @@ static int mlxsw_thermal_set_trip_temp(struct thermal_zone_device *tzdev, + struct mlxsw_thermal *thermal = tzdev->devdata; + + if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS || +- temp > MLXSW_THERMAL_MAX_TEMP) ++ temp > MLXSW_THERMAL_ASIC_TEMP_CRIT) + return -EINVAL; + + thermal->trips[trip].temp = temp; + return 0; + } + ++static int mlxsw_thermal_get_trip_hyst(struct thermal_zone_device *tzdev, ++ int trip, int *p_hyst) ++{ ++ struct mlxsw_thermal *thermal = tzdev->devdata; ++ ++ *p_hyst = thermal->trips[trip].hyst; ++ return 0; ++} ++ ++static int mlxsw_thermal_set_trip_hyst(struct thermal_zone_device *tzdev, ++ int trip, int hyst) ++{ ++ struct mlxsw_thermal *thermal = tzdev->devdata; ++ ++ thermal->trips[trip].hyst = hyst; ++ return 0; ++} ++ ++struct thermal_zone_params mlxsw_thermal_params = { ++ .no_hwmon = true, ++}; ++ + static struct thermal_zone_device_ops mlxsw_thermal_ops = { + .bind = mlxsw_thermal_bind, + .unbind = mlxsw_thermal_unbind, +@@ -243,6 +376,242 @@ static int mlxsw_thermal_set_trip_temp(struct thermal_zone_device *tzdev, + .get_trip_type = mlxsw_thermal_get_trip_type, + .get_trip_temp = mlxsw_thermal_get_trip_temp, + .set_trip_temp = mlxsw_thermal_set_trip_temp, ++ .get_trip_hyst = mlxsw_thermal_get_trip_hyst, ++ .set_trip_hyst = mlxsw_thermal_set_trip_hyst, ++}; ++ ++static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev, ++ struct thermal_cooling_device *cdev) ++{ ++ struct mlxsw_thermal_module *tz = tzdev->devdata; ++ struct mlxsw_thermal *thermal = tz->parent; ++ int i, j, err; ++ ++ /* If the cooling device is one of ours bind it */ ++ if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0) ++ return 0; ++ ++ for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) { ++ const struct mlxsw_thermal_trip *trip = &tz->trips[i]; ++ ++ err = thermal_zone_bind_cooling_device(tzdev, i, cdev, ++ trip->max_state, ++ trip->min_state, ++ THERMAL_WEIGHT_DEFAULT); ++ if (err < 0) ++ goto err_bind_cooling_device; ++ } ++ return 0; ++ ++err_bind_cooling_device: ++ for (j = i - 1; j >= 0; j--) ++ thermal_zone_unbind_cooling_device(tzdev, j, cdev); ++ return err; ++} ++ ++static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev, ++ struct thermal_cooling_device *cdev) ++{ ++ struct mlxsw_thermal_module *tz = tzdev->devdata; ++ struct mlxsw_thermal *thermal = tz->parent; ++ int i; ++ int err; ++ ++ /* If the cooling device is one of ours unbind it */ ++ if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0) ++ return 0; ++ ++ for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) { ++ err = thermal_zone_unbind_cooling_device(tzdev, i, cdev); ++ WARN_ON(err); ++ } ++ return err; ++} ++ ++static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev, ++ enum thermal_device_mode *mode) ++{ ++ struct mlxsw_thermal_module *tz = tzdev->devdata; ++ ++ *mode = tz->mode; ++ ++ return 0; ++} ++ ++static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev, ++ enum thermal_device_mode mode) ++{ ++ struct mlxsw_thermal_module *tz = tzdev->devdata; ++ struct mlxsw_thermal *thermal = tz->parent; ++ ++ mutex_lock(&tzdev->lock); ++ ++ if (mode == THERMAL_DEVICE_ENABLED) ++ tzdev->polling_delay = thermal->polling_delay; ++ else ++ tzdev->polling_delay = 0; ++ ++ mutex_unlock(&tzdev->lock); ++ ++ tz->mode = mode; ++ thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED); ++ ++ return 0; ++} ++ ++static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, ++ int *p_temp) ++{ ++ struct mlxsw_thermal_module *tz = tzdev->devdata; ++ struct mlxsw_thermal *thermal = tz->parent; ++ struct device *dev = thermal->bus_info->dev; ++ char mtmp_pl[MLXSW_REG_MTMP_LEN]; ++ int temp; ++ int err; ++ ++ /* Do not read temperature in initialization stage. */ ++ if (thermal->initializing) { ++ *p_temp = 0; ++ return 0; ++ } ++ ++ /* Read module temperature. */ ++ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + ++ tz->module, false, false); ++ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); ++ if (err) { ++ /* Do not return error - in case of broken module's sensor ++ * it will cause error message flooding. ++ */ ++ temp = 0; ++ *p_temp = (int) temp; ++ return 0; ++ } ++ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); ++ *p_temp = temp; ++ ++ if (!temp) ++ return 0; ++ ++ /* Update trip points. */ ++ err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz); ++ ++ return 0; ++} ++ ++static int ++mlxsw_thermal_module_trip_type_get(struct thermal_zone_device *tzdev, int trip, ++ enum thermal_trip_type *p_type) ++{ ++ struct mlxsw_thermal_module *tz = tzdev->devdata; ++ ++ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) ++ return -EINVAL; ++ ++ *p_type = tz->trips[trip].type; ++ return 0; ++} ++ ++static int ++mlxsw_thermal_module_trip_temp_get(struct thermal_zone_device *tzdev, ++ int trip, int *p_temp) ++{ ++ struct mlxsw_thermal_module *tz = tzdev->devdata; ++ ++ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) ++ return -EINVAL; ++ ++ *p_temp = tz->trips[trip].temp; ++ return 0; ++} ++ ++static int ++mlxsw_thermal_module_trip_temp_set(struct thermal_zone_device *tzdev, ++ int trip, int temp) ++{ ++ struct mlxsw_thermal_module *tz = tzdev->devdata; ++ ++ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS || ++ temp > tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp) ++ return -EINVAL; ++ ++ tz->trips[trip].temp = temp; ++ return 0; ++} ++ ++static int ++mlxsw_thermal_module_trip_hyst_get(struct thermal_zone_device *tzdev, int trip, ++ int *p_hyst) ++{ ++ struct mlxsw_thermal_module *tz = tzdev->devdata; ++ ++ *p_hyst = tz->trips[trip].hyst; ++ return 0; ++} ++ ++static int ++mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip, ++ int hyst) ++{ ++ struct mlxsw_thermal_module *tz = tzdev->devdata; ++ ++ tz->trips[trip].hyst = hyst; ++ return 0; ++} ++ ++static struct thermal_zone_device_ops mlxsw_thermal_module_ops = { ++ .bind = mlxsw_thermal_module_bind, ++ .unbind = mlxsw_thermal_module_unbind, ++ .get_mode = mlxsw_thermal_module_mode_get, ++ .set_mode = mlxsw_thermal_module_mode_set, ++ .get_temp = mlxsw_thermal_module_temp_get, ++ .get_trip_type = mlxsw_thermal_module_trip_type_get, ++ .get_trip_temp = mlxsw_thermal_module_trip_temp_get, ++ .set_trip_temp = mlxsw_thermal_module_trip_temp_set, ++ .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get, ++ .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set, ++}; ++ ++static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, ++ int *p_temp) ++{ ++ struct mlxsw_thermal_module *tz = tzdev->devdata; ++ struct mlxsw_thermal *thermal = tz->parent; ++ char mtmp_pl[MLXSW_REG_MTMP_LEN]; ++ u16 index; ++ int temp; ++ int err; ++ ++ /* Do not read temperature in initialization stage. */ ++ if (thermal->initializing) { ++ *p_temp = 0; ++ return 0; ++ } ++ ++ index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module; ++ mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); ++ ++ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); ++ ++ *p_temp = temp; ++ return 0; ++} ++ ++static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = { ++ .bind = mlxsw_thermal_module_bind, ++ .unbind = mlxsw_thermal_module_unbind, ++ .get_mode = mlxsw_thermal_module_mode_get, ++ .set_mode = mlxsw_thermal_module_mode_set, ++ .get_temp = mlxsw_thermal_gearbox_temp_get, ++ .get_trip_type = mlxsw_thermal_module_trip_type_get, ++ .get_trip_temp = mlxsw_thermal_module_trip_temp_get, ++ .set_trip_temp = mlxsw_thermal_module_trip_temp_set, ++ .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get, ++ .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set, + }; + + static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev, +@@ -285,12 +654,51 @@ 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]; +- int err, idx; ++ unsigned long cur_state, i; ++ int idx; ++ u8 duty; ++ int err; + + 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)); + err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl); + if (err) { +@@ -306,6 +714,218 @@ static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev, + .set_cur_state = mlxsw_thermal_set_cur_state, + }; + ++static int ++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); ++ module_tz->tzdev = thermal_zone_device_register(tz_name, ++ MLXSW_THERMAL_NUM_TRIPS, ++ MLXSW_THERMAL_TRIP_MASK, ++ module_tz, ++ &mlxsw_thermal_module_ops, ++ &mlxsw_thermal_params, 0, 0); ++ if (IS_ERR(module_tz->tzdev)) { ++ err = PTR_ERR(module_tz->tzdev); ++ return err; ++ } ++ ++ module_tz->mode = THERMAL_DEVICE_DISABLED; ++ return 0; ++} ++ ++static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev) ++{ ++ thermal_zone_device_unregister(tzdev); ++} ++ ++static int ++mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, ++ struct mlxsw_thermal *thermal, u8 module) ++{ ++ struct mlxsw_thermal_module *module_tz; ++ ++ module_tz = &thermal->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->parent = thermal; ++ memcpy(module_tz->trips, default_thermal_trips, ++ sizeof(thermal->trips)); ++ /* Initialize all trip point. */ ++ mlxsw_thermal_module_trips_reset(module_tz); ++ ++ return 0; ++} ++ ++static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz) ++{ ++ if (module_tz && module_tz->tzdev) { ++ mlxsw_thermal_module_tz_fini(module_tz->tzdev); ++ module_tz->tzdev = NULL; ++ module_tz->parent = NULL; ++ } ++} ++ ++static int ++mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, ++ struct mlxsw_thermal *thermal) ++{ ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; ++ struct mlxsw_thermal_module *module_tz; ++ 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) ++ return err; ++ ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, ++ &thermal->tz_module_num); ++ if (!thermal->tz_module_num) ++ return 0; ++ ++ thermal->tz_module_arr = kcalloc(thermal->tz_module_num, ++ sizeof(*thermal->tz_module_arr), ++ GFP_KERNEL); ++ if (!thermal->tz_module_arr) ++ return -ENOMEM; ++ ++ 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; ++ } ++ ++ for (i = 0; i < thermal->tz_module_num; i++) { ++ module_tz = &thermal->tz_module_arr[i]; ++ if (!module_tz->parent) ++ continue; ++ err = mlxsw_thermal_module_tz_init(module_tz); ++ if (err) ++ goto err_unreg_tz_module_arr; ++ } ++ ++ return 0; ++ ++err_unreg_tz_module_arr: ++ for (i = thermal->tz_module_num - 1; i >= 0; i--) ++ mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); ++ kfree(thermal->tz_module_arr); ++ return err; ++} ++ ++static void ++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); ++} ++ ++static int ++mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) ++{ ++ char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; ++ ++ 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, ++ gearbox_tz, ++ &mlxsw_thermal_gearbox_ops, ++ &mlxsw_thermal_params, 0, 0); ++ if (IS_ERR(gearbox_tz->tzdev)) ++ return PTR_ERR(gearbox_tz->tzdev); ++ ++ gearbox_tz->mode = THERMAL_DEVICE_DISABLED; ++ return 0; ++} ++ ++static void ++mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz) ++{ ++ thermal_zone_device_unregister(gearbox_tz->tzdev); ++} ++ ++static int ++mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, ++ struct mlxsw_thermal *thermal) ++{ ++ 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; ++ ++ 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) ++ return err; ++ ++ mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, ++ NULL); ++ if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || ++ !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) ++ return -ENOMEM; ++ ++ for (i = 0; i < thermal->tz_gearbox_num; i++) { ++ gearbox_tz = &thermal->tz_gearbox_arr[i]; ++ memcpy(gearbox_tz->trips, default_thermal_trips, ++ sizeof(thermal->trips)); ++ gearbox_tz->module = i; ++ gearbox_tz->parent = thermal; ++ err = mlxsw_thermal_gearbox_tz_init(gearbox_tz); ++ if (err) ++ goto err_unreg_tz_gearbox; ++ } ++ ++ return 0; ++ ++err_unreg_tz_gearbox: ++ for (i--; i >= 0; i--) ++ mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); ++ kfree(thermal->tz_gearbox_arr); ++ return err; ++} ++ ++static void ++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); ++} ++ + int mlxsw_thermal_init(struct mlxsw_core *core, + const struct mlxsw_bus_info *bus_info, + struct mlxsw_thermal **p_thermal) +@@ -326,6 +946,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + thermal->core = core; + thermal->bus_info = bus_info; + memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips)); ++ thermal->initializing = true; + + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl); + if (err) { +@@ -358,8 +979,9 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + if (pwm_active & BIT(i)) { + struct thermal_cooling_device *cdev; + +- cdev = thermal_cooling_device_register("Fan", thermal, +- &mlxsw_cooling_ops); ++ cdev = thermal_cooling_device_register("mlxsw_fan", ++ thermal, ++ &mlxsw_cooling_ops); + if (IS_ERR(cdev)) { + err = PTR_ERR(cdev); + dev_err(dev, "Failed to register cooling device\n"); +@@ -369,22 +991,48 @@ 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_SPEED_MIN_LEVEL, ++ i); ++ ++ thermal->polling_delay = bus_info->low_frequency ? ++ MLXSW_THERMAL_SLOW_POLL_INT : ++ MLXSW_THERMAL_POLL_INT; ++ + thermal->tzdev = thermal_zone_device_register("mlxsw", + MLXSW_THERMAL_NUM_TRIPS, + MLXSW_THERMAL_TRIP_MASK, + thermal, + &mlxsw_thermal_ops, +- NULL, 0, +- MLXSW_THERMAL_POLL_INT); ++ &mlxsw_thermal_params, 0, ++ thermal->polling_delay); + if (IS_ERR(thermal->tzdev)) { + err = PTR_ERR(thermal->tzdev); + dev_err(dev, "Failed to register thermal zone\n"); + goto err_unreg_cdevs; + } + +- thermal->mode = THERMAL_DEVICE_ENABLED; ++ err = mlxsw_thermal_modules_init(dev, core, thermal); ++ if (err) ++ goto err_unreg_tzdev; ++ ++ err = mlxsw_thermal_gearboxes_init(dev, core, thermal); ++ if (err) ++ goto err_unreg_modules_tzdev; ++ ++ thermal->mode = THERMAL_DEVICE_DISABLED; ++ thermal->initializing = false; + *p_thermal = thermal; + return 0; ++ ++err_unreg_modules_tzdev: ++ mlxsw_thermal_modules_fini(thermal); ++err_unreg_tzdev: ++ if (thermal->tzdev) { ++ thermal_zone_device_unregister(thermal->tzdev); ++ thermal->tzdev = NULL; ++ } + err_unreg_cdevs: + for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) + if (thermal->cdevs[i]) +@@ -398,6 +1046,8 @@ void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) + { + int i; + ++ mlxsw_thermal_gearboxes_fini(thermal); ++ mlxsw_thermal_modules_fini(thermal); + if (thermal->tzdev) { + thermal_zone_device_unregister(thermal->tzdev); + thermal->tzdev = NULL; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +index 798bd5a..e04d521 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +@@ -14,14 +14,17 @@ + #include "cmd.h" + #include "core.h" + #include "i2c.h" ++#include "resources.h" + + #define MLXSW_I2C_CIR2_BASE 0x72000 + #define MLXSW_I2C_CIR_STATUS_OFF 0x18 + #define MLXSW_I2C_CIR2_OFF_STATUS (MLXSW_I2C_CIR2_BASE + \ + MLXSW_I2C_CIR_STATUS_OFF) + #define MLXSW_I2C_OPMOD_SHIFT 12 ++#define MLXSW_I2C_EVENT_BIT_SHIFT 22 + #define MLXSW_I2C_GO_BIT_SHIFT 23 + #define MLXSW_I2C_CIR_CTRL_STATUS_SHIFT 24 ++#define MLXSW_I2C_EVENT_BIT BIT(MLXSW_I2C_EVENT_BIT_SHIFT) + #define MLXSW_I2C_GO_BIT BIT(MLXSW_I2C_GO_BIT_SHIFT) + #define MLXSW_I2C_GO_OPMODE BIT(MLXSW_I2C_OPMOD_SHIFT) + #define MLXSW_I2C_SET_IMM_CMD (MLXSW_I2C_GO_OPMODE | \ +@@ -33,17 +36,20 @@ + #define MLXSW_I2C_TLV_HDR_SIZE 0x10 + #define MLXSW_I2C_ADDR_WIDTH 4 + #define MLXSW_I2C_PUSH_CMD_SIZE (MLXSW_I2C_ADDR_WIDTH + 4) ++#define MLXSW_I2C_SET_EVENT_CMD (MLXSW_I2C_EVENT_BIT) ++#define MLXSW_I2C_PUSH_EVENT_CMD (MLXSW_I2C_GO_BIT | \ ++ MLXSW_I2C_SET_EVENT_CMD) + #define MLXSW_I2C_READ_SEMA_SIZE 4 + #define MLXSW_I2C_PREP_SIZE (MLXSW_I2C_ADDR_WIDTH + 28) + #define MLXSW_I2C_MBOX_SIZE 20 + #define MLXSW_I2C_MBOX_OUT_PARAM_OFF 12 +-#define MLXSW_I2C_MAX_BUFF_SIZE 32 + #define MLXSW_I2C_MBOX_OFFSET_BITS 20 + #define MLXSW_I2C_MBOX_SIZE_BITS 12 + #define MLXSW_I2C_ADDR_BUF_SIZE 4 +-#define MLXSW_I2C_BLK_MAX 32 ++#define MLXSW_I2C_BLK_DEF 32 + #define MLXSW_I2C_RETRY 5 + #define MLXSW_I2C_TIMEOUT_MSECS 5000 ++#define MLXSW_I2C_MAX_DATA_SIZE 256 + + /** + * struct mlxsw_i2c - device private data: +@@ -55,6 +61,7 @@ + * @dev: I2C device; + * @core: switch core pointer; + * @bus_info: bus info block; ++ * @block_size: maximum block size allowed to pass to under layer; + */ + struct mlxsw_i2c { + struct { +@@ -67,6 +74,7 @@ struct mlxsw_i2c { + struct device *dev; + struct mlxsw_core *core; + struct mlxsw_bus_info bus_info; ++ u16 block_size; + }; + + #define MLXSW_I2C_READ_MSG(_client, _addr_buf, _buf, _len) { \ +@@ -167,7 +175,7 @@ static int mlxsw_i2c_wait_go_bit(struct i2c_client *client, + return err > 0 ? 0 : err; + } + +-/* Routine posts a command to ASIC though mail box. */ ++/* Routine posts a command to ASIC through mail box. */ + static int mlxsw_i2c_write_cmd(struct i2c_client *client, + struct mlxsw_i2c *mlxsw_i2c, + int immediate) +@@ -213,6 +221,66 @@ static int mlxsw_i2c_write_cmd(struct i2c_client *client, + return 0; + } + ++/* Routine posts initialization command to ASIC through mail box. */ ++static int ++mlxsw_i2c_write_init_cmd(struct i2c_client *client, ++ struct mlxsw_i2c *mlxsw_i2c, u16 opcode, u32 in_mod) ++{ ++ __be32 push_cmd_buf[MLXSW_I2C_PUSH_CMD_SIZE / 4] = { ++ 0, cpu_to_be32(MLXSW_I2C_PUSH_EVENT_CMD) ++ }; ++ __be32 prep_cmd_buf[MLXSW_I2C_PREP_SIZE / 4] = { ++ 0, 0, 0, 0, 0, 0, ++ cpu_to_be32(client->adapter->nr & 0xffff), ++ cpu_to_be32(MLXSW_I2C_SET_EVENT_CMD) ++ }; ++ struct i2c_msg push_cmd = ++ MLXSW_I2C_WRITE_MSG(client, push_cmd_buf, ++ MLXSW_I2C_PUSH_CMD_SIZE); ++ struct i2c_msg prep_cmd = ++ MLXSW_I2C_WRITE_MSG(client, prep_cmd_buf, MLXSW_I2C_PREP_SIZE); ++ u8 status; ++ int err; ++ ++ push_cmd_buf[1] = cpu_to_be32(MLXSW_I2C_PUSH_EVENT_CMD | opcode); ++ prep_cmd_buf[3] = cpu_to_be32(in_mod); ++ prep_cmd_buf[7] = cpu_to_be32(MLXSW_I2C_GO_BIT | opcode); ++ mlxsw_i2c_set_slave_addr((u8 *)prep_cmd_buf, ++ MLXSW_I2C_CIR2_BASE); ++ mlxsw_i2c_set_slave_addr((u8 *)push_cmd_buf, ++ MLXSW_I2C_CIR2_OFF_STATUS); ++ ++ /* Prepare Command Interface Register for transaction */ ++ err = i2c_transfer(client->adapter, &prep_cmd, 1); ++ if (err < 0) ++ return err; ++ else if (err != 1) ++ return -EIO; ++ ++ /* Write out Command Interface Register GO bit to push transaction */ ++ err = i2c_transfer(client->adapter, &push_cmd, 1); ++ if (err < 0) ++ return err; ++ else if (err != 1) ++ return -EIO; ++ ++ /* 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"); ++ return err; ++ } ++ ++ /* Validate transaction completion status. */ ++ if (status) { ++ dev_err(&client->dev, "Bad transaction completion status %x\n", ++ status); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ + /* Routine obtains mail box offsets from ASIC register space. */ + static int mlxsw_i2c_get_mbox(struct i2c_client *client, + struct mlxsw_i2c *mlxsw_i2c) +@@ -248,20 +316,26 @@ static int mlxsw_i2c_get_mbox(struct i2c_client *client, + struct i2c_client *client = to_i2c_client(dev); + struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); + unsigned long timeout = msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS); +- u8 tran_buf[MLXSW_I2C_MAX_BUFF_SIZE + MLXSW_I2C_ADDR_BUF_SIZE]; + int off = mlxsw_i2c->cmd.mb_off_in, chunk_size, i, j; + unsigned long end; ++ u8 *tran_buf; + struct i2c_msg write_tran = +- MLXSW_I2C_WRITE_MSG(client, tran_buf, MLXSW_I2C_PUSH_CMD_SIZE); ++ MLXSW_I2C_WRITE_MSG(client, NULL, MLXSW_I2C_PUSH_CMD_SIZE); + int err; + ++ tran_buf = kmalloc(mlxsw_i2c->block_size + MLXSW_I2C_ADDR_BUF_SIZE, ++ GFP_KERNEL); ++ if (!tran_buf) ++ return -ENOMEM; ++ ++ write_tran.buf = tran_buf; + for (i = 0; i < num; i++) { +- chunk_size = (in_mbox_size > MLXSW_I2C_BLK_MAX) ? +- MLXSW_I2C_BLK_MAX : in_mbox_size; ++ chunk_size = (in_mbox_size > mlxsw_i2c->block_size) ? ++ mlxsw_i2c->block_size : in_mbox_size; + write_tran.len = MLXSW_I2C_ADDR_WIDTH + chunk_size; + mlxsw_i2c_set_slave_addr(tran_buf, off); + memcpy(&tran_buf[MLXSW_I2C_ADDR_BUF_SIZE], in_mbox + +- MLXSW_I2C_BLK_MAX * i, chunk_size); ++ mlxsw_i2c->block_size * i, chunk_size); + + j = 0; + end = jiffies + timeout; +@@ -275,9 +349,10 @@ static int mlxsw_i2c_get_mbox(struct i2c_client *client, + (j++ < MLXSW_I2C_RETRY)); + + if (err != 1) { +- if (!err) ++ if (!err) { + err = -EIO; +- return err; ++ goto mlxsw_i2c_write_exit; ++ } + } + + off += chunk_size; +@@ -288,30 +363,33 @@ static int mlxsw_i2c_get_mbox(struct i2c_client *client, + err = mlxsw_i2c_write_cmd(client, mlxsw_i2c, 0); + if (err) { + dev_err(&client->dev, "Could not start transaction"); +- return -EIO; ++ err = -EIO; ++ goto mlxsw_i2c_write_exit; + } + + /* Wait until go bit is cleared. */ + err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, p_status); + if (err) { + dev_err(&client->dev, "HW semaphore is not released"); +- return err; ++ goto mlxsw_i2c_write_exit; + } + + /* Validate transaction completion status. */ + if (*p_status) { + dev_err(&client->dev, "Bad transaction completion status %x\n", + *p_status); +- return -EIO; ++ err = -EIO; + } + +- return 0; ++mlxsw_i2c_write_exit: ++ kfree(tran_buf); ++ return err; + } + + /* Routine executes I2C command. */ + static int +-mlxsw_i2c_cmd(struct device *dev, size_t in_mbox_size, u8 *in_mbox, +- size_t out_mbox_size, u8 *out_mbox, u8 *status) ++mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, ++ u8 *in_mbox, size_t out_mbox_size, u8 *out_mbox, u8 *status) + { + struct i2c_client *client = to_i2c_client(dev); + struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); +@@ -326,31 +404,47 @@ static int mlxsw_i2c_get_mbox(struct i2c_client *client, + + WARN_ON(in_mbox_size % sizeof(u32) || out_mbox_size % sizeof(u32)); + +- reg_size = mlxsw_i2c_get_reg_size(in_mbox); +- num = reg_size / MLXSW_I2C_BLK_MAX; +- if (reg_size % MLXSW_I2C_BLK_MAX) +- num++; ++ if (in_mbox) { ++ reg_size = mlxsw_i2c_get_reg_size(in_mbox); ++ num = reg_size / mlxsw_i2c->block_size; ++ if (reg_size % mlxsw_i2c->block_size) ++ num++; + +- if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { +- dev_err(&client->dev, "Could not acquire lock"); +- return -EINVAL; +- } ++ if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { ++ dev_err(&client->dev, "Could not acquire lock"); ++ return -EINVAL; ++ } + +- err = mlxsw_i2c_write(dev, reg_size, in_mbox, num, status); +- if (err) +- goto cmd_fail; ++ err = mlxsw_i2c_write(dev, reg_size, in_mbox, num, status); ++ if (err) ++ goto cmd_fail; ++ ++ /* No out mailbox is case of write transaction. */ ++ if (!out_mbox) { ++ mutex_unlock(&mlxsw_i2c->cmd.lock); ++ return 0; ++ } ++ } else { ++ /* No input mailbox is case of initialization query command. */ ++ reg_size = MLXSW_I2C_MAX_DATA_SIZE; ++ num = reg_size / mlxsw_i2c->block_size; ++ ++ if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { ++ dev_err(&client->dev, "Could not acquire lock"); ++ return -EINVAL; ++ } + +- /* No out mailbox is case of write transaction. */ +- if (!out_mbox) { +- mutex_unlock(&mlxsw_i2c->cmd.lock); +- return 0; ++ err = mlxsw_i2c_write_init_cmd(client, mlxsw_i2c, opcode, ++ in_mod); ++ if (err) ++ goto cmd_fail; + } + + /* Send read transaction to get output mailbox content. */ + read_tran[1].buf = out_mbox; + for (i = 0; i < num; i++) { +- chunk_size = (reg_size > MLXSW_I2C_BLK_MAX) ? +- MLXSW_I2C_BLK_MAX : reg_size; ++ chunk_size = (reg_size > mlxsw_i2c->block_size) ? ++ mlxsw_i2c->block_size : reg_size; + read_tran[1].len = chunk_size; + mlxsw_i2c_set_slave_addr(tran_buf, off); + +@@ -395,8 +489,8 @@ static int mlxsw_i2c_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod, + { + struct mlxsw_i2c *mlxsw_i2c = bus_priv; + +- return mlxsw_i2c_cmd(mlxsw_i2c->dev, in_mbox_size, in_mbox, +- out_mbox_size, out_mbox, status); ++ return mlxsw_i2c_cmd(mlxsw_i2c->dev, opcode, in_mod, in_mbox_size, ++ in_mbox, out_mbox_size, out_mbox, status); + } + + static bool mlxsw_i2c_skb_transmit_busy(void *bus_priv, +@@ -414,13 +508,34 @@ 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 *resources) ++ struct mlxsw_res *res) + { + struct mlxsw_i2c *mlxsw_i2c = bus_priv; ++ char *mbox; ++ int err; + + mlxsw_i2c->core = mlxsw_core; + +- return 0; ++ mbox = mlxsw_cmd_mbox_alloc(); ++ if (!mbox) ++ return -ENOMEM; ++ ++ err = mlxsw_cmd_query_fw(mlxsw_core, mbox); ++ if (err) ++ goto mbox_put; ++ ++ mlxsw_i2c->bus_info.fw_rev.major = ++ mlxsw_cmd_mbox_query_fw_fw_rev_major_get(mbox); ++ mlxsw_i2c->bus_info.fw_rev.minor = ++ mlxsw_cmd_mbox_query_fw_fw_rev_minor_get(mbox); ++ mlxsw_i2c->bus_info.fw_rev.subminor = ++ mlxsw_cmd_mbox_query_fw_fw_rev_subminor_get(mbox); ++ ++ err = mlxsw_core_resources_query(mlxsw_core, mbox, res); ++ ++mbox_put: ++ mlxsw_cmd_mbox_free(mbox); ++ return err; + } + + static void mlxsw_i2c_fini(void *bus_priv) +@@ -442,6 +557,7 @@ static void mlxsw_i2c_fini(void *bus_priv) + static int mlxsw_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) + { ++ const struct i2c_adapter_quirks *quirks = client->adapter->quirks; + struct mlxsw_i2c *mlxsw_i2c; + u8 status; + int err; +@@ -450,6 +566,22 @@ static int mlxsw_i2c_probe(struct i2c_client *client, + if (!mlxsw_i2c) + return -ENOMEM; + ++ if (quirks) { ++ if ((quirks->max_read_len && ++ quirks->max_read_len < MLXSW_I2C_BLK_DEF) || ++ (quirks->max_write_len && ++ quirks->max_write_len < MLXSW_I2C_BLK_DEF)) { ++ dev_err(&client->dev, "Insufficient transaction buffer length\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ mlxsw_i2c->block_size = max_t(u16, MLXSW_I2C_BLK_DEF, ++ min_t(u16, quirks->max_read_len, ++ quirks->max_write_len)); ++ } else { ++ mlxsw_i2c->block_size = MLXSW_I2C_BLK_DEF; ++ } ++ + i2c_set_clientdata(client, mlxsw_i2c); + mutex_init(&mlxsw_i2c->cmd.lock); + +@@ -503,6 +635,7 @@ static int mlxsw_i2c_probe(struct i2c_client *client, + mlxsw_i2c->bus_info.device_kind = id->name; + mlxsw_i2c->bus_info.device_name = client->name; + mlxsw_i2c->bus_info.dev = &client->dev; ++ mlxsw_i2c->bus_info.low_frequency = true; + mlxsw_i2c->dev = &client->dev; + + err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info, +@@ -513,6 +646,11 @@ static int mlxsw_i2c_probe(struct i2c_client *client, + return err; + } + ++ dev_info(&client->dev, "Firmware revision: %d.%d.%d\n", ++ mlxsw_i2c->bus_info.fw_rev.major, ++ mlxsw_i2c->bus_info.fw_rev.minor, ++ mlxsw_i2c->bus_info.fw_rev.subminor); ++ + return 0; + + errout: +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 5a6c445..504db12 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -1,66 +1,354 @@ + // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +-/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */ ++/* Copyright (c) 2016-2019 Mellanox Technologies. All rights reserved */ + ++#include ++#include ++#include + #include + #include + #include + #include ++#include + #include + + #include "core.h" ++#include "core_env.h" + #include "i2c.h" + +-static const char mlxsw_minimal_driver_name[] = "mlxsw_minimal"; ++static const char mlxsw_m_driver_name[] = "mlxsw_minimal"; + +-static const struct mlxsw_config_profile mlxsw_minimal_config_profile; ++#define MLXSW_M_FWREV_MINOR 2000 ++#define MLXSW_M_FWREV_SUBMINOR 1886 + +-static struct mlxsw_driver mlxsw_minimal_driver = { +- .kind = mlxsw_minimal_driver_name, +- .priv_size = 1, +- .profile = &mlxsw_minimal_config_profile, ++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; ++}; ++ ++struct mlxsw_m_port { ++ struct net_device *dev; ++ struct mlxsw_m *mlxsw_m; ++ u8 local_port; ++ u8 module; ++}; ++ ++static int mlxsw_m_port_dummy_open_stop(struct net_device *dev) ++{ ++ return 0; ++} ++ ++static const struct net_device_ops mlxsw_m_port_netdev_ops = { ++ .ndo_open = mlxsw_m_port_dummy_open_stop, ++ .ndo_stop = mlxsw_m_port_dummy_open_stop, ++}; ++ ++static void mlxsw_m_module_get_drvinfo(struct net_device *dev, ++ struct ethtool_drvinfo *drvinfo) ++{ ++ struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev); ++ struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; ++ ++ strlcpy(drvinfo->driver, mlxsw_m->bus_info->device_kind, ++ sizeof(drvinfo->driver)); ++ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), ++ "%d.%d.%d", ++ mlxsw_m->bus_info->fw_rev.major, ++ mlxsw_m->bus_info->fw_rev.minor, ++ mlxsw_m->bus_info->fw_rev.subminor); ++ strlcpy(drvinfo->bus_info, mlxsw_m->bus_info->device_name, ++ sizeof(drvinfo->bus_info)); ++} ++ ++static int mlxsw_m_get_module_info(struct net_device *netdev, ++ struct ethtool_modinfo *modinfo) ++{ ++ 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); ++} ++ ++static int ++mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee, ++ u8 *data) ++{ ++ 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); ++} ++ ++static const struct ethtool_ops mlxsw_m_port_ethtool_ops = { ++ .get_drvinfo = mlxsw_m_module_get_drvinfo, ++ .get_module_info = mlxsw_m_get_module_info, ++ .get_module_eeprom = mlxsw_m_get_module_eeprom, ++}; ++ ++static int ++mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port) ++{ ++ struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; ++ struct net_device *dev = mlxsw_m_port->dev; ++ char ppad_pl[MLXSW_REG_PPAD_LEN]; ++ int err; ++ ++ mlxsw_reg_ppad_pack(ppad_pl, false, 0); ++ err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(ppad), ppad_pl); ++ if (err) ++ return err; ++ mlxsw_reg_ppad_mac_memcpy_from(ppad_pl, dev->dev_addr); ++ /* The last byte value in base mac address is guaranteed ++ * to be such it does not overflow when adding local_port ++ * value. ++ */ ++ dev->dev_addr[ETH_ALEN - 1] = mlxsw_m_port->module + 1; ++ return 0; ++} ++ ++static void mlxsw_m_port_switchdev_init(struct mlxsw_m_port *mlxsw_m_port) ++{ ++} ++ ++static void mlxsw_m_port_switchdev_fini(struct mlxsw_m_port *mlxsw_m_port) ++{ ++} ++ ++static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m) ++{ ++ const struct mlxsw_fw_rev *rev = &mlxsw_m->bus_info->fw_rev; ++ ++ dev_info(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d\n", ++ rev->major, rev->minor, rev->subminor); ++ /* Validate driver & FW are compatible */ ++ if (rev->minor >= MLXSW_M_FWREV_MINOR && ++ rev->subminor >= MLXSW_M_FWREV_SUBMINOR) ++ return 0; ++ ++ dev_info(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n", ++ rev->major, rev->minor, rev->subminor, rev->major, ++ MLXSW_M_FWREV_MINOR, MLXSW_M_FWREV_SUBMINOR); ++ ++ return -EINVAL; ++} ++ ++static int ++mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) ++{ ++ struct mlxsw_m_port *mlxsw_m_port; ++ struct net_device *dev; ++ int err; ++ ++ err = mlxsw_core_port_init(mlxsw_m->core, local_port); ++ if (err) { ++ dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to init core port\n", ++ local_port); ++ return err; ++ } ++ ++ dev = alloc_etherdev(sizeof(struct mlxsw_m_port)); ++ if (!dev) { ++ err = -ENOMEM; ++ goto err_alloc_etherdev; ++ } ++ ++ SET_NETDEV_DEV(dev, mlxsw_m->bus_info->dev); ++ mlxsw_m_port = netdev_priv(dev); ++ mlxsw_m_port->dev = dev; ++ mlxsw_m_port->mlxsw_m = mlxsw_m; ++ mlxsw_m_port->local_port = module; ++ mlxsw_m_port->module = module; ++ ++ dev->netdev_ops = &mlxsw_m_port_netdev_ops; ++ dev->ethtool_ops = &mlxsw_m_port_ethtool_ops; ++ ++ err = mlxsw_m_port_dev_addr_get(mlxsw_m_port); ++ if (err) { ++ dev_err(mlxsw_m->bus_info->dev, "Port %d: Unable to get port mac address\n", ++ mlxsw_m_port->local_port); ++ goto err_dev_addr_get; ++ } ++ ++ netif_carrier_off(dev); ++ mlxsw_m_port_switchdev_init(mlxsw_m_port); ++ mlxsw_m->ports[local_port] = mlxsw_m_port; ++ err = register_netdev(dev); ++ if (err) { ++ dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to register netdev\n", ++ mlxsw_m_port->local_port); ++ goto err_register_netdev; ++ } ++ ++ return 0; ++ ++err_register_netdev: ++ mlxsw_m->ports[local_port] = NULL; ++ mlxsw_m_port_switchdev_fini(mlxsw_m_port); ++ free_netdev(dev); ++err_dev_addr_get: ++err_alloc_etherdev: ++ mlxsw_core_port_fini(mlxsw_m->core, local_port); ++ return err; ++} ++ ++static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 local_port) ++{ ++ struct mlxsw_m_port *mlxsw_m_port = mlxsw_m->ports[local_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; ++ mlxsw_m_port_switchdev_fini(mlxsw_m_port); ++ 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) ++{ ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; ++ int i; ++ int err; ++ ++ mlxsw_reg_mgpir_pack(mgpir_pl); ++ 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); ++ if (!mlxsw_m->max_ports) ++ return 0; ++ ++ mlxsw_m->ports = kcalloc(mlxsw_m->max_ports, sizeof(*mlxsw_m->ports), ++ GFP_KERNEL); ++ if (!mlxsw_m->ports) ++ return -ENOMEM; ++ ++ 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; ++ } ++ ++ /* 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; ++ } ++ ++ 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); ++ return err; ++} ++ ++static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) ++{ ++ 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); ++} ++ ++static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, ++ const struct mlxsw_bus_info *mlxsw_bus_info) ++{ ++ struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); ++ int err; ++ ++ mlxsw_m->core = mlxsw_core; ++ mlxsw_m->bus_info = mlxsw_bus_info; ++ ++ err = mlxsw_m_fw_rev_validate(mlxsw_m); ++ if (err) ++ return err; ++ ++ err = mlxsw_m_ports_create(mlxsw_m); ++ if (err) { ++ dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n"); ++ return err; ++ } ++ ++ return 0; ++} ++ ++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); ++} ++ ++static const struct mlxsw_config_profile mlxsw_m_config_profile; ++ ++static struct mlxsw_driver mlxsw_m_driver = { ++ .kind = mlxsw_m_driver_name, ++ .priv_size = sizeof(struct mlxsw_m), ++ .init = mlxsw_m_init, ++ .fini = mlxsw_m_fini, ++ .profile = &mlxsw_m_config_profile, ++ .res_query_enabled = true, + }; + +-static const struct i2c_device_id mlxsw_minimal_i2c_id[] = { ++static const struct i2c_device_id mlxsw_m_i2c_id[] = { + { "mlxsw_minimal", 0}, + { }, + }; + +-static struct i2c_driver mlxsw_minimal_i2c_driver = { ++static struct i2c_driver mlxsw_m_i2c_driver = { + .driver.name = "mlxsw_minimal", + .class = I2C_CLASS_HWMON, +- .id_table = mlxsw_minimal_i2c_id, ++ .id_table = mlxsw_m_i2c_id, + }; + +-static int __init mlxsw_minimal_module_init(void) ++static int __init mlxsw_m_module_init(void) + { + int err; + +- err = mlxsw_core_driver_register(&mlxsw_minimal_driver); ++ err = mlxsw_core_driver_register(&mlxsw_m_driver); + if (err) + return err; + +- err = mlxsw_i2c_driver_register(&mlxsw_minimal_i2c_driver); ++ err = mlxsw_i2c_driver_register(&mlxsw_m_i2c_driver); + if (err) + goto err_i2c_driver_register; + + return 0; + + err_i2c_driver_register: +- mlxsw_core_driver_unregister(&mlxsw_minimal_driver); ++ mlxsw_core_driver_unregister(&mlxsw_m_driver); + + return err; + } + +-static void __exit mlxsw_minimal_module_exit(void) ++static void __exit mlxsw_m_module_exit(void) + { +- mlxsw_i2c_driver_unregister(&mlxsw_minimal_i2c_driver); +- mlxsw_core_driver_unregister(&mlxsw_minimal_driver); ++ mlxsw_i2c_driver_unregister(&mlxsw_m_i2c_driver); ++ mlxsw_core_driver_unregister(&mlxsw_m_driver); + } + +-module_init(mlxsw_minimal_module_init); +-module_exit(mlxsw_minimal_module_exit); ++module_init(mlxsw_m_module_init); ++module_exit(mlxsw_m_module_exit); + + MODULE_LICENSE("Dual BSD/GPL"); + MODULE_AUTHOR("Vadim Pasternak "); + MODULE_DESCRIPTION("Mellanox minimal driver"); +-MODULE_DEVICE_TABLE(i2c, mlxsw_minimal_i2c_id); ++MODULE_DEVICE_TABLE(i2c, mlxsw_m_i2c_id); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c +index a903e97..b40455f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c +@@ -1039,42 +1039,6 @@ static void mlxsw_pci_aqs_fini(struct mlxsw_pci *mlxsw_pci) + mlxsw_cmd_mbox_config_profile_swid_config_mask_set(mbox, index, mask); + } + +-static int mlxsw_pci_resources_query(struct mlxsw_pci *mlxsw_pci, char *mbox, +- struct mlxsw_res *res) +-{ +- int index, i; +- u64 data; +- u16 id; +- int err; +- +- if (!res) +- return 0; +- +- mlxsw_cmd_mbox_zero(mbox); +- +- for (index = 0; index < MLXSW_CMD_QUERY_RESOURCES_MAX_QUERIES; +- index++) { +- err = mlxsw_cmd_query_resources(mlxsw_pci->core, mbox, index); +- if (err) +- return err; +- +- for (i = 0; i < MLXSW_CMD_QUERY_RESOURCES_PER_QUERY; i++) { +- id = mlxsw_cmd_mbox_query_resource_id_get(mbox, i); +- data = mlxsw_cmd_mbox_query_resource_data_get(mbox, i); +- +- if (id == MLXSW_CMD_QUERY_RESOURCES_TABLE_END_ID) +- return 0; +- +- mlxsw_res_parse(res, id, data); +- } +- } +- +- /* If after MLXSW_RESOURCES_QUERY_MAX_QUERIES we still didn't get +- * MLXSW_RESOURCES_TABLE_END_ID, something went bad in the FW. +- */ +- return -EIO; +-} +- + static int + mlxsw_pci_profile_get_kvd_sizes(const struct mlxsw_pci *mlxsw_pci, + const struct mlxsw_config_profile *profile, +@@ -1459,7 +1423,7 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, + if (err) + goto err_boardinfo; + +- err = mlxsw_pci_resources_query(mlxsw_pci, mbox, res); ++ err = mlxsw_core_resources_query(mlxsw_core, mbox, res); + if (err) + goto err_query_resources; + +@@ -1722,7 +1686,6 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + { + const char *driver_name = pdev->driver->name; + struct mlxsw_pci *mlxsw_pci; +- bool called_again = false; + int err; + + mlxsw_pci = kzalloc(sizeof(*mlxsw_pci), GFP_KERNEL); +@@ -1779,18 +1742,10 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) + mlxsw_pci->bus_info.dev = &pdev->dev; + mlxsw_pci->id = id; + +-again: + err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info, + &mlxsw_pci_bus, mlxsw_pci, false, + NULL); +- /* -EAGAIN is returned in case the FW was updated. FW needs +- * a reset, so lets try to call mlxsw_core_bus_device_register() +- * again. +- */ +- if (err == -EAGAIN && !called_again) { +- called_again = true; +- goto again; +- } else if (err) { ++ if (err) { + dev_err(&pdev->dev, "cannot register bus device\n"); + goto err_bus_device_register; + } +diff --git a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c +new file mode 100644 +index 0000000..49563a7 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c +@@ -0,0 +1,454 @@ ++/* ++ * drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c ++ * Copyright (c) 2017 Mellanox Technologies. All rights reserved. ++ * Copyright (c) 2017 Vadim Pasternak ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. 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. ++ * 3. Neither the names of the copyright holders nor the names of its ++ * contributors may be used to endorse or promote products derived from ++ * this software without specific prior written permission. ++ * ++ * Alternatively, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") version 2 as published by the Free ++ * Software Foundation. ++ * ++ * 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 "core.h" ++ ++#define MLXSW_QSFP_I2C_ADDR 0x50 ++#define MLXSW_QSFP_PAGE_NUM 5 ++#define MLXSW_QSFP_PAGE_SIZE 128 ++#define MLXSW_QSFP_SUB_PAGE_NUM 3 ++#define MLXSW_QSFP_SUB_PAGE_SIZE 48 ++#define MLXSW_QSFP_LAST_SUB_PAGE_SIZE 32 ++#define MLXSW_QSFP_MAX_NUM 128 ++#define MLXSW_QSFP_MIN_REQ_LEN 4 ++#define MLXSW_QSFP_STATUS_VALID_TIME (HZ) ++#define MLXSW_QSFP_MAX_CPLD_NUM 3 ++#define MLXSW_QSFP_MIN_CPLD_NUM 1 ++ ++static const u8 mlxsw_qsfp_page_number[] = { 0xa0, 0x00, 0x01, 0x02, 0x03 }; ++static const u16 mlxsw_qsfp_page_shift[] = { 0x00, 0x80, 0x80, 0x80, 0x80 }; ++ ++/** ++ * Mellanox device Management Cable Info Access Register buffer for reading ++ * QSFP EEPROM info is limited by 48 bytes. In case full page is to be read ++ * (128 bytes), such request will be implemented by three transactions of size ++ * 48, 48, 32. ++ */ ++static const u16 mlxsw_qsfp_sub_page_size[] = { ++ MLXSW_QSFP_SUB_PAGE_SIZE, ++ MLXSW_QSFP_SUB_PAGE_SIZE, ++ MLXSW_QSFP_LAST_SUB_PAGE_SIZE ++}; ++ ++struct mlxsw_qsfp_module { ++ unsigned long last_updated; ++ u8 cache_status; ++}; ++ ++struct mlxsw_qsfp { ++ struct mlxsw_core *core; ++ const struct mlxsw_bus_info *bus_info; ++ struct attribute *attrs[MLXSW_QSFP_MAX_NUM + 1]; ++ struct device_attribute *dev_attrs; ++ struct bin_attribute *eeprom; ++ struct bin_attribute **eeprom_attr_list; ++ struct mlxsw_qsfp_module modules[MLXSW_QSFP_MAX_NUM]; ++ u8 module_ind[MLXSW_QSFP_MAX_NUM]; ++ u8 module_count; ++ struct attribute *cpld_attrs[MLXSW_QSFP_MAX_CPLD_NUM + 1]; ++ struct device_attribute *cpld_dev_attrs; ++}; ++ ++static int mlxsw_qsfp_cpld_num = MLXSW_QSFP_MIN_CPLD_NUM; ++static int mlxsw_qsfp_num = MLXSW_QSFP_MAX_NUM / 2; ++ ++static int ++mlxsw_qsfp_query_module_eeprom(struct mlxsw_qsfp *mlxsw_qsfp, u8 index, ++ loff_t off, size_t count, int page, char *buf) ++{ ++ char eeprom_tmp[MLXSW_QSFP_PAGE_SIZE]; ++ char mcia_pl[MLXSW_REG_MCIA_LEN]; ++ int status; ++ int err; ++ ++ mlxsw_reg_mcia_pack(mcia_pl, index, 0, page, off, count, ++ MLXSW_QSFP_I2C_ADDR); ++ ++ err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(mcia), mcia_pl); ++ if (err) ++ return err; ++ ++ status = mlxsw_reg_mcia_status_get(mcia_pl); ++ if (status) ++ return -EIO; ++ ++ mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp); ++ memcpy(buf, eeprom_tmp, count); ++ ++ return 0; ++} ++ ++static int ++mlxsw_qsfp_get_module_eeprom(struct mlxsw_qsfp *mlxsw_qsfp, u8 index, ++ char *buf, loff_t off, size_t count) ++{ ++ int page_ind, page, page_off, subpage, offset, size, res = 0; ++ int err; ++ ++ if (!count) ++ return -EINVAL; ++ ++ memset(buf, 0, count); ++ size = count; ++ while (res < count) { ++ page_ind = off / MLXSW_QSFP_PAGE_SIZE; ++ page_off = off % MLXSW_QSFP_PAGE_SIZE; ++ page = mlxsw_qsfp_page_number[page_ind]; ++ offset = mlxsw_qsfp_page_shift[page_ind] + page_off; ++ subpage = page_off / MLXSW_QSFP_SUB_PAGE_SIZE; ++ size = min_t(u16, size, mlxsw_qsfp_sub_page_size[subpage]); ++ err = mlxsw_qsfp_query_module_eeprom(mlxsw_qsfp, index, offset, ++ size, page, buf + res); ++ if (err) { ++ dev_err(mlxsw_qsfp->bus_info->dev, "Eeprom query failed\n"); ++ return err; ++ } ++ off += size; ++ res += size; ++ size = count - size; ++ } ++ ++ return res; ++} ++ ++static ssize_t mlxsw_qsfp_bin_read(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *attr, char *buf, ++ loff_t off, size_t count) ++{ ++ struct mlxsw_qsfp *mlxsw_qsfp = dev_get_platdata(container_of(kobj, ++ struct device, kobj)); ++ u8 *module_ind = attr->private; ++ size_t size; ++ ++ size = mlxsw_qsfp->eeprom[*module_ind].size; ++ ++ if (off > size) ++ return -ESPIPE; ++ else if (off == size) ++ return 0; ++ else if ((off + count) > size) ++ count = size - off; ++ ++ return mlxsw_qsfp_get_module_eeprom(mlxsw_qsfp, *module_ind, buf, off, ++ count); ++} ++ ++static ssize_t ++mlxsw_qsfp_status_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct mlxsw_qsfp *mlxsw_qsfp = dev_get_platdata(dev); ++ char mcia_pl[MLXSW_REG_MCIA_LEN]; ++ int status; ++ u32 i; ++ int err; ++ ++ for (i = 0; i < mlxsw_qsfp->module_count; i++) { ++ if ((mlxsw_qsfp->dev_attrs + i) == attr) ++ break; ++ } ++ if (i == mlxsw_qsfp->module_count) ++ return -EINVAL; ++ ++ if (time_before(jiffies, mlxsw_qsfp->modules[i].last_updated + ++ MLXSW_QSFP_STATUS_VALID_TIME)) ++ return sprintf(buf, "%u\n", ++ mlxsw_qsfp->modules[i].cache_status); ++ ++ mlxsw_reg_mcia_pack(mcia_pl, i, 0, 0, 0, MLXSW_QSFP_MIN_REQ_LEN, ++ MLXSW_QSFP_I2C_ADDR); ++ err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(mcia), mcia_pl); ++ if (err) ++ return err; ++ ++ status = mlxsw_reg_mcia_status_get(mcia_pl); ++ mlxsw_qsfp->modules[i].cache_status = !status; ++ mlxsw_qsfp->modules[i].last_updated = jiffies; ++ ++ return sprintf(buf, "%u\n", !status); ++} ++ ++static ssize_t ++mlxsw_qsfp_cpld_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct mlxsw_qsfp *mlxsw_qsfp = dev_get_platdata(dev); ++ char msci_pl[MLXSW_REG_MSCI_LEN]; ++ u32 version, i; ++ int err; ++ ++ for (i = 0; i < mlxsw_qsfp_cpld_num; i++) { ++ if ((mlxsw_qsfp->cpld_dev_attrs + i) == attr) ++ break; ++ } ++ if (i == mlxsw_qsfp_cpld_num) ++ return -EINVAL; ++ ++ mlxsw_reg_msci_pack(msci_pl, i); ++ err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(msci), msci_pl); ++ if (err) ++ return err; ++ ++ version = mlxsw_reg_msci_version_get(msci_pl); ++ ++ return sprintf(buf, "%u\n", version); ++} ++ ++static int mlxsw_qsfp_dmi_set_cpld_num(const struct dmi_system_id *dmi) ++{ ++ mlxsw_qsfp_cpld_num = MLXSW_QSFP_MAX_CPLD_NUM; ++ ++ return 1; ++}; ++ ++static int mlxsw_qsfp_dmi_set_qsfp_num(const struct dmi_system_id *dmi) ++{ ++ mlxsw_qsfp_num = MLXSW_QSFP_MAX_NUM; ++ ++ return 1; ++}; ++ ++static const struct dmi_system_id mlxsw_qsfp_dmi_table[] = { ++ { ++ .callback = mlxsw_qsfp_dmi_set_cpld_num, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"), ++ }, ++ }, ++ { ++ .callback = mlxsw_qsfp_dmi_set_cpld_num, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"), ++ }, ++ }, ++ { ++ .callback = mlxsw_qsfp_dmi_set_qsfp_num, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MSN37"), ++ }, ++ }, ++ { ++ .callback = mlxsw_qsfp_dmi_set_qsfp_num, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MSN38"), ++ }, ++ }, ++ { } ++}; ++MODULE_DEVICE_TABLE(dmi, mlxsw_qsfp_dmi_table); ++ ++static int mlxsw_qsfp_set_module_num(struct mlxsw_qsfp *mlxsw_qsfp) ++{ ++ char pmlp_pl[MLXSW_REG_PMLP_LEN]; ++ u8 width; ++ int i, err; ++ ++ for (i = 1; i <= mlxsw_qsfp_num; i++) { ++ mlxsw_reg_pmlp_pack(pmlp_pl, i); ++ err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(pmlp), ++ pmlp_pl); ++ if (err) ++ return err; ++ width = mlxsw_reg_pmlp_width_get(pmlp_pl); ++ if (!width) ++ continue; ++ mlxsw_qsfp->module_count++; ++ } ++ ++ return 0; ++} ++ ++int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, ++ const struct mlxsw_bus_info *mlxsw_bus_info, ++ struct mlxsw_qsfp **p_qsfp) ++{ ++ struct device_attribute *dev_attr, *cpld_dev_attr; ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; ++ struct mlxsw_qsfp *mlxsw_qsfp; ++ struct bin_attribute *eeprom; ++ int i, count; ++ int err; ++ ++ if (!strcmp(mlxsw_bus_info->device_kind, "i2c")) ++ return 0; ++ ++ dmi_check_system(mlxsw_qsfp_dmi_table); ++ ++ mlxsw_qsfp = devm_kzalloc(mlxsw_bus_info->dev, sizeof(*mlxsw_qsfp), ++ GFP_KERNEL); ++ if (!mlxsw_qsfp) ++ return -ENOMEM; ++ ++ mlxsw_qsfp->core = mlxsw_core; ++ mlxsw_qsfp->bus_info = mlxsw_bus_info; ++ mlxsw_bus_info->dev->platform_data = mlxsw_qsfp; ++ ++ mlxsw_reg_mgpir_pack(mgpir_pl); ++ err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(mgpir), mgpir_pl); ++ if (err) { ++ err = mlxsw_qsfp_set_module_num(mlxsw_qsfp); ++ if (err) ++ return err; ++ } else { ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, ++ &mlxsw_qsfp->module_count); ++ if (!mlxsw_qsfp->module_count) ++ return 0; ++ } ++ ++ count = mlxsw_qsfp->module_count + 1; ++ mlxsw_qsfp->eeprom = devm_kzalloc(mlxsw_bus_info->dev, ++ mlxsw_qsfp->module_count * ++ sizeof(*mlxsw_qsfp->eeprom), ++ GFP_KERNEL); ++ if (!mlxsw_qsfp->eeprom) ++ return -ENOMEM; ++ ++ mlxsw_qsfp->eeprom_attr_list = devm_kzalloc(mlxsw_bus_info->dev, ++ count * ++ sizeof(mlxsw_qsfp->eeprom), ++ GFP_KERNEL); ++ if (!mlxsw_qsfp->eeprom_attr_list) ++ return -ENOMEM; ++ ++ mlxsw_qsfp->dev_attrs = devm_kzalloc(mlxsw_bus_info->dev, count * ++ sizeof(*mlxsw_qsfp->dev_attrs), ++ GFP_KERNEL); ++ if (!mlxsw_qsfp->dev_attrs) ++ return -ENOMEM; ++ ++ mlxsw_qsfp->cpld_dev_attrs = devm_kzalloc(mlxsw_bus_info->dev, ++ mlxsw_qsfp_cpld_num * ++ sizeof(*mlxsw_qsfp->cpld_dev_attrs), ++ GFP_KERNEL); ++ if (!mlxsw_qsfp->cpld_dev_attrs) ++ return -ENOMEM; ++ ++ eeprom = mlxsw_qsfp->eeprom; ++ dev_attr = mlxsw_qsfp->dev_attrs; ++ for (i = 0; i < mlxsw_qsfp->module_count; i++, eeprom++, dev_attr++) { ++ dev_attr->show = mlxsw_qsfp_status_show; ++ dev_attr->attr.mode = 0444; ++ dev_attr->attr.name = devm_kasprintf(mlxsw_bus_info->dev, ++ GFP_KERNEL, ++ "qsfp%d_status", i + 1); ++ mlxsw_qsfp->attrs[i] = &dev_attr->attr; ++ sysfs_attr_init(&dev_attr->attr); ++ err = sysfs_create_file(&mlxsw_bus_info->dev->kobj, ++ mlxsw_qsfp->attrs[i]); ++ if (err) ++ goto err_create_file; ++ ++ sysfs_bin_attr_init(eeprom); ++ eeprom->attr.name = devm_kasprintf(mlxsw_bus_info->dev, ++ GFP_KERNEL, "qsfp%d", ++ i + 1); ++ eeprom->attr.mode = 0444; ++ eeprom->read = mlxsw_qsfp_bin_read; ++ eeprom->size = MLXSW_QSFP_PAGE_NUM * MLXSW_QSFP_PAGE_SIZE; ++ mlxsw_qsfp->module_ind[i] = i; ++ eeprom->private = &mlxsw_qsfp->module_ind[i]; ++ mlxsw_qsfp->eeprom_attr_list[i] = eeprom; ++ err = sysfs_create_bin_file(&mlxsw_bus_info->dev->kobj, ++ eeprom); ++ if (err) ++ goto err_create_bin_file; ++ } ++ ++ cpld_dev_attr = mlxsw_qsfp->cpld_dev_attrs; ++ for (i = 0; i < mlxsw_qsfp_cpld_num; i++, cpld_dev_attr++) { ++ cpld_dev_attr->show = mlxsw_qsfp_cpld_show; ++ cpld_dev_attr->attr.mode = 0444; ++ cpld_dev_attr->attr.name = devm_kasprintf(mlxsw_bus_info->dev, ++ GFP_KERNEL, ++ "cpld%d_version", i + 1); ++ mlxsw_qsfp->cpld_attrs[i] = &cpld_dev_attr->attr; ++ sysfs_attr_init(&cpld_dev_attr->attr); ++ err = sysfs_create_file(&mlxsw_bus_info->dev->kobj, ++ mlxsw_qsfp->cpld_attrs[i]); ++ if (err) ++ goto err_create_cpld_file; ++ } ++ ++ *p_qsfp = mlxsw_qsfp; ++ ++ return 0; ++ ++err_create_cpld_file: ++ sysfs_remove_file(&mlxsw_bus_info->dev->kobj, ++ mlxsw_qsfp->cpld_attrs[i--]); ++ i = mlxsw_qsfp->module_count; ++err_create_bin_file: ++ sysfs_remove_file(&mlxsw_bus_info->dev->kobj, ++ mlxsw_qsfp->attrs[i--]); ++err_create_file: ++ while (--i > 0) { ++ sysfs_remove_bin_file(&mlxsw_bus_info->dev->kobj, ++ mlxsw_qsfp->eeprom_attr_list[i]); ++ sysfs_remove_file(&mlxsw_bus_info->dev->kobj, ++ mlxsw_qsfp->attrs[i]); ++ } ++ ++ return err; ++} ++ ++void mlxsw_qsfp_fini(struct mlxsw_qsfp *mlxsw_qsfp) ++{ ++ int i; ++ ++ if (!strcmp(mlxsw_qsfp->bus_info->device_kind, "i2c")) ++ return; ++ ++ for (i = mlxsw_qsfp->module_count - 1; i >= 0; i--) { ++ sysfs_remove_bin_file(&mlxsw_qsfp->bus_info->dev->kobj, ++ mlxsw_qsfp->eeprom_attr_list[i]); ++ sysfs_remove_file(&mlxsw_qsfp->bus_info->dev->kobj, ++ mlxsw_qsfp->attrs[i]); ++ } ++} ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Vadim Pasternak "); ++MODULE_DESCRIPTION("Mellanox switch QSFP sysfs driver"); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index aee58b3..7ca9814 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -295,6 +295,7 @@ enum mlxsw_reg_sfd_rec_type { + MLXSW_REG_SFD_REC_TYPE_UNICAST = 0x0, + MLXSW_REG_SFD_REC_TYPE_UNICAST_LAG = 0x1, + MLXSW_REG_SFD_REC_TYPE_MULTICAST = 0x2, ++ MLXSW_REG_SFD_REC_TYPE_UNICAST_TUNNEL = 0xC, + }; + + /* reg_sfd_rec_type +@@ -525,6 +526,61 @@ static inline void mlxsw_reg_sfd_uc_lag_unpack(char *payload, int rec_index, + mlxsw_reg_sfd_mc_mid_set(payload, rec_index, mid); + } + ++/* reg_sfd_uc_tunnel_uip_msb ++ * When protocol is IPv4, the most significant byte of the underlay IPv4 ++ * destination IP. ++ * When protocol is IPv6, reserved. ++ * Access: RW ++ */ ++MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_uip_msb, MLXSW_REG_SFD_BASE_LEN, 24, ++ 8, MLXSW_REG_SFD_REC_LEN, 0x08, false); ++ ++/* reg_sfd_uc_tunnel_fid ++ * Filtering ID. ++ * Access: Index ++ */ ++MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_fid, MLXSW_REG_SFD_BASE_LEN, 0, 16, ++ MLXSW_REG_SFD_REC_LEN, 0x08, false); ++ ++enum mlxsw_reg_sfd_uc_tunnel_protocol { ++ MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV4, ++ MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV6, ++}; ++ ++/* reg_sfd_uc_tunnel_protocol ++ * IP protocol. ++ * Access: RW ++ */ ++MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_protocol, MLXSW_REG_SFD_BASE_LEN, 27, ++ 1, MLXSW_REG_SFD_REC_LEN, 0x0C, false); ++ ++/* reg_sfd_uc_tunnel_uip_lsb ++ * When protocol is IPv4, the least significant bytes of the underlay ++ * IPv4 destination IP. ++ * When protocol is IPv6, pointer to the underlay IPv6 destination IP ++ * which is configured by RIPS. ++ * Access: RW ++ */ ++MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_uip_lsb, MLXSW_REG_SFD_BASE_LEN, 0, ++ 24, MLXSW_REG_SFD_REC_LEN, 0x0C, false); ++ ++static inline void ++mlxsw_reg_sfd_uc_tunnel_pack(char *payload, int rec_index, ++ enum mlxsw_reg_sfd_rec_policy policy, ++ const char *mac, u16 fid, ++ enum mlxsw_reg_sfd_rec_action action, u32 uip, ++ enum mlxsw_reg_sfd_uc_tunnel_protocol proto) ++{ ++ mlxsw_reg_sfd_rec_pack(payload, rec_index, ++ MLXSW_REG_SFD_REC_TYPE_UNICAST_TUNNEL, mac, ++ action); ++ mlxsw_reg_sfd_rec_policy_set(payload, rec_index, policy); ++ mlxsw_reg_sfd_uc_tunnel_uip_msb_set(payload, rec_index, uip >> 24); ++ mlxsw_reg_sfd_uc_tunnel_uip_lsb_set(payload, rec_index, uip); ++ mlxsw_reg_sfd_uc_tunnel_fid_set(payload, rec_index, fid); ++ mlxsw_reg_sfd_uc_tunnel_protocol_set(payload, rec_index, proto); ++} ++ + /* SFN - Switch FDB Notification Register + * ------------------------------------------- + * The switch provides notifications on newly learned FDB entries and +@@ -585,6 +641,10 @@ enum mlxsw_reg_sfn_rec_type { + MLXSW_REG_SFN_REC_TYPE_AGED_OUT_MAC = 0x7, + /* Aged-out MAC address on a LAG port. */ + MLXSW_REG_SFN_REC_TYPE_AGED_OUT_MAC_LAG = 0x8, ++ /* Learned unicast tunnel record. */ ++ MLXSW_REG_SFN_REC_TYPE_LEARNED_UNICAST_TUNNEL = 0xD, ++ /* Aged-out unicast tunnel record. */ ++ MLXSW_REG_SFN_REC_TYPE_AGED_OUT_UNICAST_TUNNEL = 0xE, + }; + + /* reg_sfn_rec_type +@@ -648,6 +708,66 @@ static inline void mlxsw_reg_sfn_mac_lag_unpack(char *payload, int rec_index, + *p_lag_id = mlxsw_reg_sfn_mac_lag_lag_id_get(payload, rec_index); + } + ++/* reg_sfn_uc_tunnel_uip_msb ++ * When protocol is IPv4, the most significant byte of the underlay IPv4 ++ * address of the remote VTEP. ++ * When protocol is IPv6, reserved. ++ * Access: RO ++ */ ++MLXSW_ITEM32_INDEXED(reg, sfn, uc_tunnel_uip_msb, MLXSW_REG_SFN_BASE_LEN, 24, ++ 8, MLXSW_REG_SFN_REC_LEN, 0x08, false); ++ ++enum mlxsw_reg_sfn_uc_tunnel_protocol { ++ MLXSW_REG_SFN_UC_TUNNEL_PROTOCOL_IPV4, ++ MLXSW_REG_SFN_UC_TUNNEL_PROTOCOL_IPV6, ++}; ++ ++/* reg_sfn_uc_tunnel_protocol ++ * IP protocol. ++ * Access: RO ++ */ ++MLXSW_ITEM32_INDEXED(reg, sfn, uc_tunnel_protocol, MLXSW_REG_SFN_BASE_LEN, 27, ++ 1, MLXSW_REG_SFN_REC_LEN, 0x0C, false); ++ ++/* reg_sfn_uc_tunnel_uip_lsb ++ * When protocol is IPv4, the least significant bytes of the underlay ++ * IPv4 address of the remote VTEP. ++ * When protocol is IPv6, ipv6_id to be queried from TNIPSD. ++ * Access: RO ++ */ ++MLXSW_ITEM32_INDEXED(reg, sfn, uc_tunnel_uip_lsb, MLXSW_REG_SFN_BASE_LEN, 0, ++ 24, MLXSW_REG_SFN_REC_LEN, 0x0C, false); ++ ++enum mlxsw_reg_sfn_tunnel_port { ++ MLXSW_REG_SFN_TUNNEL_PORT_NVE, ++ MLXSW_REG_SFN_TUNNEL_PORT_VPLS, ++ MLXSW_REG_SFN_TUNNEL_FLEX_TUNNEL0, ++ MLXSW_REG_SFN_TUNNEL_FLEX_TUNNEL1, ++}; ++ ++/* reg_sfn_uc_tunnel_port ++ * Tunnel port. ++ * Reserved on Spectrum. ++ * Access: RO ++ */ ++MLXSW_ITEM32_INDEXED(reg, sfn, tunnel_port, MLXSW_REG_SFN_BASE_LEN, 0, 4, ++ MLXSW_REG_SFN_REC_LEN, 0x10, false); ++ ++static inline void ++mlxsw_reg_sfn_uc_tunnel_unpack(char *payload, int rec_index, char *mac, ++ u16 *p_fid, u32 *p_uip, ++ enum mlxsw_reg_sfn_uc_tunnel_protocol *p_proto) ++{ ++ u32 uip_msb, uip_lsb; ++ ++ mlxsw_reg_sfn_rec_mac_memcpy_from(payload, rec_index, mac); ++ *p_fid = mlxsw_reg_sfn_mac_fid_get(payload, rec_index); ++ uip_msb = mlxsw_reg_sfn_uc_tunnel_uip_msb_get(payload, rec_index); ++ uip_lsb = mlxsw_reg_sfn_uc_tunnel_uip_lsb_get(payload, rec_index); ++ *p_uip = uip_msb << 24 | uip_lsb; ++ *p_proto = mlxsw_reg_sfn_uc_tunnel_protocol_get(payload, rec_index); ++} ++ + /* SPMS - Switch Port MSTP/RSTP State Register + * ------------------------------------------- + * Configures the spanning tree state of a physical port. +@@ -1069,6 +1189,8 @@ enum mlxsw_reg_sfdf_flush_type { + MLXSW_REG_SFDF_FLUSH_PER_PORT_AND_FID, + MLXSW_REG_SFDF_FLUSH_PER_LAG, + MLXSW_REG_SFDF_FLUSH_PER_LAG_AND_FID, ++ MLXSW_REG_SFDF_FLUSH_PER_NVE, ++ MLXSW_REG_SFDF_FLUSH_PER_NVE_AND_FID, + }; + + /* reg_sfdf_flush_type +@@ -1079,6 +1201,10 @@ enum mlxsw_reg_sfdf_flush_type { + * 3 - All FID dynamic entries pointing to port are flushed. + * 4 - All dynamic entries pointing to LAG are flushed. + * 5 - All FID dynamic entries pointing to LAG are flushed. ++ * 6 - All entries of type "Unicast Tunnel" or "Multicast Tunnel" are ++ * flushed. ++ * 7 - All entries of type "Unicast Tunnel" or "Multicast Tunnel" are ++ * flushed, per FID. + * Access: RW + */ + MLXSW_ITEM32(reg, sfdf, flush_type, 0x04, 28, 4); +@@ -1315,12 +1441,19 @@ enum mlxsw_reg_slcr_type { + */ + MLXSW_ITEM32(reg, slcr, lag_hash, 0x04, 0, 20); + +-static inline void mlxsw_reg_slcr_pack(char *payload, u16 lag_hash) ++/* reg_slcr_seed ++ * LAG seed value. The seed is the same for all ports. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, slcr, seed, 0x08, 0, 32); ++ ++static inline void mlxsw_reg_slcr_pack(char *payload, u16 lag_hash, u32 seed) + { + MLXSW_REG_ZERO(slcr, payload); + mlxsw_reg_slcr_pp_set(payload, MLXSW_REG_SLCR_PP_GLOBAL); + mlxsw_reg_slcr_type_set(payload, MLXSW_REG_SLCR_TYPE_CRC); + mlxsw_reg_slcr_lag_hash_set(payload, lag_hash); ++ mlxsw_reg_slcr_seed_set(payload, seed); + } + + /* SLCOR - Switch LAG Collector Register +@@ -2066,6 +2199,14 @@ static inline void mlxsw_reg_pacl_pack(char *payload, u16 acl_id, + */ + MLXSW_ITEM32(reg, pagt, acl_group_id, 0x08, 0, 16); + ++/* reg_pagt_multi ++ * Multi-ACL ++ * 0 - This ACL is the last ACL in the multi-ACL ++ * 1 - This ACL is part of a multi-ACL ++ * Access: RW ++ */ ++MLXSW_ITEM32_INDEXED(reg, pagt, multi, 0x30, 31, 1, 0x04, 0x00, false); ++ + /* reg_pagt_acl_id + * ACL identifier + * Access: RW +@@ -2079,12 +2220,13 @@ static inline void mlxsw_reg_pagt_pack(char *payload, u16 acl_group_id) + } + + static inline void mlxsw_reg_pagt_acl_id_pack(char *payload, int index, +- u16 acl_id) ++ u16 acl_id, bool multi) + { + u8 size = mlxsw_reg_pagt_size_get(payload); + + if (index >= size) + mlxsw_reg_pagt_size_set(payload, index + 1); ++ mlxsw_reg_pagt_multi_set(payload, index, multi); + mlxsw_reg_pagt_acl_id_set(payload, index, acl_id); + } + +@@ -2362,6 +2504,43 @@ static inline void mlxsw_reg_pefa_unpack(char *payload, bool *p_a) + *p_a = mlxsw_reg_pefa_a_get(payload); + } + ++/* PEMRBT - Policy-Engine Multicast Router Binding Table Register ++ * -------------------------------------------------------------- ++ * This register is used for binding Multicast router to an ACL group ++ * that serves the MC router. ++ * This register is not supported by SwitchX/-2 and Spectrum. ++ */ ++#define MLXSW_REG_PEMRBT_ID 0x3014 ++#define MLXSW_REG_PEMRBT_LEN 0x14 ++ ++MLXSW_REG_DEFINE(pemrbt, MLXSW_REG_PEMRBT_ID, MLXSW_REG_PEMRBT_LEN); ++ ++enum mlxsw_reg_pemrbt_protocol { ++ MLXSW_REG_PEMRBT_PROTO_IPV4, ++ MLXSW_REG_PEMRBT_PROTO_IPV6, ++}; ++ ++/* reg_pemrbt_protocol ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, pemrbt, protocol, 0x00, 0, 1); ++ ++/* reg_pemrbt_group_id ++ * ACL group identifier. ++ * Range 0..cap_max_acl_groups-1 ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, pemrbt, group_id, 0x10, 0, 16); ++ ++static inline void ++mlxsw_reg_pemrbt_pack(char *payload, enum mlxsw_reg_pemrbt_protocol protocol, ++ u16 group_id) ++{ ++ MLXSW_REG_ZERO(pemrbt, payload); ++ mlxsw_reg_pemrbt_protocol_set(payload, protocol); ++ mlxsw_reg_pemrbt_group_id_set(payload, group_id); ++} ++ + /* PTCE-V2 - Policy-Engine TCAM Entry Register Version 2 + * ----------------------------------------------------- + * This register is used for accessing rules within a TCAM region. +@@ -2573,7 +2752,7 @@ static inline void mlxsw_reg_perpt_erp_vector_pack(char *payload, + mlxsw_reg_perpt_erpt_bank_set(payload, erpt_bank); + mlxsw_reg_perpt_erpt_index_set(payload, erpt_index); + mlxsw_reg_perpt_key_size_set(payload, key_size); +- mlxsw_reg_perpt_bf_bypass_set(payload, true); ++ mlxsw_reg_perpt_bf_bypass_set(payload, false); + mlxsw_reg_perpt_erp_id_set(payload, erp_id); + mlxsw_reg_perpt_erpt_base_bank_set(payload, erpt_base_bank); + mlxsw_reg_perpt_erpt_base_index_set(payload, erpt_base_index); +@@ -2765,8 +2944,9 @@ static inline void mlxsw_reg_ptce3_pack(char *payload, bool valid, + u32 priority, + const char *tcam_region_info, + const char *key, u8 erp_id, +- bool large_exists, u32 lkey_id, +- u32 action_pointer) ++ u16 delta_start, u8 delta_mask, ++ u8 delta_value, bool large_exists, ++ u32 lkey_id, u32 action_pointer) + { + MLXSW_REG_ZERO(ptce3, payload); + mlxsw_reg_ptce3_v_set(payload, valid); +@@ -2775,6 +2955,9 @@ static inline void mlxsw_reg_ptce3_pack(char *payload, bool valid, + mlxsw_reg_ptce3_tcam_region_info_memcpy_to(payload, tcam_region_info); + mlxsw_reg_ptce3_flex2_key_blocks_memcpy_to(payload, key); + mlxsw_reg_ptce3_erp_id_set(payload, erp_id); ++ mlxsw_reg_ptce3_delta_start_set(payload, delta_start); ++ mlxsw_reg_ptce3_delta_mask_set(payload, delta_mask); ++ mlxsw_reg_ptce3_delta_value_set(payload, delta_value); + mlxsw_reg_ptce3_large_exists_set(payload, large_exists); + mlxsw_reg_ptce3_large_entry_key_id_set(payload, lkey_id); + mlxsw_reg_ptce3_action_pointer_set(payload, action_pointer); +@@ -2832,7 +3015,7 @@ static inline void mlxsw_reg_percr_pack(char *payload, u16 region_id) + mlxsw_reg_percr_region_id_set(payload, region_id); + mlxsw_reg_percr_atcam_ignore_prune_set(payload, false); + mlxsw_reg_percr_ctcam_ignore_prune_set(payload, false); +- mlxsw_reg_percr_bf_bypass_set(payload, true); ++ mlxsw_reg_percr_bf_bypass_set(payload, false); + } + + /* PERERP - Policy-Engine Region eRP Register +@@ -2921,6 +3104,72 @@ static inline void mlxsw_reg_pererp_pack(char *payload, u16 region_id, + mlxsw_reg_pererp_master_rp_id_set(payload, master_rp_id); + } + ++/* PEABFE - Policy-Engine Algorithmic Bloom Filter Entries Register ++ * ---------------------------------------------------------------- ++ * This register configures the Bloom filter entries. ++ */ ++#define MLXSW_REG_PEABFE_ID 0x3022 ++#define MLXSW_REG_PEABFE_BASE_LEN 0x10 ++#define MLXSW_REG_PEABFE_BF_REC_LEN 0x4 ++#define MLXSW_REG_PEABFE_BF_REC_MAX_COUNT 256 ++#define MLXSW_REG_PEABFE_LEN (MLXSW_REG_PEABFE_BASE_LEN + \ ++ MLXSW_REG_PEABFE_BF_REC_LEN * \ ++ MLXSW_REG_PEABFE_BF_REC_MAX_COUNT) ++ ++MLXSW_REG_DEFINE(peabfe, MLXSW_REG_PEABFE_ID, MLXSW_REG_PEABFE_LEN); ++ ++/* reg_peabfe_size ++ * Number of BF entries to be updated. ++ * Range 1..256 ++ * Access: Op ++ */ ++MLXSW_ITEM32(reg, peabfe, size, 0x00, 0, 9); ++ ++/* reg_peabfe_bf_entry_state ++ * Bloom filter state ++ * 0 - Clear ++ * 1 - Set ++ * Access: RW ++ */ ++MLXSW_ITEM32_INDEXED(reg, peabfe, bf_entry_state, ++ MLXSW_REG_PEABFE_BASE_LEN, 31, 1, ++ MLXSW_REG_PEABFE_BF_REC_LEN, 0x00, false); ++ ++/* reg_peabfe_bf_entry_bank ++ * Bloom filter bank ID ++ * Range 0..cap_max_erp_table_banks-1 ++ * Access: Index ++ */ ++MLXSW_ITEM32_INDEXED(reg, peabfe, bf_entry_bank, ++ MLXSW_REG_PEABFE_BASE_LEN, 24, 4, ++ MLXSW_REG_PEABFE_BF_REC_LEN, 0x00, false); ++ ++/* reg_peabfe_bf_entry_index ++ * Bloom filter entry index ++ * Range 0..2^cap_max_bf_log-1 ++ * Access: Index ++ */ ++MLXSW_ITEM32_INDEXED(reg, peabfe, bf_entry_index, ++ MLXSW_REG_PEABFE_BASE_LEN, 0, 24, ++ MLXSW_REG_PEABFE_BF_REC_LEN, 0x00, false); ++ ++static inline void mlxsw_reg_peabfe_pack(char *payload) ++{ ++ MLXSW_REG_ZERO(peabfe, payload); ++} ++ ++static inline void mlxsw_reg_peabfe_rec_pack(char *payload, int rec_index, ++ u8 state, u8 bank, u32 bf_index) ++{ ++ u8 num_rec = mlxsw_reg_peabfe_size_get(payload); ++ ++ if (rec_index >= num_rec) ++ mlxsw_reg_peabfe_size_set(payload, rec_index + 1); ++ mlxsw_reg_peabfe_bf_entry_state_set(payload, rec_index, state); ++ mlxsw_reg_peabfe_bf_entry_bank_set(payload, rec_index, bank); ++ mlxsw_reg_peabfe_bf_entry_index_set(payload, rec_index, bf_index); ++} ++ + /* IEDR - Infrastructure Entry Delete Register + * ---------------------------------------------------- + * This register is used for deleting entries from the entry tables. +@@ -3215,7 +3464,7 @@ static inline void mlxsw_reg_qtct_pack(char *payload, u8 local_port, + * Configures the ETS elements. + */ + #define MLXSW_REG_QEEC_ID 0x400D +-#define MLXSW_REG_QEEC_LEN 0x1C ++#define MLXSW_REG_QEEC_LEN 0x20 + + MLXSW_REG_DEFINE(qeec, MLXSW_REG_QEEC_ID, MLXSW_REG_QEEC_LEN); + +@@ -3257,6 +3506,15 @@ enum mlxsw_reg_qeec_hr { + */ + MLXSW_ITEM32(reg, qeec, next_element_index, 0x08, 0, 8); + ++/* reg_qeec_mise ++ * Min shaper configuration enable. Enables configuration of the min ++ * shaper on this ETS element ++ * 0 - Disable ++ * 1 - Enable ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, qeec, mise, 0x0C, 31, 1); ++ + enum { + MLXSW_REG_QEEC_BYTES_MODE, + MLXSW_REG_QEEC_PACKETS_MODE, +@@ -3273,6 +3531,17 @@ enum { + */ + MLXSW_ITEM32(reg, qeec, pb, 0x0C, 28, 1); + ++/* The smallest permitted min shaper rate. */ ++#define MLXSW_REG_QEEC_MIS_MIN 200000 /* Kbps */ ++ ++/* reg_qeec_min_shaper_rate ++ * Min shaper information rate. ++ * For CPU port, can only be configured for port hierarchy. ++ * When in bytes mode, value is specified in units of 1000bps. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, qeec, min_shaper_rate, 0x0C, 0, 28); ++ + /* reg_qeec_mase + * Max shaper configuration enable. Enables configuration of the max + * shaper on this ETS element. +@@ -4142,8 +4411,11 @@ static inline void mlxsw_reg_pfcc_pack(char *payload, u8 local_port) + + enum mlxsw_reg_ppcnt_grp { + MLXSW_REG_PPCNT_IEEE_8023_CNT = 0x0, ++ MLXSW_REG_PPCNT_RFC_2863_CNT = 0x1, + MLXSW_REG_PPCNT_RFC_2819_CNT = 0x2, ++ MLXSW_REG_PPCNT_RFC_3635_CNT = 0x3, + MLXSW_REG_PPCNT_EXT_CNT = 0x5, ++ MLXSW_REG_PPCNT_DISCARD_CNT = 0x6, + MLXSW_REG_PPCNT_PRIO_CNT = 0x10, + MLXSW_REG_PPCNT_TC_CNT = 0x11, + MLXSW_REG_PPCNT_TC_CONG_TC = 0x13, +@@ -4158,6 +4430,7 @@ enum mlxsw_reg_ppcnt_grp { + * 0x2: RFC 2819 Counters + * 0x3: RFC 3635 Counters + * 0x5: Ethernet Extended Counters ++ * 0x6: Ethernet Discard Counters + * 0x8: Link Level Retransmission Counters + * 0x10: Per Priority Counters + * 0x11: Per Traffic Class Counters +@@ -4301,8 +4574,46 @@ enum mlxsw_reg_ppcnt_grp { + MLXSW_ITEM64(reg, ppcnt, a_pause_mac_ctrl_frames_transmitted, + MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x90, 0, 64); + ++/* Ethernet RFC 2863 Counter Group */ ++ ++/* reg_ppcnt_if_in_discards ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, if_in_discards, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x10, 0, 64); ++ ++/* reg_ppcnt_if_out_discards ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, if_out_discards, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x38, 0, 64); ++ ++/* reg_ppcnt_if_out_errors ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, if_out_errors, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x40, 0, 64); ++ + /* Ethernet RFC 2819 Counter Group */ + ++/* reg_ppcnt_ether_stats_undersize_pkts ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, ether_stats_undersize_pkts, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x30, 0, 64); ++ ++/* reg_ppcnt_ether_stats_oversize_pkts ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, ether_stats_oversize_pkts, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x38, 0, 64); ++ ++/* reg_ppcnt_ether_stats_fragments ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, ether_stats_fragments, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x40, 0, 64); ++ + /* reg_ppcnt_ether_stats_pkts64octets + * Access: RO + */ +@@ -4363,6 +4674,32 @@ enum mlxsw_reg_ppcnt_grp { + MLXSW_ITEM64(reg, ppcnt, ether_stats_pkts8192to10239octets, + MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0xA0, 0, 64); + ++/* Ethernet RFC 3635 Counter Group */ ++ ++/* reg_ppcnt_dot3stats_fcs_errors ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, dot3stats_fcs_errors, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x08, 0, 64); ++ ++/* reg_ppcnt_dot3stats_symbol_errors ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, dot3stats_symbol_errors, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x60, 0, 64); ++ ++/* reg_ppcnt_dot3control_in_unknown_opcodes ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, dot3control_in_unknown_opcodes, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x68, 0, 64); ++ ++/* reg_ppcnt_dot3in_pause_frames ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, dot3in_pause_frames, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x70, 0, 64); ++ + /* Ethernet Extended Counter Group Counters */ + + /* reg_ppcnt_ecn_marked +@@ -4371,6 +4708,80 @@ enum mlxsw_reg_ppcnt_grp { + MLXSW_ITEM64(reg, ppcnt, ecn_marked, + MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x08, 0, 64); + ++/* Ethernet Discard Counter Group Counters */ ++ ++/* reg_ppcnt_ingress_general ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, ingress_general, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x00, 0, 64); ++ ++/* reg_ppcnt_ingress_policy_engine ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, ingress_policy_engine, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x08, 0, 64); ++ ++/* reg_ppcnt_ingress_vlan_membership ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, ingress_vlan_membership, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x10, 0, 64); ++ ++/* reg_ppcnt_ingress_tag_frame_type ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, ingress_tag_frame_type, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x18, 0, 64); ++ ++/* reg_ppcnt_egress_vlan_membership ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, egress_vlan_membership, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x20, 0, 64); ++ ++/* reg_ppcnt_loopback_filter ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, loopback_filter, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x28, 0, 64); ++ ++/* reg_ppcnt_egress_general ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, egress_general, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x30, 0, 64); ++ ++/* reg_ppcnt_egress_hoq ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, egress_hoq, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x40, 0, 64); ++ ++/* reg_ppcnt_egress_policy_engine ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, egress_policy_engine, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x50, 0, 64); ++ ++/* reg_ppcnt_ingress_tx_link_down ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, ingress_tx_link_down, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x58, 0, 64); ++ ++/* reg_ppcnt_egress_stp_filter ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, egress_stp_filter, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x60, 0, 64); ++ ++/* reg_ppcnt_egress_sll ++ * Access: RO ++ */ ++MLXSW_ITEM64(reg, ppcnt, egress_sll, ++ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x70, 0, 64); ++ + /* Ethernet Per Priority Group Counters */ + + /* reg_ppcnt_rx_octets +@@ -4773,6 +5184,7 @@ enum mlxsw_reg_htgt_trap_group { + MLXSW_REG_HTGT_TRAP_GROUP_SP_EVENT, + MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6_MLD, + MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6_ND, ++ MLXSW_REG_HTGT_TRAP_GROUP_SP_LBERROR, + }; + + /* reg_htgt_trap_group +@@ -5263,6 +5675,8 @@ enum mlxsw_reg_ritr_loopback_protocol { + MLXSW_REG_RITR_LOOPBACK_PROTOCOL_IPIP_IPV4, + /* IPinIP IPv6 underlay Unicast */ + MLXSW_REG_RITR_LOOPBACK_PROTOCOL_IPIP_IPV6, ++ /* IPinIP generic - used for Spectrum-2 underlay RIF */ ++ MLXSW_REG_RITR_LOOPBACK_GENERIC, + }; + + /* reg_ritr_loopback_protocol +@@ -5303,6 +5717,13 @@ enum mlxsw_reg_ritr_loopback_ipip_options { + */ + MLXSW_ITEM32(reg, ritr, loopback_ipip_uvr, 0x10, 0, 16); + ++/* reg_ritr_loopback_ipip_underlay_rif ++ * Underlay ingress router interface. ++ * Reserved for Spectrum. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, ritr, loopback_ipip_underlay_rif, 0x14, 0, 16); ++ + /* reg_ritr_loopback_ipip_usip* + * Encapsulation Underlay source IP. + * Access: RW +@@ -5418,11 +5839,12 @@ static inline void mlxsw_reg_ritr_mac_pack(char *payload, const char *mac) + mlxsw_reg_ritr_loopback_ipip_common_pack(char *payload, + enum mlxsw_reg_ritr_loopback_ipip_type ipip_type, + enum mlxsw_reg_ritr_loopback_ipip_options options, +- u16 uvr_id, u32 gre_key) ++ u16 uvr_id, u16 underlay_rif, u32 gre_key) + { + mlxsw_reg_ritr_loopback_ipip_type_set(payload, ipip_type); + mlxsw_reg_ritr_loopback_ipip_options_set(payload, options); + mlxsw_reg_ritr_loopback_ipip_uvr_set(payload, uvr_id); ++ mlxsw_reg_ritr_loopback_ipip_underlay_rif_set(payload, underlay_rif); + mlxsw_reg_ritr_loopback_ipip_gre_key_set(payload, gre_key); + } + +@@ -5430,12 +5852,12 @@ static inline void mlxsw_reg_ritr_mac_pack(char *payload, const char *mac) + mlxsw_reg_ritr_loopback_ipip4_pack(char *payload, + enum mlxsw_reg_ritr_loopback_ipip_type ipip_type, + enum mlxsw_reg_ritr_loopback_ipip_options options, +- u16 uvr_id, u32 usip, u32 gre_key) ++ u16 uvr_id, u16 underlay_rif, u32 usip, u32 gre_key) + { + mlxsw_reg_ritr_loopback_protocol_set(payload, + MLXSW_REG_RITR_LOOPBACK_PROTOCOL_IPIP_IPV4); + mlxsw_reg_ritr_loopback_ipip_common_pack(payload, ipip_type, options, +- uvr_id, gre_key); ++ uvr_id, underlay_rif, gre_key); + mlxsw_reg_ritr_loopback_ipip_usip4_set(payload, usip); + } + +@@ -6797,6 +7219,13 @@ enum mlxsw_reg_rtdp_type { + */ + MLXSW_ITEM32(reg, rtdp, tunnel_index, 0x00, 0, 24); + ++/* reg_rtdp_egress_router_interface ++ * Underlay egress router interface. ++ * Valid range is from 0 to cap_max_router_interfaces - 1 ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, rtdp, egress_router_interface, 0x40, 0, 16); ++ + /* IPinIP */ + + /* reg_rtdp_ipip_irif +@@ -7446,6 +7875,35 @@ static inline void mlxsw_reg_mfsl_unpack(char *payload, u8 tacho, + *p_tach_max = mlxsw_reg_mfsl_tach_max_get(payload); + } + ++/* FORE - Fan Out of Range Event Register ++ * -------------------------------------- ++ * This register reports the status of the controlled fans compared to the ++ * range defined by the MFSL register. ++ */ ++#define MLXSW_REG_FORE_ID 0x9007 ++#define MLXSW_REG_FORE_LEN 0x0C ++ ++MLXSW_REG_DEFINE(fore, MLXSW_REG_FORE_ID, MLXSW_REG_FORE_LEN); ++ ++/* fan_under_limit ++ * Fan speed is below the low limit defined in MFSL register. Each bit relates ++ * to a single tachometer and indicates the specific tachometer reading is ++ * below the threshold. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, fore, fan_under_limit, 0x00, 16, 10); ++ ++static inline void mlxsw_reg_fore_unpack(char *payload, u8 tacho, ++ bool *fault) ++{ ++ u16 limit; ++ ++ if (fault) { ++ limit = mlxsw_reg_fore_fan_under_limit_get(payload); ++ *fault = limit & BIT(tacho); ++ } ++} ++ + /* MTCAP - Management Temperature Capabilities + * ------------------------------------------- + * This register exposes the capabilities of the device and +@@ -7474,16 +7932,21 @@ static inline void mlxsw_reg_mfsl_unpack(char *payload, u8 tacho, + + MLXSW_REG_DEFINE(mtmp, MLXSW_REG_MTMP_ID, MLXSW_REG_MTMP_LEN); + ++#define MLXSW_REG_MTMP_MODULE_INDEX_MIN 64 ++#define MLXSW_REG_MTMP_GBOX_INDEX_MIN 256 + /* reg_mtmp_sensor_index + * Sensors index to access. + * 64-127 of sensor_index are mapped to the SFP+/QSFP modules sequentially + * (module 0 is mapped to sensor_index 64). + * Access: Index + */ +-MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 7); ++MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 12); + + /* Convert to milli degrees Celsius */ +-#define MLXSW_REG_MTMP_TEMP_TO_MC(val) (val * 125) ++#define MLXSW_REG_MTMP_TEMP_TO_MC(val) ({ typeof(val) v_ = (val); \ ++ ((v_) >= 0) ? ((v_) * 125) : \ ++ ((s16)((GENMASK(15, 0) + (v_) + 1) \ ++ * 125)); }) + + /* reg_mtmp_temperature + * Temperature reading from the sensor. Reading is in 0.125 Celsius +@@ -7542,7 +8005,7 @@ static inline void mlxsw_reg_mfsl_unpack(char *payload, u8 tacho, + */ + MLXSW_ITEM_BUF(reg, mtmp, sensor_name, 0x18, MLXSW_REG_MTMP_SENSOR_NAME_SIZE); + +-static inline void mlxsw_reg_mtmp_pack(char *payload, u8 sensor_index, ++static inline void mlxsw_reg_mtmp_pack(char *payload, u16 sensor_index, + bool max_temp_enable, + bool max_temp_reset) + { +@@ -7554,11 +8017,10 @@ static inline void mlxsw_reg_mtmp_pack(char *payload, u8 sensor_index, + MLXSW_REG_MTMP_THRESH_HI); + } + +-static inline void mlxsw_reg_mtmp_unpack(char *payload, unsigned int *p_temp, +- unsigned int *p_max_temp, +- char *sensor_name) ++static inline void mlxsw_reg_mtmp_unpack(char *payload, int *p_temp, ++ int *p_max_temp, char *sensor_name) + { +- u16 temp; ++ s16 temp; + + if (p_temp) { + temp = mlxsw_reg_mtmp_temperature_get(payload); +@@ -7572,6 +8034,80 @@ static inline void mlxsw_reg_mtmp_unpack(char *payload, unsigned int *p_temp, + mlxsw_reg_mtmp_sensor_name_memcpy_from(payload, sensor_name); + } + ++/* MTBR - Management Temperature Bulk Register ++ * ------------------------------------------- ++ * This register is used for bulk temperature reading. ++ */ ++#define MLXSW_REG_MTBR_ID 0x900F ++#define MLXSW_REG_MTBR_BASE_LEN 0x10 /* base length, without records */ ++#define MLXSW_REG_MTBR_REC_LEN 0x04 /* record length */ ++#define MLXSW_REG_MTBR_REC_MAX_COUNT 47 /* firmware limitation */ ++#define MLXSW_REG_MTBR_LEN (MLXSW_REG_MTBR_BASE_LEN + \ ++ MLXSW_REG_MTBR_REC_LEN * \ ++ MLXSW_REG_MTBR_REC_MAX_COUNT) ++ ++MLXSW_REG_DEFINE(mtbr, MLXSW_REG_MTBR_ID, MLXSW_REG_MTBR_LEN); ++ ++/* 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). ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mtbr, base_sensor_index, 0x00, 0, 12); ++ ++/* reg_mtbr_num_rec ++ * Request: Number of records to read ++ * Response: Number of records read ++ * See above description for more details. ++ * Range 1..255 ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, mtbr, num_rec, 0x04, 0, 8); ++ ++/* reg_mtbr_rec_max_temp ++ * The highest measured temperature from the sensor. ++ * When the bit mte is cleared, the field max_temperature is reserved. ++ * Access: RO ++ */ ++MLXSW_ITEM32_INDEXED(reg, mtbr, rec_max_temp, MLXSW_REG_MTBR_BASE_LEN, 16, ++ 16, MLXSW_REG_MTBR_REC_LEN, 0x00, false); ++ ++/* reg_mtbr_rec_temp ++ * Temperature reading from the sensor. Reading is in 0..125 Celsius ++ * degrees units. ++ * Access: RO ++ */ ++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) ++{ ++ MLXSW_REG_ZERO(mtbr, payload); ++ mlxsw_reg_mtbr_base_sensor_index_set(payload, base_sensor_index); ++ mlxsw_reg_mtbr_num_rec_set(payload, num_rec); ++} ++ ++/* Error codes from temperatute reading */ ++enum mlxsw_reg_mtbr_temp_status { ++ MLXSW_REG_MTBR_NO_CONN = 0x8000, ++ MLXSW_REG_MTBR_NO_TEMP_SENS = 0x8001, ++ MLXSW_REG_MTBR_INDEX_NA = 0x8002, ++ MLXSW_REG_MTBR_BAD_SENS_INFO = 0x8003, ++}; ++ ++/* Base index for reading modules temperature */ ++#define MLXSW_REG_MTBR_BASE_MODULE_INDEX 64 ++ ++static inline void mlxsw_reg_mtbr_temp_unpack(char *payload, int rec_ind, ++ u16 *p_temp, u16 *p_max_temp) ++{ ++ if (p_temp) ++ *p_temp = mlxsw_reg_mtbr_rec_temp_get(payload, rec_ind); ++ if (p_max_temp) ++ *p_max_temp = mlxsw_reg_mtbr_rec_max_temp_get(payload, rec_ind); ++} ++ + /* MCIA - Management Cable Info Access + * ----------------------------------- + * MCIA register is used to access the SFP+ and QSFP connector's EPROM. +@@ -7626,13 +8162,48 @@ static inline void mlxsw_reg_mtmp_unpack(char *payload, unsigned int *p_temp, + */ + MLXSW_ITEM32(reg, mcia, size, 0x08, 0, 16); + +-#define MLXSW_SP_REG_MCIA_EEPROM_SIZE 48 ++#define MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH 256 ++#define MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH 128 ++#define MLXSW_REG_MCIA_EEPROM_SIZE 48 ++#define MLXSW_REG_MCIA_I2C_ADDR_LOW 0x50 ++#define MLXSW_REG_MCIA_I2C_ADDR_HIGH 0x51 ++#define MLXSW_REG_MCIA_PAGE0_LO_OFF 0xa0 ++#define MLXSW_REG_MCIA_TH_ITEM_SIZE 2 ++#define MLXSW_REG_MCIA_TH_PAGE_NUM 3 ++#define MLXSW_REG_MCIA_PAGE0_LO 0 ++#define MLXSW_REG_MCIA_TH_PAGE_OFF 0x80 ++ ++enum mlxsw_reg_mcia_eeprom_module_info_rev_id { ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_UNSPC = 0x00, ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8436 = 0x01, ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636 = 0x03, ++}; ++ ++enum mlxsw_reg_mcia_eeprom_module_info_id { ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP = 0x03, ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP = 0x0C, ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS = 0x0D, ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 = 0x11, ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD = 0x18, ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP_DD = 0x1A, ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS_CMIS = 0x1E, ++}; ++ ++enum mlxsw_reg_mcia_eeprom_module_info { ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID, ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID, ++ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE, ++}; + + /* reg_mcia_eeprom + * Bytes to read/write. + * Access: RW + */ +-MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_SP_REG_MCIA_EEPROM_SIZE); ++MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE); ++ ++#define MLXSW_REG_MCIA_PAGE_GET(off) (((off) - \ ++ 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, +@@ -7968,6 +8539,43 @@ static inline void mlxsw_reg_mlcr_pack(char *payload, u8 local_port, + MLXSW_REG_MLCR_DURATION_MAX : 0); + } + ++/* MSCI - Management System CPLD Information Register ++ * --------------------------------------------------- ++ * This register allows querying for the System CPLD(s) information. ++ */ ++#define MLXSW_REG_MSCI_ID 0x902A ++#define MLXSW_REG_MSCI_LEN 0x10 ++ ++static const struct mlxsw_reg_info mlxsw_reg_msci = { ++ .id = MLXSW_REG_MSCI_ID, ++ .len = MLXSW_REG_MSCI_LEN, ++}; ++ ++/* reg_msci_index ++ * Index to access. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, msci, index, 0x00, 0, 4); ++ ++/* reg_msci_version ++ * CPLD version. ++ * Access: R0 ++ */ ++MLXSW_ITEM32(reg, msci, version, 0x04, 0, 32); ++ ++static inline void ++mlxsw_reg_msci_pack(char *payload, u8 index) ++{ ++ MLXSW_REG_ZERO(msci, payload); ++ mlxsw_reg_msci_index_set(payload, index); ++} ++ ++static inline void ++mlxsw_reg_msci_unpack(char *payload, u16 *p_version) ++{ ++ *p_version = mlxsw_reg_msci_version_get(payload); ++} ++ + /* MCQI - Management Component Query Information + * --------------------------------------------- + * This register allows querying information about firmware components. +@@ -8279,6 +8887,567 @@ static inline void mlxsw_reg_mgpc_pack(char *payload, u32 counter_index, + mlxsw_reg_mgpc_opcode_set(payload, opcode); + } + ++/* MPRS - Monitoring Parsing State Register ++ * ---------------------------------------- ++ * The MPRS register is used for setting up the parsing for hash, ++ * policy-engine and routing. ++ */ ++#define MLXSW_REG_MPRS_ID 0x9083 ++#define MLXSW_REG_MPRS_LEN 0x14 ++ ++MLXSW_REG_DEFINE(mprs, MLXSW_REG_MPRS_ID, MLXSW_REG_MPRS_LEN); ++ ++/* reg_mprs_parsing_depth ++ * Minimum parsing depth. ++ * Need to enlarge parsing depth according to L3, MPLS, tunnels, ACL ++ * rules, traps, hash, etc. Default is 96 bytes. Reserved when SwitchX-2. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, mprs, parsing_depth, 0x00, 0, 16); ++ ++/* reg_mprs_parsing_en ++ * Parsing enable. ++ * Bit 0 - Enable parsing of NVE of types VxLAN, VxLAN-GPE, GENEVE and ++ * NVGRE. Default is enabled. Reserved when SwitchX-2. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, mprs, parsing_en, 0x04, 0, 16); ++ ++/* reg_mprs_vxlan_udp_dport ++ * VxLAN UDP destination port. ++ * Used for identifying VxLAN packets and for dport field in ++ * encapsulation. Default is 4789. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, mprs, vxlan_udp_dport, 0x10, 0, 16); ++ ++static inline void mlxsw_reg_mprs_pack(char *payload, u16 parsing_depth, ++ u16 vxlan_udp_dport) ++{ ++ MLXSW_REG_ZERO(mprs, payload); ++ mlxsw_reg_mprs_parsing_depth_set(payload, parsing_depth); ++ mlxsw_reg_mprs_parsing_en_set(payload, true); ++ mlxsw_reg_mprs_vxlan_udp_dport_set(payload, vxlan_udp_dport); ++} ++ ++/* MGPIR - Management General Peripheral Information Register ++ * ---------------------------------------------------------- ++ * MGPIR register allows software to query the hardware and ++ * firmware general information of peripheral entities. ++ */ ++#define MLXSW_REG_MGPIR_ID 0x9100 ++#define MLXSW_REG_MGPIR_LEN 0xA0 ++ ++MLXSW_REG_DEFINE(mgpir, MLXSW_REG_MGPIR_ID, MLXSW_REG_MGPIR_LEN); ++ ++enum mlxsw_reg_mgpir_device_type { ++ MLXSW_REG_MGPIR_DEVICE_TYPE_NONE, ++ MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE, ++}; ++ ++/* device_type ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mgpir, device_type, 0x00, 24, 4); ++ ++/* 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 ++ * Number of devices of device_type. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8); ++ ++/* 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) ++{ ++ MLXSW_REG_ZERO(mgpir, payload); ++} ++ ++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) ++{ ++ if (num_of_devices) ++ *num_of_devices = mlxsw_reg_mgpir_num_of_devices_get(payload); ++ if (device_type) ++ *device_type = mlxsw_reg_mgpir_device_type_get(payload); ++ if (devices_per_flash) ++ *devices_per_flash = ++ mlxsw_reg_mgpir_devices_per_flash_get(payload); ++ if (num_of_modules) ++ *num_of_modules = mlxsw_reg_mgpir_num_of_modules_get(payload); ++} ++ ++/* TNGCR - Tunneling NVE General Configuration Register ++ * ---------------------------------------------------- ++ * The TNGCR register is used for setting up the NVE Tunneling configuration. ++ */ ++#define MLXSW_REG_TNGCR_ID 0xA001 ++#define MLXSW_REG_TNGCR_LEN 0x44 ++ ++MLXSW_REG_DEFINE(tngcr, MLXSW_REG_TNGCR_ID, MLXSW_REG_TNGCR_LEN); ++ ++enum mlxsw_reg_tngcr_type { ++ MLXSW_REG_TNGCR_TYPE_VXLAN, ++ MLXSW_REG_TNGCR_TYPE_VXLAN_GPE, ++ MLXSW_REG_TNGCR_TYPE_GENEVE, ++ MLXSW_REG_TNGCR_TYPE_NVGRE, ++}; ++ ++/* reg_tngcr_type ++ * Tunnel type for encapsulation and decapsulation. The types are mutually ++ * exclusive. ++ * Note: For Spectrum the NVE parsing must be enabled in MPRS. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, type, 0x00, 0, 4); ++ ++/* reg_tngcr_nve_valid ++ * The VTEP is valid. Allows adding FDB entries for tunnel encapsulation. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, nve_valid, 0x04, 31, 1); ++ ++/* reg_tngcr_nve_ttl_uc ++ * The TTL for NVE tunnel encapsulation underlay unicast packets. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, nve_ttl_uc, 0x04, 0, 8); ++ ++/* reg_tngcr_nve_ttl_mc ++ * The TTL for NVE tunnel encapsulation underlay multicast packets. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, nve_ttl_mc, 0x08, 0, 8); ++ ++enum { ++ /* Do not copy flow label. Calculate flow label using nve_flh. */ ++ MLXSW_REG_TNGCR_FL_NO_COPY, ++ /* Copy flow label from inner packet if packet is IPv6 and ++ * encapsulation is by IPv6. Otherwise, calculate flow label using ++ * nve_flh. ++ */ ++ MLXSW_REG_TNGCR_FL_COPY, ++}; ++ ++/* reg_tngcr_nve_flc ++ * For NVE tunnel encapsulation: Flow label copy from inner packet. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, nve_flc, 0x0C, 25, 1); ++ ++enum { ++ /* Flow label is static. In Spectrum this means '0'. Spectrum-2 ++ * uses {nve_fl_prefix, nve_fl_suffix}. ++ */ ++ MLXSW_REG_TNGCR_FL_NO_HASH, ++ /* 8 LSBs of the flow label are calculated from ECMP hash of the ++ * inner packet. 12 MSBs are configured by nve_fl_prefix. ++ */ ++ MLXSW_REG_TNGCR_FL_HASH, ++}; ++ ++/* reg_tngcr_nve_flh ++ * NVE flow label hash. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, nve_flh, 0x0C, 24, 1); ++ ++/* reg_tngcr_nve_fl_prefix ++ * NVE flow label prefix. Constant 12 MSBs of the flow label. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, nve_fl_prefix, 0x0C, 8, 12); ++ ++/* reg_tngcr_nve_fl_suffix ++ * NVE flow label suffix. Constant 8 LSBs of the flow label. ++ * Reserved when nve_flh=1 and for Spectrum. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, nve_fl_suffix, 0x0C, 0, 8); ++ ++enum { ++ /* Source UDP port is fixed (default '0') */ ++ MLXSW_REG_TNGCR_UDP_SPORT_NO_HASH, ++ /* Source UDP port is calculated based on hash */ ++ MLXSW_REG_TNGCR_UDP_SPORT_HASH, ++}; ++ ++/* reg_tngcr_nve_udp_sport_type ++ * NVE UDP source port type. ++ * Spectrum uses LAG hash (SLCRv2). Spectrum-2 uses ECMP hash (RECRv2). ++ * When the source UDP port is calculated based on hash, then the 8 LSBs ++ * are calculated from hash the 8 MSBs are configured by ++ * nve_udp_sport_prefix. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, nve_udp_sport_type, 0x10, 24, 1); ++ ++/* reg_tngcr_nve_udp_sport_prefix ++ * NVE UDP source port prefix. Constant 8 MSBs of the UDP source port. ++ * Reserved when NVE type is NVGRE. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, nve_udp_sport_prefix, 0x10, 8, 8); ++ ++/* reg_tngcr_nve_group_size_mc ++ * The amount of sequential linked lists of MC entries. The first linked ++ * list is configured by SFD.underlay_mc_ptr. ++ * Valid values: 1, 2, 4, 8, 16, 32, 64 ++ * The linked list are configured by TNUMT. ++ * The hash is set by LAG hash. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, nve_group_size_mc, 0x18, 0, 8); ++ ++/* reg_tngcr_nve_group_size_flood ++ * The amount of sequential linked lists of flooding entries. The first ++ * linked list is configured by SFMR.nve_tunnel_flood_ptr ++ * Valid values: 1, 2, 4, 8, 16, 32, 64 ++ * The linked list are configured by TNUMT. ++ * The hash is set by LAG hash. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, nve_group_size_flood, 0x1C, 0, 8); ++ ++/* reg_tngcr_learn_enable ++ * During decapsulation, whether to learn from NVE port. ++ * Reserved when Spectrum-2. See TNPC. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, learn_enable, 0x20, 31, 1); ++ ++/* reg_tngcr_underlay_virtual_router ++ * Underlay virtual router. ++ * Reserved when Spectrum-2. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, underlay_virtual_router, 0x20, 0, 16); ++ ++/* reg_tngcr_underlay_rif ++ * Underlay ingress router interface. RIF type should be loopback generic. ++ * Reserved when Spectrum. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, underlay_rif, 0x24, 0, 16); ++ ++/* reg_tngcr_usipv4 ++ * Underlay source IPv4 address of the NVE. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tngcr, usipv4, 0x28, 0, 32); ++ ++/* reg_tngcr_usipv6 ++ * Underlay source IPv6 address of the NVE. For Spectrum, must not be ++ * modified under traffic of NVE tunneling encapsulation. ++ * Access: RW ++ */ ++MLXSW_ITEM_BUF(reg, tngcr, usipv6, 0x30, 16); ++ ++static inline void mlxsw_reg_tngcr_pack(char *payload, ++ enum mlxsw_reg_tngcr_type type, ++ bool valid, u8 ttl) ++{ ++ MLXSW_REG_ZERO(tngcr, payload); ++ mlxsw_reg_tngcr_type_set(payload, type); ++ mlxsw_reg_tngcr_nve_valid_set(payload, valid); ++ mlxsw_reg_tngcr_nve_ttl_uc_set(payload, ttl); ++ mlxsw_reg_tngcr_nve_ttl_mc_set(payload, ttl); ++ mlxsw_reg_tngcr_nve_flc_set(payload, MLXSW_REG_TNGCR_FL_NO_COPY); ++ mlxsw_reg_tngcr_nve_flh_set(payload, 0); ++ mlxsw_reg_tngcr_nve_udp_sport_type_set(payload, ++ MLXSW_REG_TNGCR_UDP_SPORT_HASH); ++ mlxsw_reg_tngcr_nve_udp_sport_prefix_set(payload, 0); ++ mlxsw_reg_tngcr_nve_group_size_mc_set(payload, 1); ++ mlxsw_reg_tngcr_nve_group_size_flood_set(payload, 1); ++} ++ ++/* TNUMT - Tunneling NVE Underlay Multicast Table Register ++ * ------------------------------------------------------- ++ * The TNUMT register is for building the underlay MC table. It is used ++ * for MC, flooding and BC traffic into the NVE tunnel. ++ */ ++#define MLXSW_REG_TNUMT_ID 0xA003 ++#define MLXSW_REG_TNUMT_LEN 0x20 ++ ++MLXSW_REG_DEFINE(tnumt, MLXSW_REG_TNUMT_ID, MLXSW_REG_TNUMT_LEN); ++ ++enum mlxsw_reg_tnumt_record_type { ++ MLXSW_REG_TNUMT_RECORD_TYPE_IPV4, ++ MLXSW_REG_TNUMT_RECORD_TYPE_IPV6, ++ MLXSW_REG_TNUMT_RECORD_TYPE_LABEL, ++}; ++ ++/* reg_tnumt_record_type ++ * Record type. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tnumt, record_type, 0x00, 28, 4); ++ ++enum mlxsw_reg_tnumt_tunnel_port { ++ MLXSW_REG_TNUMT_TUNNEL_PORT_NVE, ++ MLXSW_REG_TNUMT_TUNNEL_PORT_VPLS, ++ MLXSW_REG_TNUMT_TUNNEL_FLEX_TUNNEL0, ++ MLXSW_REG_TNUMT_TUNNEL_FLEX_TUNNEL1, ++}; ++ ++/* reg_tnumt_tunnel_port ++ * Tunnel port. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tnumt, tunnel_port, 0x00, 24, 4); ++ ++/* reg_tnumt_underlay_mc_ptr ++ * Index to the underlay multicast table. ++ * For Spectrum the index is to the KVD linear. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, tnumt, underlay_mc_ptr, 0x00, 0, 24); ++ ++/* reg_tnumt_vnext ++ * The next_underlay_mc_ptr is valid. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tnumt, vnext, 0x04, 31, 1); ++ ++/* reg_tnumt_next_underlay_mc_ptr ++ * The next index to the underlay multicast table. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tnumt, next_underlay_mc_ptr, 0x04, 0, 24); ++ ++/* reg_tnumt_record_size ++ * Number of IP addresses in the record. ++ * Range is 1..cap_max_nve_mc_entries_ipv{4,6} ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tnumt, record_size, 0x08, 0, 3); ++ ++/* reg_tnumt_udip ++ * The underlay IPv4 addresses. udip[i] is reserved if i >= size ++ * Access: RW ++ */ ++MLXSW_ITEM32_INDEXED(reg, tnumt, udip, 0x0C, 0, 32, 0x04, 0x00, false); ++ ++/* reg_tnumt_udip_ptr ++ * The pointer to the underlay IPv6 addresses. udip_ptr[i] is reserved if ++ * i >= size. The IPv6 addresses are configured by RIPS. ++ * Access: RW ++ */ ++MLXSW_ITEM32_INDEXED(reg, tnumt, udip_ptr, 0x0C, 0, 24, 0x04, 0x00, false); ++ ++static inline void mlxsw_reg_tnumt_pack(char *payload, ++ enum mlxsw_reg_tnumt_record_type type, ++ enum mlxsw_reg_tnumt_tunnel_port tport, ++ u32 underlay_mc_ptr, bool vnext, ++ u32 next_underlay_mc_ptr, ++ u8 record_size) ++{ ++ MLXSW_REG_ZERO(tnumt, payload); ++ mlxsw_reg_tnumt_record_type_set(payload, type); ++ mlxsw_reg_tnumt_tunnel_port_set(payload, tport); ++ mlxsw_reg_tnumt_underlay_mc_ptr_set(payload, underlay_mc_ptr); ++ mlxsw_reg_tnumt_vnext_set(payload, vnext); ++ mlxsw_reg_tnumt_next_underlay_mc_ptr_set(payload, next_underlay_mc_ptr); ++ mlxsw_reg_tnumt_record_size_set(payload, record_size); ++} ++ ++/* TNQCR - Tunneling NVE QoS Configuration Register ++ * ------------------------------------------------ ++ * The TNQCR register configures how QoS is set in encapsulation into the ++ * underlay network. ++ */ ++#define MLXSW_REG_TNQCR_ID 0xA010 ++#define MLXSW_REG_TNQCR_LEN 0x0C ++ ++MLXSW_REG_DEFINE(tnqcr, MLXSW_REG_TNQCR_ID, MLXSW_REG_TNQCR_LEN); ++ ++/* reg_tnqcr_enc_set_dscp ++ * For encapsulation: How to set DSCP field: ++ * 0 - Copy the DSCP from the overlay (inner) IP header to the underlay ++ * (outer) IP header. If there is no IP header, use TNQDR.dscp ++ * 1 - Set the DSCP field as TNQDR.dscp ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tnqcr, enc_set_dscp, 0x04, 28, 1); ++ ++static inline void mlxsw_reg_tnqcr_pack(char *payload) ++{ ++ MLXSW_REG_ZERO(tnqcr, payload); ++ mlxsw_reg_tnqcr_enc_set_dscp_set(payload, 0); ++} ++ ++/* TNQDR - Tunneling NVE QoS Default Register ++ * ------------------------------------------ ++ * The TNQDR register configures the default QoS settings for NVE ++ * encapsulation. ++ */ ++#define MLXSW_REG_TNQDR_ID 0xA011 ++#define MLXSW_REG_TNQDR_LEN 0x08 ++ ++MLXSW_REG_DEFINE(tnqdr, MLXSW_REG_TNQDR_ID, MLXSW_REG_TNQDR_LEN); ++ ++/* reg_tnqdr_local_port ++ * Local port number (receive port). CPU port is supported. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, tnqdr, local_port, 0x00, 16, 8); ++ ++/* reg_tnqdr_dscp ++ * For encapsulation, the default DSCP. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tnqdr, dscp, 0x04, 0, 6); ++ ++static inline void mlxsw_reg_tnqdr_pack(char *payload, u8 local_port) ++{ ++ MLXSW_REG_ZERO(tnqdr, payload); ++ mlxsw_reg_tnqdr_local_port_set(payload, local_port); ++ mlxsw_reg_tnqdr_dscp_set(payload, 0); ++} ++ ++/* TNEEM - Tunneling NVE Encapsulation ECN Mapping Register ++ * -------------------------------------------------------- ++ * The TNEEM register maps ECN of the IP header at the ingress to the ++ * encapsulation to the ECN of the underlay network. ++ */ ++#define MLXSW_REG_TNEEM_ID 0xA012 ++#define MLXSW_REG_TNEEM_LEN 0x0C ++ ++MLXSW_REG_DEFINE(tneem, MLXSW_REG_TNEEM_ID, MLXSW_REG_TNEEM_LEN); ++ ++/* reg_tneem_overlay_ecn ++ * ECN of the IP header in the overlay network. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, tneem, overlay_ecn, 0x04, 24, 2); ++ ++/* reg_tneem_underlay_ecn ++ * ECN of the IP header in the underlay network. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tneem, underlay_ecn, 0x04, 16, 2); ++ ++static inline void mlxsw_reg_tneem_pack(char *payload, u8 overlay_ecn, ++ u8 underlay_ecn) ++{ ++ MLXSW_REG_ZERO(tneem, payload); ++ mlxsw_reg_tneem_overlay_ecn_set(payload, overlay_ecn); ++ mlxsw_reg_tneem_underlay_ecn_set(payload, underlay_ecn); ++} ++ ++/* TNDEM - Tunneling NVE Decapsulation ECN Mapping Register ++ * -------------------------------------------------------- ++ * The TNDEM register configures the actions that are done in the ++ * decapsulation. ++ */ ++#define MLXSW_REG_TNDEM_ID 0xA013 ++#define MLXSW_REG_TNDEM_LEN 0x0C ++ ++MLXSW_REG_DEFINE(tndem, MLXSW_REG_TNDEM_ID, MLXSW_REG_TNDEM_LEN); ++ ++/* reg_tndem_underlay_ecn ++ * ECN field of the IP header in the underlay network. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, tndem, underlay_ecn, 0x04, 24, 2); ++ ++/* reg_tndem_overlay_ecn ++ * ECN field of the IP header in the overlay network. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, tndem, overlay_ecn, 0x04, 16, 2); ++ ++/* reg_tndem_eip_ecn ++ * Egress IP ECN. ECN field of the IP header of the packet which goes out ++ * from the decapsulation. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tndem, eip_ecn, 0x04, 8, 2); ++ ++/* reg_tndem_trap_en ++ * Trap enable: ++ * 0 - No trap due to decap ECN ++ * 1 - Trap enable with trap_id ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tndem, trap_en, 0x08, 28, 4); ++ ++/* reg_tndem_trap_id ++ * Trap ID. Either DECAP_ECN0 or DECAP_ECN1. ++ * Reserved when trap_en is '0'. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tndem, trap_id, 0x08, 0, 9); ++ ++static inline void mlxsw_reg_tndem_pack(char *payload, u8 underlay_ecn, ++ u8 overlay_ecn, u8 ecn, bool trap_en, ++ u16 trap_id) ++{ ++ MLXSW_REG_ZERO(tndem, payload); ++ mlxsw_reg_tndem_underlay_ecn_set(payload, underlay_ecn); ++ mlxsw_reg_tndem_overlay_ecn_set(payload, overlay_ecn); ++ mlxsw_reg_tndem_eip_ecn_set(payload, ecn); ++ mlxsw_reg_tndem_trap_en_set(payload, trap_en); ++ mlxsw_reg_tndem_trap_id_set(payload, trap_id); ++} ++ ++/* TNPC - Tunnel Port Configuration Register ++ * ----------------------------------------- ++ * The TNPC register is used for tunnel port configuration. ++ * Reserved when Spectrum. ++ */ ++#define MLXSW_REG_TNPC_ID 0xA020 ++#define MLXSW_REG_TNPC_LEN 0x18 ++ ++MLXSW_REG_DEFINE(tnpc, MLXSW_REG_TNPC_ID, MLXSW_REG_TNPC_LEN); ++ ++enum mlxsw_reg_tnpc_tunnel_port { ++ MLXSW_REG_TNPC_TUNNEL_PORT_NVE, ++ MLXSW_REG_TNPC_TUNNEL_PORT_VPLS, ++ MLXSW_REG_TNPC_TUNNEL_FLEX_TUNNEL0, ++ MLXSW_REG_TNPC_TUNNEL_FLEX_TUNNEL1, ++}; ++ ++/* reg_tnpc_tunnel_port ++ * Tunnel port. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, tnpc, tunnel_port, 0x00, 0, 4); ++ ++/* reg_tnpc_learn_enable_v6 ++ * During IPv6 underlay decapsulation, whether to learn from tunnel port. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tnpc, learn_enable_v6, 0x04, 1, 1); ++ ++/* reg_tnpc_learn_enable_v4 ++ * During IPv4 underlay decapsulation, whether to learn from tunnel port. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, tnpc, learn_enable_v4, 0x04, 0, 1); ++ ++static inline void mlxsw_reg_tnpc_pack(char *payload, ++ enum mlxsw_reg_tnpc_tunnel_port tport, ++ bool learn_enable) ++{ ++ MLXSW_REG_ZERO(tnpc, payload); ++ mlxsw_reg_tnpc_tunnel_port_set(payload, tport); ++ mlxsw_reg_tnpc_learn_enable_v4_set(payload, learn_enable); ++ mlxsw_reg_tnpc_learn_enable_v6_set(payload, learn_enable); ++} ++ + /* TIGCR - Tunneling IPinIP General Configuration Register + * ------------------------------------------------------- + * The TIGCR register is used for setting up the IPinIP Tunnel configuration. +@@ -8336,8 +9505,15 @@ enum mlxsw_reg_sbxx_dir { + */ + MLXSW_ITEM32(reg, sbpr, pool, 0x00, 0, 4); + ++/* reg_sbpr_infi_size ++ * Size is infinite. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, sbpr, infi_size, 0x04, 31, 1); ++ + /* reg_sbpr_size + * Pool size in buffer cells. ++ * Reserved when infi_size = 1. + * Access: RW + */ + MLXSW_ITEM32(reg, sbpr, size, 0x04, 0, 24); +@@ -8355,13 +9531,15 @@ enum mlxsw_reg_sbpr_mode { + + static inline void mlxsw_reg_sbpr_pack(char *payload, u8 pool, + enum mlxsw_reg_sbxx_dir dir, +- enum mlxsw_reg_sbpr_mode mode, u32 size) ++ enum mlxsw_reg_sbpr_mode mode, u32 size, ++ bool infi_size) + { + MLXSW_REG_ZERO(sbpr, payload); + mlxsw_reg_sbpr_pool_set(payload, pool); + mlxsw_reg_sbpr_dir_set(payload, dir); + mlxsw_reg_sbpr_mode_set(payload, mode); + mlxsw_reg_sbpr_size_set(payload, size); ++ mlxsw_reg_sbpr_infi_size_set(payload, infi_size); + } + + /* SBCM - Shared Buffer Class Management Register +@@ -8409,6 +9587,12 @@ static inline void mlxsw_reg_sbpr_pack(char *payload, u8 pool, + #define MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN 1 + #define MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX 14 + ++/* reg_sbcm_infi_max ++ * Max buffer is infinite. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, sbcm, infi_max, 0x1C, 31, 1); ++ + /* reg_sbcm_max_buff + * When the pool associated to the port-pg/tclass is configured to + * static, Maximum buffer size for the limiter configured in cells. +@@ -8418,6 +9602,7 @@ static inline void mlxsw_reg_sbpr_pack(char *payload, u8 pool, + * 0: 0 + * i: (1/128)*2^(i-1), for i=1..14 + * 0xFF: Infinity ++ * Reserved when infi_max = 1. + * Access: RW + */ + MLXSW_ITEM32(reg, sbcm, max_buff, 0x1C, 0, 24); +@@ -8430,7 +9615,8 @@ static inline void mlxsw_reg_sbpr_pack(char *payload, u8 pool, + + static inline void mlxsw_reg_sbcm_pack(char *payload, u8 local_port, u8 pg_buff, + enum mlxsw_reg_sbxx_dir dir, +- u32 min_buff, u32 max_buff, u8 pool) ++ u32 min_buff, u32 max_buff, ++ bool infi_max, u8 pool) + { + MLXSW_REG_ZERO(sbcm, payload); + mlxsw_reg_sbcm_local_port_set(payload, local_port); +@@ -8438,6 +9624,7 @@ static inline void mlxsw_reg_sbcm_pack(char *payload, u8 local_port, u8 pg_buff, + mlxsw_reg_sbcm_dir_set(payload, dir); + mlxsw_reg_sbcm_min_buff_set(payload, min_buff); + mlxsw_reg_sbcm_max_buff_set(payload, max_buff); ++ mlxsw_reg_sbcm_infi_max_set(payload, infi_max); + mlxsw_reg_sbcm_pool_set(payload, pool); + } + +@@ -8748,8 +9935,10 @@ static inline void mlxsw_reg_sbib_pack(char *payload, u8 local_port, + MLXSW_REG(ppbs), + MLXSW_REG(prcr), + MLXSW_REG(pefa), ++ MLXSW_REG(pemrbt), + MLXSW_REG(ptce2), + MLXSW_REG(perpt), ++ MLXSW_REG(peabfe), + MLXSW_REG(perar), + MLXSW_REG(ptce3), + MLXSW_REG(percr), +@@ -8798,18 +9987,30 @@ static inline void mlxsw_reg_sbib_pack(char *payload, u8 local_port, + MLXSW_REG(mfsc), + MLXSW_REG(mfsm), + MLXSW_REG(mfsl), ++ MLXSW_REG(fore), + MLXSW_REG(mtcap), + MLXSW_REG(mtmp), ++ MLXSW_REG(mtbr), + MLXSW_REG(mcia), + MLXSW_REG(mpat), + MLXSW_REG(mpar), + MLXSW_REG(mrsr), + MLXSW_REG(mlcr), ++ MLXSW_REG(msci), + MLXSW_REG(mpsc), + MLXSW_REG(mcqi), + MLXSW_REG(mcc), + MLXSW_REG(mcda), + MLXSW_REG(mgpc), ++ MLXSW_REG(mprs), ++ MLXSW_REG(mgpir), ++ MLXSW_REG(tngcr), ++ MLXSW_REG(tnumt), ++ MLXSW_REG(tnqcr), ++ MLXSW_REG(tnqdr), ++ MLXSW_REG(tneem), ++ MLXSW_REG(tndem), ++ MLXSW_REG(tnpc), + MLXSW_REG(tigcr), + MLXSW_REG(sbpr), + MLXSW_REG(sbcm), +diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h +index 79a31de..b8b3a01 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/resources.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h +@@ -41,11 +41,14 @@ enum mlxsw_res_id { + MLXSW_RES_ID_ACL_ERPT_ENTRIES_4KB, + MLXSW_RES_ID_ACL_ERPT_ENTRIES_8KB, + MLXSW_RES_ID_ACL_ERPT_ENTRIES_12KB, ++ MLXSW_RES_ID_ACL_MAX_BF_LOG, + MLXSW_RES_ID_MAX_CPU_POLICERS, + MLXSW_RES_ID_MAX_VRS, + MLXSW_RES_ID_MAX_RIFS, + MLXSW_RES_ID_MC_ERIF_LIST_ENTRIES, + MLXSW_RES_ID_MAX_LPM_TREES, ++ MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV4, ++ MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV6, + + /* Internal resources. + * Determined by the SW, not queried from the HW. +@@ -91,11 +94,14 @@ enum mlxsw_res_id { + [MLXSW_RES_ID_ACL_ERPT_ENTRIES_4KB] = 0x2951, + [MLXSW_RES_ID_ACL_ERPT_ENTRIES_8KB] = 0x2952, + [MLXSW_RES_ID_ACL_ERPT_ENTRIES_12KB] = 0x2953, ++ [MLXSW_RES_ID_ACL_MAX_BF_LOG] = 0x2960, + [MLXSW_RES_ID_MAX_CPU_POLICERS] = 0x2A13, + [MLXSW_RES_ID_MAX_VRS] = 0x2C01, + [MLXSW_RES_ID_MAX_RIFS] = 0x2C02, + [MLXSW_RES_ID_MC_ERIF_LIST_ENTRIES] = 0x2C10, + [MLXSW_RES_ID_MAX_LPM_TREES] = 0x2C30, ++ [MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV4] = 0x2E02, ++ [MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV6] = 0x2E03, + }; + + struct mlxsw_res { +diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c +index d52c821..77be37a 100644 +--- a/drivers/platform/mellanox/mlxreg-hotplug.c ++++ b/drivers/platform/mellanox/mlxreg-hotplug.c +@@ -496,18 +496,53 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) + { + struct mlxreg_core_hotplug_platform_data *pdata; + struct mlxreg_core_item *item; +- int i, ret; ++ struct mlxreg_core_data *data; ++ u32 regval; ++ int i, j, ret; + + pdata = dev_get_platdata(&priv->pdev->dev); + item = pdata->items; + + for (i = 0; i < pdata->counter; i++, item++) { ++ if (item->capability) { ++ /* ++ * Read group capability register to get actual number ++ * of interrupt capable components and set group mask ++ * accordingly. ++ */ ++ ret = regmap_read(priv->regmap, item->capability, ++ ®val); ++ if (ret) ++ goto out; ++ ++ item->mask = GENMASK((regval & item->mask) - 1, 0); ++ } ++ + /* Clear group presense event. */ + ret = regmap_write(priv->regmap, item->reg + + MLXREG_HOTPLUG_EVENT_OFF, 0); + if (ret) + goto out; + ++ /* ++ * Verify if hardware configuration requires to disable ++ * interrupt capability for some of components. ++ */ ++ data = item->data; ++ for (j = 0; j < item->count; j++, data++) { ++ /* Verify if the attribute has capability register. */ ++ if (data->capability) { ++ /* Read capability register. */ ++ ret = regmap_read(priv->regmap, ++ data->capability, ®val); ++ if (ret) ++ goto out; ++ ++ if (!(regval & data->bit)) ++ item->mask &= ~BIT(j); ++ } ++ } ++ + /* Set group initial status as mask and unmask group event. */ + if (item->inversed) { + item->cache = item->mask; +@@ -621,11 +656,8 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) + priv->irq = pdata->irq; + } else { + priv->irq = platform_get_irq(pdev, 0); +- if (priv->irq < 0) { +- dev_err(&pdev->dev, "Failed to get platform irq: %d\n", +- priv->irq); ++ if (priv->irq < 0) + return priv->irq; +- } + } + + priv->regmap = pdata->regmap; +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 742a0c2..c27548f 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -1,34 +1,9 @@ ++// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 + /* +- * Copyright (c) 2016 Mellanox Technologies. All rights reserved. +- * Copyright (c) 2016 Vadim Pasternak ++ * Mellanox platform driver + * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions are met: +- * +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * 2. 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. +- * 3. Neither the names of the copyright holders nor the names of its +- * contributors may be used to endorse or promote products derived from +- * this software without specific prior written permission. +- * +- * Alternatively, this software may be distributed under the terms of the +- * GNU General Public License ("GPL") version 2 as published by the Free +- * Software Foundation. +- * +- * 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. ++ * Copyright (C) 2016-2018 Mellanox Technologies ++ * Copyright (C) 2016-2018 Vadim Pasternak + */ + + #include +@@ -49,12 +24,19 @@ + #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 + #define MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET 0x00 + #define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET 0x01 ++#define MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET 0x02 ++#define MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET 0x03 + #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_LED1_OFFSET 0x20 + #define MLXPLAT_CPLD_LPC_REG_LED2_OFFSET 0x21 + #define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET 0x22 + #define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET 0x23 + #define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET 0x24 ++#define MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION 0x2a ++#define MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET 0x2b ++#define MLXPLAT_CPLD_LPC_REG_GP0_OFFSET 0x2e + #define MLXPLAT_CPLD_LPC_REG_GP1_OFFSET 0x30 + #define MLXPLAT_CPLD_LPC_REG_WP1_OFFSET 0x31 + #define MLXPLAT_CPLD_LPC_REG_GP2_OFFSET 0x32 +@@ -64,6 +46,10 @@ + #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b + #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_ASIC_HEALTH_OFFSET 0x50 + #define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51 + #define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52 +@@ -76,6 +62,17 @@ + #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 + #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 + #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a ++#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET 0xc7 ++#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET 0xc8 ++#define MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET 0xc9 ++#define MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET 0xcb ++#define MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET 0xcd ++#define MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET 0xce ++#define MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET 0xcf ++#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_UFM_VERSION_OFFSET 0xe2 + #define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3 + #define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4 + #define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5 +@@ -89,9 +86,17 @@ + #define MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET 0xee + #define MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET 0xef + #define MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET 0xf0 ++#define MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET 0xf5 ++#define MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET 0xf6 ++#define MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET 0xf7 ++#define MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET 0xf8 ++#define MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET 0xf9 ++#define MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET 0xfb ++#define MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET 0xfc + #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_PIO_OFFSET 0x10000UL + #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ +@@ -100,6 +105,9 @@ + #define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ + MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \ + 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_PIO_OFFSET) + + /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ + #define MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF 0x04 +@@ -111,20 +119,34 @@ + MLXPLAT_CPLD_AGGR_FAN_MASK_DEF) + #define MLXPLAT_CPLD_AGGR_ASIC_MASK_NG 0x01 + #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04 ++#define MLXPLAT_CPLD_AGGR_MASK_COMEX BIT(0) + #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 ++#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) ++#define MLXPLAT_CPLD_PSU_EXT_MASK GENMASK(3, 0) ++#define MLXPLAT_CPLD_PWR_EXT_MASK GENMASK(3, 0) + #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) + #define MLXPLAT_CPLD_ASIC_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_FAN_NG_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) ++#define MLXPLAT_CPLD_I2C_CAP_BIT 0x04 ++#define MLXPLAT_CPLD_I2C_CAP_MASK GENMASK(5, MLXPLAT_CPLD_I2C_CAP_BIT) ++ ++/* Masks for aggregation for comex carriers */ ++#define MLXPLAT_CPLD_AGGR_MASK_CARRIER BIT(1) ++#define MLXPLAT_CPLD_AGGR_MASK_CARR_DEF (MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF | \ ++ MLXPLAT_CPLD_AGGR_MASK_CARRIER) ++#define MLXPLAT_CPLD_LOW_AGGRCX_MASK 0xc1 + + /* Default I2C parent bus number */ + #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1 + + /* Maximum number of possible physical buses equipped on system */ + #define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16 ++#define MLXPLAT_CPLD_MAX_PHYS_EXT_ADAPTER_NUM 24 + + /* Number of channels in group */ + #define MLXPLAT_CPLD_GRP_CHNL_NUM 8 +@@ -132,19 +154,33 @@ + /* Start channel numbers */ + #define MLXPLAT_CPLD_CH1 2 + #define MLXPLAT_CPLD_CH2 10 ++#define MLXPLAT_CPLD_CH3 18 + + /* Number of LPC attached MUX platform devices */ +-#define MLXPLAT_CPLD_LPC_MUX_DEVS 2 ++#define MLXPLAT_CPLD_LPC_MUX_DEVS 3 + + /* Hotplug devices adapter numbers */ + #define MLXPLAT_CPLD_NR_NONE -1 + #define MLXPLAT_CPLD_PSU_DEFAULT_NR 10 + #define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4 ++#define MLXPLAT_CPLD_PSU_MSNXXXX_NR2 3 + #define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11 + #define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12 + #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13 + #define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14 + ++/* Masks and default values for watchdogs */ ++#define MLXPLAT_CPLD_WD1_CLEAR_MASK GENMASK(7, 1) ++#define MLXPLAT_CPLD_WD2_CLEAR_MASK (GENMASK(7, 0) & ~BIT(1)) ++ ++#define MLXPLAT_CPLD_WD_TYPE1_TO_MASK GENMASK(7, 4) ++#define MLXPLAT_CPLD_WD_TYPE2_TO_MASK 0 ++#define MLXPLAT_CPLD_WD_RESET_ACT_MASK GENMASK(7, 1) ++#define MLXPLAT_CPLD_WD_FAN_ACT_MASK (GENMASK(7, 0) & ~BIT(4)) ++#define MLXPLAT_CPLD_WD_COUNT_ACT_MASK (GENMASK(7, 0) & ~BIT(7)) ++#define MLXPLAT_CPLD_WD_DFLT_TIMEOUT 30 ++#define MLXPLAT_CPLD_WD_MAX_DEVS 2 ++ + /* mlxplat_priv - platform private data + * @pdev_i2c - i2c controller platform device + * @pdev_mux - array of mux platform devices +@@ -152,6 +188,8 @@ + * @pdev_led - led platform devices + * @pdev_io_regs - register access platform devices + * @pdev_fan - FAN platform devices ++ * @pdev_wd - array of watchdog platform devices ++ * @regmap: device register map + */ + struct mlxplat_priv { + struct platform_device *pdev_i2c; +@@ -160,6 +198,8 @@ struct mlxplat_priv { + struct platform_device *pdev_led; + struct platform_device *pdev_io_regs; + struct platform_device *pdev_fan; ++ struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS]; ++ void *regmap; + }; + + /* Regions for LPC I2C controller and LPC base register space */ +@@ -173,6 +213,30 @@ struct mlxplat_priv { + IORESOURCE_IO), + }; + ++/* Platform i2c next generation systems data */ ++static struct mlxreg_core_data mlxplat_mlxcpld_i2c_ng_items_data[] = { ++ { ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, ++ .mask = MLXPLAT_CPLD_I2C_CAP_MASK, ++ .bit = MLXPLAT_CPLD_I2C_CAP_BIT, ++ }, ++}; ++ ++static struct mlxreg_core_item mlxplat_mlxcpld_i2c_ng_items[] = { ++ { ++ .data = mlxplat_mlxcpld_i2c_ng_items_data, ++ }, ++}; ++ ++/* Platform next generation systems i2c data */ ++static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = { ++ .items = mlxplat_mlxcpld_i2c_ng_items, ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, ++ .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET, ++ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_I2C, ++}; ++ + /* Platform default channels */ + static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = { + { +@@ -191,7 +255,33 @@ struct mlxplat_priv { + static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + /* Platform mux data */ +-static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { ++static struct i2c_mux_reg_platform_data mlxplat_default_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, ++ }, ++ { ++ .parent = 1, ++ .base_nr = MLXPLAT_CPLD_CH2, ++ .write_only = 1, ++ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, ++ .reg_size = 1, ++ .idle_in_use = 1, ++ }, ++ ++}; ++ ++/* Platform mux configuration variables */ ++static int mlxplat_max_adap_num; ++static int mlxplat_mux_num; ++static struct i2c_mux_reg_platform_data *mlxplat_mux_data; ++ ++/* Platform extended mux data */ ++static struct i2c_mux_reg_platform_data mlxplat_extended_mux_data[] = { + { + .parent = 1, + .base_nr = MLXPLAT_CPLD_CH1, +@@ -204,6 +294,14 @@ struct mlxplat_priv { + .parent = 1, + .base_nr = MLXPLAT_CPLD_CH2, + .write_only = 1, ++ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG3, ++ .reg_size = 1, ++ .idle_in_use = 1, ++ }, ++ { ++ .parent = 1, ++ .base_nr = MLXPLAT_CPLD_CH3, ++ .write_only = 1, + .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, + .reg_size = 1, + .idle_in_use = 1, +@@ -254,6 +352,22 @@ struct mlxplat_priv { + }, + }; + ++/* Platform hotplug comex carrier system family data */ ++static struct mlxreg_core_data mlxplat_mlxcpld_comex_psu_items_data[] = { ++ { ++ .label = "psu1", ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = BIT(0), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "psu2", ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = BIT(1), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++}; ++ + /* Platform hotplug default data */ + static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = { + { +@@ -368,6 +482,45 @@ struct mlxplat_priv { + }, + }; + ++static struct mlxreg_core_item mlxplat_mlxcpld_comex_items[] = { ++ { ++ .data = mlxplat_mlxcpld_comex_psu_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = MLXPLAT_CPLD_PSU_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_pwr_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = MLXPLAT_CPLD_PWR_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), ++ .inversed = 0, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_fan_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = MLXPLAT_CPLD_FAN_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_fan), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_asic_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_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_data = { + .items = mlxplat_mlxcpld_default_items, +@@ -378,6 +531,16 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, + }; + ++static ++struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_comex_data = { ++ .items = mlxplat_mlxcpld_comex_items, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_comex_items), ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, ++ .mask = MLXPLAT_CPLD_AGGR_MASK_CARR_DEF, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET, ++ .mask_low = MLXPLAT_CPLD_LOW_AGGRCX_MASK, ++}; ++ + static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = { + { + .label = "pwr1", +@@ -575,7 +738,7 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = { + + static + struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = { +- .items = mlxplat_mlxcpld_msn21xx_items, ++ .items = mlxplat_mlxcpld_msn201x_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items), + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, + .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, +@@ -606,36 +769,48 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_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, + }, + }; +@@ -684,7 +859,117 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { + .items = mlxplat_mlxcpld_default_ng_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items), + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, +- .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .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[] = { ++ { ++ .label = "psu1", ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = BIT(0), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "psu2", ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = BIT(1), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "psu3", ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = BIT(2), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "psu4", ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = BIT(3), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++}; ++ ++static struct mlxreg_core_data mlxplat_mlxcpld_ext_pwr_items_data[] = { ++ { ++ .label = "pwr1", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = BIT(0), ++ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[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[1], ++ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, ++ }, ++ { ++ .label = "pwr3", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = BIT(2), ++ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], ++ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR2, ++ }, ++ { ++ .label = "pwr4", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = BIT(3), ++ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], ++ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR2, ++ }, ++}; ++ ++static struct mlxreg_core_item mlxplat_mlxcpld_ext_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_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, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_ext_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, + }; +@@ -838,61 +1123,90 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { + .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, + }, + }; + +@@ -901,61 +1215,135 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data), + }; + +-/* Platform register access default */ +-static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { ++/* Platform led for Comex based 100GbE systems */ ++static struct mlxreg_core_data mlxplat_mlxcpld_comex_100G_led_data[] = { + { +- .label = "cpld1_version", +- .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, +- .bit = GENMASK(7, 0), +- .mode = 0444, ++ .label = "status:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { +- .label = "cpld2_version", +- .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, +- .bit = GENMASK(7, 0), +- .mode = 0444, ++ .label = "status:red", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK + }, + { +- .label = "reset_long_pb", +- .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, +- .mask = GENMASK(7, 0) & ~BIT(0), +- .mode = 0444, ++ .label = "psu:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { +- .label = "reset_short_pb", +- .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, +- .mask = GENMASK(7, 0) & ~BIT(1), +- .mode = 0444, ++ .label = "psu:red", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { +- .label = "reset_aux_pwr_or_ref", +- .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, +- .mask = GENMASK(7, 0) & ~BIT(2), +- .mode = 0444, ++ .label = "fan1:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { +- .label = "reset_main_pwr_fail", +- .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, +- .mask = GENMASK(7, 0) & ~BIT(3), +- .mode = 0444, ++ .label = "fan1:red", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { +- .label = "reset_sw_reset", +- .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, +- .mask = GENMASK(7, 0) & ~BIT(4), +- .mode = 0444, ++ .label = "fan2:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { +- .label = "reset_fw_reset", +- .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, +- .mask = GENMASK(7, 0) & ~BIT(5), +- .mode = 0444, ++ .label = "fan2:red", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { +- .label = "reset_hotswap_or_wd", +- .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, +- .mask = GENMASK(7, 0) & ~BIT(6), +- .mode = 0444, ++ .label = "fan3:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ }, ++ { ++ .label = "fan3:red", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ }, ++ { ++ .label = "fan4:green", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ }, ++ { ++ .label = "fan4:red", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, ++ }, ++ { ++ .label = "uid:blue", ++ .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET, ++ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, ++ }, ++}; ++ ++static struct mlxreg_core_platform_data mlxplat_comex_100G_led_data = { ++ .data = mlxplat_mlxcpld_comex_100G_led_data, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_comex_100G_led_data), ++}; ++ ++/* Platform register access default */ ++static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { ++ { ++ .label = "cpld1_version", ++ .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++ { ++ .label = "cpld2_version", ++ .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_long_pb", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(0), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_short_pb", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(1), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_aux_pwr_or_ref", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(2), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_main_pwr_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(3), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_sw_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(4), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_fw_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_hotswap_or_wd", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0444, + }, + { + .label = "reset_asic_thermal", +@@ -1064,6 +1452,12 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { + .mode = 0444, + }, + { ++ .label = "reset_sff_wd", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0444, ++ }, ++ { + .label = "psu1_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), +@@ -1088,6 +1482,12 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { + .mode = 0200, + }, + { ++ .label = "select_iio", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0644, ++ }, ++ { + .label = "asic_health", + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, +@@ -1101,6 +1501,221 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { + .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_regs_io_data), + }; + ++/* Platform register access for next generation systems families data */ ++static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { ++ { ++ .label = "cpld1_version", ++ .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++ { ++ .label = "cpld2_version", ++ .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++ { ++ .label = "cpld3_version", ++ .reg = MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++ { ++ .label = "cpld4_version", ++ .reg = MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_long_pb", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(0), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_short_pb", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(1), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_aux_pwr_or_ref", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .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, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_swb_wd", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_asic_thermal", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(7), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_comex_pwr_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(3), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_platform", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(4), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_soc", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_comex_wd", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_voltmon_upgrade_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(0), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_system", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(1), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_sw_pwr_off", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(2), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_comex_thermal", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(3), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_reload_bios", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_ac_pwr_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0444, ++ }, ++ { ++ .label = "psu1_on", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(0), ++ .mode = 0200, ++ }, ++ { ++ .label = "psu2_on", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(1), ++ .mode = 0200, ++ }, ++ { ++ .label = "pwr_cycle", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(2), ++ .mode = 0200, ++ }, ++ { ++ .label = "pwr_down", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(3), ++ .mode = 0200, ++ }, ++ { ++ .label = "jtag_enable", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(4), ++ .mode = 0644, ++ }, ++ { ++ .label = "asic_health", ++ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, ++ .mask = MLXPLAT_CPLD_ASIC_MASK, ++ .bit = 1, ++ .mode = 0444, ++ }, ++ { ++ .label = "fan_dir", ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++ { ++ .label = "voltreg_update_status", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET, ++ .mask = MLXPLAT_CPLD_VOLTREG_UPD_MASK, ++ .bit = 5, ++ .mode = 0444, ++ }, ++ { ++ .label = "vpd_wp", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(3), ++ .mode = 0644, ++ }, ++ { ++ .label = "pcie_asic_reset_dis", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(4), ++ .mode = 0644, ++ }, ++ { ++ .label = "config1", ++ .reg = MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++ { ++ .label = "config2", ++ .reg = MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++ { ++ .label = "ufm_version", ++ .reg = MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++}; ++ ++static struct mlxreg_core_platform_data mlxplat_default_ng_regs_io_data = { ++ .data = mlxplat_mlxcpld_default_ng_regs_io_data, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_regs_io_data), ++}; ++ + /* Platform FAN default */ + static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { + { +@@ -1111,61 +1726,89 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { + .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, + }, + }; + +@@ -1174,6 +1817,148 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data), + }; + ++/* Watchdog type1: hardware implementation version1 ++ * (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140 systems). ++ */ ++static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type1[] = { ++ { ++ .label = "action", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK, ++ .bit = 0, ++ }, ++ { ++ .label = "timeout", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK, ++ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, ++ }, ++ { ++ .label = "ping", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET, ++ .mask = MLXPLAT_CPLD_WD1_CLEAR_MASK, ++ .bit = 0, ++ }, ++ { ++ .label = "reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .bit = 6, ++ }, ++}; ++ ++static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type1[] = { ++ { ++ .label = "action", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK, ++ .bit = 4, ++ }, ++ { ++ .label = "timeout", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK, ++ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, ++ }, ++ { ++ .label = "ping", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET, ++ .mask = MLXPLAT_CPLD_WD1_CLEAR_MASK, ++ .bit = 1, ++ }, ++}; ++ ++static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type1[] = { ++ { ++ .data = mlxplat_mlxcpld_wd_main_regs_type1, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type1), ++ .version = MLX_WDT_TYPE1, ++ .identity = "mlx-wdt-main", ++ }, ++ { ++ .data = mlxplat_mlxcpld_wd_aux_regs_type1, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type1), ++ .version = MLX_WDT_TYPE1, ++ .identity = "mlx-wdt-aux", ++ }, ++}; ++ ++/* Watchdog type2: hardware implementation version 2 ++ * (all systems except (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140). ++ */ ++static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type2[] = { ++ { ++ .label = "action", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK, ++ .bit = 0, ++ }, ++ { ++ .label = "timeout", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, ++ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, ++ }, ++ { ++ .label = "timeleft", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, ++ }, ++ { ++ .label = "ping", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK, ++ .bit = 0, ++ }, ++ { ++ .label = "reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .bit = 6, ++ }, ++}; ++ ++static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type2[] = { ++ { ++ .label = "action", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK, ++ .bit = 4, ++ }, ++ { ++ .label = "timeout", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, ++ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, ++ }, ++ { ++ .label = "timeleft", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, ++ }, ++ { ++ .label = "ping", ++ .reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, ++ .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK, ++ .bit = 4, ++ }, ++}; ++ ++static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type2[] = { ++ { ++ .data = mlxplat_mlxcpld_wd_main_regs_type2, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type2), ++ .version = MLX_WDT_TYPE2, ++ .identity = "mlx-wdt-main", ++ }, ++ { ++ .data = mlxplat_mlxcpld_wd_aux_regs_type2, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type2), ++ .version = MLX_WDT_TYPE2, ++ .identity = "mlx-wdt-aux", ++ }, ++}; ++ + static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + { + switch (reg) { +@@ -1182,12 +1967,15 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_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_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: +@@ -1196,6 +1984,14 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: + return true; +@@ -1208,12 +2004,19 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + switch (reg) { + case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: ++ 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_LED2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION: ++ case MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: +@@ -1222,6 +2025,10 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRCX_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: +@@ -1234,6 +2041,16 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET: ++ 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_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: +@@ -1248,6 +2065,14 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET: + return true; + } + return false; +@@ -1258,18 +2083,29 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + switch (reg) { + case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: ++ 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_LED2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION: ++ case MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRCX_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: +@@ -1282,6 +2118,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: +@@ -1296,6 +2136,14 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET: + return true; + } + return false; +@@ -1305,6 +2153,25 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + { MLXPLAT_CPLD_LPC_REG_WP1_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_WP2_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 }, ++}; ++ ++static const struct reg_default mlxplat_mlxcpld_regmap_ng[] = { ++ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 }, ++}; ++ ++static const struct reg_default mlxplat_mlxcpld_regmap_comex_default[] = { ++ { MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET, ++ MLXPLAT_CPLD_LOW_AGGRCX_MASK }, ++ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, ++}; ++ ++static const struct reg_default mlxplat_mlxcpld_regmap_ng400[] = { ++ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 }, + }; + + struct mlxplat_mlxcpld_regmap_context { +@@ -1345,21 +2212,70 @@ struct mlxplat_mlxcpld_regmap_context { + .reg_write = mlxplat_mlxcpld_reg_write, + }; + ++static const struct regmap_config mlxplat_mlxcpld_regmap_config_ng = { ++ .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_ng, ++ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_ng), ++ .reg_read = mlxplat_mlxcpld_reg_read, ++ .reg_write = mlxplat_mlxcpld_reg_write, ++}; ++ ++static const struct regmap_config mlxplat_mlxcpld_regmap_config_comex = { ++ .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_comex_default, ++ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_comex_default), ++ .reg_read = mlxplat_mlxcpld_reg_read, ++ .reg_write = mlxplat_mlxcpld_reg_write, ++}; ++ ++static const struct regmap_config mlxplat_mlxcpld_regmap_config_ng400 = { ++ .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_ng400, ++ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_ng400), ++ .reg_read = mlxplat_mlxcpld_reg_read, ++ .reg_write = mlxplat_mlxcpld_reg_write, ++}; ++ + static struct resource mlxplat_mlxcpld_resources[] = { + [0] = DEFINE_RES_IRQ_NAMED(17, "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; + static struct mlxreg_core_platform_data *mlxplat_regs_io; + static struct mlxreg_core_platform_data *mlxplat_fan; ++static struct mlxreg_core_platform_data ++ *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS]; ++static const struct regmap_config *mlxplat_regmap_config; + + static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) + { + int i; + +- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); 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_default_channels[i]; + mlxplat_mux_data[i].n_values = + ARRAY_SIZE(mlxplat_default_channels[i]); +@@ -1369,15 +2285,19 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) + mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_led_data; + mlxplat_regs_io = &mlxplat_default_regs_io_data; ++ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + + return 1; +-}; ++} + + static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) + { + int i; + +- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); 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); +@@ -1387,15 +2307,19 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_msn21xx_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; ++ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + + return 1; +-}; ++} + + static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) + { + int i; + +- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); 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); +@@ -1405,15 +2329,19 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; ++ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + + return 1; +-}; ++} + + static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) + { + int i; + +- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); 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); +@@ -1421,17 +2349,21 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) + mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data; + mlxplat_hotplug->deferred_nr = + mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; +- mlxplat_led = &mlxplat_default_ng_led_data; ++ mlxplat_led = &mlxplat_msn21xx_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; ++ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + + return 1; +-}; ++} + + static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) + { + int i; + +- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); 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); +@@ -1439,14 +2371,117 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) + mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data; + mlxplat_hotplug->deferred_nr = + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; +- mlxplat_led = &mlxplat_msn21xx_led_data; ++ 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_ng; + + return 1; +-}; ++} ++ ++static int __init mlxplat_dmi_comex_matched(const struct dmi_system_id *dmi) ++{ ++ int i; ++ ++ mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_EXT_ADAPTER_NUM; ++ mlxplat_mux_num = ARRAY_SIZE(mlxplat_extended_mux_data); ++ mlxplat_mux_data = mlxplat_extended_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_comex_data; ++ mlxplat_hotplug->deferred_nr = MLXPLAT_CPLD_MAX_PHYS_EXT_ADAPTER_NUM; ++ mlxplat_led = &mlxplat_comex_100G_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_regmap_config = &mlxplat_mlxcpld_regmap_config_comex; ++ ++ return 1; ++} ++ ++static int __init mlxplat_dmi_ng400_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_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_mlxcpld_regmap_config_ng400; ++ ++ return 1; ++} + + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + { ++ .callback = mlxplat_dmi_default_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_msn21xx_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_msn274x_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_msn201x_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_qmb7xx_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_qmb7xx_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0007"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_comex_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0009"), ++ }, ++ }, ++ { ++ .callback = mlxplat_dmi_ng400_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0010"), ++ }, ++ }, ++ { + .callback = mlxplat_dmi_msn274x_matched, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), +@@ -1499,51 +2534,28 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) + .callback = mlxplat_dmi_qmb7xx_matched, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), +- DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MQM87"), + }, + }, + { + .callback = mlxplat_dmi_qmb7xx_matched, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), +- DMI_MATCH(DMI_PRODUCT_NAME, "SN37"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MSN37"), + }, + }, + { + .callback = mlxplat_dmi_qmb7xx_matched, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), +- DMI_MATCH(DMI_PRODUCT_NAME, "SN34"), +- }, +- }, +- { +- .callback = mlxplat_dmi_default_matched, +- .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"), +- }, +- }, +- { +- .callback = mlxplat_dmi_msn21xx_matched, +- .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"), +- }, +- }, +- { +- .callback = mlxplat_dmi_msn274x_matched, +- .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"), +- }, +- }, +- { +- .callback = mlxplat_dmi_msn201x_matched, +- .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MSN34"), + }, + }, + { + .callback = mlxplat_dmi_qmb7xx_matched, + .matches = { +- DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), ++ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "MSN38"), + }, + }, + { } +@@ -1559,7 +2571,7 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr) + /* Scan adapters from expected id to verify it is free. */ + *nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; + for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i < +- MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) { ++ mlxplat_max_adap_num; i++) { + search_adap = i2c_get_adapter(i); + if (search_adap) { + i2c_put_adapter(search_adap); +@@ -1573,12 +2585,12 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr) + } + + /* Return with error if free id for adapter is not found. */ +- if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ++ if (i == mlxplat_max_adap_num) + return -ENODEV; + + /* Shift adapter ids, since expected parent adapter is not free. */ + *nr = i; +- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { ++ 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; +@@ -1612,19 +2624,42 @@ 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; ++ } ++ ++ 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_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr; +- priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr, +- NULL, 0); ++ 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, mlxplat_mlxcpld_resources, ++ ARRAY_SIZE(mlxplat_mlxcpld_resources), ++ mlxplat_i2c, sizeof(*mlxplat_i2c)); + if (IS_ERR(priv->pdev_i2c)) { + err = PTR_ERR(priv->pdev_i2c); + goto fail_alloc; + } + +- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { ++ 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, +@@ -1636,21 +2671,8 @@ static int __init mlxplat_init(void) + } + } + +- 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_platform_mux_register; +- } +- +- mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, +- &mlxplat_mlxcpld_regmap_ctx, +- &mlxplat_mlxcpld_regmap_config); +- if (IS_ERR(mlxplat_hotplug->regmap)) { +- err = PTR_ERR(mlxplat_hotplug->regmap); +- goto fail_platform_mux_register; +- } +- ++ /* Add hotplug driver */ ++ mlxplat_hotplug->regmap = priv->regmap; + priv->pdev_hotplug = platform_device_register_resndata( + &mlxplat_dev->dev, "mlxreg-hotplug", + PLATFORM_DEVID_NONE, +@@ -1663,16 +2685,16 @@ static int __init mlxplat_init(void) + } + + /* Set default registers. */ +- for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) { +- err = regmap_write(mlxplat_hotplug->regmap, +- mlxplat_mlxcpld_regmap_default[j].reg, +- mlxplat_mlxcpld_regmap_default[j].def); ++ 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. */ +- mlxplat_led->regmap = mlxplat_hotplug->regmap; ++ mlxplat_led->regmap = priv->regmap; + priv->pdev_led = platform_device_register_resndata( + &mlxplat_dev->dev, "leds-mlxreg", + PLATFORM_DEVID_NONE, NULL, 0, +@@ -1684,7 +2706,7 @@ static int __init mlxplat_init(void) + + /* Add registers io access driver. */ + if (mlxplat_regs_io) { +- mlxplat_regs_io->regmap = mlxplat_hotplug->regmap; ++ mlxplat_regs_io->regmap = priv->regmap; + priv->pdev_io_regs = platform_device_register_resndata( + &mlxplat_dev->dev, "mlxreg-io", + PLATFORM_DEVID_NONE, NULL, 0, +@@ -1698,7 +2720,7 @@ static int __init mlxplat_init(void) + + /* Add FAN driver. */ + if (mlxplat_fan) { +- mlxplat_fan->regmap = mlxplat_hotplug->regmap; ++ mlxplat_fan->regmap = priv->regmap; + priv->pdev_fan = platform_device_register_resndata( + &mlxplat_dev->dev, "mlxreg-fan", + PLATFORM_DEVID_NONE, NULL, 0, +@@ -1710,15 +2732,33 @@ static int __init mlxplat_init(void) + } + } + ++ /* Add WD drivers. */ ++ for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) { ++ if (mlxplat_wd_data[j]) { ++ mlxplat_wd_data[j]->regmap = 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]); ++ goto fail_platform_wd_register; ++ } ++ } ++ } ++ + /* Sync registers with hardware. */ +- regcache_mark_dirty(mlxplat_hotplug->regmap); +- err = regcache_sync(mlxplat_hotplug->regmap); ++ regcache_mark_dirty(priv->regmap); ++ err = regcache_sync(priv->regmap); + if (err) +- goto fail_platform_fan_register; ++ goto fail_platform_wd_register; + + return 0; + +-fail_platform_fan_register: ++fail_platform_wd_register: ++ while (--j >= 0) ++ platform_device_unregister(priv->pdev_wd[j]); + if (mlxplat_fan) + platform_device_unregister(priv->pdev_fan); + fail_platform_io_regs_register: +@@ -1744,6 +2784,8 @@ static void __exit mlxplat_exit(void) + struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); + int i; + ++ for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) ++ platform_device_unregister(priv->pdev_wd[i]); + if (priv->pdev_fan) + platform_device_unregister(priv->pdev_fan); + if (priv->pdev_io_regs) +@@ -1751,7 +2793,7 @@ static void __exit mlxplat_exit(void) + platform_device_unregister(priv->pdev_led); + platform_device_unregister(priv->pdev_hotplug); + +- for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) ++ for (i = mlxplat_mux_num - 1; i >= 0 ; i--) + platform_device_unregister(priv->pdev_mux[i]); + + platform_device_unregister(priv->pdev_i2c); +diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig +index b165c46..5763dfc 100644 +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -241,6 +241,22 @@ config RAVE_SP_WATCHDOG + help + Support for the watchdog on RAVE SP device. + ++config MLX_WDT ++ tristate "Mellanox Watchdog" ++ depends on MELLANOX_PLATFORM ++ select WATCHDOG_CORE ++ select REGMAP ++ help ++ This is the driver for the hardware watchdog on Mellanox systems. ++ If you are going to use it, say Y here, otherwise N. ++ This driver can be used together with the watchdog daemon. ++ It can also watch your kernel to make sure it doesn't freeze, ++ and if it does, it reboots your system after a certain amount of ++ time. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called mlx-wdt. ++ + # ALPHA Architecture + + # ARM Architecture +diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile +index bf92e7b..42709be 100644 +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -139,6 +139,7 @@ obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o + obj-$(CONFIG_INTEL_MEI_WDT) += mei_wdt.o + obj-$(CONFIG_NI903X_WDT) += ni903x_wdt.o + obj-$(CONFIG_NIC7018_WDT) += nic7018_wdt.o ++obj-$(CONFIG_MLX_WDT) += mlx_wdt.o + + # M68K Architecture + obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o +diff --git a/drivers/watchdog/mlx_wdt.c b/drivers/watchdog/mlx_wdt.c +new file mode 100644 +index 0000000..74b0622 +--- /dev/null ++++ b/drivers/watchdog/mlx_wdt.c +@@ -0,0 +1,289 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Mellanox watchdog driver ++ * ++ * Copyright (C) 2019 Mellanox Technologies ++ * Copyright (C) 2019 Michael Shych ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MLXREG_WDT_CLOCK_SCALE 1000 ++#define MLXREG_WDT_MAX_TIMEOUT_TYPE1 32 ++#define MLXREG_WDT_MAX_TIMEOUT_TYPE2 255 ++#define MLXREG_WDT_MIN_TIMEOUT 1 ++#define MLXREG_WDT_OPTIONS_BASE (WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | \ ++ WDIOF_SETTIMEOUT) ++ ++/** ++ * struct mlxreg_wdt - wd private data: ++ * ++ * @wdd: watchdog device; ++ * @device: basic device; ++ * @pdata: data received from platform driver; ++ * @regmap: register map of parent device; ++ * @timeout: defined timeout in sec.; ++ * @action_idx: index for direct access to action register; ++ * @timeout_idx:index for direct access to TO register; ++ * @tleft_idx: index for direct access to time left register; ++ * @ping_idx: index for direct access to ping register; ++ * @reset_idx: index for direct access to reset cause register; ++ * @wd_type: watchdog HW type; ++ */ ++struct mlxreg_wdt { ++ struct watchdog_device wdd; ++ struct mlxreg_core_platform_data *pdata; ++ void *regmap; ++ int action_idx; ++ int timeout_idx; ++ int tleft_idx; ++ int ping_idx; ++ int reset_idx; ++ enum mlxreg_wdt_type wdt_type; ++}; ++ ++static void mlxreg_wdt_check_card_reset(struct mlxreg_wdt *wdt) ++{ ++ struct mlxreg_core_data *reg_data; ++ u32 regval; ++ int rc; ++ ++ if (wdt->reset_idx == -EINVAL) ++ return; ++ ++ if (!(wdt->wdd.info->options & WDIOF_CARDRESET)) ++ return; ++ ++ reg_data = &wdt->pdata->data[wdt->reset_idx]; ++ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); ++ if (!rc) { ++ if (regval & ~reg_data->mask) { ++ wdt->wdd.bootstatus = WDIOF_CARDRESET; ++ dev_info(wdt->wdd.parent, ++ "watchdog previously reset the CPU\n"); ++ } ++ } ++} ++ ++static int mlxreg_wdt_start(struct watchdog_device *wdd) ++{ ++ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); ++ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->action_idx]; ++ ++ return regmap_update_bits(wdt->regmap, reg_data->reg, ~reg_data->mask, ++ BIT(reg_data->bit)); ++} ++ ++static int mlxreg_wdt_stop(struct watchdog_device *wdd) ++{ ++ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); ++ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->action_idx]; ++ ++ return regmap_update_bits(wdt->regmap, reg_data->reg, ~reg_data->mask, ++ ~BIT(reg_data->bit)); ++} ++ ++static int mlxreg_wdt_ping(struct watchdog_device *wdd) ++{ ++ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); ++ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->ping_idx]; ++ ++ return regmap_update_bits_base(wdt->regmap, reg_data->reg, ++ ~reg_data->mask, BIT(reg_data->bit), ++ NULL, false, true); ++} ++ ++static int mlxreg_wdt_set_timeout(struct watchdog_device *wdd, ++ unsigned int timeout) ++{ ++ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); ++ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->timeout_idx]; ++ u32 regval, set_time, hw_timeout; ++ int rc; ++ ++ if (wdt->wdt_type == MLX_WDT_TYPE1) { ++ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); ++ if (rc) ++ return rc; ++ ++ hw_timeout = order_base_2(timeout * MLXREG_WDT_CLOCK_SCALE); ++ regval = (regval & reg_data->mask) | hw_timeout; ++ /* Rowndown to actual closest number of sec. */ ++ set_time = BIT(hw_timeout) / MLXREG_WDT_CLOCK_SCALE; ++ } else { ++ set_time = timeout; ++ regval = timeout; ++ } ++ ++ wdd->timeout = set_time; ++ rc = regmap_write(wdt->regmap, reg_data->reg, regval); ++ ++ if (!rc) { ++ /* ++ * Restart watchdog with new timeout period ++ * if watchdog is already started. ++ */ ++ if (watchdog_active(wdd)) { ++ rc = mlxreg_wdt_stop(wdd); ++ if (!rc) ++ rc = mlxreg_wdt_start(wdd); ++ } ++ } ++ ++ return rc; ++} ++ ++static unsigned int mlxreg_wdt_get_timeleft(struct watchdog_device *wdd) ++{ ++ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); ++ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->tleft_idx]; ++ u32 regval; ++ int rc; ++ ++ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); ++ /* Return 0 timeleft in case of failure register read. */ ++ return rc == 0 ? regval : 0; ++} ++ ++static const struct watchdog_ops mlxreg_wdt_ops_type1 = { ++ .start = mlxreg_wdt_start, ++ .stop = mlxreg_wdt_stop, ++ .ping = mlxreg_wdt_ping, ++ .set_timeout = mlxreg_wdt_set_timeout, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct watchdog_ops mlxreg_wdt_ops_type2 = { ++ .start = mlxreg_wdt_start, ++ .stop = mlxreg_wdt_stop, ++ .ping = mlxreg_wdt_ping, ++ .set_timeout = mlxreg_wdt_set_timeout, ++ .get_timeleft = mlxreg_wdt_get_timeleft, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct watchdog_info mlxreg_wdt_main_info = { ++ .options = MLXREG_WDT_OPTIONS_BASE ++ | WDIOF_CARDRESET, ++ .identity = "mlx-wdt-main", ++}; ++ ++static const struct watchdog_info mlxreg_wdt_aux_info = { ++ .options = MLXREG_WDT_OPTIONS_BASE ++ | WDIOF_ALARMONLY, ++ .identity = "mlx-wdt-aux", ++}; ++ ++static void mlxreg_wdt_config(struct mlxreg_wdt *wdt, ++ struct mlxreg_core_platform_data *pdata) ++{ ++ struct mlxreg_core_data *data = pdata->data; ++ int i; ++ ++ wdt->reset_idx = -EINVAL; ++ for (i = 0; i < pdata->counter; i++, data++) { ++ if (strnstr(data->label, "action", sizeof(data->label))) ++ wdt->action_idx = i; ++ else if (strnstr(data->label, "timeout", sizeof(data->label))) ++ wdt->timeout_idx = i; ++ else if (strnstr(data->label, "timeleft", sizeof(data->label))) ++ wdt->tleft_idx = i; ++ else if (strnstr(data->label, "ping", sizeof(data->label))) ++ wdt->ping_idx = i; ++ else if (strnstr(data->label, "reset", sizeof(data->label))) ++ wdt->reset_idx = i; ++ } ++ ++ wdt->pdata = pdata; ++ if (strnstr(pdata->identity, mlxreg_wdt_main_info.identity, ++ sizeof(mlxreg_wdt_main_info.identity))) ++ wdt->wdd.info = &mlxreg_wdt_main_info; ++ else ++ wdt->wdd.info = &mlxreg_wdt_aux_info; ++ ++ wdt->wdt_type = pdata->version; ++ if (wdt->wdt_type == MLX_WDT_TYPE2) { ++ wdt->wdd.ops = &mlxreg_wdt_ops_type2; ++ wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE2; ++ } else { ++ wdt->wdd.ops = &mlxreg_wdt_ops_type1; ++ wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE1; ++ } ++ wdt->wdd.min_timeout = MLXREG_WDT_MIN_TIMEOUT; ++} ++ ++static int mlxreg_wdt_init_timeout(struct mlxreg_wdt *wdt, ++ struct mlxreg_core_platform_data *pdata) ++{ ++ u32 timeout; ++ ++ timeout = pdata->data[wdt->timeout_idx].health_cntr; ++ return mlxreg_wdt_set_timeout(&wdt->wdd, timeout); ++} ++ ++static int mlxreg_wdt_probe(struct platform_device *pdev) ++{ ++ struct mlxreg_core_platform_data *pdata; ++ struct mlxreg_wdt *wdt; ++ int rc; ++ ++ pdata = dev_get_platdata(&pdev->dev); ++ if (!pdata) { ++ dev_err(&pdev->dev, "Failed to get platform data.\n"); ++ return -EINVAL; ++ } ++ wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); ++ if (!wdt) ++ return -ENOMEM; ++ ++ wdt->wdd.parent = &pdev->dev; ++ wdt->regmap = pdata->regmap; ++ mlxreg_wdt_config(wdt, pdata); ++ ++ if ((pdata->features & MLXREG_CORE_WD_FEATURE_NOWAYOUT)) ++ watchdog_set_nowayout(&wdt->wdd, WATCHDOG_NOWAYOUT); ++ watchdog_stop_on_reboot(&wdt->wdd); ++ watchdog_set_drvdata(&wdt->wdd, wdt); ++ rc = mlxreg_wdt_init_timeout(wdt, pdata); ++ if (rc) ++ goto register_error; ++ ++ if ((pdata->features & MLXREG_CORE_WD_FEATURE_START_AT_BOOT)) { ++ rc = mlxreg_wdt_start(&wdt->wdd); ++ if (rc) ++ goto register_error; ++ set_bit(WDOG_HW_RUNNING, &wdt->wdd.status); ++ } ++ mlxreg_wdt_check_card_reset(wdt); ++ rc = devm_watchdog_register_device(&pdev->dev, &wdt->wdd); ++ ++register_error: ++ if (rc) ++ dev_err(&pdev->dev, ++ "Cannot register watchdog device (err=%d)\n", rc); ++ return rc; ++} ++ ++static struct platform_driver mlxreg_wdt_driver = { ++ .probe = mlxreg_wdt_probe, ++ .driver = { ++ .name = "mlx-wdt", ++ }, ++}; ++ ++module_platform_driver(mlxreg_wdt_driver); ++ ++MODULE_AUTHOR("Michael Shych "); ++MODULE_DESCRIPTION("Mellanox watchdog driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:mlx-wdt"); +diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h +index 19f5cb6..b8da8ae 100644 +--- a/include/linux/platform_data/mlxreg.h ++++ b/include/linux/platform_data/mlxreg.h +@@ -35,6 +35,19 @@ + #define __LINUX_PLATFORM_DATA_MLXREG_H + + #define MLXREG_CORE_LABEL_MAX_SIZE 32 ++#define MLXREG_CORE_WD_FEATURE_NOWAYOUT BIT(0) ++#define MLXREG_CORE_WD_FEATURE_START_AT_BOOT BIT(1) ++ ++/** ++ * enum mlxreg_wdt_type - type of HW watchdog ++ * ++ * TYPE1 HW watchdog implementation exist in old systems. ++ * All new systems have TYPE2 HW watchdog. ++ */ ++enum mlxreg_wdt_type { ++ MLX_WDT_TYPE1, ++ MLX_WDT_TYPE2, ++}; + + /** + * struct mlxreg_hotplug_device - I2C device data: +@@ -61,6 +74,7 @@ struct mlxreg_hotplug_device { + * @reg: attribute register; + * @mask: attribute access mask; + * @bit: attribute effective bit; ++ * @capability: attribute capability register; + * @mode: access mode; + * @np - pointer to node platform associated with attribute; + * @hpdev - hotplug device data; +@@ -72,6 +86,7 @@ struct mlxreg_core_data { + u32 reg; + u32 mask; + u32 bit; ++ u32 capability; + umode_t mode; + struct device_node *np; + struct mlxreg_hotplug_device hpdev; +@@ -86,6 +101,7 @@ struct mlxreg_core_data { + * @aggr_mask: group aggregation mask; + * @reg: group interrupt status register; + * @mask: group interrupt mask; ++ * @capability: group capability register; + * @cache: last status value for elements fro the same group; + * @count: number of available elements in the group; + * @ind: element's index inside the group; +@@ -97,6 +113,7 @@ struct mlxreg_core_item { + u32 aggr_mask; + u32 reg; + u32 mask; ++ u32 capability; + u32 cache; + u8 count; + u8 ind; +@@ -107,14 +124,20 @@ struct mlxreg_core_item { + /** + * struct mlxreg_core_platform_data - platform data: + * +- * @led_data: led private data; ++ * @data: instance private data; + * @regmap: register map of parent device; +- * @counter: number of led instances; ++ * @counter: number of instances; ++ * @features: supported features of device; ++ * @version: implementation version; ++ * @identity: device identity name; + */ + struct mlxreg_core_platform_data { + struct mlxreg_core_data *data; + void *regmap; + int counter; ++ u32 features; ++ u32 version; ++ char identity[MLXREG_CORE_LABEL_MAX_SIZE]; + }; + + /** +diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h +index dc69391..08bb155 100644 +--- a/include/uapi/linux/ethtool.h ++++ b/include/uapi/linux/ethtool.h +@@ -1691,6 +1691,9 @@ static inline int ethtool_validate_duplex(__u8 duplex) + #define ETH_MODULE_SFF_8436 0x4 + #define ETH_MODULE_SFF_8436_LEN 256 + ++#define ETH_MODULE_SFF_8636_MAX_LEN 640 ++#define ETH_MODULE_SFF_8436_MAX_LEN 640 ++ + /* Reset flags */ + /* The reset() operation must clear the flags for the components which + * were actually reset. On successful return, the flags indicate the +-- +1.9.1 + diff --git a/patch/0002-config-mellanox-configuration.patch b/patch/0002-config-mellanox-configuration.patch new file mode 100644 index 000000000000..a94c50b83016 --- /dev/null +++ b/patch/0002-config-mellanox-configuration.patch @@ -0,0 +1,209 @@ +From c4e099fa32c81e09cca7f5252b8c8cc413d1a056 Mon Sep 17 00:00:00 2001 +From: root +Date: Mon, 16 Mar 2020 02:30:11 +0000 +Subject: [PATCH 2/2] config: mellanox configuration + +It adds the next configuration flags, used by Mellanox systems: + +CONFIG_MLXSW_CORE=m +CONFIG_MLXSW_CORE_HWMON=y +CONFIG_MLXSW_CORE_THERMAL=y +CONFIG_MLXSW_CORE_QSFP=y +CONFIG_MLXSW_PCI=m +CONFIG_MLXSW_I2C=m +CONFIG_MLXSW_MINIMAL=m +CONFIG_I2C_MUX_REG=y +CONFIG_I2C_MUX_MLXCPLD=m +CONFIG_I2C_MLXCPLD=m +CONFIG_SENSORS_IIO_HWMON=y +CONFIG_PMBUS=y +CONFIG_SENSORS_PMBUS=y +CONFIG_SENSORS_LM25066=m +CONFIG_SENSORS_TPS53679=m +CONFIG_SENSORS_UCD9000=m +CONFIG_SENSORS_UCD9200=m +CONFIG_LEDS_MLXREG=m +CONFIG_MLX_PLATFORM=m +CONFIG_MELLANOX_PLATFORM=y +CONFIG_MLXREG_HOTPLUG=m +CONFIG_MLXREG_IO=m +CONFIG_MAX1363=y + +Signed-off-by: Vadim Pastrenak +Signed-off-by: Stephen + +config: mellanox fan configuration It adds configuration flag, used by Mellanox systems: + +SENSORS_MLXREG_FAN=m + +Signed-off-by: Oleksandr Shamray +Signed-off-by: Stephen + +update kernel config add CONFIG_MLX_WDT + +Signed-off-by: Mykola Kostenok +Signed-off-by: Stephen + +sonic update kernel config mlsxw pci + +Signed-off-by: Vadim Pasternak +Signed-off-by: Stephen + +Adjust configurations + +Signed-off-by: Stephen +--- + debian/build/build_amd64_none_amd64/.config | 53 +++++++++++++++++++++-------- + 1 file changed, 39 insertions(+), 14 deletions(-) + +diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config +index b62b167..d74909b 100644 +--- a/debian/build/build_amd64_none_amd64/.config ++++ b/debian/build/build_amd64_none_amd64/.config +@@ -2235,9 +2235,9 @@ CONFIG_EEPROM_LEGACY=m + CONFIG_EEPROM_MAX6875=m + CONFIG_EEPROM_93CX6=m + # CONFIG_EEPROM_93XX46 is not set ++# CONFIG_EEPROM_IDT_89HPESX is not set + CONFIG_EEPROM_SFF_8436=m + CONFIG_EEPROM_OPTOE=m +-# CONFIG_EEPROM_IDT_89HPESX is not set + CONFIG_CB710_CORE=m + # CONFIG_CB710_DEBUG is not set + CONFIG_CB710_DEBUG_ASSUMPTIONS=y +@@ -2860,7 +2860,13 @@ CONFIG_MLX5_MPFS=y + CONFIG_MLX5_CORE_EN_DCB=y + CONFIG_MLX5_CORE_IPOIB=y + # CONFIG_MLX5_EN_IPSEC is not set +-# CONFIG_MLXSW_CORE is not set ++CONFIG_MLXSW_CORE=m ++CONFIG_MLXSW_CORE_HWMON=y ++CONFIG_MLXSW_CORE_THERMAL=y ++CONFIG_MLXSW_CORE_QSFP=y ++# CONFIG_MLXSW_PCI is not set ++CONFIG_MLXSW_I2C=m ++CONFIG_MLXSW_MINIMAL=m + CONFIG_MLXFW=m + CONFIG_NET_VENDOR_MICREL=y + # CONFIG_KS8842 is not set +@@ -3874,8 +3880,8 @@ CONFIG_I2C_MUX_GPIO=m + # CONFIG_I2C_MUX_LTC4306 is not set + # CONFIG_I2C_MUX_PCA9541 is not set + CONFIG_I2C_MUX_PCA954x=m +-# CONFIG_I2C_MUX_REG is not set +-# CONFIG_I2C_MUX_MLXCPLD is not set ++CONFIG_I2C_MUX_REG=m ++CONFIG_I2C_MUX_MLXCPLD=m + CONFIG_I2C_HELPER_AUTO=y + CONFIG_I2C_SMBUS=m + CONFIG_I2C_ALGOBIT=m +@@ -3944,7 +3950,7 @@ CONFIG_I2C_VIPERBOARD=m + # + # Other I2C/SMBus bus drivers + # +-# CONFIG_I2C_MLXCPLD is not set ++CONFIG_I2C_MLXCPLD=m + CONFIG_I2C_STUB=m + # CONFIG_I2C_SLAVE is not set + # CONFIG_I2C_DEBUG_CORE is not set +@@ -4214,7 +4218,7 @@ CONFIG_SENSORS_G760A=m + # CONFIG_SENSORS_HIH6130 is not set + CONFIG_SENSORS_IBMAEM=m + CONFIG_SENSORS_IBMPEX=m +-# CONFIG_SENSORS_IIO_HWMON is not set ++CONFIG_SENSORS_IIO_HWMON=m + CONFIG_SENSORS_I5500=m + CONFIG_SENSORS_CORETEMP=m + CONFIG_SENSORS_IT87=m +@@ -4243,6 +4247,7 @@ CONFIG_SENSORS_MAX6620=m + CONFIG_SENSORS_MAX6697=m + CONFIG_SENSORS_MAX31790=m + # CONFIG_SENSORS_MCP3021 is not set ++CONFIG_SENSORS_MLXREG_FAN=m + # CONFIG_SENSORS_TC654 is not set + CONFIG_SENSORS_MENF21BMC_HWMON=m + CONFIG_SENSORS_ADCXX=m +@@ -4271,7 +4276,24 @@ CONFIG_SENSORS_NCT7802=m + CONFIG_SENSORS_NCT7904=m + CONFIG_SENSORS_NPCM7XX=m + CONFIG_SENSORS_PCF8591=m +-# CONFIG_PMBUS is not set ++CONFIG_PMBUS=m ++CONFIG_SENSORS_PMBUS=m ++# CONFIG_SENSORS_ADM1275 is not set ++# CONFIG_SENSORS_IBM_CFFPS is not set ++# CONFIG_SENSORS_IR35221 is not set ++CONFIG_SENSORS_LM25066=m ++# CONFIG_SENSORS_LTC2978 is not set ++# CONFIG_SENSORS_LTC3815 is not set ++# CONFIG_SENSORS_MAX16064 is not set ++# CONFIG_SENSORS_MAX20751 is not set ++# CONFIG_SENSORS_MAX31785 is not set ++# CONFIG_SENSORS_MAX34440 is not set ++# CONFIG_SENSORS_MAX8688 is not set ++# CONFIG_SENSORS_TPS40422 is not set ++CONFIG_SENSORS_TPS53679=m ++CONFIG_SENSORS_UCD9000=m ++CONFIG_SENSORS_UCD9200=m ++# CONFIG_SENSORS_ZL6100 is not set + # CONFIG_SENSORS_SHT15 is not set + CONFIG_SENSORS_SHT21=m + # CONFIG_SENSORS_SHT3x is not set +@@ -4372,6 +4394,7 @@ CONFIG_MENF21BMC_WATCHDOG=m + CONFIG_WDAT_WDT=m + # CONFIG_XILINX_WATCHDOG is not set + # CONFIG_ZIIRAVE_WATCHDOG is not set ++CONFIG_MLX_WDT=y + # CONFIG_CADENCE_WATCHDOG is not set + # CONFIG_DW_WATCHDOG is not set + # CONFIG_MAX63XX_WATCHDOG is not set +@@ -6466,7 +6489,7 @@ CONFIG_LEDS_MENF21BMC=m + # + # CONFIG_LEDS_BLINKM is not set + # CONFIG_LEDS_MLXCPLD is not set +-# CONFIG_LEDS_MLXREG is not set ++CONFIG_LEDS_MLXREG=m + # CONFIG_LEDS_USER is not set + # CONFIG_LEDS_NIC78BX is not set + +@@ -6674,7 +6697,7 @@ CONFIG_INTEL_MIC_X100_DMA=m + # CONFIG_QCOM_HIDMA is not set + CONFIG_DW_DMAC_CORE=m + CONFIG_DW_DMAC=m +-# CONFIG_DW_DMAC_PCI is not set ++CONFIG_DW_DMAC_PCI=m + CONFIG_HSU_DMA=y + + # +@@ -7055,7 +7078,7 @@ CONFIG_INTEL_PMC_IPC=m + CONFIG_SURFACE_PRO3_BUTTON=m + # CONFIG_SURFACE_3_BUTTON is not set + # CONFIG_INTEL_PUNIT_IPC is not set +-# CONFIG_MLX_PLATFORM is not set ++CONFIG_MLX_PLATFORM=m + # CONFIG_INTEL_TURBO_MAX_3 is not set + # CONFIG_INTEL_CHTDC_TI_PWRBTN is not set + # CONFIG_I2C_MULTI_INSTANTIATE is not set +@@ -7066,7 +7089,9 @@ CONFIG_CHROMEOS_LAPTOP=m + CONFIG_CHROMEOS_PSTORE=m + # CONFIG_CHROMEOS_TBMC is not set + CONFIG_CROS_KBD_LED_BACKLIGHT=m +-# CONFIG_MELLANOX_PLATFORM is not set ++CONFIG_MELLANOX_PLATFORM=y ++CONFIG_MLXREG_HOTPLUG=m ++CONFIG_MLXREG_IO=m + CONFIG_CLKDEV_LOOKUP=y + CONFIG_HAVE_CLK_PREPARE=y + CONFIG_COMMON_CLK=y +@@ -7252,7 +7277,7 @@ CONFIG_MMA9553=m + # CONFIG_MAX1027 is not set + # CONFIG_MAX11100 is not set + # CONFIG_MAX1118 is not set +-# CONFIG_MAX1363 is not set ++CONFIG_MAX1363=m + # CONFIG_MAX9611 is not set + # CONFIG_MCP320X is not set + # CONFIG_MCP3422 is not set +-- +1.9.1 + diff --git a/patch/0002-i2c-mux-mlxcpld-add-driver-for-Mellanox-systems.patch b/patch/0002-i2c-mux-mlxcpld-add-driver-for-Mellanox-systems.patch deleted file mode 100644 index 4ce713858914..000000000000 --- a/patch/0002-i2c-mux-mlxcpld-add-driver-for-Mellanox-systems.patch +++ /dev/null @@ -1,317 +0,0 @@ -Linux backport patch. Includes following commits: -e3448e71adb1fdd7f403c568ef5c2ed5adf2b197 -c3bb77620da428884807fb2f6f3485644e146f84 -db5f807ee3dcc779b78f59982cc3e89863069e9c - - -diff -Nur a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig ---- a/drivers/i2c/muxes/Kconfig 2017-11-12 08:13:59.176044126 +0000 -+++ b/drivers/i2c/muxes/Kconfig 2017-11-12 08:14:27.992044509 +0000 -@@ -82,4 +82,15 @@ - demultiplexer that uses the pinctrl subsystem. This is useful if you - want to change the I2C master at run-time depending on features. - -+config I2C_MUX_MLXCPLD -+ tristate "Mellanox CPLD based I2C multiplexer" -+ help -+ If you say yes to this option, support will be included for a -+ CPLD based I2C multiplexer. This driver provides access to -+ I2C busses connected through a MUX, which is controlled -+ by a CPLD register. -+ -+ This driver can also be built as a module. If so, the module -+ will be called i2c-mux-mlxcpld. -+ - endmenu -diff -Nur a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile ---- a/drivers/i2c/muxes/Makefile 2017-11-12 08:13:59.176044126 +0000 -+++ b/drivers/i2c/muxes/Makefile 2017-11-12 08:14:27.992044509 +0000 -@@ -6,6 +6,7 @@ - obj-$(CONFIG_I2C_DEMUX_PINCTRL) += i2c-demux-pinctrl.o - - obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o -+obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o - 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 -diff -Nur a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c ---- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c 2017-11-12 08:14:27.992044509 +0000 -@@ -0,0 +1,221 @@ -+/* -+ * drivers/i2c/muxes/i2c-mux-mlxcpld.c -+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2016 Michael Shych -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. 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. -+ * 3. Neither the names of the copyright holders nor the names of its -+ * contributors may be used to endorse or promote products derived from -+ * this software without specific prior written permission. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2 as published by the Free -+ * Software Foundation. -+ * -+ * 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 -+#include -+#include -+ -+#define CPLD_MUX_MAX_NCHANS 8 -+ -+/* mlxcpld_mux - mux control structure: -+ * @last_chan - last register value -+ * @client - I2C device client -+ */ -+struct mlxcpld_mux { -+ u8 last_chan; -+ struct i2c_client *client; -+}; -+ -+/* MUX logic description. -+ * Driver can support different mux control logic, according to CPLD -+ * implementation. -+ * -+ * Connectivity schema. -+ * -+ * i2c-mlxcpld Digital Analog -+ * driver -+ * *--------* * -> mux1 (virt bus2) -> mux -> | -+ * | I2CLPC | i2c physical * -> mux2 (virt bus3) -> mux -> | -+ * | bridge | bus 1 *---------* | -+ * | logic |---------------------> * mux reg * | -+ * | in CPLD| *---------* | -+ * *--------* i2c-mux-mlxpcld ^ * -> muxn (virt busn) -> mux -> | -+ * | driver | | -+ * | *---------------* | Devices -+ * | * CPLD (i2c bus)* select | -+ * | * registers for *--------* -+ * | * mux selection * deselect -+ * | *---------------* -+ * | | -+ * <--------> <-----------> -+ * i2c cntrl Board cntrl reg -+ * reg space space (mux select, -+ * IO, LED, WD, info) -+ * -+ */ -+ -+static const struct i2c_device_id mlxcpld_mux_id[] = { -+ { "mlxcpld_mux_module", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, mlxcpld_mux_id); -+ -+/* Write to mux register. Don't use i2c_transfer() and i2c_smbus_xfer() -+ * for this as they will try to lock adapter a second time. -+ */ -+static int mlxcpld_mux_reg_write(struct i2c_adapter *adap, -+ struct i2c_client *client, u8 val) -+{ -+ struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev); -+ int ret = -ENODEV; -+ -+ if (adap->algo->master_xfer) { -+ struct i2c_msg msg; -+ u8 msgbuf[] = {pdata->sel_reg_addr, val}; -+ -+ msg.addr = client->addr; -+ msg.flags = 0; -+ msg.len = 2; -+ msg.buf = msgbuf; -+ ret = __i2c_transfer(adap, &msg, 1); -+ -+ if (ret >= 0 && ret != 1) -+ ret = -EREMOTEIO; -+ } else if (adap->algo->smbus_xfer) { -+ union i2c_smbus_data data; -+ -+ data.byte = val; -+ ret = adap->algo->smbus_xfer(adap, client->addr, -+ client->flags, I2C_SMBUS_WRITE, -+ pdata->sel_reg_addr, -+ I2C_SMBUS_BYTE_DATA, &data); -+ } -+ -+ return ret; -+} -+ -+static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) -+{ -+ struct mlxcpld_mux *data = i2c_mux_priv(muxc); -+ struct i2c_client *client = data->client; -+ u8 regval = chan + 1; -+ int err = 0; -+ -+ /* Only select the channel if its different from the last channel */ -+ if (data->last_chan != regval) { -+ err = mlxcpld_mux_reg_write(muxc->parent, client, regval); -+ data->last_chan = err < 0 ? 0 : regval; -+ } -+ -+ return err; -+} -+ -+static int mlxcpld_mux_deselect(struct i2c_mux_core *muxc, u32 chan) -+{ -+ struct mlxcpld_mux *data = i2c_mux_priv(muxc); -+ struct i2c_client *client = data->client; -+ -+ /* Deselect active channel */ -+ data->last_chan = 0; -+ -+ return mlxcpld_mux_reg_write(muxc->parent, client, data->last_chan); -+} -+ -+/* Probe/reomove functions */ -+static int mlxcpld_mux_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); -+ struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev); -+ struct i2c_mux_core *muxc; -+ int num, force; -+ struct mlxcpld_mux *data; -+ int err; -+ -+ if (!pdata) -+ return -EINVAL; -+ -+ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) -+ return -ENODEV; -+ -+ muxc = i2c_mux_alloc(adap, &client->dev, CPLD_MUX_MAX_NCHANS, -+ sizeof(*data), 0, mlxcpld_mux_select_chan, -+ mlxcpld_mux_deselect); -+ if (!muxc) -+ return -ENOMEM; -+ -+ data = i2c_mux_priv(muxc); -+ i2c_set_clientdata(client, muxc); -+ data->client = client; -+ data->last_chan = 0; /* force the first selection */ -+ -+ /* Create an adapter for each channel. */ -+ for (num = 0; num < CPLD_MUX_MAX_NCHANS; num++) { -+ if (num >= pdata->num_adaps) -+ /* discard unconfigured channels */ -+ break; -+ -+ force = pdata->adap_ids[num]; -+ -+ err = i2c_mux_add_adapter(muxc, force, num, 0); -+ if (err) -+ goto virt_reg_failed; -+ } -+ -+ return 0; -+ -+virt_reg_failed: -+ i2c_mux_del_adapters(muxc); -+ return err; -+} -+ -+static int mlxcpld_mux_remove(struct i2c_client *client) -+{ -+ struct i2c_mux_core *muxc = i2c_get_clientdata(client); -+ -+ i2c_mux_del_adapters(muxc); -+ return 0; -+} -+ -+static struct i2c_driver mlxcpld_mux_driver = { -+ .driver = { -+ .name = "mlxcpld-mux", -+ }, -+ .probe = mlxcpld_mux_probe, -+ .remove = mlxcpld_mux_remove, -+ .id_table = mlxcpld_mux_id, -+}; -+ -+module_i2c_driver(mlxcpld_mux_driver); -+ -+MODULE_AUTHOR("Michael Shych (michaels@mellanox.com)"); -+MODULE_DESCRIPTION("Mellanox I2C-CPLD-MUX driver"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_ALIAS("platform:i2c-mux-mlxcpld"); -diff -Nur a/include/linux/i2c/mlxcpld.h b/include/linux/i2c/mlxcpld.h ---- a/include/linux/i2c/mlxcpld.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/linux/i2c/mlxcpld.h 2017-11-12 08:17:03.032046568 +0000 -@@ -0,0 +1,52 @@ -+/* -+ * mlxcpld.h - Mellanox I2C multiplexer support in CPLD -+ * -+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2016 Michael Shych -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. 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. -+ * 3. Neither the names of the copyright holders nor the names of its -+ * contributors may be used to endorse or promote products derived from -+ * this software without specific prior written permission. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2 as published by the Free -+ * Software Foundation. -+ * -+ * 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 _LINUX_I2C_MLXCPLD_H -+#define _LINUX_I2C_MLXCPLD_H -+ -+/* Platform data for the CPLD I2C multiplexers */ -+ -+/* mlxcpld_mux_plat_data - per mux data, used with i2c_register_board_info -+ * @adap_ids - adapter array -+ * @num_adaps - number of adapters -+ * @sel_reg_addr - mux select register offset in CPLD space -+ */ -+struct mlxcpld_mux_plat_data { -+ int *adap_ids; -+ int num_adaps; -+ int sel_reg_addr; -+}; -+ -+#endif /* _LINUX_I2C_MLXCPLD_H */ diff --git a/patch/0057-mlxsw-minimal-Fix-validation-for-FW-minor-version.patch b/patch/0003-mlxsw-minimal-Fix-validation-for-FW-minor-version.patch similarity index 77% rename from patch/0057-mlxsw-minimal-Fix-validation-for-FW-minor-version.patch rename to patch/0003-mlxsw-minimal-Fix-validation-for-FW-minor-version.patch index 9bda4b1d27df..0fe4923f78e7 100644 --- a/patch/0057-mlxsw-minimal-Fix-validation-for-FW-minor-version.patch +++ b/patch/0003-mlxsw-minimal-Fix-validation-for-FW-minor-version.patch @@ -1,10 +1,11 @@ -From d4689cb7a12bd37ac0ace709b87dd91dd316bfd9 Mon Sep 17 00:00:00 2001 +From d45701f5f15e77f3961717d7f076163d3c2124e2 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak -Date: Mon, 10 Feb 2020 06:44:16 +0000 -Subject: [net] mlxsw: minimal: Fix validation for FW minor version +Date: Mon, 17 Feb 2020 08:38:01 +0200 +Subject: [v4.19 backport 2/2] mlxsw: minimal: Fix validation for FW minor + version -Fix validation for FW minor version in order to prevent driver initialization -in case FW minor version is older than expected. +Fix validation for FW minor version in order to prevent driver +initialization in case FW minor version is older than expected. Signed-off-by: Vadim Pasternak --- @@ -28,5 +29,5 @@ index 504db124ee2f..8cc969758f2f 100644 dev_info(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n", -- -2.11.0 +2.20.1 diff --git a/patch/0003-platform-mellanox-Introduce-Mellanox-hardware-platfo.patch b/patch/0003-platform-mellanox-Introduce-Mellanox-hardware-platfo.patch deleted file mode 100644 index a2b6a9f45eac..000000000000 --- a/patch/0003-platform-mellanox-Introduce-Mellanox-hardware-platfo.patch +++ /dev/null @@ -1,1463 +0,0 @@ -Linux backport patch. Includes following commits: -2926024b5081fc8d4b086677bafa1ac55ea0b911 -eab85698a91e0191e1a00b547ebded411dd9061c -91973760712f350048a0fa8e0363e260bf874313 -ae4c6f185a791890dcf9cab7bc7764ba44e2e696 -90fcad9b077a4660896dbdc815509cee3440886b -290e505b287fe664549cb72b26507d8ffb4a6d39 -d53bc5dc941653f0ed93b11a647bd6ff40f40ef2 -daf155fe70c9d69c28bba632b6a758ac8feab6e7 -c7c1fe5b608cd11668834761404f9d03bf616bdd - - -diff -Nur a/arch/x86/Kconfig b/arch/x86/Kconfig ---- a/arch/x86/Kconfig 2017-11-12 10:26:01.808149323 +0000 -+++ b/arch/x86/Kconfig 2017-11-12 10:27:38.576150608 +0000 -@@ -550,18 +550,6 @@ - Say Y here if you have a Quark based system such as the Arduino - compatible Intel Galileo. - --config MLX_PLATFORM -- tristate "Mellanox Technologies platform support" -- depends on X86_64 -- depends on X86_EXTENDED_PLATFORM -- ---help--- -- This option enables system support for the Mellanox Technologies -- platform. -- -- Say Y here if you are building a kernel for Mellanox system. -- -- Otherwise, say N. -- - config X86_INTEL_LPSS - bool "Intel Low Power Subsystem Support" - depends on X86 && ACPI -diff -Nur a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile ---- a/arch/x86/platform/Makefile 2017-11-12 10:25:48.640149148 +0000 -+++ b/arch/x86/platform/Makefile 2017-11-12 10:27:24.924150426 +0000 -@@ -8,7 +8,6 @@ - obj-y += intel/ - obj-y += intel-mid/ - obj-y += intel-quark/ --obj-y += mellanox/ - obj-y += olpc/ - obj-y += scx200/ - obj-y += sfi/ -diff -Nur a/arch/x86/platform/mellanox/Makefile b/arch/x86/platform/mellanox/Makefile ---- a/arch/x86/platform/mellanox/Makefile 2017-11-12 10:25:26.704148857 +0000 -+++ b/arch/x86/platform/mellanox/Makefile 1970-01-01 00:00:00.000000000 +0000 -@@ -1 +0,0 @@ --obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o -diff -Nur a/arch/x86/platform/mellanox/mlx-platform.c b/arch/x86/platform/mellanox/mlx-platform.c ---- a/arch/x86/platform/mellanox/mlx-platform.c 2017-11-12 10:25:26.704148857 +0000 -+++ b/arch/x86/platform/mellanox/mlx-platform.c 1970-01-01 00:00:00.000000000 +0000 -@@ -1,266 +0,0 @@ --/* -- * arch/x86/platform/mellanox/mlx-platform.c -- * Copyright (c) 2016 Mellanox Technologies. All rights reserved. -- * Copyright (c) 2016 Vadim Pasternak -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. 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. -- * 3. Neither the names of the copyright holders nor the names of its -- * contributors may be used to endorse or promote products derived from -- * this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * 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 -- --#define MLX_PLAT_DEVICE_NAME "mlxplat" -- --/* LPC bus IO offsets */ --#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 --#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 --#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_PIO_OFFSET 0x10000UL --#define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ -- MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \ -- 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_PIO_OFFSET) -- --/* Start channel numbers */ --#define MLXPLAT_CPLD_CH1 2 --#define MLXPLAT_CPLD_CH2 10 -- --/* Number of LPC attached MUX platform devices */ --#define MLXPLAT_CPLD_LPC_MUX_DEVS 2 -- --/* mlxplat_priv - platform private data -- * @pdev_i2c - i2c controller platform device -- * @pdev_mux - array of mux platform devices -- */ --struct mlxplat_priv { -- struct platform_device *pdev_i2c; -- struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS]; --}; -- --/* 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, -- MLXPLAT_CPLD_LPC_IO_RANGE, -- "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO), -- [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR, -- MLXPLAT_CPLD_LPC_IO_RANGE, -- "mlxplat_cpld_lpc_regs", -- IORESOURCE_IO), --}; -- --/* Platform default channels */ --static const int mlxplat_default_channels[][8] = { -- { -- MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2, -- MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 + -- 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7 -- }, -- { -- MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2, -- MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 + -- 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7 -- }, --}; -- --/* Platform channels for MSN21xx system family */ --static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; -- --/* Platform mux data */ --static struct i2c_mux_reg_platform_data mlxplat_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, -- }, -- { -- .parent = 1, -- .base_nr = MLXPLAT_CPLD_CH2, -- .write_only = 1, -- .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, -- .reg_size = 1, -- .idle_in_use = 1, -- }, -- --}; -- --static struct platform_device *mlxplat_dev; -- --static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) --{ -- int i; -- -- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -- mlxplat_mux_data[i].values = mlxplat_default_channels[i]; -- mlxplat_mux_data[i].n_values = -- ARRAY_SIZE(mlxplat_default_channels[i]); -- } -- -- return 1; --}; -- --static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) --{ -- int i; -- -- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -- mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; -- mlxplat_mux_data[i].n_values = -- ARRAY_SIZE(mlxplat_msn21xx_channels); -- } -- -- return 1; --}; -- --static struct dmi_system_id mlxplat_dmi_table[] __initdata = { -- { -- .callback = mlxplat_dmi_default_matched, -- .matches = { -- DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -- DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"), -- }, -- }, -- { -- .callback = mlxplat_dmi_default_matched, -- .matches = { -- DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -- DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"), -- }, -- }, -- { -- .callback = mlxplat_dmi_default_matched, -- .matches = { -- DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -- DMI_MATCH(DMI_PRODUCT_NAME, "MSB"), -- }, -- }, -- { -- .callback = mlxplat_dmi_default_matched, -- .matches = { -- DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -- DMI_MATCH(DMI_PRODUCT_NAME, "MSX"), -- }, -- }, -- { -- .callback = mlxplat_dmi_msn21xx_matched, -- .matches = { -- DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -- DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"), -- }, -- }, -- { } --}; -- --static int __init mlxplat_init(void) --{ -- struct mlxplat_priv *priv; -- int i, 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); -- -- 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->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1, -- NULL, 0); -- if (IS_ERR(priv->pdev_i2c)) { -- err = PTR_ERR(priv->pdev_i2c); -- goto fail_alloc; -- }; -- -- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -- priv->pdev_mux[i] = platform_device_register_resndata( -- &mlxplat_dev->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 0; -- --fail_platform_mux_register: -- while (--i >= 0) -- platform_device_unregister(priv->pdev_mux[i]); -- platform_device_unregister(priv->pdev_i2c); --fail_alloc: -- platform_device_unregister(mlxplat_dev); -- -- return err; --} --module_init(mlxplat_init); -- --static void __exit mlxplat_exit(void) --{ -- struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); -- int i; -- -- for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) -- platform_device_unregister(priv->pdev_mux[i]); -- -- platform_device_unregister(priv->pdev_i2c); -- platform_device_unregister(mlxplat_dev); --} --module_exit(mlxplat_exit); -- --MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); --MODULE_DESCRIPTION("Mellanox platform driver"); --MODULE_LICENSE("Dual BSD/GPL"); --MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:"); --MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:"); --MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:"); --MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:"); --MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:"); -diff -Nur a/drivers/platform/Kconfig b/drivers/platform/Kconfig ---- a/drivers/platform/Kconfig 2017-11-12 11:01:23.768177498 +0000 -+++ b/drivers/platform/Kconfig 2017-11-12 11:01:47.784177817 +0000 -@@ -8,3 +8,5 @@ - source "drivers/platform/goldfish/Kconfig" - - source "drivers/platform/chrome/Kconfig" -+ -+source "drivers/platform/mellanox/Kconfig" -diff -Nur a/drivers/platform/Makefile b/drivers/platform/Makefile ---- a/drivers/platform/Makefile 2017-11-12 11:01:23.768177498 +0000 -+++ b/drivers/platform/Makefile 2017-11-12 11:01:47.784177817 +0000 -@@ -3,6 +3,7 @@ - # - - obj-$(CONFIG_X86) += x86/ -+obj-$(CONFIG_MELLANOX_PLATFORM) += mellanox/ - obj-$(CONFIG_MIPS) += mips/ - obj-$(CONFIG_OLPC) += olpc/ - obj-$(CONFIG_GOLDFISH) += goldfish/ -diff -Nur a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig ---- a/drivers/platform/x86/Kconfig 2017-11-12 11:03:10.600178917 +0000 -+++ b/drivers/platform/x86/Kconfig 2017-11-12 11:03:56.776179530 +0000 -@@ -1027,4 +1027,17 @@ - used to get various SoC events and parameters - directly via debugfs files. Various tools may use - this interface for SoC state monitoring. -+ -+config MLX_PLATFORM -+ tristate "Mellanox Technologies platform support" -+ depends on X86_64 -+ ---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. -+ - endif # X86_PLATFORM_DEVICES -diff -Nur a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile ---- a/drivers/platform/x86/Makefile 2017-11-12 11:03:10.600178917 +0000 -+++ b/drivers/platform/x86/Makefile 2017-11-12 11:03:56.776179530 +0000 -@@ -71,3 +71,4 @@ - intel_telemetry_pltdrv.o \ - intel_telemetry_debugfs.o - obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o -+obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o -diff -Nur a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c ---- a/drivers/platform/x86/mlx-platform.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/platform/x86/mlx-platform.c 2017-11-12 11:03:56.776179530 +0000 -@@ -0,0 +1,1090 @@ -+/* -+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2016 Vadim Pasternak -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. 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. -+ * 3. Neither the names of the copyright holders nor the names of its -+ * contributors may be used to endorse or promote products derived from -+ * this software without specific prior written permission. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2 as published by the Free -+ * Software Foundation. -+ * -+ * 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 -+#include -+#include -+#include -+ -+#define MLX_PLAT_DEVICE_NAME "mlxplat" -+ -+/* LPC bus IO offsets */ -+#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 -+#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 -+#define MLXPLAT_CPLD_LPC_REG_LED1_OFF 0x20 -+#define MLXPLAT_CPLD_LPC_REG_LED2_OFF 0x21 -+#define MLXPLAT_CPLD_LPC_REG_LED3_OFF 0x22 -+#define MLXPLAT_CPLD_LPC_REG_LED4_OFF 0x23 -+#define MLXPLAT_CPLD_LPC_REG_LED5_OFF 0x24 -+#define MLXPLAT_CPLD_LPC_REG_AGGR_OFF 0x3a -+#define MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF 0x40 -+#define MLXPLAT_CPLD_LPC_REG_PSU_OFF 0x58 -+#define MLXPLAT_CPLD_LPC_REG_PWR_OFF 0x64 -+#define MLXPLAT_CPLD_LPC_REG_FAN_OFF 0x88 -+#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_PIO_OFFSET 0x10000UL -+#define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ -+ MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \ -+ 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_PIO_OFFSET) -+ -+/* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ -+#define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08 -+#define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08 -+#define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40 -+#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ -+ MLXPLAT_CPLD_AGGR_FAN_MASK_DEF) -+#define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04 -+#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc0 -+#define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04 -+#define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) -+#define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) -+#define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) -+#define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0) -+#define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) -+#define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) -+ -+/* Start channel numbers */ -+#define MLXPLAT_CPLD_CH1 2 -+#define MLXPLAT_CPLD_CH2 10 -+ -+/* Number of LPC attached MUX platform devices */ -+#define MLXPLAT_CPLD_LPC_MUX_DEVS 2 -+ -+/* PSU adapter numbers */ -+#define MLXPLAT_CPLD_PSU_DEFAULT_NR 10 -+#define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4 -+ -+/* mlxplat_priv - platform private data -+ * @pdev_i2c - i2c controller platform device -+ * @pdev_mux - array of mux platform devices -+ * @pdev_hotplug - hotplug platform devices -+ * @pdev_led - led platform devices -+ */ -+struct mlxplat_priv { -+ struct platform_device *pdev_i2c; -+ struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS]; -+ struct platform_device *pdev_hotplug; -+ struct platform_device *pdev_led; -+}; -+ -+/* 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, -+ MLXPLAT_CPLD_LPC_IO_RANGE, -+ "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO), -+ [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR, -+ MLXPLAT_CPLD_LPC_IO_RANGE, -+ "mlxplat_cpld_lpc_regs", -+ IORESOURCE_IO), -+}; -+ -+/* Platform default channels */ -+static const int mlxplat_default_channels[][8] = { -+ { -+ MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2, -+ MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 + -+ 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7 -+ }, -+ { -+ MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2, -+ MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 + -+ 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7 -+ }, -+}; -+ -+/* Platform channels for MSN21xx system family */ -+static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; -+ -+/* Platform mux data */ -+static struct i2c_mux_reg_platform_data mlxplat_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, -+ }, -+ { -+ .parent = 1, -+ .base_nr = MLXPLAT_CPLD_CH2, -+ .write_only = 1, -+ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, -+ .reg_size = 1, -+ .idle_in_use = 1, -+ }, -+ -+}; -+ -+/* Platform hotplug devices */ -+static struct i2c_board_info mlxplat_mlxcpld_psu[] = { -+ { -+ I2C_BOARD_INFO("24c02", 0x51), -+ }, -+ { -+ I2C_BOARD_INFO("24c02", 0x50), -+ }, -+}; -+ -+static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { -+ { -+ I2C_BOARD_INFO("dps460", 0x59), -+ }, -+ { -+ I2C_BOARD_INFO("dps460", 0x58), -+ }, -+}; -+ -+static struct i2c_board_info mlxplat_mlxcpld_fan[] = { -+ { -+ I2C_BOARD_INFO("24c32", 0x50), -+ }, -+ { -+ I2C_BOARD_INFO("24c32", 0x50), -+ }, -+ { -+ I2C_BOARD_INFO("24c32", 0x50), -+ }, -+ { -+ I2C_BOARD_INFO("24c32", 0x50), -+ }, -+}; -+ -+/* Platform hotplug default data */ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = { -+ { -+ .label = "psu1", -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .mask = BIT(0), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, -+ }, -+ { -+ .label = "psu2", -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .mask = BIT(1), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, -+ }, -+}; -+ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = { -+ { -+ .label = "pwr1", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .mask = BIT(0), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, -+ }, -+ { -+ .label = "pwr2", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .mask = BIT(1), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, -+ }, -+}; -+ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { -+ { -+ .label = "fan1", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(0), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0], -+ .hpdev.nr = 11, -+ }, -+ { -+ .label = "fan2", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(1), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1], -+ .hpdev.nr = 12, -+ }, -+ { -+ .label = "fan3", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(2), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2], -+ .hpdev.nr = 13, -+ }, -+ { -+ .label = "fan4", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(3), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3], -+ .hpdev.nr = 14, -+ }, -+}; -+ -+static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { -+ { -+ .data = mlxplat_mlxcpld_default_psu_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .mask = MLXPLAT_CPLD_PSU_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), -+ .inversed = 1, -+ .health = false, -+ }, -+ { -+ .data = mlxplat_mlxcpld_default_pwr_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .mask = MLXPLAT_CPLD_PWR_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), -+ .inversed = 0, -+ .health = false, -+ }, -+ { -+ .data = mlxplat_mlxcpld_default_fan_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = MLXPLAT_CPLD_FAN_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_fan), -+ .inversed = 1, -+ .health = false, -+ }, -+}; -+ -+static -+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { -+ .items = mlxplat_mlxcpld_default_items, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items), -+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, -+ .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, -+}; -+ -+/* Platform hotplug MSN21xx system family data */ -+static struct i2c_board_info mlxplat_mlxcpld_msn21xx_pwr[] = { -+ { -+ I2C_BOARD_INFO("holder", 0x59), -+ }, -+ { -+ I2C_BOARD_INFO("holder", 0x58), -+ }, -+}; -+ -+static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = { -+ { -+ .label = "pwr1", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .mask = BIT(0), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_msn21xx_pwr[0], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, -+ }, -+ { -+ .label = "pwr2", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .mask = BIT(1), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_msn21xx_pwr[1], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, -+ }, -+}; -+ -+static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = { -+ { -+ .data = mlxplat_mlxcpld_msn21xx_pwr_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .mask = MLXPLAT_CPLD_PWR_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data), -+ .inversed = 0, -+ .health = false, -+ }, -+}; -+ -+static -+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { -+ .items = mlxplat_mlxcpld_msn21xx_items, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items), -+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, -+ .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, -+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF, -+ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, -+}; -+ -+/* Platform hotplug MSN201x system family data */ -+static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data[] = { -+ { -+ .label = "pwr1", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .mask = BIT(0), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_msn21xx_pwr[0], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, -+ }, -+ { -+ .label = "pwr2", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .mask = BIT(1), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_msn21xx_pwr[1], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, -+ }, -+}; -+ -+static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = { -+ { -+ .data = mlxplat_mlxcpld_msn201x_pwr_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .mask = MLXPLAT_CPLD_PWR_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_pwr_items_data), -+ .inversed = 0, -+ .health = false, -+ }, -+}; -+ -+static -+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = { -+ .items = mlxplat_mlxcpld_msn21xx_items, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items), -+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, -+ .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, -+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF, -+ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, -+}; -+ -+/* Platform hotplug next generation system family data */ -+static struct i2c_board_info mlxplat_mlxcpld_ng_fan = { -+ I2C_BOARD_INFO("holder", 0x50), -+}; -+ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = { -+ { -+ .label = "psu1", -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .mask = BIT(0), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, -+ }, -+ { -+ .label = "psu2", -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .mask = BIT(1), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, -+ }, -+}; -+ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data[] = { -+ { -+ .label = "pwr1", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .mask = BIT(0), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, -+ }, -+ { -+ .label = "pwr2", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .mask = BIT(1), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, -+ }, -+}; -+ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = { -+ { -+ .label = "fan1", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(0), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -+ .hpdev.nr = 11, -+ }, -+ { -+ .label = "fan2", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(1), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -+ .hpdev.nr = 12, -+ }, -+ { -+ .label = "fan3", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(2), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -+ .hpdev.nr = 13, -+ }, -+ { -+ .label = "fan4", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(3), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -+ .hpdev.nr = 14, -+ }, -+ { -+ .label = "fan5", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(3), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -+ .hpdev.nr = 15, -+ }, -+ { -+ .label = "fan6", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(3), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -+ .hpdev.nr = 16, -+ }, -+}; -+ -+static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = { -+ { -+ .data = mlxplat_mlxcpld_default_ng_psu_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .mask = MLXPLAT_CPLD_PSU_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), -+ .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_OFF, -+ .mask = MLXPLAT_CPLD_PWR_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), -+ .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_OFF, -+ .mask = MLXPLAT_CPLD_FAN_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), -+ .inversed = 1, -+ .health = false, -+ }, -+}; -+ -+static -+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { -+ .items = mlxplat_mlxcpld_default_ng_items, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items), -+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, -+ .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, -+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF, -+ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, -+}; -+ -+static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = { -+ { -+ .label = "fan1", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(0), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -+ .hpdev.nr = 11, -+ }, -+ { -+ .label = "fan2", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(1), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -+ .hpdev.nr = 12, -+ }, -+ { -+ .label = "fan3", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(2), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -+ .hpdev.nr = 13, -+ }, -+ { -+ .label = "fan4", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = BIT(3), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -+ .hpdev.nr = 14, -+ }, -+}; -+ -+static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = { -+ { -+ .data = mlxplat_mlxcpld_default_ng_psu_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .mask = MLXPLAT_CPLD_PSU_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), -+ .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_OFF, -+ .mask = MLXPLAT_CPLD_PWR_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), -+ .inversed = 0, -+ .health = false, -+ }, -+ { -+ .data = mlxplat_mlxcpld_msn274x_fan_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .mask = MLXPLAT_CPLD_FAN_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data), -+ .inversed = 1, -+ .health = false, -+ }, -+}; -+ -+static -+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = { -+ .items = mlxplat_mlxcpld_msn274x_items, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items), -+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, -+ .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, -+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF, -+ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, -+}; -+ -+/* Platform led default data */ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { -+ { -+ .label = "status:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "status:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK -+ }, -+ { -+ .label = "psu:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "psu:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan1:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan1:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan2:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan2:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan3:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan3:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan4:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan4:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+}; -+ -+static struct mlxreg_core_led_platform_data mlxplat_default_led_data = { -+ .data = mlxplat_mlxcpld_default_led_data, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_data), -+}; -+ -+/* Platform led MSN21xx system family data */ -+static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_led_data[] = { -+ { -+ .label = "status:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "status:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK -+ }, -+ { -+ .label = "fan:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "psu1:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "psu1:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "psu2:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "psu2:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "uid:blue", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+}; -+ -+static struct mlxreg_core_led_platform_data mlxplat_msn21xx_led_data = { -+ .data = mlxplat_mlxcpld_msn21xx_led_data, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_led_data), -+}; -+ -+/* Platform led for default data for 200GbE systems */ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_led_data[] = { -+ { -+ .label = "status:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "status:orange", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK -+ }, -+ { -+ .label = "psu:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "psu:orange", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan1:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan1:orange", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan2:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan2:orange", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan3:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan3:orange", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan4:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan4:orange", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan5:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan5:orange", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan6:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan6:orange", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+}; -+ -+static struct mlxreg_core_led_platform_data mlxplat_default_ng_led_data = { -+ .data = mlxplat_mlxcpld_default_ng_led_data, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data), -+}; -+ -+static int -+mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val) -+{ -+ *val = ioread8(context + reg); -+ return 0; -+} -+ -+static int -+mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val) -+{ -+ iowrite8(val, context + reg); -+ return 0; -+} -+ -+const struct regmap_config mlxplat_mlxcpld_regmap_config = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ .max_register = 255, -+ .reg_read = mlxplat_mlxcpld_reg_read, -+ .reg_write = mlxplat_mlxcpld_reg_write, -+}; -+ -+static struct resource mlxplat_mlxcpld_resources[] = { -+ [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"), -+}; -+ -+struct platform_device *mlxplat_dev; -+struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; -+struct mlxreg_core_led_platform_data *mlxplat_led; -+ -+static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -+ mlxplat_mux_data[i].values = mlxplat_default_channels[i]; -+ mlxplat_mux_data[i].n_values = -+ ARRAY_SIZE(mlxplat_default_channels[i]); -+ } -+ mlxplat_hotplug = &mlxplat_mlxcpld_default_data; -+ mlxplat_led = &mlxplat_default_led_data; -+ -+ return 1; -+}; -+ -+static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -+ mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; -+ mlxplat_mux_data[i].n_values = -+ ARRAY_SIZE(mlxplat_msn21xx_channels); -+ } -+ mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data; -+ mlxplat_led = &mlxplat_msn21xx_led_data; -+ -+ return 1; -+}; -+ -+static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -+ mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; -+ mlxplat_mux_data[i].n_values = -+ ARRAY_SIZE(mlxplat_msn21xx_channels); -+ } -+ mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data; -+ mlxplat_led = &mlxplat_default_led_data; -+ -+ return 1; -+}; -+ -+static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -+ mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; -+ mlxplat_mux_data[i].n_values = -+ ARRAY_SIZE(mlxplat_msn21xx_channels); -+ } -+ mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data; -+ mlxplat_led = &mlxplat_default_ng_led_data; -+ -+ return 1; -+}; -+ -+static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -+ mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; -+ mlxplat_mux_data[i].n_values = -+ ARRAY_SIZE(mlxplat_msn21xx_channels); -+ } -+ mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data; -+ mlxplat_led = &mlxplat_msn21xx_led_data; -+ -+ return 1; -+}; -+ -+static struct dmi_system_id mlxplat_dmi_table[] __initdata = { -+ { -+ .callback = mlxplat_dmi_msn274x_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN274"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_default_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_default_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_default_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSB"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_default_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSX"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_msn21xx_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_msn201x_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN201"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_qmb7xx_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_qmb7xx_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "SN37"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_qmb7xx_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "SN34"), -+ }, -+ }, -+ { } -+}; -+ -+static int __init mlxplat_init(void) -+{ -+ struct mlxplat_priv *priv; -+ void __iomem *base; -+ int i, err = 0; -+ -+ 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); -+ -+ 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->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1, -+ NULL, 0); -+ if (IS_ERR(priv->pdev_i2c)) { -+ err = PTR_ERR(priv->pdev_i2c); -+ goto fail_alloc; -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -+ priv->pdev_mux[i] = platform_device_register_resndata( -+ &mlxplat_dev->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; -+ } -+ } -+ -+ base = devm_ioport_map(&mlxplat_dev->dev, -+ mlxplat_lpc_resources[1].start, 1); -+ if (IS_ERR(base)) -+ goto fail_platform_mux_register; -+ -+ mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, -+ base, &mlxplat_mlxcpld_regmap_config); -+ if (IS_ERR(mlxplat_hotplug->regmap)) -+ goto fail_platform_mux_register; -+ -+ priv->pdev_hotplug = platform_device_register_resndata( -+ &mlxplat_dev->dev, "mlxreg-hotplug", -+ PLATFORM_DEVID_NONE, -+ mlxplat_mlxcpld_resources, -+ ARRAY_SIZE(mlxplat_mlxcpld_resources), -+ mlxplat_hotplug, sizeof(*mlxplat_hotplug)); -+ if (IS_ERR(priv->pdev_hotplug)) { -+ err = PTR_ERR(priv->pdev_hotplug); -+ goto fail_platform_mux_register; -+ } -+ -+ mlxplat_led->regmap = mlxplat_hotplug->regmap; -+ priv->pdev_led = platform_device_register_resndata( -+ &mlxplat_dev->dev, "leds-mlxreg", -+ PLATFORM_DEVID_NONE, NULL, 0, -+ mlxplat_led, sizeof(*mlxplat_led)); -+ if (IS_ERR(priv->pdev_led)) { -+ err = PTR_ERR(priv->pdev_led); -+ goto fail_platform_hotplug_register; -+ } -+ -+ return 0; -+ -+fail_platform_hotplug_register: -+ 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: -+ platform_device_unregister(mlxplat_dev); -+ -+ return err; -+} -+module_init(mlxplat_init); -+ -+static void __exit mlxplat_exit(void) -+{ -+ struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); -+ int i; -+ -+ platform_device_unregister(priv->pdev_led); -+ platform_device_unregister(priv->pdev_hotplug); -+ -+ for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) -+ platform_device_unregister(priv->pdev_mux[i]); -+ -+ platform_device_unregister(priv->pdev_i2c); -+ platform_device_unregister(mlxplat_dev); -+} -+module_exit(mlxplat_exit); -+ -+MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); -+MODULE_DESCRIPTION("Mellanox platform driver"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:"); -+MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:"); -+MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:"); -+MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:"); -+MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:"); -+MODULE_ALIAS("dmi:*:*Mellanox*MSN274*:"); -+MODULE_ALIAS("dmi:*:*Mellanox*MSN201*:"); -+MODULE_ALIAS("dmi:*:*Mellanox*QMB7*:"); -+MODULE_ALIAS("dmi:*:*Mellanox*SN37*:"); -+MODULE_ALIAS("dmi:*:*Mellanox*QM34*:"); diff --git a/patch/0004-mlxsw-core-Add-the-hottest-thermal-zone-detection.patch b/patch/0004-mlxsw-core-Add-the-hottest-thermal-zone-detection.patch new file mode 100644 index 000000000000..e8ea2829c1c2 --- /dev/null +++ b/patch/0004-mlxsw-core-Add-the-hottest-thermal-zone-detection.patch @@ -0,0 +1,166 @@ +From 835fc5247dc6c3991fcc1bfbbb5cfa05db613cbc Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 7 Aug 2019 09:59:48 +0000 +Subject: [PATCH 5.3 backport 3/3] mlxsw: core: Add the hottest thermal zone + detection + +When multiple sensors are mapped to the same cooling device, the +cooling device should be set according the worst sensor from the +sensors associated with this cooling device. + +Provide the hottest thermal zone detection and enforce cooling device +to follow the temperature trends of the hottest zone only. +Prevent competition for the cooling device control from others zones, +by "stable trend" indication. A cooling device will not perform any +actions associated with a zone with a "stable trend". + +When other thermal zone is detected as a hottest, a cooling device is +to be switched to following temperature trends of new hottest zone. + +Thermal zone score is represented by 32 bits unsigned integer and +calculated according to the next formula: +For T < TZ, where t from {normal trip = 0, high trip = 1, hot +trip = 2, critical = 3}: +TZ score = (T + (TZ - T) / 2) / (TZ - T) * 256 ** j; +Highest thermal zone score s is set as MAX(TZscore); +Following this formula, if TZ is in trip point higher than TZ, +the higher score is to be always assigned to TZ. + +For two thermal zones located at the same kind of trip point, the higher +score will be assigned to the zone which is closer to the next trip +point. Thus, the highest score will always be assigned objectively to +the hottest thermal zone. + +All the thermal zones initially are to be configured with mode +"enabled" with the "step_wise" governor. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 55 ++++++++++++++++++++++ + 1 file changed, 55 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 17a340aa9f75..8f5850445cab 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -23,6 +23,7 @@ + #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_MAX_DUTY 255 + /* Minimum and maximum fan allowed speed in percent: from 20% to 100%. Values +@@ -200,6 +201,34 @@ mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core, + return 0; + } + ++static void mlxsw_thermal_tz_score_update(struct mlxsw_thermal *thermal, ++ struct thermal_zone_device *tzdev, ++ struct mlxsw_thermal_trip *trips, ++ int temp) ++{ ++ struct mlxsw_thermal_trip *trip = trips; ++ unsigned int score, delta, i, shift = 1; ++ ++ /* Calculate thermal zone score, if temperature is above the critical ++ * threshold score is set to MLXSW_THERMAL_TEMP_SCORE_MAX. ++ */ ++ score = MLXSW_THERMAL_TEMP_SCORE_MAX; ++ for (i = MLXSW_THERMAL_TEMP_TRIP_NORM; i < MLXSW_THERMAL_NUM_TRIPS; ++ i++, trip++) { ++ if (temp < trip->temp) { ++ delta = DIV_ROUND_CLOSEST(temp, trip->temp - temp); ++ score = delta * shift; ++ break; ++ } ++ shift *= 256; ++ } ++ ++ if (score > thermal->tz_highest_score) { ++ thermal->tz_highest_score = score; ++ thermal->tz_highest_dev = tzdev; ++ } ++} ++ + static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev, + struct thermal_cooling_device *cdev) + { +@@ -295,6 +324,9 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, + return err; + } + mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); ++ if (temp > 0) ++ mlxsw_thermal_tz_score_update(thermal, tzdev, thermal->trips, ++ temp); + + *p_temp = temp; + return 0; +@@ -356,6 +388,22 @@ static int mlxsw_thermal_set_trip_hyst(struct thermal_zone_device *tzdev, + return 0; + } + ++static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev, ++ int trip, enum thermal_trend *trend) ++{ ++ struct mlxsw_thermal_module *tz = tzdev->devdata; ++ struct mlxsw_thermal *thermal = tz->parent; ++ ++ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) ++ return -EINVAL; ++ ++ if (tzdev == thermal->tz_highest_dev) ++ return 1; ++ ++ *trend = THERMAL_TREND_STABLE; ++ return 0; ++} ++ + struct thermal_zone_params mlxsw_thermal_params = { + .no_hwmon = true, + }; +@@ -367,6 +415,7 @@ static struct thermal_zone_device_ops mlxsw_thermal_ops = { + .set_trip_temp = mlxsw_thermal_set_trip_temp, + .get_trip_hyst = mlxsw_thermal_get_trip_hyst, + .set_trip_hyst = mlxsw_thermal_set_trip_hyst, ++ .get_trend = mlxsw_thermal_trend_get, + }; + + static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev, +@@ -478,6 +527,8 @@ static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, + + /* Update trip points. */ + err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz); ++ if (!err && temp > 0) ++ mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp); + + return 0; + } +@@ -553,6 +604,7 @@ static struct thermal_zone_device_ops mlxsw_thermal_module_ops = { + .set_trip_temp = mlxsw_thermal_module_trip_temp_set, + .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get, + .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set, ++ .get_trend = mlxsw_thermal_trend_get, + }; + + static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, +@@ -573,6 +625,8 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, + return err; + + mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); ++ if (temp > 0) ++ mlxsw_thermal_tz_score_update(thermal, tzdev, tz->trips, temp); + + *p_temp = temp; + return 0; +@@ -589,6 +643,7 @@ static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = { + .set_trip_temp = mlxsw_thermal_module_trip_temp_set, + .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get, + .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set, ++ .get_trend = mlxsw_thermal_trend_get, + }; + + static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev, +-- +2.11.0 + diff --git a/patch/0004-platform-x86-Introduce-support-for-Mellanox-hotplug-.patch b/patch/0004-platform-x86-Introduce-support-for-Mellanox-hotplug-.patch deleted file mode 100644 index 58973010c689..000000000000 --- a/patch/0004-platform-x86-Introduce-support-for-Mellanox-hotplug-.patch +++ /dev/null @@ -1,905 +0,0 @@ -Linux backport patch. Includes following commits: -2926024b5081fc8d4b086677bafa1ac55ea0b911 -6124fdf76488681713f278f3fdf2ba2dfe760211 -c84002d15210ca130263e23911cc399202124eb4 -07b89c2b2a5e8ce30166b96f87b324c6b419f108 -91973760712f350048a0fa8e0363e260bf874313 -c2e714e56360e34f88e0a75ee74e467d8b82de75 -af4779be0f2cec63f4cb15d3db78c5de3523756a -d53bc5dc941653f0ed93b11a647bd6ff40f40ef2 - - -diff -Nur a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig ---- a/drivers/platform/mellanox/Kconfig 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/platform/mellanox/Kconfig 2017-11-12 08:54:58.200076777 +0000 -@@ -0,0 +1,25 @@ -+# -+# Platform support for Mellanox hardware -+# -+ -+menuconfig MELLANOX_PLATFORM -+ bool "Platform support for Mellanox hardware" -+ depends on X86 || ARM || COMPILE_TEST -+ ---help--- -+ Say Y here to get to see options for platform support for -+ Mellanox systems. This option alone does not add any kernel code. -+ -+ If you say N, all options in this submenu will be skipped and disabled. -+ -+if MELLANOX_PLATFORM -+ -+config MLXREG_HOTPLUG -+ tristate "Mellanox platform hotplug driver support" -+ depends on REGMAP -+ depends on HWMON -+ depends on I2C -+ ---help--- -+ This driver handles hot-plug events for the power suppliers, power -+ cables and fans on the wide range Mellanox IB and Ethernet systems. -+ -+endif # MELLANOX_PLATFORM -diff -Nur a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile ---- a/drivers/platform/mellanox/Makefile 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/platform/mellanox/Makefile 2017-11-12 08:54:58.200076777 +0000 -@@ -0,0 +1 @@ -+obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o -diff -Nur a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c ---- a/drivers/platform/mellanox/mlxreg-hotplug.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/platform/mellanox/mlxreg-hotplug.c 2017-11-12 08:54:58.200076777 +0000 -@@ -0,0 +1,710 @@ -+/* -+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2017 Vadim Pasternak -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. 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. -+ * 3. Neither the names of the copyright holders nor the names of its -+ * contributors may be used to endorse or promote products derived from -+ * this software without specific prior written permission. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2 as published by the Free -+ * Software Foundation. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+ -+/* Offset of event and mask registers from status register. */ -+#define MLXREG_HOTPLUG_EVENT_OFF 1 -+#define MLXREG_HOTPLUG_MASK_OFF 2 -+#define MLXREG_HOTPLUG_AGGR_MASK_OFF 1 -+ -+/* ASIC health parameters. */ -+#define MLXREG_HOTPLUG_HEALTH_MASK 0x02 -+#define MLXREG_HOTPLUG_RST_CNTR 3 -+ -+#define MLXREG_HOTPLUG_PROP_OKAY "okay" -+#define MLXREG_HOTPLUG_PROP_DISABLED "disabled" -+#define MLXREG_HOTPLUG_PROP_STATUS "status" -+ -+#define MLXREG_HOTPLUG_ATTRS_MAX 24 -+ -+/** -+ * struct mlxreg_hotplug_priv_data - platform private data: -+ * @irq: platform device interrupt number; -+ * @pdev: platform device; -+ * @plat: platform data; -+ * @dwork: delayed work template; -+ * @lock: spin lock; -+ * @hwmon: hwmon device; -+ * @mlxreg_hotplug_attr: sysfs attributes array; -+ * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array; -+ * @group: sysfs attribute group; -+ * @groups: list of sysfs attribute group for hwmon registration; -+ * @cell: location of top aggregation interrupt register; -+ * @mask: top aggregation interrupt common mask; -+ * @aggr_cache: last value of aggregation register status; -+ */ -+struct mlxreg_hotplug_priv_data { -+ int irq; -+ struct device *dev; -+ struct platform_device *pdev; -+ struct mlxreg_hotplug_platform_data *plat; -+ struct regmap *regmap; -+ struct delayed_work dwork_irq; -+ struct delayed_work dwork; -+ spinlock_t lock; /* sync with interrupt */ -+ struct device *hwmon; -+ struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1]; -+ struct sensor_device_attribute_2 -+ mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX]; -+ struct attribute_group group; -+ const struct attribute_group *groups[2]; -+ u32 cell; -+ u32 mask; -+ u32 aggr_cache; -+ bool after_probe; -+}; -+ -+#if defined(CONFIG_OF_DYNAMIC) -+/** -+ * struct mlxreg_hotplug_device_en - Open Firmware property for enabling device -+ * -+ * @name - property name; -+ * @value - property value string; -+ * @length - length of proprty value string; -+ * -+ * The structure is used for the devices, which require some dynamic -+ * selection operation allowing access to them. -+ */ -+static struct property mlxreg_hotplug_device_en = { -+ .name = MLXREG_HOTPLUG_PROP_STATUS, -+ .value = MLXREG_HOTPLUG_PROP_OKAY, -+ .length = sizeof(MLXREG_HOTPLUG_PROP_OKAY), -+}; -+ -+/** -+ * struct mlxreg_hotplug_device_dis - Open Firmware property for disabling -+ * device -+ * -+ * @name - property name; -+ * @value - property value string; -+ * @length - length of proprty value string; -+ * -+ * The structure is used for the devices, which require some dynamic -+ * selection operation disallowing access to them. -+ */ -+static struct property mlxreg_hotplug_device_dis = { -+ .name = MLXREG_HOTPLUG_PROP_STATUS, -+ .value = MLXREG_HOTPLUG_PROP_DISABLED, -+ .length = sizeof(MLXREG_HOTPLUG_PROP_DISABLED), -+}; -+ -+static int mlxreg_hotplug_of_device_create(struct mlxreg_core_data *data) -+{ -+ return of_update_property(data->np, &mlxreg_hotplug_device_en); -+} -+ -+static void mlxreg_hotplug_of_device_destroy(struct mlxreg_core_data *data) -+{ -+ of_update_property(data->np, &mlxreg_hotplug_device_dis); -+ of_node_clear_flag(data->np, OF_POPULATED); -+} -+#else -+static int mlxreg_hotplug_of_device_create(struct mlxreg_core_data *data) -+{ -+ return 0; -+} -+ -+static void mlxreg_hotplug_of_device_destroy(struct mlxreg_core_data *data) -+{ -+} -+#endif -+ -+static int mlxreg_hotplug_device_create(struct mlxreg_core_data *data) -+{ -+ data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr); -+ if (!data->hpdev.adapter) -+ return -EFAULT; -+ -+ data->hpdev.client = i2c_new_device(data->hpdev.adapter, -+ data->hpdev.brdinfo); -+ if (!data->hpdev.client) { -+ i2c_put_adapter(data->hpdev.adapter); -+ data->hpdev.adapter = NULL; -+ return -EFAULT; -+ } -+ -+ return 0; -+} -+ -+static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data) -+{ -+ if (data->hpdev.client) { -+ i2c_unregister_device(data->hpdev.client); -+ data->hpdev.client = NULL; -+ } -+ -+ if (data->hpdev.adapter) { -+ i2c_put_adapter(data->hpdev.adapter); -+ data->hpdev.adapter = NULL; -+ } -+} -+ -+static int mlxreg_hotplug_dev_enable(struct mlxreg_core_data *data) -+{ -+ int err; -+ -+ /* Enable and create device. */ -+ if (data->np) -+ err = mlxreg_hotplug_of_device_create(data); -+ else -+ err = mlxreg_hotplug_device_create(data); -+ -+ return err; -+} -+ -+static void mlxreg_hotplug_dev_disable(struct mlxreg_core_data *data) -+{ -+ /* Disable and unregister platform device. */ -+ if (data->np) -+ mlxreg_hotplug_of_device_destroy(data); -+ else -+ mlxreg_hotplug_device_destroy(data); -+} -+ -+static ssize_t mlxreg_hotplug_attr_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev); -+ struct mlxreg_core_hotplug_platform_data *pdata; -+ int index = to_sensor_dev_attr_2(attr)->index; -+ int nr = to_sensor_dev_attr_2(attr)->nr; -+ struct mlxreg_core_item *item; -+ struct mlxreg_core_data *data; -+ u32 regval; -+ int ret; -+ -+ pdata = dev_get_platdata(&priv->pdev->dev); -+ item = pdata->items + nr; -+ data = item->data + index; -+ -+ ret = regmap_read(priv->regmap, data->reg, ®val); -+ if (ret) -+ return ret; -+ -+ if (item->health) { -+ regval &= data->mask; -+ } else { -+ /* Bit = 0 : functional if item->inversed is true. */ -+ if (item->inversed) -+ regval = !(regval & data->mask); -+ else -+ regval = !!(regval & data->mask); -+ } -+ -+ return sprintf(buf, "%u\n", regval); -+} -+ -+#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i] -+#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i] -+ -+static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) -+{ -+ struct mlxreg_core_hotplug_platform_data *pdata; -+ struct mlxreg_core_item *item; -+ struct mlxreg_core_data *data; -+ int num_attrs = 0, id = 0, i, j; -+ -+ pdata = dev_get_platdata(&priv->pdev->dev); -+ item = pdata->items; -+ -+ /* Go over all kinds of items - psu, pwr, fan. */ -+ for (i = 0; i < pdata->counter; i++, item++) { -+ num_attrs += item->count; -+ data = item->data; -+ /* Go over all units within the item. */ -+ for (j = 0; j < item->count; j++, data++, id++) { -+ 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); -+ return -ENOMEM; -+ } -+ -+ PRIV_DEV_ATTR(id).dev_attr.attr.name = -+ PRIV_ATTR(id)->name; -+ PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444; -+ PRIV_DEV_ATTR(id).dev_attr.show = -+ mlxreg_hotplug_attr_show; -+ PRIV_DEV_ATTR(id).nr = i; -+ PRIV_DEV_ATTR(id).index = j; -+ sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr); -+ } -+ } -+ -+ priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs * -+ sizeof(struct attribute *), -+ GFP_KERNEL); -+ if (!priv->group.attrs) -+ return -ENOMEM; -+ -+ priv->group.attrs = priv->mlxreg_hotplug_attr; -+ priv->groups[0] = &priv->group; -+ priv->groups[1] = NULL; -+ -+ return 0; -+} -+ -+static void -+mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, -+ struct mlxreg_core_item *item) -+{ -+ struct mlxreg_core_data *data; -+ u32 asserted, regval, bit; -+ int ret; -+ -+ /* -+ * Validate if item related to received signal type is valid. -+ * It should never happen, excepted the situation when some -+ * piece of hardware is broken. In such situation just produce -+ * error message and return. Caller must continue to handle the -+ * signals from other devices if any. -+ */ -+ if (unlikely(!item)) { -+ dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n", -+ item->reg, item->mask); -+ -+ return; -+ } -+ -+ /* Mask event. */ -+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, -+ 0); -+ if (ret) -+ goto access_error; -+ -+ /* Read status. */ -+ ret = regmap_read(priv->regmap, item->reg, ®val); -+ if (ret) -+ goto access_error; -+ -+ /* Set asserted bits and save last status. */ -+ regval &= item->mask; -+ asserted = item->cache ^ regval; -+ item->cache = regval; -+ -+ for_each_set_bit(bit, (unsigned long *)&asserted, 8) { -+ data = item->data + bit; -+ if (regval & BIT(bit)) { -+ if (item->inversed) -+ mlxreg_hotplug_dev_disable(data); -+ else -+ mlxreg_hotplug_dev_enable(data); -+ } else { -+ if (item->inversed) -+ mlxreg_hotplug_dev_enable(data); -+ else -+ mlxreg_hotplug_dev_disable(data); -+ } -+ } -+ -+ /* Acknowledge event. */ -+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF, -+ 0); -+ if (ret) -+ goto access_error; -+ -+ /* Unmask event. */ -+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, -+ item->mask); -+ if (ret) -+ goto access_error; -+ -+ return; -+ -+access_error: -+ dev_err(priv->dev, "Failed to complete workqueue.\n"); -+} -+ -+static void -+mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, -+ struct mlxreg_core_item *item) -+{ -+ struct mlxreg_core_data *data = item->data; -+ u32 regval; -+ int i, ret; -+ -+ for (i = 0; i < item->count; i++, data++) { -+ /* Mask event. */ -+ ret = regmap_write(priv->regmap, data->reg + -+ MLXREG_HOTPLUG_MASK_OFF, 0); -+ if (ret) -+ goto access_error; -+ -+ /* Read status. */ -+ ret = regmap_read(priv->regmap, data->reg, ®val); -+ if (ret) -+ goto access_error; -+ -+ regval &= data->mask; -+ item->cache = regval; -+ if (regval == MLXREG_HOTPLUG_HEALTH_MASK) { -+ if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) || -+ !priv->after_probe) { -+ mlxreg_hotplug_dev_enable(data); -+ data->attached = true; -+ } -+ } else { -+ if (data->attached) { -+ mlxreg_hotplug_dev_disable(data); -+ data->attached = false; -+ data->health_cntr = 0; -+ } -+ } -+ -+ /* Acknowledge event. */ -+ ret = regmap_write(priv->regmap, data->reg + -+ MLXREG_HOTPLUG_EVENT_OFF, 0); -+ if (ret) -+ goto access_error; -+ -+ /* Unmask event. */ -+ ret = regmap_write(priv->regmap, data->reg + -+ MLXREG_HOTPLUG_MASK_OFF, data->mask); -+ if (ret) -+ goto access_error; -+ } -+ -+ return; -+ -+access_error: -+ dev_err(priv->dev, "Failed to complete workqueue.\n"); -+} -+ -+/* -+ * mlxreg_hotplug_work_handler - performs traversing of device interrupt -+ * registers according to the below hierarchy schema: -+ * -+ * Aggregation registers (status/mask) -+ * PSU registers: *---* -+ * *-----------------* | | -+ * |status/event/mask|-----> | * | -+ * *-----------------* | | -+ * Power registers: | | -+ * *-----------------* | | -+ * |status/event/mask|-----> | * | -+ * *-----------------* | | -+ * FAN registers: | |--> CPU -+ * *-----------------* | | -+ * |status/event/mask|-----> | * | -+ * *-----------------* | | -+ * ASIC registers: | | -+ * *-----------------* | | -+ * |status/event/mask|-----> | * | -+ * *-----------------* | | -+ * *---* -+ * -+ * In case some system changed are detected: FAN in/out, PSU in/out, power -+ * cable attached/detached, ASIC helath good/bad, relevant device is created -+ * or destroyed. -+ */ -+static void mlxreg_hotplug_work_handler(struct work_struct *work) -+{ -+ struct mlxreg_hotplug_priv_data *priv = container_of(work, -+ struct mlxreg_hotplug_priv_data, dwork_irq.work); -+ struct mlxreg_core_hotplug_platform_data *pdata; -+ struct mlxreg_core_item *item; -+ unsigned long flags; -+ u32 regval, aggr_asserted; -+ int i; -+ int ret; -+ -+ pdata = dev_get_platdata(&priv->pdev->dev); -+ item = pdata->items; -+ /* Mask aggregation event. */ -+ ret = regmap_write(priv->regmap, pdata->cell + -+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0); -+ if (ret < 0) -+ goto access_error; -+ -+ /* Read aggregation status. */ -+ ret = regmap_read(priv->regmap, pdata->cell, ®val); -+ if (ret) -+ goto access_error; -+ -+ regval &= pdata->mask; -+ aggr_asserted = priv->aggr_cache ^ regval; -+ priv->aggr_cache = regval; -+ -+ /* Handle topology and health configuration changes. */ -+ for (i = 0; i < pdata->counter; i++, item++) { -+ if (aggr_asserted & item->aggr_mask) { -+ if (item->health) -+ mlxreg_hotplug_health_work_helper(priv, item); -+ else -+ mlxreg_hotplug_work_helper(priv, item); -+ } -+ } -+ -+ if (aggr_asserted) { -+ spin_lock_irqsave(&priv->lock, flags); -+ -+ /* -+ * It is possible, that some signals have been inserted, while -+ * interrupt has been masked by mlxreg_hotplug_work_handler. -+ * In this case such signals will 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(&priv->dwork_irq); -+ schedule_delayed_work(&priv->dwork_irq, 0); -+ -+ spin_unlock_irqrestore(&priv->lock, flags); -+ -+ return; -+ } -+ -+ /* Unmask aggregation event (no need acknowledge). */ -+ ret = regmap_write(priv->regmap, pdata->cell + -+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); -+ if (ret) -+ goto access_error; -+ -+ return; -+ -+access_error: -+ dev_err(priv->dev, "Failed to complete workqueue.\n"); -+} -+ -+static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) -+{ -+ struct mlxreg_core_hotplug_platform_data *pdata; -+ struct mlxreg_core_item *item; -+ int i; -+ int ret; -+ -+ pdata = dev_get_platdata(&priv->pdev->dev); -+ item = pdata->items; -+ -+ for (i = 0; i < pdata->counter; i++, item++) { -+ /* Clear group presense event. */ -+ ret = regmap_write(priv->regmap, item->reg + -+ MLXREG_HOTPLUG_EVENT_OFF, 0); -+ if (ret) -+ goto access_error; -+ -+ /* Set group initial status as mask and unmask group event. */ -+ if (item->inversed) { -+ item->cache = item->mask; -+ ret = regmap_write(priv->regmap, item->reg + -+ MLXREG_HOTPLUG_MASK_OFF, -+ item->mask); -+ if (ret) -+ goto access_error; -+ } -+ } -+ -+ /* Keep aggregation initial status as zero and unmask events. */ -+ ret = regmap_write(priv->regmap, pdata->cell + -+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); -+ if (ret) -+ goto access_error; -+ -+ /* Keep low aggregation initial status as zero and unmask events. */ -+ ret = regmap_write(priv->regmap, pdata->cell_low + -+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask_low); -+ if (ret) -+ goto access_error; -+ -+ /* Invoke work handler for initializing hot plug devices setting. */ -+ mlxreg_hotplug_work_handler(&priv->dwork_irq.work); -+ -+ enable_irq(priv->irq); -+ -+ return 0; -+ -+access_error: -+ dev_err(priv->dev, "Failed to set interrupts.\n"); -+ -+ enable_irq(priv->irq); -+ -+ return ret; -+} -+ -+static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv) -+{ -+ struct mlxreg_core_hotplug_platform_data *pdata; -+ struct mlxreg_core_item *item; -+ struct mlxreg_core_data *data; -+ int count, i, j; -+ -+ pdata = dev_get_platdata(&priv->pdev->dev); -+ item = pdata->items; -+ disable_irq(priv->irq); -+ cancel_delayed_work_sync(&priv->dwork_irq); -+ -+ /* Mask low aggregation event. */ -+ regmap_write(priv->regmap, pdata->cell_low + -+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0); -+ -+ /* Mask aggregation event. */ -+ regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF, -+ 0); -+ -+ /* Clear topology configurations. */ -+ for (i = 0; i < pdata->counter; i++, item++) { -+ data = item->data; -+ /* Mask group presense event. */ -+ regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF, -+ 0); -+ /* Clear group presense event. */ -+ regmap_write(priv->regmap, data->reg + -+ MLXREG_HOTPLUG_EVENT_OFF, 0); -+ -+ /* Remove all the attached devices in group. */ -+ count = item->count; -+ for (j = 0; j < count; j++, data++) -+ mlxreg_hotplug_dev_disable(data); -+ } -+} -+ -+static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev) -+{ -+ struct mlxreg_hotplug_priv_data *priv = -+ (struct mlxreg_hotplug_priv_data *)dev; -+ -+ /* Schedule work task for immediate execution.*/ -+ schedule_delayed_work(&priv->dwork_irq, 0); -+ -+ return IRQ_HANDLED; -+} -+ -+static int mlxreg_hotplug_probe(struct platform_device *pdev) -+{ -+ struct mlxreg_core_hotplug_platform_data *pdata; -+ struct mlxreg_hotplug_priv_data *priv; -+ int err; -+ -+ pdata = dev_get_platdata(&pdev->dev); -+ if (!pdata) { -+ dev_err(&pdev->dev, "Failed to get platform data.\n"); -+ return -EINVAL; -+ } -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ if (pdata->irq) { -+ priv->irq = pdata->irq; -+ } else { -+ priv->irq = platform_get_irq(pdev, 0); -+ if (priv->irq < 0) { -+ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", -+ priv->irq); -+ return priv->irq; -+ } -+ } -+ -+ priv->regmap = pdata->regmap; -+ priv->dev = pdev->dev.parent; -+ priv->pdev = pdev; -+ -+ err = devm_request_irq(&pdev->dev, priv->irq, -+ mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING -+ | IRQF_SHARED, "mlxreg-hotplug", priv); -+ if (err) { -+ dev_err(&pdev->dev, "Failed to request irq: %d\n", err); -+ return err; -+ } -+ -+ disable_irq(priv->irq); -+ spin_lock_init(&priv->lock); -+ INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler); -+ /* Perform initial interrupts setup. */ -+ mlxreg_hotplug_set_irq(priv); -+ -+ priv->after_probe = true; -+ dev_set_drvdata(&pdev->dev, priv); -+ -+ err = mlxreg_hotplug_attr_init(priv); -+ if (err) { -+ dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", -+ err); -+ return err; -+ } -+ -+ priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, -+ "mlxreg_hotplug", priv, priv->groups); -+ if (IS_ERR(priv->hwmon)) { -+ dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", -+ PTR_ERR(priv->hwmon)); -+ return PTR_ERR(priv->hwmon); -+ } -+ -+ return 0; -+} -+ -+static int mlxreg_hotplug_remove(struct platform_device *pdev) -+{ -+ struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev); -+ -+ /* Clean interrupts setup. */ -+ mlxreg_hotplug_unset_irq(priv); -+ -+ return 0; -+} -+ -+static struct platform_driver mlxreg_hotplug_driver = { -+ .driver = { -+ .name = "mlxreg-hotplug", -+ }, -+ .probe = mlxreg_hotplug_probe, -+ .remove = mlxreg_hotplug_remove, -+}; -+ -+module_platform_driver(mlxreg_hotplug_driver); -+ -+MODULE_AUTHOR("Vadim Pasternak "); -+MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_ALIAS("platform:mlxreg-hotplug"); -diff -Nur a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h ---- a/include/linux/platform_data/mlxreg.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/include/linux/platform_data/mlxreg.h 2017-11-12 09:04:09.796084101 +0000 -@@ -0,0 +1,142 @@ -+/* -+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2017 Vadim Pasternak -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. 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. -+ * 3. Neither the names of the copyright holders nor the names of its -+ * contributors may be used to endorse or promote products derived from -+ * this software without specific prior written permission. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2 as published by the Free -+ * Software Foundation. -+ * -+ * 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 __LINUX_PLATFORM_DATA_MLXREG_H -+#define __LINUX_PLATFORM_DATA_MLXREG_H -+ -+#define MLXREG_CORE_LABEL_MAX_SIZE 32 -+ -+/** -+ * struct mlxreg_hotplug_device - I2C device data: -+ * -+ * @adapter: I2C device adapter; -+ * @client: I2C device client; -+ * @brdinfo: device board information; -+ * @nr: I2C device adapter number, to which device is to be attached; -+ * -+ * Structure represents I2C hotplug device static data (board topology) and -+ * dynamic data (related kernel objects handles). -+ */ -+struct mlxreg_hotplug_device { -+ struct i2c_adapter *adapter; -+ struct i2c_client *client; -+ struct i2c_board_info *brdinfo; -+ int nr; -+}; -+ -+/** -+ * struct mlxreg_core_data - attributes control data: -+ * -+ * @label: attribute label; -+ * @label: attribute register offset; -+ * @reg: attribute register; -+ * @mask: attribute access mask; -+ * @bit: attribute effective bit; -+ * @np - pointer to node platform associated with attribute; -+ * @hpdev - hotplug device data; -+ * @health_cntr: dynamic device health indication counter; -+ * @attached: true if device has been attached after good helath indication; -+ */ -+struct mlxreg_core_data { -+ char label[MLXREG_CORE_LABEL_MAX_SIZE]; -+ u32 reg; -+ u32 mask; -+ u32 bit; -+ struct device_node *np; -+ struct mlxreg_hotplug_device hpdev; -+ u8 health_cntr; -+ bool attached; -+}; -+ -+/** -+ * struct mlxreg_core_item - same type components controlled by the driver: -+ * -+ * @data: component data; -+ * @aggr_mask: group aggregation mask; -+ * @reg: group interrupt status register; -+ * @mask: group interrupt mask; -+ * @cache: last status value for elements fro the same group; -+ * @count: number of available elements in the group; -+ * @ind: element's index inside the group; -+ * @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK; -+ * @health: true if device has health indication, false in other case; -+ */ -+struct mlxreg_core_item { -+ struct mlxreg_core_data *data; -+ u32 aggr_mask; -+ u32 reg; -+ u32 mask; -+ u32 cache; -+ u8 count; -+ u8 ind; -+ u8 inversed; -+ u8 health; -+}; -+ -+/** -+ * struct mlxreg_core_led_platform_data - led platform data: -+ * -+ * @led_data: led private data; -+ * @regmap: register map of parent device; -+ * @counter: number of led instances; -+ */ -+struct mlxreg_core_led_platform_data { -+ struct mlxreg_core_data *data; -+ void *regmap; -+ int counter; -+}; -+ -+/** -+ * struct mlxreg_core_hotplug_platform_data - hotplug platform data: -+ * -+ * @items: same type components with the hotplug capability; -+ * @irq: platform interrupt number; -+ * @regmap: register map of parent device; -+ * @counter: number of the components with the hotplug capability; -+ * @cell: location of top aggregation interrupt register; -+ * @mask: top aggregation interrupt common mask; -+ * @cell_low: location of low aggregation interrupt register; -+ * @mask_low: low aggregation interrupt common mask; -+ */ -+struct mlxreg_core_hotplug_platform_data { -+ struct mlxreg_core_item *items; -+ int irq; -+ void *regmap; -+ int counter; -+ u32 cell; -+ u32 mask; -+ u32 cell_low; -+ u32 mask_low; -+}; -+ -+#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */ diff --git a/patch/0005-hwmon-pmbus-core-Add-support-for-vid-mode-detection-.patch b/patch/0005-hwmon-pmbus-core-Add-support-for-vid-mode-detection-.patch new file mode 100644 index 000000000000..cda0b465d8a6 --- /dev/null +++ b/patch/0005-hwmon-pmbus-core-Add-support-for-vid-mode-detection-.patch @@ -0,0 +1,418 @@ +From 5766c21f1bb28b43048f188195e8bae90163049c Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 12 Mar 2020 17:17:25 +0200 +Subject: [PATCH] hwmon: (pmbus/core) Add support for vid mode detection per + page bases + +Add support for VID protocol detection per page bases, instead of +detecting it based on PMBU_VOUT readout from page 0. +The reason that some devices allows to configure different VID modes +per page within the same device. + +Extend "vrm_version" with the type for Intel IMVP9 and AMD 6.25mV VID +modes. +Add calculation for those types. + +Add support for devices XDPE12254, XDPE12284. +All these device support two pages. +The below lists of VOUT_MODE command readout with their related VID +protocols, Digital to Analog Converter steps, supported by these +devices: +VR12.0 mode, 5-mV DAC - 0x01; +VR12.5 mode, 10-mV DAC - 0x02; +IMVP9 mode, 5-mV DAC - 0x03; +AMD mode 6.25mV - 0x10. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Stephen Sun +--- + debian/build/build_amd64_none_amd64/.config | 5 +- + drivers/hwmon/pmbus/Kconfig | 9 ++ + drivers/hwmon/pmbus/Makefile | 1 + + drivers/hwmon/pmbus/max20751.c | 2 +- + drivers/hwmon/pmbus/pmbus.c | 5 +- + drivers/hwmon/pmbus/pmbus.h | 4 +- + drivers/hwmon/pmbus/pmbus_core.c | 10 +- + drivers/hwmon/pmbus/tps53679.c | 44 ++--- + drivers/hwmon/pmbus/xdpe12284.c | 171 ++++++++++++++++++++ + 9 files changed, 222 insertions(+), 29 deletions(-) + create mode 100644 drivers/hwmon/pmbus/xdpe12284.c + +diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config +index e787c2796..5d7a68019 100644 +--- a/debian/build/build_amd64_none_amd64/.config ++++ b/debian/build/build_amd64_none_amd64/.config +@@ -4205,8 +4205,6 @@ CONFIG_SENSORS_ATXP1=m + CONFIG_SENSORS_DS620=m + CONFIG_SENSORS_DS1621=m + CONFIG_SENSORS_DELL_SMM=m +-CONFIG_SENSORS_DNI_DPS460=m +-CONFIG_SENSORS_DPS1900=m + CONFIG_SENSORS_I5K_AMB=m + CONFIG_SENSORS_F71805F=m + CONFIG_SENSORS_F71882FG=m +@@ -4290,12 +4288,15 @@ CONFIG_SENSORS_LM25066=m + # CONFIG_SENSORS_MAX20751 is not set + # CONFIG_SENSORS_MAX31785 is not set + # CONFIG_SENSORS_MAX34440 is not set ++CONFIG_SENSORS_DNI_DPS460=m + # CONFIG_SENSORS_MAX8688 is not set + # CONFIG_SENSORS_TPS40422 is not set + CONFIG_SENSORS_TPS53679=m + CONFIG_SENSORS_UCD9000=m + CONFIG_SENSORS_UCD9200=m ++CONFIG_SENSORS_XDPE122=m + # CONFIG_SENSORS_ZL6100 is not set ++CONFIG_SENSORS_DPS1900=m + # CONFIG_SENSORS_SHT15 is not set + CONFIG_SENSORS_SHT21=m + # CONFIG_SENSORS_SHT3x is not set +diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig +index 505ca2be0..eda871222 100644 +--- a/drivers/hwmon/pmbus/Kconfig ++++ b/drivers/hwmon/pmbus/Kconfig +@@ -196,6 +196,15 @@ config SENSORS_UCD9200 + This driver can also be built as a module. If so, the module will + be called ucd9200. + ++config SENSORS_XDPE122 ++ tristate "Infineon XDPE122 family" ++ help ++ If you say yes here you get hardware monitoring support for Infineon ++ XDPE12254, XDPE12284, device. ++ ++ This driver can also be built as a module. If so, the module will ++ be called xdpe12284. ++ + config SENSORS_ZL6100 + tristate "Intersil ZL6100 and compatibles" + default n +diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile +index c76820a4d..edc7c315c 100644 +--- a/drivers/hwmon/pmbus/Makefile ++++ b/drivers/hwmon/pmbus/Makefile +@@ -21,5 +21,6 @@ obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o + obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o + obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o + obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o ++obj-$(CONFIG_SENSORS_XDPE122) += xdpe12284.o + obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o + obj-$(CONFIG_SENSORS_DPS1900) += dps1900.o +diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c +index ab74aeae8..394c662c8 100644 +--- a/drivers/hwmon/pmbus/max20751.c ++++ b/drivers/hwmon/pmbus/max20751.c +@@ -25,7 +25,7 @@ static struct pmbus_driver_info max20751_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = vid, +- .vrm_version = vr12, ++ .vrm_version[0] = vr12, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, +diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c +index 7688dab32..4db0400b7 100644 +--- a/drivers/hwmon/pmbus/pmbus.c ++++ b/drivers/hwmon/pmbus/pmbus.c +@@ -123,7 +123,7 @@ static int pmbus_identify(struct i2c_client *client, + } + + if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) { +- int vout_mode; ++ int vout_mode, i; + + vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); + if (vout_mode >= 0 && vout_mode != 0xff) { +@@ -132,7 +132,8 @@ static int pmbus_identify(struct i2c_client *client, + break; + case 1: + info->format[PSC_VOLTAGE_OUT] = vid; +- info->vrm_version = vr11; ++ for (i = 0; i < info->pages; i++) ++ info->vrm_version[i] = vr11; + break; + case 2: + info->format[PSC_VOLTAGE_OUT] = direct; +diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h +index 1d24397d3..5481ff9f8 100644 +--- a/drivers/hwmon/pmbus/pmbus.h ++++ b/drivers/hwmon/pmbus/pmbus.h +@@ -375,12 +375,12 @@ enum pmbus_sensor_classes { + #define PMBUS_PAGE_VIRTUAL BIT(31) + + enum pmbus_data_format { linear = 0, direct, vid }; +-enum vrm_version { vr11 = 0, vr12, vr13 }; ++enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv }; + + struct pmbus_driver_info { + int pages; /* Total number of pages */ + enum pmbus_data_format format[PSC_NUM_CLASSES]; +- enum vrm_version vrm_version; ++ enum vrm_version vrm_version[PMBUS_PAGES]; /* vrm version per page */ + /* + * Support one set of coefficients for each sensor type + * Used for chips providing data in direct mode. +diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c +index cd24b375d..1d7f950e6 100644 +--- a/drivers/hwmon/pmbus/pmbus_core.c ++++ b/drivers/hwmon/pmbus/pmbus_core.c +@@ -709,7 +709,7 @@ static long pmbus_reg2data_vid(struct pmbus_data *data, + long val = sensor->data; + long rv = 0; + +- switch (data->info->vrm_version) { ++ switch (data->info->vrm_version[sensor->page]) { + case vr11: + if (val >= 0x02 && val <= 0xb2) + rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); +@@ -722,6 +722,14 @@ static long pmbus_reg2data_vid(struct pmbus_data *data, + if (val >= 0x01) + rv = 500 + (val - 1) * 10; + break; ++ case imvp9: ++ if (val >= 0x01) ++ rv = 200 + (val - 1) * 10; ++ break; ++ case amd625mv: ++ if (val >= 0x0 && val <= 0xd8) ++ rv = DIV_ROUND_CLOSEST(155000 - val * 625, 100); ++ break; + } + return rv; + } +diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c +index 45eacc504..28d3de029 100644 +--- a/drivers/hwmon/pmbus/tps53679.c ++++ b/drivers/hwmon/pmbus/tps53679.c +@@ -33,27 +33,29 @@ static int tps53679_identify(struct i2c_client *client, + struct pmbus_driver_info *info) + { + u8 vout_params; +- int ret; +- +- /* Read the register with VOUT scaling value.*/ +- ret = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); +- if (ret < 0) +- return ret; +- +- vout_params = ret & GENMASK(4, 0); +- +- switch (vout_params) { +- case TPS53679_PROT_VR13_10MV: +- case TPS53679_PROT_VR12_5_10MV: +- info->vrm_version = vr13; +- break; +- case TPS53679_PROT_VR13_5MV: +- case TPS53679_PROT_VR12_5MV: +- case TPS53679_PROT_IMVP8_5MV: +- info->vrm_version = vr12; +- break; +- default: +- return -EINVAL; ++ int i, ret; ++ ++ for (i = 0; i < TPS53679_PAGE_NUM; i++) { ++ /* Read the register with VOUT scaling value.*/ ++ ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); ++ if (ret < 0) ++ return ret; ++ ++ vout_params = ret & GENMASK(4, 0); ++ ++ switch (vout_params) { ++ case TPS53679_PROT_VR13_10MV: ++ case TPS53679_PROT_VR12_5_10MV: ++ info->vrm_version[i] = vr13; ++ break; ++ case TPS53679_PROT_VR13_5MV: ++ case TPS53679_PROT_VR12_5MV: ++ case TPS53679_PROT_IMVP8_5MV: ++ info->vrm_version[i] = vr12; ++ break; ++ default: ++ return -EINVAL; ++ } + } + + return 0; +diff --git a/drivers/hwmon/pmbus/xdpe12284.c b/drivers/hwmon/pmbus/xdpe12284.c +new file mode 100644 +index 000000000..660556b89 +--- /dev/null ++++ b/drivers/hwmon/pmbus/xdpe12284.c +@@ -0,0 +1,171 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Hardware monitoring driver for Infineon Multi-phase Digital VR Controllers ++ * ++ * Copyright (c) 2020 Mellanox Technologies. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "pmbus.h" ++ ++#define XDPE122_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */ ++#define XDPE122_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */ ++#define XDPE122_PROT_IMVP9_10MV 0x03 /* IMVP9 mode, 10-mV DAC */ ++#define XDPE122_AMD_625MV 0x10 /* AMD mode 6.25mV */ ++#define XDPE122_PAGE_NUM 2 ++ ++static int xdpe122_read_word_data(struct i2c_client *client, int page, int reg) ++{ ++ const struct pmbus_driver_info *info = pmbus_get_driver_info(client); ++ long val; ++ s16 exponent; ++ s32 mantissa; ++ int ret; ++ ++ switch (reg) { ++ case PMBUS_VOUT_OV_FAULT_LIMIT: ++ case PMBUS_VOUT_UV_FAULT_LIMIT: ++ ret = pmbus_read_word_data(client, page, reg); ++ if (ret < 0) ++ return ret; ++ ++ /* Convert register value to LINEAR11 data. */ ++ exponent = ((s16)ret) >> 11; ++ mantissa = ((s16)((ret & GENMASK(10, 0)) << 5)) >> 5; ++ val = mantissa * 1000L; ++ if (exponent >= 0) ++ val <<= exponent; ++ else ++ val >>= -exponent; ++ ++ /* Convert data to VID register. */ ++ switch (info->vrm_version[page]) { ++ case vr13: ++ if (val >= 500) ++ return 1 + DIV_ROUND_CLOSEST(val - 500, 10); ++ return 0; ++ case vr12: ++ if (val >= 250) ++ return 1 + DIV_ROUND_CLOSEST(val - 250, 5); ++ return 0; ++ case imvp9: ++ if (val >= 200) ++ return 1 + DIV_ROUND_CLOSEST(val - 200, 10); ++ return 0; ++ case amd625mv: ++ if (val >= 200 && val <= 1550) ++ return DIV_ROUND_CLOSEST((1550 - val) * 100, ++ 625); ++ return 0; ++ default: ++ return -EINVAL; ++ } ++ default: ++ return -ENODATA; ++ } ++ ++ return 0; ++} ++ ++static int xdpe122_identify(struct i2c_client *client, ++ struct pmbus_driver_info *info) ++{ ++ u8 vout_params; ++ int i, ret; ++ ++ for (i = 0; i < XDPE122_PAGE_NUM; i++) { ++ /* Read the register with VOUT scaling value.*/ ++ ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); ++ if (ret < 0) ++ return ret; ++ ++ vout_params = ret & GENMASK(4, 0); ++ ++ switch (vout_params) { ++ case XDPE122_PROT_VR12_5_10MV: ++ info->vrm_version[i] = vr13; ++ break; ++ case XDPE122_PROT_VR12_5MV: ++ info->vrm_version[i] = vr12; ++ break; ++ case XDPE122_PROT_IMVP9_10MV: ++ info->vrm_version[i] = imvp9; ++ break; ++ case XDPE122_AMD_625MV: ++ info->vrm_version[i] = amd625mv; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static struct pmbus_driver_info xdpe122_info = { ++ .pages = XDPE122_PAGE_NUM, ++ .format[PSC_VOLTAGE_IN] = linear, ++ .format[PSC_VOLTAGE_OUT] = vid, ++ .format[PSC_TEMPERATURE] = linear, ++ .format[PSC_CURRENT_IN] = linear, ++ .format[PSC_CURRENT_OUT] = linear, ++ .format[PSC_POWER] = linear, ++ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ++ PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | ++ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | ++ PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT, ++ .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ++ PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | ++ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | ++ PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT, ++ .identify = xdpe122_identify, ++ .read_word_data = xdpe122_read_word_data, ++}; ++ ++static int xdpe122_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct pmbus_driver_info *info; ++ ++ info = devm_kmemdup(&client->dev, &xdpe122_info, sizeof(*info), ++ GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ return pmbus_do_probe(client, id, info); ++} ++ ++static const struct i2c_device_id xdpe122_id[] = { ++ {"xdpe12254", 0}, ++ {"xdpe12284", 0}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, xdpe122_id); ++ ++static const struct of_device_id __maybe_unused xdpe122_of_match[] = { ++ {.compatible = "infineon,xdpe12254"}, ++ {.compatible = "infineon,xdpe12284"}, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, xdpe122_of_match); ++ ++static struct i2c_driver xdpe122_driver = { ++ .driver = { ++ .name = "xdpe12284", ++ .of_match_table = of_match_ptr(xdpe122_of_match), ++ }, ++ .probe = xdpe122_probe, ++ .remove = pmbus_do_remove, ++ .id_table = xdpe122_id, ++}; ++ ++module_i2c_driver(xdpe122_driver); ++ ++MODULE_AUTHOR("Vadim Pasternak "); ++MODULE_DESCRIPTION("PMBus driver for Infineon XDPE122 family"); ++MODULE_LICENSE("GPL"); +-- +2.20.1 + diff --git a/patch/0005-leds-add-driver-for-support-Mellanox-regmap-LEDs-for.patch b/patch/0005-leds-add-driver-for-support-Mellanox-regmap-LEDs-for.patch deleted file mode 100644 index 558cbbc4e8d0..000000000000 --- a/patch/0005-leds-add-driver-for-support-Mellanox-regmap-LEDs-for.patch +++ /dev/null @@ -1,398 +0,0 @@ -Linux backport patch. Includes following commits: -7dc37aeb560416771cbdc286357157c7565dc1fe -9244ef4cb79a8411656cb8fc2366f32f2294a0c9 -daf155fe70c9d69c28bba632b6a758ac8feab6e7 - - -diff -Nur a/drivers/leds/Kconfig b/drivers/leds/Kconfig ---- a/drivers/leds/Kconfig 2017-11-12 09:08:40.740087699 +0000 -+++ b/drivers/leds/Kconfig 2017-11-12 09:06:54.580086289 +0000 -@@ -659,6 +659,35 @@ - This option enabled support for the LEDs on the Mellanox - boards. Say Y to enabled these. - -+config LEDS_MLXREG -+ tristate "LED support for the Mellanox BMC cards" -+ depends on LEDS_CLASS -+ help -+ This option enabled support for the LEDs on the Mellanox BMC cards. -+ The driver can be activated from the device tree or by the direct -+ platform device add call. Say Y to enabled these. To compile this -+ driver as a module, choose 'M' here: the module will be called -+ leds-mlxreg. -+ -+config LEDS_USER -+ tristate "Userspace LED support" -+ depends on LEDS_CLASS -+ help -+ This option enables support for userspace LEDs. Say 'y' to enable this -+ support in kernel. To compile this driver as a module, choose 'm' here: -+ the module will be called uleds. -+ -+config LEDS_NIC78BX -+ tristate "LED support for NI PXI NIC78bx devices" -+ depends on LEDS_CLASS -+ depends on X86 && ACPI -+ help -+ This option enables support for the User1 and User2 LEDs on NI -+ PXI NIC78bx devices. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called leds-nic78bx. -+ - comment "LED Triggers" - source "drivers/leds/trigger/Kconfig" - -diff -Nur a/drivers/leds/Makefile b/drivers/leds/Makefile ---- a/drivers/leds/Makefile 2017-11-12 09:08:40.740087699 +0000 -+++ b/drivers/leds/Makefile 2017-11-12 09:06:54.580086289 +0000 -@@ -71,6 +71,7 @@ - obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o - obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o - obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o -+obj-$(CONFIG_LEDS_MLXREG) += leds-mlxreg.o - - # LED SPI Drivers - obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o -diff -Nur a/drivers/leds/leds-mlxcpld.c b/drivers/leds/leds-mlxcpld.c ---- a/drivers/leds/leds-mlxcpld.c 2017-11-12 09:08:40.740087699 +0000 -+++ b/drivers/leds/leds-mlxcpld.c 2017-11-12 09:08:05.620087233 +0000 -@@ -400,6 +400,9 @@ - struct platform_device *pdev; - int err; - -+ if (!dmi_match(DMI_CHASSIS_VENDOR, "Mellanox Technologies Ltd.")) -+ return -ENODEV; -+ - pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0); - if (IS_ERR(pdev)) { - pr_err("Device allocation failed\n"); -@@ -426,5 +429,5 @@ - - MODULE_AUTHOR("Vadim Pasternak "); - MODULE_DESCRIPTION("Mellanox board LED driver"); --MODULE_LICENSE("GPL v2"); -+MODULE_LICENSE("Dual BSD/GPL"); - MODULE_ALIAS("platform:leds_mlxcpld"); -diff -Nur a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c ---- a/drivers/leds/leds-mlxreg.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/leds/leds-mlxreg.c 2017-11-12 09:06:54.580086289 +0000 -@@ -0,0 +1,318 @@ -+/* -+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2017 Vadim Pasternak -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. 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. -+ * 3. Neither the names of the copyright holders nor the names of its -+ * contributors may be used to endorse or promote products derived from -+ * this software without specific prior written permission. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2 as published by the Free -+ * Software Foundation. -+ * -+ * 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 -+#include -+#include -+ -+/* Codes for LEDs. */ -+#define MLXREG_LED_OFFSET_BLINK_3HZ 0x01 /* Offset from solid: 3Hz blink */ -+#define MLXREG_LED_OFFSET_BLINK_6HZ 0x02 /* Offset from solid: 6Hz blink */ -+#define MLXREG_LED_IS_OFF 0x00 /* Off */ -+#define MLXREG_LED_RED_SOLID 0x05 /* Solid red */ -+#define MLXREG_LED_GREEN_SOLID 0x0D /* Solid green */ -+#define MLXREG_LED_AMBER_SOLID 0x09 /* Solid amber */ -+#define MLXREG_LED_BLINK_3HZ 167 /* ~167 msec off/on - HW support */ -+#define MLXREG_LED_BLINK_6HZ 83 /* ~83 msec off/on - HW support */ -+ -+/** -+ * struct mlxreg_led_data - led control data: -+ * -+ * @data: led configuration data; -+ * @led_classdev: led class data; -+ * @base_color: base led color (other colors have constant offset from base); -+ * @led_data: led data; -+ * @data_parent: pointer to private device control data of parent; -+ */ -+struct mlxreg_led_data { -+ struct mlxreg_core_data *data; -+ struct led_classdev led_cdev; -+ u8 base_color; -+ void *data_parent; -+ char led_cdev_name[MLXREG_CORE_LABEL_MAX_SIZE]; -+}; -+ -+#define cdev_to_priv(c) container_of(c, struct mlxreg_led_data, led_cdev) -+ -+/** -+ * struct mlxreg_led_priv_data - platform private data: -+ * -+ * @pdev: platform device; -+ * @pdata: platform data; -+ * @access_lock: mutex for attribute IO access; -+ */ -+struct mlxreg_led_priv_data { -+ struct platform_device *pdev; -+ struct mlxreg_core_led_platform_data *pdata; -+ struct mutex access_lock; /* protect IO operations */ -+}; -+ -+static int -+mlxreg_led_store_hw(struct mlxreg_led_data *led_data, u8 vset) -+{ -+ struct mlxreg_led_priv_data *priv = led_data->data_parent; -+ struct mlxreg_core_led_platform_data *led_pdata = priv->pdata; -+ struct mlxreg_core_data *data = led_data->data; -+ u32 regval; -+ u32 nib; -+ int ret; -+ -+ /* -+ * Each LED is controlled through low or high nibble of the relevant -+ * register byte. Register offset is specified by off parameter. -+ * Parameter vset provides color code: 0x0 for off, 0x5 for solid red, -+ * 0x6 for 3Hz blink red, 0xd for solid green, 0xe for 3Hz blink -+ * green. -+ * Parameter mask specifies which nibble is used for specific LED: mask -+ * 0xf0 - lower nibble is to be used (bits from 0 to 3), mask 0x0f - -+ * higher nibble (bits from 4 to 7). -+ */ -+ mutex_lock(&priv->access_lock); -+ -+ ret = regmap_read(led_pdata->regmap, data->reg, ®val); -+ if (ret) -+ goto access_error; -+ -+ nib = (ror32(data->mask, data->bit) == 0xf0) ? rol32(vset, data->bit) : -+ rol32(vset, data->bit + 4); -+ regval = (regval & data->mask) | nib; -+ -+ ret = regmap_write(led_pdata->regmap, data->reg, regval); -+ -+access_error: -+ mutex_unlock(&priv->access_lock); -+ -+ return ret; -+} -+ -+static enum led_brightness -+mlxreg_led_get_hw(struct mlxreg_led_data *led_data) -+{ -+ struct mlxreg_led_priv_data *priv = led_data->data_parent; -+ struct mlxreg_core_led_platform_data *led_pdata = priv->pdata; -+ struct mlxreg_core_data *data = led_data->data; -+ u32 regval; -+ int ret; -+ -+ /* -+ * Each LED is controlled through low or high nibble of the relevant -+ * register byte. Register offset is specified by off parameter. -+ * Parameter vset provides color code: 0x0 for off, 0x5 for solid red, -+ * 0x6 for 3Hz blink red, 0xd for solid green, 0xe for 3Hz blink -+ * green. -+ * Parameter mask specifies which nibble is used for specific LED: mask -+ * 0xf0 - lower nibble is to be used (bits from 0 to 3), mask 0x0f - -+ * higher nibble (bits from 4 to 7). -+ */ -+ ret = regmap_read(led_pdata->regmap, data->reg, ®val); -+ if (ret < 0) { -+ dev_warn(led_data->led_cdev.dev, "Failed to get current brightness, error: %d\n", -+ ret); -+ /* Assume the LED is OFF */ -+ return LED_OFF; -+ } -+ -+ regval = regval & ~data->mask; -+ regval = (ror32(data->mask, data->bit) == 0xf0) ? ror32(regval, -+ data->bit) : ror32(regval, data->bit + 4); -+ if (regval >= led_data->base_color && -+ regval <= (led_data->base_color + MLXREG_LED_OFFSET_BLINK_6HZ)) -+ ret = LED_FULL; -+ else -+ ret = LED_OFF; -+ -+ return ret; -+} -+ -+static int -+mlxreg_led_brightness_set(struct led_classdev *cled, enum led_brightness value) -+{ -+ struct mlxreg_led_data *led_data = cdev_to_priv(cled); -+ -+ if (value) -+ return mlxreg_led_store_hw(led_data, led_data->base_color); -+ else -+ return mlxreg_led_store_hw(led_data, MLXREG_LED_IS_OFF); -+} -+ -+static enum led_brightness -+mlxreg_led_brightness_get(struct led_classdev *cled) -+{ -+ struct mlxreg_led_data *led_data = cdev_to_priv(cled); -+ -+ return mlxreg_led_get_hw(led_data); -+} -+ -+static int -+mlxreg_led_blink_set(struct led_classdev *cled, unsigned long *delay_on, -+ unsigned long *delay_off) -+{ -+ struct mlxreg_led_data *led_data = cdev_to_priv(cled); -+ int err; -+ -+ /* -+ * HW supports two types of blinking: full (6Hz) and half (3Hz). -+ * For delay on/off zero LED is setting to solid color. For others -+ * combination blinking is to be controlled by the software timer. -+ */ -+ if (!(*delay_on == 0 && *delay_off == 0) && -+ !(*delay_on == MLXREG_LED_BLINK_3HZ && -+ *delay_off == MLXREG_LED_BLINK_3HZ) && -+ !(*delay_on == MLXREG_LED_BLINK_6HZ && -+ *delay_off == MLXREG_LED_BLINK_6HZ)) -+ return -EINVAL; -+ -+ if (*delay_on == MLXREG_LED_BLINK_6HZ) -+ err = mlxreg_led_store_hw(led_data, led_data->base_color + -+ MLXREG_LED_OFFSET_BLINK_6HZ); -+ else if (*delay_on == MLXREG_LED_BLINK_3HZ) -+ err = mlxreg_led_store_hw(led_data, led_data->base_color + -+ MLXREG_LED_OFFSET_BLINK_3HZ); -+ else -+ err = mlxreg_led_store_hw(led_data, led_data->base_color); -+ -+ return err; -+} -+ -+static int mlxreg_led_config(struct mlxreg_led_priv_data *priv) -+{ -+ struct mlxreg_core_led_platform_data *led_pdata = priv->pdata; -+ struct mlxreg_core_data *data = led_pdata->data; -+ struct mlxreg_led_data *led_data; -+ struct led_classdev *led_cdev; -+ int brightness; -+ int i; -+ int err; -+ -+ for (i = 0; i < led_pdata->counter; i++, data++) { -+ led_data = devm_kzalloc(&priv->pdev->dev, sizeof(*led_data), -+ GFP_KERNEL); -+ if (!led_data) -+ return -ENOMEM; -+ -+ led_cdev = &led_data->led_cdev; -+ led_data->data_parent = priv; -+ if (strstr(data->label, "red") || -+ strstr(data->label, "orange")) { -+ brightness = LED_OFF; -+ led_data->base_color = MLXREG_LED_RED_SOLID; -+ } else if (strstr(data->label, "amber")) { -+ brightness = LED_OFF; -+ led_data->base_color = MLXREG_LED_AMBER_SOLID; -+ } else { -+ brightness = LED_OFF; -+ led_data->base_color = MLXREG_LED_GREEN_SOLID; -+ } -+ sprintf(led_data->led_cdev_name, "%s:%s", "mlxreg", -+ data->label); -+ led_cdev->name = led_data->led_cdev_name; -+ led_cdev->brightness = brightness; -+ led_cdev->max_brightness = 1; -+ led_cdev->brightness_set_blocking = -+ mlxreg_led_brightness_set; -+ led_cdev->brightness_get = mlxreg_led_brightness_get; -+ led_cdev->blink_set = mlxreg_led_blink_set; -+ led_cdev->flags = LED_CORE_SUSPENDRESUME; -+ led_data->data = data; -+ err = devm_led_classdev_register(&priv->pdev->dev, led_cdev); -+ if (err) -+ return err; -+ -+ if (led_cdev->brightness) -+ mlxreg_led_brightness_set(led_cdev, -+ led_cdev->brightness); -+ dev_info(led_cdev->dev, "label: %s, mask: 0x%02x, offset:0x%02x\n", -+ data->label, data->mask, data->reg); -+ } -+ -+ return 0; -+} -+ -+static int mlxreg_led_probe(struct platform_device *pdev) -+{ -+ struct mlxreg_core_led_platform_data *led_pdata; -+ struct mlxreg_led_priv_data *priv; -+ -+ led_pdata = dev_get_platdata(&pdev->dev); -+ if (!led_pdata) { -+ dev_err(&pdev->dev, "Failed to get platform data.\n"); -+ return -EINVAL; -+ } -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ mutex_init(&priv->access_lock); -+ priv->pdev = pdev; -+ priv->pdata = led_pdata; -+ -+ return mlxreg_led_config(priv); -+} -+ -+static int mlxreg_led_remove(struct platform_device *pdev) -+{ -+ struct mlxreg_led_priv_data *priv = dev_get_drvdata(&pdev->dev); -+ -+ mutex_destroy(&priv->access_lock); -+ -+ return 0; -+} -+ -+static const struct of_device_id mlxreg_led_dt_match[] = { -+ { .compatible = "mellanox,leds-mlxreg" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, mlxreg_led_dt_match); -+ -+static struct platform_driver mlxreg_led_driver = { -+ .driver = { -+ .name = "leds-mlxreg", -+ .of_match_table = of_match_ptr(mlxreg_led_dt_match), -+ }, -+ .probe = mlxreg_led_probe, -+ .remove = mlxreg_led_remove, -+}; -+ -+module_platform_driver(mlxreg_led_driver); -+ -+MODULE_AUTHOR("Vadim Pasternak "); -+MODULE_DESCRIPTION("Mellanox LED regmap driver"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_ALIAS("platform:leds-mlxreg"); diff --git a/patch/0006-Mellanox-switch-drivers-changes.patch b/patch/0006-Mellanox-switch-drivers-changes.patch deleted file mode 100644 index c820bbdc02b4..000000000000 --- a/patch/0006-Mellanox-switch-drivers-changes.patch +++ /dev/null @@ -1,2118 +0,0 @@ -Linux backport patch. Includes following commits: -02f1d19ecd08f7da83bf17d556ba147b16ed9dab -50deb9064015956274a989d035c0a101188c5bf2 -515dc42e5f57aa4b2dbb18fbe6b3200224d051a7 -63b01357d3f002ebed8e532b503a84dde6f45060 -7c2ed7426f0835d5408a2c97fc6ebcc67c5feea0 -65f178307a4274f1ab52f4e729e1eabe00ee2d96 -81ce6e3fefba4ed1578db80609b54ccc3ae624cb -3f65860a8b01652fbda978b991d13c02848c8ee2 -05cdb2439ba8bb00a1746ec68e27cec62ea1e142 -021697a48b00b51636d88e5056015ad65b6da821 -f6410966453b7671a0c4032652db36b2e67ba43c -acf30a9f0714a734531078b7a6d85ab7762c3589 -f334341a185bad33bbc3cf0a3b7d7189d8803bc0 -aec592f5c0d44b3ac4038dc539859fa247738f6e -589428b6233c6a9bffbf8c8bca86f62838f35021 - - -diff -Nur a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig ---- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig 2017-05-25 13:45:05.000000000 +0000 -+++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig 2017-11-09 12:40:31.940814834 +0000 -@@ -19,6 +19,24 @@ - ---help--- - Say Y here if you want to expose HWMON interface on mlxsw devices. - -+config MLXSW_CORE_THERMAL -+ bool "Thermal zone support for Mellanox Technologies Switch ASICs" -+ depends on MLXSW_CORE && THERMAL -+ depends on !(MLXSW_CORE=y && THERMAL=m) -+ default y -+ ---help--- -+ Say Y here if you want to automatically control fans speed according -+ ambient temperature reported by ASIC. -+ -+config MLXSW_CORE_QSFP -+ bool "QSFP support for Mellanox Technologies Switch ASICs" -+ depends on MLXSW_CORE && HWMON -+ depends on !(MLXSW_CORE=y && HWMON=m) -+ default y -+ ---help--- -+ Say Y here if you want to expose sysfs QSFP interface on mlxsw -+ devices. -+ - config MLXSW_PCI - tristate "PCI bus implementation for Mellanox Technologies Switch ASICs" - depends on PCI && HAS_DMA && HAS_IOMEM && MLXSW_CORE -@@ -29,6 +47,27 @@ - To compile this driver as a module, choose M here: the - module will be called mlxsw_pci. - -+config MLXSW_I2C -+ tristate "I2C bus implementation for Mellanox Technologies Switch ASICs" -+ depends on I2C && MLXSW_CORE -+ default m -+ ---help--- -+ This is I2C bus implementation for Mellanox Technologies Switch ASICs. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mlxsw_i2c. -+ -+config MLXSW_SWITCHIB -+ tristate "Mellanox Technologies SwitchIB and SwitchIB-2 support" -+ depends on MLXSW_CORE && NET_SWITCHDEV -+ default m -+ ---help--- -+ This driver supports Mellanox Technologies SwitchIB and SwitchIB-2 -+ Infiniband Switch ASICs. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mlxsw_switchib. -+ - config MLXSW_SWITCHX2 - tristate "Mellanox Technologies SwitchX-2 support" - depends on MLXSW_CORE && NET_SWITCHDEV -@@ -58,3 +97,14 @@ - ---help--- - Say Y here if you want to use Data Center Bridging (DCB) in the - driver. -+ -+config MLXSW_MINIMAL -+ tristate "Mellanox Technologies minimal I2C support" -+ depends on MLXSW_CORE && MLXSW_I2C -+ default m -+ ---help--- -+ This driver supports I2C access for Mellanox Technologies Switch -+ ASICs. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mlxsw_minimal. -diff -Nur a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile ---- a/drivers/net/ethernet/mellanox/mlxsw/Makefile 2017-05-25 13:45:05.000000000 +0000 -+++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile 2017-11-09 12:40:31.940814834 +0000 -@@ -1,8 +1,14 @@ - obj-$(CONFIG_MLXSW_CORE) += mlxsw_core.o - mlxsw_core-objs := core.o - mlxsw_core-$(CONFIG_MLXSW_CORE_HWMON) += core_hwmon.o -+mlxsw_core-$(CONFIG_MLXSW_CORE_THERMAL) += core_thermal.o -+mlxsw_core-$(CONFIG_MLXSW_CORE_QSFP) += qsfp_sysfs.o - obj-$(CONFIG_MLXSW_PCI) += mlxsw_pci.o - mlxsw_pci-objs := pci.o -+obj-$(CONFIG_MLXSW_I2C) += mlxsw_i2c.o -+mlxsw_i2c-objs := i2c.o -+obj-$(CONFIG_MLXSW_SWITCHIB) += mlxsw_switchib.o -+mlxsw_switchib-objs := switchib.o - obj-$(CONFIG_MLXSW_SWITCHX2) += mlxsw_switchx2.o - mlxsw_switchx2-objs := switchx2.o - obj-$(CONFIG_MLXSW_SPECTRUM) += mlxsw_spectrum.o -@@ -10,3 +16,5 @@ - spectrum_switchdev.o spectrum_router.o \ - spectrum_kvdl.o - mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o -+obj-$(CONFIG_MLXSW_MINIMAL) += mlxsw_minimal.o -+mlxsw_minimal-objs := minimal.o -diff -Nur a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c ---- a/drivers/net/ethernet/mellanox/mlxsw/core.c 2017-05-25 13:45:05.000000000 +0000 -+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c 2017-11-09 13:03:45.824833341 +0000 -@@ -113,6 +113,9 @@ - } lag; - struct mlxsw_resources resources; - struct mlxsw_hwmon *hwmon; -+ struct mlxsw_thermal *thermal; -+struct mlxsw_qsfp *qsfp; -+ struct mlxsw_core_port ports[MLXSW_PORT_MAX_PORTS]; - unsigned long driver_priv[0]; - /* driver_priv has to be always the last item */ - }; -@@ -579,6 +582,9 @@ - u64 tid; - int err; - -+ if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX)) -+ return 0; -+ - /* Set the upper 32 bits of the transaction ID field to a random - * number. This allows us to discard EMADs addressed to other - * devices. -@@ -615,6 +621,9 @@ - { - char hpkt_pl[MLXSW_REG_HPKT_LEN]; - -+ if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX)) -+ return; -+ - mlxsw_core->emad.use_emad = false; - mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_DISCARD, - MLXSW_TRAP_ID_ETHEMAD); -@@ -1128,9 +1137,21 @@ - if (err) - goto err_hwmon_init; - -- err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info); -+ err = mlxsw_thermal_init(mlxsw_core, mlxsw_bus_info, -+ &mlxsw_core->thermal); - if (err) -- goto err_driver_init; -+ goto err_thermal_init; -+ -+ err = mlxsw_qsfp_init(mlxsw_core, mlxsw_bus_info, -+ &mlxsw_core->qsfp); -+ if (err) -+ goto err_qsfp_init; -+ -+ if (mlxsw_driver->init) { -+ err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info); -+ if (err) -+ goto err_driver_init; -+ } - - err = mlxsw_core_debugfs_init(mlxsw_core); - if (err) -@@ -1141,6 +1162,10 @@ - err_debugfs_init: - mlxsw_core->driver->fini(mlxsw_core); - err_driver_init: -+ mlxsw_qsfp_fini(mlxsw_core->qsfp); -+err_qsfp_init: -+ mlxsw_thermal_fini(mlxsw_core->thermal); -+err_thermal_init: - err_hwmon_init: - devlink_unregister(devlink); - err_devlink_register: -@@ -1165,7 +1190,10 @@ - struct devlink *devlink = priv_to_devlink(mlxsw_core); - - mlxsw_core_debugfs_fini(mlxsw_core); -- mlxsw_core->driver->fini(mlxsw_core); -+ if (mlxsw_core->driver->fini) -+ mlxsw_core->driver->fini(mlxsw_core); -+ mlxsw_qsfp_fini(mlxsw_core->qsfp); -+ mlxsw_thermal_fini(mlxsw_core->thermal); - devlink_unregister(devlink); - mlxsw_emad_fini(mlxsw_core); - mlxsw_core->bus->fini(mlxsw_core->bus_priv); -diff -Nur a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h ---- a/drivers/net/ethernet/mellanox/mlxsw/core.h 2017-05-25 13:45:05.000000000 +0000 -+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h 2017-11-09 13:03:45.824833341 +0000 -@@ -300,6 +300,8 @@ - - struct mlxsw_resources *mlxsw_core_resources_get(struct mlxsw_core *mlxsw_core); - -+#define MLXSW_BUS_F_TXRX BIT(0) -+ - struct mlxsw_bus { - const char *kind; - int (*init)(void *bus_priv, struct mlxsw_core *mlxsw_core, -@@ -315,6 +317,7 @@ - char *in_mbox, size_t in_mbox_size, - char *out_mbox, size_t out_mbox_size, - u8 *p_status); -+ u8 features; - }; - - struct mlxsw_bus_info { -@@ -349,5 +352,53 @@ - } - - #endif -+ -+struct mlxsw_thermal; -+ -+#ifdef CONFIG_MLXSW_CORE_THERMAL -+ -+int mlxsw_thermal_init(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_bus_info *mlxsw_bus_info, -+ struct mlxsw_thermal **p_thermal); -+void mlxsw_thermal_fini(struct mlxsw_thermal *thermal); -+ -+#else -+ -+static inline int mlxsw_thermal_init(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_bus_info *mlxsw_bus_info, -+ struct mlxsw_thermal **p_thermal) -+{ -+ return 0; -+} -+ -+static inline void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) -+{ -+} -+ -+#endif -+ -+struct mlxsw_qsfp; -+ -+#ifdef CONFIG_MLXSW_CORE_QSFP -+ -+int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_bus_info *mlxsw_bus_info, -+ struct mlxsw_qsfp **p_qsfp); -+void mlxsw_qsfp_fini(struct mlxsw_qsfp *qsfp); -+ -+#else -+ -+static inline int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_bus_info *mlxsw_bus_info, -+ struct mlxsw_qsfp **p_qsfp) -+{ -+ return 0; -+} -+ -+static inline void mlxsw_qsfp_fini(struct mlxsw_qsfp *qsfp) -+{ -+} -+ -+#endif - - #endif -diff -Nur a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ---- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c 2017-05-25 13:45:05.000000000 +0000 -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c 2017-11-09 13:04:29.120833916 +0000 -@@ -262,7 +262,7 @@ - - static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon) - { -- char mtcap_pl[MLXSW_REG_MTCAP_LEN]; -+ char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0}; - char mtmp_pl[MLXSW_REG_MTMP_LEN]; - u8 sensor_count; - int i; -@@ -295,7 +295,7 @@ - - static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) - { -- char mfcr_pl[MLXSW_REG_MFCR_LEN]; -+ char mfcr_pl[MLXSW_REG_MFCR_LEN] = {0}; - enum mlxsw_reg_mfcr_pwm_frequency freq; - unsigned int type_index; - unsigned int num; -diff -Nur a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c 2017-11-09 13:04:52.192834223 +0000 -@@ -0,0 +1,436 @@ -+/* -+ * drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+ * Copyright (c) 2016 Ivan Vecera -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. 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. -+ * 3. Neither the names of the copyright holders nor the names of its -+ * contributors may be used to endorse or promote products derived from -+ * this software without specific prior written permission. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2 as published by the Free -+ * Software Foundation. -+ * -+ * 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 "core.h" -+ -+#define MLXSW_THERMAL_POLL_INT 1000 /* ms */ -+#define MLXSW_THERMAL_MAX_TEMP 110000 /* 110C */ -+#define MLXSW_THERMAL_MAX_STATE 10 -+#define MLXSW_THERMAL_MAX_DUTY 255 -+ -+struct mlxsw_thermal_trip { -+ int type; -+ int temp; -+ int min_state; -+ int max_state; -+}; -+ -+static const struct mlxsw_thermal_trip default_thermal_trips[] = { -+ { /* Above normal - 60%-100% PWM */ -+ .type = THERMAL_TRIP_ACTIVE, -+ .temp = 75000, -+ .min_state = (6 * MLXSW_THERMAL_MAX_STATE) / 10, -+ .max_state = MLXSW_THERMAL_MAX_STATE, -+ }, -+ { -+ /* Very high - 100% PWM */ -+ .type = THERMAL_TRIP_ACTIVE, -+ .temp = 85000, -+ .min_state = MLXSW_THERMAL_MAX_STATE, -+ .max_state = MLXSW_THERMAL_MAX_STATE, -+ }, -+ { /* Warning */ -+ .type = THERMAL_TRIP_HOT, -+ .temp = 105000, -+ .min_state = MLXSW_THERMAL_MAX_STATE, -+ .max_state = MLXSW_THERMAL_MAX_STATE, -+ }, -+ { /* Critical - soft poweroff */ -+ .type = THERMAL_TRIP_CRITICAL, -+ .temp = MLXSW_THERMAL_MAX_TEMP, -+ .min_state = MLXSW_THERMAL_MAX_STATE, -+ .max_state = MLXSW_THERMAL_MAX_STATE, -+ } -+}; -+ -+#define MLXSW_THERMAL_NUM_TRIPS ARRAY_SIZE(default_thermal_trips) -+ -+/* Make sure all trips are writable */ -+#define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1) -+ -+struct mlxsw_thermal { -+ struct mlxsw_core *core; -+ const struct mlxsw_bus_info *bus_info; -+ struct thermal_zone_device *tzdev; -+ struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX]; -+ struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; -+ enum thermal_device_mode mode; -+}; -+ -+static inline u8 mlxsw_state_to_duty(int state) -+{ -+ return DIV_ROUND_CLOSEST(state * MLXSW_THERMAL_MAX_DUTY, -+ MLXSW_THERMAL_MAX_STATE); -+} -+ -+static inline int mlxsw_duty_to_state(u8 duty) -+{ -+ return DIV_ROUND_CLOSEST(duty * MLXSW_THERMAL_MAX_STATE, -+ MLXSW_THERMAL_MAX_DUTY); -+} -+ -+static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal, -+ struct thermal_cooling_device *cdev) -+{ -+ int i; -+ -+ for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) -+ if (thermal->cdevs[i] == cdev) -+ return i; -+ -+ return -ENODEV; -+} -+ -+static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev, -+ struct thermal_cooling_device *cdev) -+{ -+ struct mlxsw_thermal *thermal = tzdev->devdata; -+ struct device *dev = thermal->bus_info->dev; -+ int i, err; -+ -+ /* If the cooling device is one of ours bind it */ -+ if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0) -+ return 0; -+ -+ for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) { -+ const struct mlxsw_thermal_trip *trip = &thermal->trips[i]; -+ -+ err = thermal_zone_bind_cooling_device(tzdev, i, cdev, -+ trip->max_state, -+ trip->min_state, -+ THERMAL_WEIGHT_DEFAULT); -+ if (err < 0) { -+ dev_err(dev, "Failed to bind cooling device to trip %d\n", i); -+ return err; -+ } -+ } -+ return 0; -+} -+ -+static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev, -+ struct thermal_cooling_device *cdev) -+{ -+ struct mlxsw_thermal *thermal = tzdev->devdata; -+ struct device *dev = thermal->bus_info->dev; -+ int i; -+ int err; -+ -+ /* If the cooling device is our one unbind it */ -+ if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0) -+ return 0; -+ -+ for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) { -+ err = thermal_zone_unbind_cooling_device(tzdev, i, cdev); -+ if (err < 0) { -+ dev_err(dev, "Failed to unbind cooling device\n"); -+ return err; -+ } -+ } -+ return 0; -+} -+ -+static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev, -+ enum thermal_device_mode *mode) -+{ -+ struct mlxsw_thermal *thermal = tzdev->devdata; -+ -+ *mode = thermal->mode; -+ -+ return 0; -+} -+ -+static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev, -+ enum thermal_device_mode mode) -+{ -+ struct mlxsw_thermal *thermal = tzdev->devdata; -+ -+ mutex_lock(&tzdev->lock); -+ -+ if (mode == THERMAL_DEVICE_ENABLED) -+ tzdev->polling_delay = MLXSW_THERMAL_POLL_INT; -+ else -+ tzdev->polling_delay = 0; -+ -+ mutex_unlock(&tzdev->lock); -+ -+ thermal->mode = mode; -+ thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED); -+ -+ return 0; -+} -+ -+static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, -+ int *p_temp) -+{ -+ struct mlxsw_thermal *thermal = tzdev->devdata; -+ struct device *dev = thermal->bus_info->dev; -+ char mtmp_pl[MLXSW_REG_MTMP_LEN]; -+ unsigned int temp; -+ int err; -+ -+ mlxsw_reg_mtmp_pack(mtmp_pl, 0, false, false); -+ -+ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); -+ if (err) { -+ dev_err(dev, "Failed to query temp sensor\n"); -+ return err; -+ } -+ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); -+ -+ *p_temp = (int) temp; -+ return 0; -+} -+ -+static int mlxsw_thermal_get_trip_type(struct thermal_zone_device *tzdev, -+ int trip, -+ enum thermal_trip_type *p_type) -+{ -+ struct mlxsw_thermal *thermal = tzdev->devdata; -+ -+ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) -+ return -EINVAL; -+ -+ *p_type = thermal->trips[trip].type; -+ return 0; -+} -+ -+static int mlxsw_thermal_get_trip_temp(struct thermal_zone_device *tzdev, -+ int trip, int *p_temp) -+{ -+ struct mlxsw_thermal *thermal = tzdev->devdata; -+ -+ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) -+ return -EINVAL; -+ -+ *p_temp = thermal->trips[trip].temp; -+ return 0; -+} -+ -+static int mlxsw_thermal_set_trip_temp(struct thermal_zone_device *tzdev, -+ int trip, int temp) -+{ -+ struct mlxsw_thermal *thermal = tzdev->devdata; -+ -+ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS || -+ temp > MLXSW_THERMAL_MAX_TEMP) -+ return -EINVAL; -+ -+ thermal->trips[trip].temp = temp; -+ return 0; -+} -+ -+static struct thermal_zone_device_ops mlxsw_thermal_ops = { -+ .bind = mlxsw_thermal_bind, -+ .unbind = mlxsw_thermal_unbind, -+ .get_mode = mlxsw_thermal_get_mode, -+ .set_mode = mlxsw_thermal_set_mode, -+ .get_temp = mlxsw_thermal_get_temp, -+ .get_trip_type = mlxsw_thermal_get_trip_type, -+ .get_trip_temp = mlxsw_thermal_get_trip_temp, -+ .set_trip_temp = mlxsw_thermal_set_trip_temp, -+}; -+ -+static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev, -+ unsigned long *p_state) -+{ -+ *p_state = MLXSW_THERMAL_MAX_STATE; -+ return 0; -+} -+ -+static int mlxsw_thermal_get_cur_state(struct thermal_cooling_device *cdev, -+ unsigned long *p_state) -+ -+{ -+ struct mlxsw_thermal *thermal = cdev->devdata; -+ struct device *dev = thermal->bus_info->dev; -+ char mfsc_pl[MLXSW_REG_MFSC_LEN]; -+ int err, idx; -+ u8 duty; -+ -+ idx = mlxsw_get_cooling_device_idx(thermal, cdev); -+ if (idx < 0) -+ return idx; -+ -+ mlxsw_reg_mfsc_pack(mfsc_pl, idx, 0); -+ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsc), mfsc_pl); -+ if (err) { -+ dev_err(dev, "Failed to query PWM duty\n"); -+ return err; -+ } -+ -+ duty = mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl); -+ *p_state = mlxsw_duty_to_state(duty); -+ return 0; -+} -+ -+static int mlxsw_thermal_set_cur_state(struct thermal_cooling_device *cdev, -+ unsigned long state) -+ -+{ -+ struct mlxsw_thermal *thermal = cdev->devdata; -+ struct device *dev = thermal->bus_info->dev; -+ char mfsc_pl[MLXSW_REG_MFSC_LEN]; -+ int err, idx; -+ -+ idx = mlxsw_get_cooling_device_idx(thermal, cdev); -+ if (idx < 0) -+ return idx; -+ -+ mlxsw_reg_mfsc_pack(mfsc_pl, idx, mlxsw_state_to_duty(state)); -+ err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl); -+ if (err) { -+ dev_err(dev, "Failed to write PWM duty\n"); -+ return err; -+ } -+ return 0; -+} -+ -+static const struct thermal_cooling_device_ops mlxsw_cooling_ops = { -+ .get_max_state = mlxsw_thermal_get_max_state, -+ .get_cur_state = mlxsw_thermal_get_cur_state, -+ .set_cur_state = mlxsw_thermal_set_cur_state, -+}; -+ -+int mlxsw_thermal_init(struct mlxsw_core *core, -+ const struct mlxsw_bus_info *bus_info, -+ struct mlxsw_thermal **p_thermal) -+{ -+ char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 }; -+ enum mlxsw_reg_mfcr_pwm_frequency freq; -+ struct device *dev = bus_info->dev; -+ struct mlxsw_thermal *thermal; -+ u16 tacho_active; -+ u8 pwm_active; -+ int err, i; -+ -+ thermal = devm_kzalloc(dev, sizeof(*thermal), -+ GFP_KERNEL); -+ if (!thermal) -+ return -ENOMEM; -+ -+ thermal->core = core; -+ thermal->bus_info = bus_info; -+ memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips)); -+ -+ 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; -+ } -+ mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active); -+ -+ for (i = 0; i < MLXSW_MFCR_TACHOS_MAX; i++) { -+ if (tacho_active & BIT(i)) { -+ char mfsl_pl[MLXSW_REG_MFSL_LEN]; -+ -+ mlxsw_reg_mfsl_pack(mfsl_pl, i, 0, 0); -+ -+ /* We need to query the register to preserve maximum */ -+ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsl), -+ mfsl_pl); -+ if (err) -+ goto err_free_thermal; -+ -+ /* 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; -+ } -+ } -+ for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) { -+ if (pwm_active & BIT(i)) { -+ struct thermal_cooling_device *cdev; -+ -+ cdev = thermal_cooling_device_register("Fan", thermal, -+ &mlxsw_cooling_ops); -+ if (IS_ERR(cdev)) { -+ err = PTR_ERR(cdev); -+ dev_err(dev, "Failed to register cooling device\n"); -+ goto err_unreg_cdevs; -+ } -+ thermal->cdevs[i] = cdev; -+ } -+ } -+ -+ thermal->tzdev = thermal_zone_device_register("mlxsw", -+ MLXSW_THERMAL_NUM_TRIPS, -+ MLXSW_THERMAL_TRIP_MASK, -+ thermal, -+ &mlxsw_thermal_ops, -+ NULL, 0, -+ MLXSW_THERMAL_POLL_INT); -+ if (IS_ERR(thermal->tzdev)) { -+ err = PTR_ERR(thermal->tzdev); -+ dev_err(dev, "Failed to register thermal zone\n"); -+ goto err_unreg_cdevs; -+ } -+ -+ thermal->mode = THERMAL_DEVICE_ENABLED; -+ *p_thermal = thermal; -+ return 0; -+err_unreg_cdevs: -+ for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) -+ if (thermal->cdevs[i]) -+ thermal_cooling_device_unregister(thermal->cdevs[i]); -+err_free_thermal: -+ devm_kfree(dev, thermal); -+ return err; -+} -+ -+void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) -+{ -+ int i; -+ -+ if (thermal->tzdev) { -+ thermal_zone_device_unregister(thermal->tzdev); -+ thermal->tzdev = NULL; -+ } -+ -+ for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) { -+ if (thermal->cdevs[i]) { -+ thermal_cooling_device_unregister(thermal->cdevs[i]); -+ thermal->cdevs[i] = NULL; -+ } -+ } -+ -+ devm_kfree(thermal->bus_info->dev, thermal); -+} -diff -Nur a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c ---- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c 2017-11-09 13:04:29.120833916 +0000 -@@ -0,0 +1,582 @@ -+/* -+ * drivers/net/ethernet/mellanox/mlxsw/i2c.c -+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2016 Vadim Pasternak -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. 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. -+ * 3. Neither the names of the copyright holders nor the names of its -+ * contributors may be used to endorse or promote products derived from -+ * this software without specific prior written permission. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2 as published by the Free -+ * Software Foundation. -+ * -+ * 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 -+#include -+#include -+ -+#include "cmd.h" -+#include "core.h" -+#include "i2c.h" -+ -+static const char mlxsw_i2c_driver_name[] = "mlxsw_i2c"; -+ -+#define MLXSW_I2C_CIR2_BASE 0x72000 -+#define MLXSW_I2C_CIR_STATUS_OFF 0x18 -+#define MLXSW_I2C_CIR2_OFF_STATUS (MLXSW_I2C_CIR2_BASE + \ -+ MLXSW_I2C_CIR_STATUS_OFF) -+#define MLXSW_I2C_OPMOD_SHIFT 12 -+#define MLXSW_I2C_GO_BIT_SHIFT 23 -+#define MLXSW_I2C_CIR_CTRL_STATUS_SHIFT 24 -+#define MLXSW_I2C_GO_BIT BIT(MLXSW_I2C_GO_BIT_SHIFT) -+#define MLXSW_I2C_GO_OPMODE BIT(MLXSW_I2C_OPMOD_SHIFT) -+#define MLXSW_I2C_SET_IMM_CMD (MLXSW_I2C_GO_OPMODE | \ -+ MLXSW_CMD_OPCODE_QUERY_FW) -+#define MLXSW_I2C_PUSH_IMM_CMD (MLXSW_I2C_GO_BIT | \ -+ MLXSW_I2C_SET_IMM_CMD) -+#define MLXSW_I2C_SET_CMD (MLXSW_CMD_OPCODE_ACCESS_REG) -+#define MLXSW_I2C_PUSH_CMD (MLXSW_I2C_GO_BIT | MLXSW_I2C_SET_CMD) -+#define MLXSW_I2C_TLV_HDR_SIZE 0x10 -+#define MLXSW_I2C_ADDR_WIDTH 4 -+#define MLXSW_I2C_PUSH_CMD_SIZE (MLXSW_I2C_ADDR_WIDTH + 4) -+#define MLXSW_I2C_READ_SEMA_SIZE 4 -+#define MLXSW_I2C_PREP_SIZE (MLXSW_I2C_ADDR_WIDTH + 28) -+#define MLXSW_I2C_MBOX_SIZE 20 -+#define MLXSW_I2C_MBOX_OUT_PARAM_OFF 12 -+#define MLXSW_I2C_MAX_BUFF_SIZE 32 -+#define MLXSW_I2C_MBOX_OFFSET_BITS 20 -+#define MLXSW_I2C_MBOX_SIZE_BITS 12 -+#define MLXSW_I2C_ADDR_BUF_SIZE 4 -+#define MLXSW_I2C_BLK_MAX 32 -+#define MLXSW_I2C_RETRY 5 -+#define MLXSW_I2C_TIMEOUT_MSECS 5000 -+ -+/** -+ * struct mlxsw_i2c - device private data: -+ * @cmd.mb_size_in: input mailbox size; -+ * @cmd.mb_off_in: input mailbox offset in register space; -+ * @cmd.mb_size_out: output mailbox size; -+ * @cmd.mb_off_out: output mailbox offset in register space; -+ * @cmd.lock: command execution lock; -+ * @dev: I2C device; -+ * @core: switch core pointer; -+ * @bus_info: bus info block; -+ */ -+struct mlxsw_i2c { -+ struct { -+ u32 mb_size_in; -+ u32 mb_off_in; -+ u32 mb_size_out; -+ u32 mb_off_out; -+ struct mutex lock; -+ } cmd; -+ struct device *dev; -+ struct mlxsw_core *core; -+ struct mlxsw_bus_info bus_info; -+}; -+ -+#define MLXSW_I2C_READ_MSG(_client, _addr_buf, _buf, _len) { \ -+ { .addr = (_client)->addr, \ -+ .buf = (_addr_buf), \ -+ .len = MLXSW_I2C_ADDR_BUF_SIZE, \ -+ .flags = 0 }, \ -+ { .addr = (_client)->addr, \ -+ .buf = (_buf), \ -+ .len = (_len), \ -+ .flags = I2C_M_RD } } -+ -+#define MLXSW_I2C_WRITE_MSG(_client, _buf, _len) \ -+ { .addr = (_client)->addr, \ -+ .buf = (u8 *)(_buf), \ -+ .len = (_len), \ -+ .flags = 0 } -+ -+/* Routine converts in and out mail boxes offset and size. */ -+static inline void -+mlxsw_i2c_convert_mbox(struct mlxsw_i2c *mlxsw_i2c, u8 *buf) -+{ -+ u32 tmp; -+ -+ /* Local in/out mailboxes: 20 bits for offset, 12 for size */ -+ tmp = be32_to_cpup((__be32 *) buf); -+ mlxsw_i2c->cmd.mb_off_in = tmp & -+ GENMASK(MLXSW_I2C_MBOX_OFFSET_BITS - 1, 0); -+ mlxsw_i2c->cmd.mb_size_in = (tmp & GENMASK(31, -+ MLXSW_I2C_MBOX_OFFSET_BITS)) >> -+ MLXSW_I2C_MBOX_OFFSET_BITS; -+ -+ tmp = be32_to_cpup((__be32 *) (buf + MLXSW_I2C_ADDR_WIDTH)); -+ mlxsw_i2c->cmd.mb_off_out = tmp & -+ GENMASK(MLXSW_I2C_MBOX_OFFSET_BITS - 1, 0); -+ mlxsw_i2c->cmd.mb_size_out = (tmp & GENMASK(31, -+ MLXSW_I2C_MBOX_OFFSET_BITS)) >> -+ MLXSW_I2C_MBOX_OFFSET_BITS; -+} -+ -+/* Routine obtains register size from mail box buffer. */ -+static inline int mlxsw_i2c_get_reg_size(u8 *in_mbox) -+{ -+ u16 tmp = be16_to_cpup((__be16 *) (in_mbox + MLXSW_I2C_TLV_HDR_SIZE)); -+ -+ return (tmp & 0x7ff) * 4 + MLXSW_I2C_TLV_HDR_SIZE; -+} -+ -+/* Routine sets I2C device internal offset in the transaction buffer. */ -+static inline void mlxsw_i2c_set_slave_addr(u8 *buf, u32 off) -+{ -+ __be32 *val = (__be32 *) buf; -+ -+ *val = htonl(off); -+} -+ -+/* Routine waits until go bit is cleared. */ -+static int mlxsw_i2c_wait_go_bit(struct i2c_client *client, -+ struct mlxsw_i2c *mlxsw_i2c, u8 *p_status) -+{ -+ u8 addr_buf[MLXSW_I2C_ADDR_BUF_SIZE]; -+ u8 buf[MLXSW_I2C_READ_SEMA_SIZE]; -+ int len = MLXSW_I2C_READ_SEMA_SIZE; -+ struct i2c_msg read_sema[] = -+ MLXSW_I2C_READ_MSG(client, addr_buf, buf, len); -+ bool wait_done = false; -+ unsigned long end; -+ int i = 0, err; -+ -+ mlxsw_i2c_set_slave_addr(addr_buf, MLXSW_I2C_CIR2_OFF_STATUS); -+ -+ end = jiffies + msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS); -+ do { -+ u32 ctrl; -+ -+ err = i2c_transfer(client->adapter, read_sema, -+ ARRAY_SIZE(read_sema)); -+ -+ ctrl = be32_to_cpu(*(__be32 *) buf); -+ if (err == ARRAY_SIZE(read_sema)) { -+ if (!(ctrl & MLXSW_I2C_GO_BIT)) { -+ wait_done = true; -+ *p_status = ctrl >> -+ MLXSW_I2C_CIR_CTRL_STATUS_SHIFT; -+ break; -+ } -+ } -+ cond_resched(); -+ } while ((time_before(jiffies, end)) || (i++ < MLXSW_I2C_RETRY)); -+ -+ if (wait_done) { -+ if (*p_status) -+ err = -EIO; -+ } else { -+ return -ETIMEDOUT; -+ } -+ -+ return err > 0 ? 0 : err; -+} -+ -+/* Routine posts a command to ASIC though mail box. */ -+static int mlxsw_i2c_write_cmd(struct i2c_client *client, -+ struct mlxsw_i2c *mlxsw_i2c, -+ int immediate) -+{ -+ __be32 push_cmd_buf[MLXSW_I2C_PUSH_CMD_SIZE / 4] = { -+ 0, cpu_to_be32(MLXSW_I2C_PUSH_IMM_CMD) -+ }; -+ __be32 prep_cmd_buf[MLXSW_I2C_PREP_SIZE / 4] = { -+ 0, 0, 0, 0, 0, 0, -+ cpu_to_be32(client->adapter->nr & 0xffff), -+ cpu_to_be32(MLXSW_I2C_SET_IMM_CMD) -+ }; -+ struct i2c_msg push_cmd = -+ MLXSW_I2C_WRITE_MSG(client, push_cmd_buf, -+ MLXSW_I2C_PUSH_CMD_SIZE); -+ struct i2c_msg prep_cmd = -+ MLXSW_I2C_WRITE_MSG(client, prep_cmd_buf, MLXSW_I2C_PREP_SIZE); -+ int err; -+ -+ if (!immediate) { -+ push_cmd_buf[1] = cpu_to_be32(MLXSW_I2C_PUSH_CMD); -+ prep_cmd_buf[7] = cpu_to_be32(MLXSW_I2C_SET_CMD); -+ } -+ mlxsw_i2c_set_slave_addr((u8 *)prep_cmd_buf, -+ MLXSW_I2C_CIR2_BASE); -+ mlxsw_i2c_set_slave_addr((u8 *)push_cmd_buf, -+ MLXSW_I2C_CIR2_OFF_STATUS); -+ -+ /* Prepare Command Interface Register for transaction */ -+ err = i2c_transfer(client->adapter, &prep_cmd, 1); -+ if (err < 0) -+ return err; -+ else if (err != 1) -+ return -EIO; -+ -+ /* Write out Command Interface Register GO bit to push transaction */ -+ err = i2c_transfer(client->adapter, &push_cmd, 1); -+ if (err < 0) -+ return err; -+ else if (err != 1) -+ return -EIO; -+ -+ return 0; -+} -+ -+/* Routine obtains mail box offsets from ASIC register space. */ -+static int mlxsw_i2c_get_mbox(struct i2c_client *client, -+ struct mlxsw_i2c *mlxsw_i2c) -+{ -+ u8 addr_buf[MLXSW_I2C_ADDR_BUF_SIZE]; -+ u8 buf[MLXSW_I2C_MBOX_SIZE]; -+ struct i2c_msg mbox_cmd[] = -+ MLXSW_I2C_READ_MSG(client, addr_buf, buf, MLXSW_I2C_MBOX_SIZE); -+ int err; -+ -+ /* Read mail boxes offsets. */ -+ mlxsw_i2c_set_slave_addr(addr_buf, MLXSW_I2C_CIR2_BASE); -+ err = i2c_transfer(client->adapter, mbox_cmd, 2); -+ if (err != 2) { -+ dev_err(&client->dev, "Could not obtain mail boxes\n"); -+ if (!err) -+ return -EIO; -+ else -+ return err; -+ } -+ -+ /* Convert mail boxes. */ -+ mlxsw_i2c_convert_mbox(mlxsw_i2c, &buf[MLXSW_I2C_MBOX_OUT_PARAM_OFF]); -+ -+ return err; -+} -+ -+/* Routine sends I2C write transaction to ASIC device. */ -+static int -+mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num, -+ u8 *p_status) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); -+ unsigned long timeout = msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS); -+ u8 tran_buf[MLXSW_I2C_MAX_BUFF_SIZE + MLXSW_I2C_ADDR_BUF_SIZE]; -+ int off = mlxsw_i2c->cmd.mb_off_in, chunk_size, i, j; -+ unsigned long end; -+ struct i2c_msg write_tran = -+ MLXSW_I2C_WRITE_MSG(client, tran_buf, MLXSW_I2C_PUSH_CMD_SIZE); -+ int err; -+ -+ for (i = 0; i < num; i++) { -+ chunk_size = (in_mbox_size > MLXSW_I2C_BLK_MAX) ? -+ MLXSW_I2C_BLK_MAX : in_mbox_size; -+ write_tran.len = MLXSW_I2C_ADDR_WIDTH + chunk_size; -+ mlxsw_i2c_set_slave_addr(tran_buf, off); -+ memcpy(&tran_buf[MLXSW_I2C_ADDR_BUF_SIZE], in_mbox + -+ MLXSW_I2C_BLK_MAX * i, chunk_size); -+ -+ j = 0; -+ end = jiffies + timeout; -+ do { -+ err = i2c_transfer(client->adapter, &write_tran, 1); -+ if (err == 1) -+ break; -+ -+ cond_resched(); -+ } while ((time_before(jiffies, end)) || -+ (j++ < MLXSW_I2C_RETRY)); -+ -+ if (err != 1) { -+ if (!err) -+ err = -EIO; -+ return err; -+ } -+ -+ off += chunk_size; -+ in_mbox_size -= chunk_size; -+ } -+ -+ /* Prepare and write out Command Interface Register for transaction. */ -+ err = mlxsw_i2c_write_cmd(client, mlxsw_i2c, 0); -+ if (err) { -+ dev_err(&client->dev, "Could not start transaction"); -+ return -EIO; -+ } -+ -+ /* Wait until go bit is cleared. */ -+ err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, p_status); -+ if (err) { -+ dev_err(&client->dev, "HW semaphore is not released"); -+ return err; -+ } -+ -+ /* Validate transaction completion status. */ -+ if (*p_status) { -+ dev_err(&client->dev, "Bad transaction completion status %x\n", -+ *p_status); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+/* Routine executes I2C command. */ -+static int -+mlxsw_i2c_cmd(struct device *dev, size_t in_mbox_size, u8 *in_mbox, -+ size_t out_mbox_size, u8 *out_mbox, u8 *status) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); -+ unsigned long timeout = msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS); -+ u8 tran_buf[MLXSW_I2C_ADDR_BUF_SIZE]; -+ int num, chunk_size, reg_size, i, j; -+ int off = mlxsw_i2c->cmd.mb_off_out; -+ unsigned long end; -+ struct i2c_msg read_tran[] = -+ MLXSW_I2C_READ_MSG(client, tran_buf, NULL, 0); -+ int err; -+ -+ WARN_ON(in_mbox_size % sizeof(u32) || out_mbox_size % sizeof(u32)); -+ -+ reg_size = mlxsw_i2c_get_reg_size(in_mbox); -+ num = reg_size / MLXSW_I2C_BLK_MAX; -+ if (reg_size % MLXSW_I2C_BLK_MAX) -+ num++; -+ -+ if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { -+ dev_err(&client->dev, "Could not acquire lock"); -+ return -EINVAL; -+ } -+ -+ err = mlxsw_i2c_write(dev, reg_size, in_mbox, num, status); -+ if (err) -+ goto cmd_fail; -+ -+ /* No out mailbox is case of write transaction. */ -+ if (!out_mbox) { -+ mutex_unlock(&mlxsw_i2c->cmd.lock); -+ return 0; -+ } -+ -+ /* Send read transaction to get output mailbox content. */ -+ read_tran[1].buf = out_mbox; -+ for (i = 0; i < num; i++) { -+ chunk_size = (reg_size > MLXSW_I2C_BLK_MAX) ? -+ MLXSW_I2C_BLK_MAX : reg_size; -+ read_tran[1].len = chunk_size; -+ mlxsw_i2c_set_slave_addr(tran_buf, off); -+ -+ j = 0; -+ end = jiffies + timeout; -+ do { -+ err = i2c_transfer(client->adapter, read_tran, -+ ARRAY_SIZE(read_tran)); -+ if (err == ARRAY_SIZE(read_tran)) -+ break; -+ -+ cond_resched(); -+ } while ((time_before(jiffies, end)) || -+ (j++ < MLXSW_I2C_RETRY)); -+ -+ if (err != ARRAY_SIZE(read_tran)) { -+ if (!err) -+ err = -EIO; -+ -+ goto cmd_fail; -+ } -+ -+ off += chunk_size; -+ reg_size -= chunk_size; -+ read_tran[1].buf += chunk_size; -+ } -+ -+ mutex_unlock(&mlxsw_i2c->cmd.lock); -+ -+ return 0; -+ -+cmd_fail: -+ mutex_unlock(&mlxsw_i2c->cmd.lock); -+ return err; -+} -+ -+static int mlxsw_i2c_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod, -+ u32 in_mod, bool out_mbox_direct, -+ char *in_mbox, size_t in_mbox_size, -+ char *out_mbox, size_t out_mbox_size, -+ u8 *status) -+{ -+ struct mlxsw_i2c *mlxsw_i2c = bus_priv; -+ -+ return mlxsw_i2c_cmd(mlxsw_i2c->dev, in_mbox_size, in_mbox, -+ out_mbox_size, out_mbox, status); -+} -+ -+static bool mlxsw_i2c_skb_transmit_busy(void *bus_priv, -+ const struct mlxsw_tx_info *tx_info) -+{ -+ return false; -+} -+ -+static int mlxsw_i2c_skb_transmit(void *bus_priv, struct sk_buff *skb, -+ const struct mlxsw_tx_info *tx_info) -+{ -+ return 0; -+} -+ -+static int -+mlxsw_i2c_init(void *bus_priv, struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_config_profile *profile, -+ struct mlxsw_resources *resources) -+{ -+ struct mlxsw_i2c *mlxsw_i2c = bus_priv; -+ -+ mlxsw_i2c->core = mlxsw_core; -+ -+ return 0; -+} -+ -+static void mlxsw_i2c_fini(void *bus_priv) -+{ -+ struct mlxsw_i2c *mlxsw_i2c = bus_priv; -+ -+ mlxsw_i2c->core = NULL; -+} -+ -+static const struct mlxsw_bus mlxsw_i2c_bus = { -+ .kind = "i2c", -+ .init = mlxsw_i2c_init, -+ .fini = mlxsw_i2c_fini, -+ .skb_transmit_busy = mlxsw_i2c_skb_transmit_busy, -+ .skb_transmit = mlxsw_i2c_skb_transmit, -+ .cmd_exec = mlxsw_i2c_cmd_exec, -+}; -+ -+static int mlxsw_i2c_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct mlxsw_i2c *mlxsw_i2c; -+ u8 status; -+ int err; -+ -+ mlxsw_i2c = devm_kzalloc(&client->dev, sizeof(*mlxsw_i2c), GFP_KERNEL); -+ if (!mlxsw_i2c) -+ return -ENOMEM; -+ -+ i2c_set_clientdata(client, mlxsw_i2c); -+ mutex_init(&mlxsw_i2c->cmd.lock); -+ -+ /* In order to use mailboxes through the i2c, special area is reserved -+ * on the i2c address space that can be used for input and output -+ * mailboxes. Such mailboxes are called local mailboxes. When using a -+ * local mailbox, software should specify 0 as the Input/Output -+ * parameters. The location of the Local Mailbox addresses on the i2c -+ * space can be retrieved through the QUERY_FW command. -+ * For this purpose QUERY_FW is to be issued with opcode modifier equal -+ * 0x01. For such command the output parameter is an immediate value. -+ * Here QUERY_FW command is invoked for ASIC probing and for getting -+ * local mailboxes addresses from immedate output parameters. -+ */ -+ -+ /* Prepare and write out Command Interface Register for transaction */ -+ err = mlxsw_i2c_write_cmd(client, mlxsw_i2c, 1); -+ if (err) { -+ dev_err(&client->dev, "Could not start transaction"); -+ goto errout; -+ } -+ -+ /* 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"); -+ goto errout; -+ } -+ -+ /* Validate transaction completion status. */ -+ if (status) { -+ dev_err(&client->dev, "Bad transaction completion status %x\n", -+ status); -+ err = -EIO; -+ goto errout; -+ } -+ -+ /* Get mailbox offsets. */ -+ err = mlxsw_i2c_get_mbox(client, mlxsw_i2c); -+ if (err < 0) { -+ dev_err(&client->dev, "Fail to get mailboxes\n"); -+ goto errout; -+ } -+ -+ dev_info(&client->dev, "%s mb size=%x off=0x%08x out mb size=%x off=0x%08x\n", -+ id->name, mlxsw_i2c->cmd.mb_size_in, -+ mlxsw_i2c->cmd.mb_off_in, mlxsw_i2c->cmd.mb_size_out, -+ mlxsw_i2c->cmd.mb_off_out); -+ -+ /* Register device bus. */ -+ mlxsw_i2c->bus_info.device_kind = id->name; -+ mlxsw_i2c->bus_info.device_name = client->name; -+ mlxsw_i2c->bus_info.dev = &client->dev; -+ mlxsw_i2c->dev = &client->dev; -+ -+ err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info, -+ &mlxsw_i2c_bus, mlxsw_i2c); -+ if (err) { -+ dev_err(&client->dev, "Fail to register core bus\n"); -+ return err; -+ } -+ -+ return 0; -+ -+errout: -+ i2c_set_clientdata(client, NULL); -+ -+ return err; -+} -+ -+static int mlxsw_i2c_remove(struct i2c_client *client) -+{ -+ struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); -+ -+ mlxsw_core_bus_device_unregister(mlxsw_i2c->core); -+ mutex_destroy(&mlxsw_i2c->cmd.lock); -+ -+ return 0; -+} -+ -+int mlxsw_i2c_driver_register(struct i2c_driver *i2c_driver) -+{ -+ i2c_driver->probe = mlxsw_i2c_probe; -+ i2c_driver->remove = mlxsw_i2c_remove; -+ return i2c_add_driver(i2c_driver); -+} -+EXPORT_SYMBOL(mlxsw_i2c_driver_register); -+ -+void mlxsw_i2c_driver_unregister(struct i2c_driver *i2c_driver) -+{ -+ i2c_del_driver(i2c_driver); -+} -+EXPORT_SYMBOL(mlxsw_i2c_driver_unregister); -+ -+MODULE_AUTHOR("Vadim Pasternak "); -+MODULE_DESCRIPTION("Mellanox switch I2C interface driver"); -+MODULE_LICENSE("Dual BSD/GPL"); -diff -Nur a/drivers/net/ethernet/mellanox/mlxsw/i2c.h b/drivers/net/ethernet/mellanox/mlxsw/i2c.h ---- a/drivers/net/ethernet/mellanox/mlxsw/i2c.h 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.h 2017-11-09 12:03:09.944785064 +0000 -@@ -0,0 +1,60 @@ -+/* -+ * drivers/net/ethernet/mellanox/mlxsw/i2c.h -+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2016 Vadim Pasternak -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. 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. -+ * 3. Neither the names of the copyright holders nor the names of its -+ * contributors may be used to endorse or promote products derived from -+ * this software without specific prior written permission. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2 as published by the Free -+ * Software Foundation. -+ * -+ * 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 _MLXSW_I2C_H -+#define _MLXSW_I2C_H -+ -+#include -+ -+#if IS_ENABLED(CONFIG_MLXSW_I2C) -+ -+int mlxsw_i2c_driver_register(struct i2c_driver *i2c_driver); -+void mlxsw_i2c_driver_unregister(struct i2c_driver *i2c_driver); -+ -+#else -+ -+static inline int -+mlxsw_i2c_driver_register(struct i2c_driver *i2c_driver) -+{ -+ return -ENODEV; -+} -+ -+static inline void -+mlxsw_i2c_driver_unregister(struct i2c_driver *i2c_driver) -+{ -+} -+ -+#endif -+ -+#endif -diff -Nur a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c ---- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c 2017-11-09 12:03:23.332785242 +0000 -@@ -0,0 +1,97 @@ -+/* -+ * drivers/net/ethernet/mellanox/mlxsw/minimal.c -+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2016 Vadim Pasternak -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. 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. -+ * 3. Neither the names of the copyright holders nor the names of its -+ * contributors may be used to endorse or promote products derived from -+ * this software without specific prior written permission. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2 as published by the Free -+ * Software Foundation. -+ * -+ * 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 "core.h" -+#include "i2c.h" -+ -+static const char mlxsw_minimal_driver_name[] = "mlxsw_minimal"; -+ -+static const struct mlxsw_config_profile mlxsw_minimal_config_profile; -+ -+static struct mlxsw_driver mlxsw_minimal_driver = { -+ .kind = mlxsw_minimal_driver_name, -+ .priv_size = 1, -+ .profile = &mlxsw_minimal_config_profile, -+}; -+ -+static const struct i2c_device_id mlxsw_minimal_i2c_id[] = { -+ { "mlxsw_minimal", 0}, -+ { }, -+}; -+ -+static struct i2c_driver mlxsw_minimal_i2c_driver = { -+ .driver.name = "mlxsw_minimal", -+ .class = I2C_CLASS_HWMON, -+ .id_table = mlxsw_minimal_i2c_id, -+}; -+ -+static int __init mlxsw_minimal_module_init(void) -+{ -+ int err; -+ -+ err = mlxsw_core_driver_register(&mlxsw_minimal_driver); -+ if (err) -+ return err; -+ -+ err = mlxsw_i2c_driver_register(&mlxsw_minimal_i2c_driver); -+ if (err) -+ goto err_i2c_driver_register; -+ -+ return 0; -+ -+err_i2c_driver_register: -+ mlxsw_core_driver_unregister(&mlxsw_minimal_driver); -+ -+ return err; -+} -+ -+static void __exit mlxsw_minimal_module_exit(void) -+{ -+ mlxsw_i2c_driver_unregister(&mlxsw_minimal_i2c_driver); -+ mlxsw_core_driver_unregister(&mlxsw_minimal_driver); -+} -+ -+module_init(mlxsw_minimal_module_init); -+module_exit(mlxsw_minimal_module_exit); -+ -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Vadim Pasternak "); -+MODULE_DESCRIPTION("Mellanox minimal driver"); -+MODULE_DEVICE_TABLE(i2c, mlxsw_minimal_i2c_id); -diff -Nur a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c ---- a/drivers/net/ethernet/mellanox/mlxsw/pci.c 2017-05-25 13:45:05.000000000 +0000 -+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c 2017-11-09 13:03:45.824833341 +0000 -@@ -1836,6 +1836,7 @@ - .skb_transmit_busy = mlxsw_pci_skb_transmit_busy, - .skb_transmit = mlxsw_pci_skb_transmit, - .cmd_exec = mlxsw_pci_cmd_exec, -+ .features = MLXSW_BUS_F_TXRX, - }; - - static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci, -diff -Nur a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c ---- a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c 2017-11-09 13:04:52.192834223 +0000 -@@ -0,0 +1,379 @@ -+/* -+ * drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2017 Vadim Pasternak -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. 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. -+ * 3. Neither the names of the copyright holders nor the names of its -+ * contributors may be used to endorse or promote products derived from -+ * this software without specific prior written permission. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2 as published by the Free -+ * Software Foundation. -+ * -+ * 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 "core.h" -+ -+#define MLXSW_QSFP_I2C_ADDR 0x50 -+#define MLXSW_QSFP_PAGE_NUM 5 -+#define MLXSW_QSFP_PAGE_SIZE 128 -+#define MLXSW_QSFP_SUB_PAGE_NUM 3 -+#define MLXSW_QSFP_SUB_PAGE_SIZE 48 -+#define MLXSW_QSFP_LAST_SUB_PAGE_SIZE 32 -+#define MLXSW_QSFP_MAX_NUM 64 -+#define MLXSW_QSFP_MIN_REQ_LEN 4 -+#define MLXSW_QSFP_STATUS_VALID_TIME (120 * HZ) -+#define MLXSW_QSFP_MAX_CPLD_NUM 1 -+ -+static const u8 mlxsw_qsfp_page_number[] = { 0xa0, 0x00, 0x01, 0x02, 0x03 }; -+static const u16 mlxsw_qsfp_page_shift[] = { 0x00, 0x80, 0x80, 0x80, 0x80 }; -+ -+/** -+ * Mellanox device Management Cable Info Access Register buffer for reading -+ * QSFP EEPROM info is limited by 48 bytes. In case full page is to be read -+ * (128 bytes), such request will be implemented by three transactions of size -+ * 48, 48, 32. -+ */ -+static const u16 mlxsw_qsfp_sub_page_size[] = { -+ MLXSW_QSFP_SUB_PAGE_SIZE, -+ MLXSW_QSFP_SUB_PAGE_SIZE, -+ MLXSW_QSFP_LAST_SUB_PAGE_SIZE -+}; -+ -+struct mlxsw_qsfp_module { -+ unsigned long last_updated; -+ u8 cache_status; -+}; -+ -+struct mlxsw_qsfp { -+ struct mlxsw_core *core; -+ const struct mlxsw_bus_info *bus_info; -+ struct attribute *attrs[MLXSW_QSFP_MAX_NUM + 1]; -+ struct device_attribute *dev_attrs; -+ struct bin_attribute *eeprom; -+ struct bin_attribute **eeprom_attr_list; -+ struct mlxsw_qsfp_module modules[MLXSW_QSFP_MAX_NUM]; -+ u8 module_ind[MLXSW_QSFP_MAX_NUM]; -+ u8 module_count; -+ struct attribute *cpld_attrs[MLXSW_QSFP_MAX_CPLD_NUM + 1]; -+ struct device_attribute *cpld_dev_attrs; -+}; -+ -+static int -+mlxsw_qsfp_query_module_eeprom(struct mlxsw_qsfp *mlxsw_qsfp, u8 index, -+ loff_t off, size_t count, int page, char *buf) -+{ -+ char eeprom_tmp[MLXSW_QSFP_PAGE_SIZE]; -+ char mcia_pl[MLXSW_REG_MCIA_LEN]; -+ int status; -+ int err; -+ -+ mlxsw_reg_mcia_pack(mcia_pl, index, 0, page, off, count, -+ MLXSW_QSFP_I2C_ADDR); -+ -+ err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(mcia), mcia_pl); -+ if (err) -+ return err; -+ -+ status = mlxsw_reg_mcia_status_get(mcia_pl); -+ if (status) -+ return -EIO; -+ -+ mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp); -+ memcpy(buf, eeprom_tmp, count); -+ -+ return 0; -+} -+ -+static int -+mlxsw_qsfp_get_module_eeprom(struct mlxsw_qsfp *mlxsw_qsfp, u8 index, -+ char *buf, loff_t off, size_t count) -+{ -+ int page_ind, page, page_off, subpage, offset, size, res = 0; -+ int err; -+ -+ if (!count) -+ return -EINVAL; -+ -+ memset(buf, 0, count); -+ size = count; -+ while (res < count) { -+ page_ind = off / MLXSW_QSFP_PAGE_SIZE; -+ page_off = off % MLXSW_QSFP_PAGE_SIZE; -+ page = mlxsw_qsfp_page_number[page_ind]; -+ offset = mlxsw_qsfp_page_shift[page_ind] + page_off; -+ subpage = page_off / MLXSW_QSFP_SUB_PAGE_SIZE; -+ size = min_t(u16, size, mlxsw_qsfp_sub_page_size[subpage]); -+ err = mlxsw_qsfp_query_module_eeprom(mlxsw_qsfp, index, offset, -+ size, page, buf + res); -+ if (err) { -+ dev_err(mlxsw_qsfp->bus_info->dev, "Eeprom query failed\n"); -+ return err; -+ } -+ off += size; -+ res += size; -+ size = count - size; -+ } -+ -+ return res; -+} -+ -+static ssize_t mlxsw_qsfp_bin_read(struct file *filp, struct kobject *kobj, -+ struct bin_attribute *attr, char *buf, -+ loff_t off, size_t count) -+{ -+ struct mlxsw_qsfp *mlxsw_qsfp = dev_get_platdata(container_of(kobj, -+ struct device, kobj)); -+ u8 *module_ind = attr->private; -+ size_t size; -+ -+ size = mlxsw_qsfp->eeprom[*module_ind].size; -+ -+ if (off > size) -+ return -ESPIPE; -+ else if (off == size) -+ return 0; -+ else if ((off + count) > size) -+ count = size - off; -+ -+ return mlxsw_qsfp_get_module_eeprom(mlxsw_qsfp, *module_ind, buf, off, -+ count); -+} -+ -+static ssize_t -+mlxsw_qsfp_status_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct mlxsw_qsfp *mlxsw_qsfp = dev_get_platdata(dev); -+ char mcia_pl[MLXSW_REG_MCIA_LEN]; -+ int status; -+ u32 i; -+ int err; -+ -+ for (i = 0; i < mlxsw_qsfp->module_count; i++) { -+ if ((mlxsw_qsfp->dev_attrs + i) == attr) -+ break; -+ } -+ if (i == mlxsw_qsfp->module_count) -+ return -EINVAL; -+ -+ if (time_before(jiffies, mlxsw_qsfp->modules[i].last_updated + -+ MLXSW_QSFP_STATUS_VALID_TIME)) -+ return sprintf(buf, "%u\n", -+ mlxsw_qsfp->modules[i].cache_status); -+ -+ mlxsw_reg_mcia_pack(mcia_pl, i, 0, 0, 0, MLXSW_QSFP_MIN_REQ_LEN, -+ MLXSW_QSFP_I2C_ADDR); -+ err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(mcia), mcia_pl); -+ if (err) -+ return err; -+ -+ status = mlxsw_reg_mcia_status_get(mcia_pl); -+ mlxsw_qsfp->modules[i].cache_status = !status; -+ mlxsw_qsfp->modules[i].last_updated = jiffies; -+ -+ return sprintf(buf, "%u\n", !status); -+} -+ -+static ssize_t -+mlxsw_qsfp_cpld_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct mlxsw_qsfp *mlxsw_qsfp = dev_get_platdata(dev); -+ char msci_pl[MLXSW_REG_MSCI_LEN]; -+ u32 version, i; -+ int err; -+ -+ for (i = 0; i < MLXSW_QSFP_MAX_CPLD_NUM; i++) { -+ if ((mlxsw_qsfp->cpld_dev_attrs + i) == attr) -+ break; -+ } -+ if (i == MLXSW_QSFP_MAX_CPLD_NUM) -+ return -EINVAL; -+ -+ mlxsw_reg_msci_pack(msci_pl, i); -+ err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(msci), msci_pl); -+ if (err) -+ return err; -+ -+ version = mlxsw_reg_msci_version_get(msci_pl); -+ -+ return sprintf(buf, "%u\n", version); -+} -+ -+int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_bus_info *mlxsw_bus_info, -+ struct mlxsw_qsfp **p_qsfp) -+{ -+ struct device_attribute *dev_attr, *cpld_dev_attr; -+ char pmlp_pl[MLXSW_REG_PMLP_LEN]; -+ struct mlxsw_qsfp *mlxsw_qsfp; -+ struct bin_attribute *eeprom; -+ int i, count; -+ u8 width; -+ int err; -+ -+ if (!strcmp(mlxsw_bus_info->device_kind, "i2c")) -+ return 0; -+ -+ mlxsw_qsfp = devm_kzalloc(mlxsw_bus_info->dev, sizeof(*mlxsw_qsfp), -+ GFP_KERNEL); -+ if (!mlxsw_qsfp) -+ return -ENOMEM; -+ -+ mlxsw_qsfp->core = mlxsw_core; -+ mlxsw_qsfp->bus_info = mlxsw_bus_info; -+ mlxsw_bus_info->dev->platform_data = mlxsw_qsfp; -+ -+ for (i = 1; i <= MLXSW_QSFP_MAX_NUM; i++) { -+ mlxsw_reg_pmlp_pack(pmlp_pl, i); -+ err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(pmlp), -+ pmlp_pl); -+ if (err) -+ return err; -+ width = mlxsw_reg_pmlp_width_get(pmlp_pl); -+ if (!width) -+ continue; -+ mlxsw_qsfp->module_count++; -+ } -+ -+ count = mlxsw_qsfp->module_count + 1; -+ mlxsw_qsfp->eeprom = devm_kzalloc(mlxsw_bus_info->dev, -+ mlxsw_qsfp->module_count * -+ sizeof(*mlxsw_qsfp->eeprom), -+ GFP_KERNEL); -+ if (!mlxsw_qsfp->eeprom) -+ return -ENOMEM; -+ -+ mlxsw_qsfp->eeprom_attr_list = devm_kzalloc(mlxsw_bus_info->dev, -+ count * -+ sizeof(mlxsw_qsfp->eeprom), -+ GFP_KERNEL); -+ if (!mlxsw_qsfp->eeprom_attr_list) -+ return -ENOMEM; -+ -+ mlxsw_qsfp->dev_attrs = devm_kzalloc(mlxsw_bus_info->dev, count * -+ sizeof(*mlxsw_qsfp->dev_attrs), -+ GFP_KERNEL); -+ if (!mlxsw_qsfp->dev_attrs) -+ return -ENOMEM; -+ -+ mlxsw_qsfp->cpld_dev_attrs = devm_kzalloc(mlxsw_bus_info->dev, -+ MLXSW_QSFP_MAX_CPLD_NUM * -+ sizeof(*mlxsw_qsfp->cpld_dev_attrs), -+ GFP_KERNEL); -+ if (!mlxsw_qsfp->cpld_dev_attrs) -+ return -ENOMEM; -+ -+ eeprom = mlxsw_qsfp->eeprom; -+ dev_attr = mlxsw_qsfp->dev_attrs; -+ for (i = 0; i < mlxsw_qsfp->module_count; i++, eeprom++, dev_attr++) { -+ dev_attr->show = mlxsw_qsfp_status_show; -+ dev_attr->attr.mode = 0444; -+ dev_attr->attr.name = devm_kasprintf(mlxsw_bus_info->dev, -+ GFP_KERNEL, -+ "qsfp%d_status", i + 1); -+ mlxsw_qsfp->attrs[i] = &dev_attr->attr; -+ sysfs_attr_init(&dev_attr->attr); -+ err = sysfs_create_file(&mlxsw_bus_info->dev->kobj, -+ mlxsw_qsfp->attrs[i]); -+ if (err) -+ goto err_create_file; -+ -+ sysfs_bin_attr_init(eeprom); -+ eeprom->attr.name = devm_kasprintf(mlxsw_bus_info->dev, -+ GFP_KERNEL, "qsfp%d", -+ i + 1); -+ eeprom->attr.mode = 0444; -+ eeprom->read = mlxsw_qsfp_bin_read; -+ eeprom->size = MLXSW_QSFP_PAGE_NUM * MLXSW_QSFP_PAGE_SIZE; -+ mlxsw_qsfp->module_ind[i] = i; -+ eeprom->private = &mlxsw_qsfp->module_ind[i]; -+ mlxsw_qsfp->eeprom_attr_list[i] = eeprom; -+ err = sysfs_create_bin_file(&mlxsw_bus_info->dev->kobj, -+ eeprom); -+ if (err) -+ goto err_create_bin_file; -+ } -+ -+ cpld_dev_attr = mlxsw_qsfp->cpld_dev_attrs; -+ for (i = 0; i < MLXSW_QSFP_MAX_CPLD_NUM; i++, cpld_dev_attr++) { -+ cpld_dev_attr->show = mlxsw_qsfp_cpld_show; -+ cpld_dev_attr->attr.mode = 0444; -+ cpld_dev_attr->attr.name = devm_kasprintf(mlxsw_bus_info->dev, -+ GFP_KERNEL, -+ "cpld%d_version", i + 1); -+ mlxsw_qsfp->cpld_attrs[i] = &cpld_dev_attr->attr; -+ sysfs_attr_init(&cpld_dev_attr->attr); -+ err = sysfs_create_file(&mlxsw_bus_info->dev->kobj, -+ mlxsw_qsfp->cpld_attrs[i]); -+ if (err) -+ goto err_create_cpld_file; -+ } -+ -+ *p_qsfp = mlxsw_qsfp; -+ -+ return 0; -+ -+err_create_cpld_file: -+ sysfs_remove_file(&mlxsw_bus_info->dev->kobj, -+ mlxsw_qsfp->cpld_attrs[i--]); -+ i = mlxsw_qsfp->module_count; -+err_create_bin_file: -+ sysfs_remove_file(&mlxsw_bus_info->dev->kobj, -+ mlxsw_qsfp->attrs[i--]); -+err_create_file: -+ while (--i > 0) { -+ sysfs_remove_bin_file(&mlxsw_bus_info->dev->kobj, -+ mlxsw_qsfp->eeprom_attr_list[i]); -+ sysfs_remove_file(&mlxsw_bus_info->dev->kobj, -+ mlxsw_qsfp->attrs[i]); -+ } -+ -+ return err; -+} -+ -+void mlxsw_qsfp_fini(struct mlxsw_qsfp *mlxsw_qsfp) -+{ -+ int i; -+ -+ if (!strcmp(mlxsw_qsfp->bus_info->device_kind, "i2c")) -+ return; -+ -+ for (i = mlxsw_qsfp->module_count - 1; i >= 0; i--) { -+ sysfs_remove_bin_file(&mlxsw_qsfp->bus_info->dev->kobj, -+ mlxsw_qsfp->eeprom_attr_list[i]); -+ sysfs_remove_file(&mlxsw_qsfp->bus_info->dev->kobj, -+ mlxsw_qsfp->attrs[i]); -+ } -+} -+ -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_AUTHOR("Vadim Pasternak "); -+MODULE_DESCRIPTION("Mellanox switch QSFP sysfs driver"); -diff -Nur a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h ---- a/drivers/net/ethernet/mellanox/mlxsw/reg.h 2017-05-25 13:45:05.000000000 +0000 -+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h 2017-11-09 13:05:10.576834467 +0000 -@@ -50,6 +50,12 @@ - u16 len; /* In u8 */ - }; - -+#define MLXSW_REG_DEFINE(_name, _id, _len) \ -+static const struct mlxsw_reg_info mlxsw_reg_##_name = { \ -+ .id = _id, \ -+ .len = _len, \ -+} -+ - #define MLXSW_REG(type) (&mlxsw_reg_##type) - #define MLXSW_REG_LEN(type) MLXSW_REG(type)->len - #define MLXSW_REG_ZERO(type, payload) memset(payload, 0, MLXSW_REG(type)->len) -@@ -4466,7 +4472,7 @@ - */ - MLXSW_ITEM32(reg, mfcr, pwm_frequency, 0x00, 0, 6); - --#define MLXSW_MFCR_TACHOS_MAX 10 -+#define MLXSW_MFCR_TACHOS_MAX 12 - - /* reg_mfcr_tacho_active - * Indicates which of the tachometer is active (bit per tachometer). -@@ -4564,6 +4570,54 @@ - mlxsw_reg_mfsm_tacho_set(payload, tacho); - } - -+/* MFSL - Management Fan Speed Limit Register -+ * ------------------------------------------ -+ * The Fan Speed Limit register is used to configure the fan speed -+ * event / interrupt notification mechanism. Fan speed threshold are -+ * defined for both under-speed and over-speed. -+ */ -+#define MLXSW_REG_MFSL_ID 0x9004 -+#define MLXSW_REG_MFSL_LEN 0x0C -+ -+MLXSW_REG_DEFINE(mfsl, MLXSW_REG_MFSL_ID, MLXSW_REG_MFSL_LEN); -+ -+/* reg_mfsl_tacho -+ * Fan tachometer index. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, mfsl, tacho, 0x00, 24, 4); -+ -+/* reg_mfsl_tach_min -+ * Tachometer minimum value (minimum RPM). -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mfsl, tach_min, 0x04, 0, 16); -+ -+/* reg_mfsl_tach_max -+ * Tachometer maximum value (maximum RPM). -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mfsl, tach_max, 0x08, 0, 16); -+ -+static inline void mlxsw_reg_mfsl_pack(char *payload, u8 tacho, -+ u16 tach_min, u16 tach_max) -+{ -+ MLXSW_REG_ZERO(mfsl, payload); -+ mlxsw_reg_mfsl_tacho_set(payload, tacho); -+ mlxsw_reg_mfsl_tach_min_set(payload, tach_min); -+ mlxsw_reg_mfsl_tach_max_set(payload, tach_max); -+} -+ -+static inline void mlxsw_reg_mfsl_unpack(char *payload, u8 tacho, -+ u16 *p_tach_min, u16 *p_tach_max) -+{ -+ if (p_tach_min) -+ *p_tach_min = mlxsw_reg_mfsl_tach_min_get(payload); -+ -+ if (p_tach_max) -+ *p_tach_max = mlxsw_reg_mfsl_tach_max_get(payload); -+} -+ - /* MTCAP - Management Temperature Capabilities - * ------------------------------------------- - * This register exposes the capabilities of the device and -@@ -4635,6 +4689,29 @@ - */ - MLXSW_ITEM32(reg, mtmp, max_temperature, 0x08, 0, 16); - -+/* reg_mtmp_tee -+ * Temperature Event Enable. -+ * 0 - Do not generate event -+ * 1 - Generate event -+ * 2 - Generate single event -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mtmp, tee, 0x0C, 30, 2); -+ -+#define MLXSW_REG_MTMP_THRESH_HI 0x348 /* 105 Celsius */ -+ -+/* reg_mtmp_temperature_threshold_hi -+ * High threshold for Temperature Warning Event. In 0.125 Celsius. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mtmp, temperature_threshold_hi, 0x0C, 0, 16); -+ -+/* reg_mtmp_temperature_threshold_lo -+ * Low threshold for Temperature Warning Event. In 0.125 Celsius. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mtmp, temperature_threshold_lo, 0x10, 0, 16); -+ - #define MLXSW_REG_MTMP_SENSOR_NAME_SIZE 8 - - /* reg_mtmp_sensor_name -@@ -4651,6 +4728,8 @@ - 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); -+ mlxsw_reg_mtmp_temperature_threshold_hi_set(payload, -+ MLXSW_REG_MTMP_THRESH_HI); - } - - static inline void mlxsw_reg_mtmp_unpack(char *payload, unsigned int *p_temp, -@@ -4671,6 +4750,81 @@ - mlxsw_reg_mtmp_sensor_name_memcpy_from(payload, sensor_name); - } - -+/* MCIA - Management Cable Info Access -+ * ----------------------------------- -+ * MCIA register is used to access the SFP+ and QSFP connector's EPROM. -+ */ -+ -+#define MLXSW_REG_MCIA_ID 0x9014 -+#define MLXSW_REG_MCIA_LEN 0x40 -+ -+MLXSW_REG_DEFINE(mcia, MLXSW_REG_MCIA_ID, MLXSW_REG_MCIA_LEN); -+ -+/* reg_mcia_l -+ * Lock bit. Setting this bit will lock the access to the specific -+ * cable. Used for updating a full page in a cable EPROM. Any access -+ * other then subsequence writes will fail while the port is locked. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mcia, l, 0x00, 31, 1); -+ -+/* reg_mcia_module -+ * Module number. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, mcia, module, 0x00, 16, 8); -+ -+/* reg_mcia_status -+ * Module status. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, mcia, status, 0x00, 0, 8); -+ -+/* reg_mcia_i2c_device_address -+ * I2C device address. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mcia, i2c_device_address, 0x04, 24, 8); -+ -+/* reg_mcia_page_number -+ * Page number. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mcia, page_number, 0x04, 16, 8); -+ -+/* reg_mcia_device_address -+ * Device address. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mcia, device_address, 0x04, 0, 16); -+ -+/* reg_mcia_size -+ * Number of bytes to read/write (up to 48 bytes). -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mcia, size, 0x08, 0, 16); -+ -+#define MLXSW_SP_REG_MCIA_EEPROM_SIZE 48 -+ -+/* reg_mcia_eeprom -+ * Bytes to read/write. -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_SP_REG_MCIA_EEPROM_SIZE); -+ -+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) -+{ -+ MLXSW_REG_ZERO(mcia, payload); -+ mlxsw_reg_mcia_module_set(payload, module); -+ mlxsw_reg_mcia_l_set(payload, lock); -+ mlxsw_reg_mcia_page_number_set(payload, page_number); -+ mlxsw_reg_mcia_device_address_set(payload, device_addr); -+ mlxsw_reg_mcia_size_set(payload, size); -+ mlxsw_reg_mcia_i2c_device_address_set(payload, i2c_device_addr); -+} -+ - /* MPAT - Monitoring Port Analyzer Table - * ------------------------------------- - * MPAT Register is used to query and configure the Switch PortAnalyzer Table. -@@ -4788,6 +4942,43 @@ - mlxsw_reg_mpar_pa_id_set(payload, pa_id); - } - -+/* MSCI - Management System CPLD Information Register -+ * --------------------------------------------------- -+ * This register allows querying for the System CPLD(s) information. -+ */ -+#define MLXSW_REG_MSCI_ID 0x902A -+#define MLXSW_REG_MSCI_LEN 0x10 -+ -+static const struct mlxsw_reg_info mlxsw_reg_msci = { -+ .id = MLXSW_REG_MSCI_ID, -+ .len = MLXSW_REG_MSCI_LEN, -+}; -+ -+/* reg_msci_index -+ * Index to access. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, msci, index, 0x00, 0, 4); -+ -+/* reg_msci_version -+ * CPLD version. -+ * Access: R0 -+ */ -+MLXSW_ITEM32(reg, msci, version, 0x04, 0, 32); -+ -+static inline void -+mlxsw_reg_msci_pack(char *payload, u8 index) -+{ -+ MLXSW_REG_ZERO(msci, payload); -+ mlxsw_reg_msci_index_set(payload, index); -+} -+ -+static inline void -+mlxsw_reg_msci_unpack(char *payload, u16 *p_version) -+{ -+ *p_version = mlxsw_reg_msci_version_get(payload); -+} -+ - /* MLCR - Management LED Control Register - * -------------------------------------- - * Controls the system LEDs. diff --git a/patch/0006-platform-mellanox-mlxreg-hotplug-Use-capability-r.patch b/patch/0006-platform-mellanox-mlxreg-hotplug-Use-capability-r.patch new file mode 100644 index 000000000000..3de055dbb667 --- /dev/null +++ b/patch/0006-platform-mellanox-mlxreg-hotplug-Use-capability-r.patch @@ -0,0 +1,73 @@ +From af50fedeeaa767a0c7c3a9cf399fe23314adc609 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 12 Mar 2020 23:51:41 +0200 +Subject: [platform-next v1 1/2] platform/mellanox: mlxreg-hotplug: Use + capability register for attribute creation + +Create the 'sysfs' attributes according to configuration provided +through the capability register, which purpose is to indicate the +actual number of the components within the particular group. +Such components could be, for example the FAN or power supply units. +The motivation is to avoid adding a new code in the future in order to +distinct between the systems types supported different number of the +components like power supplies, FANs, ASICs, line cards. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/mellanox/mlxreg-hotplug.c | 23 +++++++++++++++++++---- + 1 file changed, 19 insertions(+), 4 deletions(-) + +diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c +index 77be37a1fbcf..c21754821789 100644 +--- a/drivers/platform/mellanox/mlxreg-hotplug.c ++++ b/drivers/platform/mellanox/mlxreg-hotplug.c +@@ -196,17 +196,29 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) + struct mlxreg_core_hotplug_platform_data *pdata; + struct mlxreg_core_item *item; + struct mlxreg_core_data *data; +- int num_attrs = 0, id = 0, i, j; ++ u32 regval; ++ int num_attrs = 0, id = 0, i, j, k, ret; + + pdata = dev_get_platdata(&priv->pdev->dev); + item = pdata->items; + + /* Go over all kinds of items - psu, pwr, fan. */ + for (i = 0; i < pdata->counter; i++, item++) { +- num_attrs += item->count; + data = item->data; + /* Go over all units within the item. */ +- for (j = 0; j < item->count; j++, data++, id++) { ++ for (j = 0, k = 0; j < item->count; j++, data++) { ++ if (data->capability) { ++ /* ++ * Read capability register and skip non ++ * relevant attributes. ++ */ ++ ret = regmap_read(priv->regmap, ++ data->capability, ®val); ++ if (ret) ++ return ret; ++ if (!(regval & data->bit)) ++ continue; ++ } + PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr; + PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev, + GFP_KERNEL, +@@ -224,9 +236,12 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) + PRIV_DEV_ATTR(id).dev_attr.show = + mlxreg_hotplug_attr_show; + PRIV_DEV_ATTR(id).nr = i; +- PRIV_DEV_ATTR(id).index = j; ++ PRIV_DEV_ATTR(id).index = k; + sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr); ++ id++; ++ k++; + } ++ num_attrs += k; + } + + priv->group.attrs = devm_kcalloc(&priv->pdev->dev, +-- +2.11.0 + diff --git a/patch/0007-hwmon-pmbus-Add-support-for-Intel-VID-protocol-VR13.patch b/patch/0007-hwmon-pmbus-Add-support-for-Intel-VID-protocol-VR13.patch deleted file mode 100644 index f0a9bde81f49..000000000000 --- a/patch/0007-hwmon-pmbus-Add-support-for-Intel-VID-protocol-VR13.patch +++ /dev/null @@ -1,30 +0,0 @@ -Linux backport patch. Includes following commits: -a4dffccb72a7fa46bb0d7f29e607375387e09956 - - -diff -Nur a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h ---- a/drivers/hwmon/pmbus/pmbus.h 2017-11-09 16:25:22.760993964 +0000 -+++ b/drivers/hwmon/pmbus/pmbus.h 2017-11-09 16:26:02.568994492 +0000 -@@ -341,7 +341,7 @@ - #define PMBUS_HAVE_STATUS_VMON BIT(19) - - enum pmbus_data_format { linear = 0, direct, vid }; --enum vrm_version { vr11 = 0, vr12 }; -+enum vrm_version { vr11 = 0, vr12, vr13 }; - - struct pmbus_driver_info { - int pages; /* Total number of pages */ -diff -Nur a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c ---- a/drivers/hwmon/pmbus/pmbus_core.c 2017-11-09 16:25:22.760993964 +0000 -+++ b/drivers/hwmon/pmbus/pmbus_core.c 2017-11-09 16:26:02.568994492 +0000 -@@ -531,6 +531,10 @@ - if (val >= 0x01) - rv = 250 + (val - 1) * 5; - break; -+ case vr13: -+ if (val >= 0x01) -+ rv = 500 + (val - 1) * 10; -+ break; - } - return rv; - } diff --git a/patch/0008-hwmon-pmbus-Add-support-for-Texas-Instruments-tps536.patch b/patch/0008-hwmon-pmbus-Add-support-for-Texas-Instruments-tps536.patch deleted file mode 100644 index f95e27695ca2..000000000000 --- a/patch/0008-hwmon-pmbus-Add-support-for-Texas-Instruments-tps536.patch +++ /dev/null @@ -1,151 +0,0 @@ -Linux backport patch. Includes following commits: -f7caf758e26ab84b2b9def9ec68235c85d645597 - - -diff -Nur a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig ---- a/drivers/hwmon/pmbus/Kconfig 2017-11-09 16:34:05.269000902 +0000 -+++ b/drivers/hwmon/pmbus/Kconfig 2017-11-09 16:35:49.701002288 +0000 -@@ -125,6 +125,15 @@ - This driver can also be built as a module. If so, the module will - be called tps40422. - -+config SENSORS_TPS53679 -+ tristate "TI TPS53679" -+ help -+ If you say yes here you get hardware monitoring support for TI -+ TPS53679. -+ -+ This driver can also be built as a module. If so, the module will -+ be called tps53679. -+ - config SENSORS_UCD9000 - tristate "TI UCD90120, UCD90124, UCD90160, UCD9090, UCD90910" - default n -diff -Nur a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile ---- a/drivers/hwmon/pmbus/Makefile 2017-11-09 16:34:05.269000902 +0000 -+++ b/drivers/hwmon/pmbus/Makefile 2017-11-09 16:35:49.701002288 +0000 -@@ -13,6 +13,7 @@ - obj-$(CONFIG_SENSORS_MAX34440) += max34440.o - obj-$(CONFIG_SENSORS_MAX8688) += max8688.o - obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o -+obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o - obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o - obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o - obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o -diff -Nur a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c ---- a/drivers/hwmon/pmbus/tps53679.c 1970-01-01 00:00:00.000000000 +0000 -+++ b/drivers/hwmon/pmbus/tps53679.c 2017-11-09 16:35:49.701002288 +0000 -@@ -0,0 +1,113 @@ -+/* -+ * Hardware monitoring driver for Texas Instruments TPS53679 -+ * -+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2017 Vadim Pasternak -+ * -+ * 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. -+ * -+ * 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 "pmbus.h" -+ -+#define TPS53679_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */ -+#define TPS53679_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */ -+#define TPS53679_PROT_VR13_10MV 0x04 /* VR13.0 mode, 10-mV DAC */ -+#define TPS53679_PROT_IMVP8_5MV 0x05 /* IMVP8 mode, 5-mV DAC */ -+#define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */ -+#define TPS53679_PAGE_NUM 2 -+ -+static int tps53679_identify(struct i2c_client *client, -+ struct pmbus_driver_info *info) -+{ -+ u8 vout_params; -+ int ret; -+ -+ /* Read the register with VOUT scaling value.*/ -+ ret = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); -+ if (ret < 0) -+ return ret; -+ -+ vout_params = ret & GENMASK(4, 0); -+ -+ switch (vout_params) { -+ case TPS53679_PROT_VR13_10MV: -+ case TPS53679_PROT_VR12_5_10MV: -+ info->vrm_version = vr13; -+ break; -+ case TPS53679_PROT_VR13_5MV: -+ case TPS53679_PROT_VR12_5MV: -+ case TPS53679_PROT_IMVP8_5MV: -+ info->vrm_version = vr12; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static struct pmbus_driver_info tps53679_info = { -+ .pages = TPS53679_PAGE_NUM, -+ .format[PSC_VOLTAGE_IN] = linear, -+ .format[PSC_VOLTAGE_OUT] = vid, -+ .format[PSC_TEMPERATURE] = linear, -+ .format[PSC_CURRENT_OUT] = linear, -+ .format[PSC_POWER] = linear, -+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | -+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | -+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | -+ PMBUS_HAVE_POUT, -+ .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | -+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | -+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | -+ PMBUS_HAVE_POUT, -+ .identify = tps53679_identify, -+}; -+ -+static int tps53679_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ return pmbus_do_probe(client, id, &tps53679_info); -+} -+ -+static const struct i2c_device_id tps53679_id[] = { -+ {"tps53679", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, tps53679_id); -+ -+static const struct of_device_id tps53679_of_match[] = { -+ {.compatible = "ti,tps53679"}, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, tps53679_of_match); -+ -+static struct i2c_driver tps53679_driver = { -+ .driver = { -+ .name = "tps53679", -+ .of_match_table = of_match_ptr(tps53679_of_match), -+ }, -+ .probe = tps53679_probe, -+ .remove = pmbus_do_remove, -+ .id_table = tps53679_id, -+}; -+ -+module_i2c_driver(tps53679_driver); -+ -+MODULE_AUTHOR("Vadim Pasternak "); -+MODULE_DESCRIPTION("PMBus driver for Texas Instruments TPS53679"); -+MODULE_LICENSE("GPL"); diff --git a/patch/0009-platform-mellonox-introduce-mlxreg-io-driver-and-add.patch b/patch/0009-platform-mellonox-introduce-mlxreg-io-driver-and-add.patch deleted file mode 100644 index db22b149b1b6..000000000000 --- a/patch/0009-platform-mellonox-introduce-mlxreg-io-driver-and-add.patch +++ /dev/null @@ -1,685 +0,0 @@ -From 2c7476ab57dd42d8cba6c417ff32a77252964858 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Thu, 16 Nov 2017 17:22:56 +0000 -Subject: [v4.9 backport 38/38] platform: mellonox: introduce mlxreg-io driver - and add driver activation to mlx-platform - -Patch introduces new module mlxreg-io, which exposes the registers of the -programmable devices, equipped on Melanox systems to sysfs. These are the -registers, which are used for system resets operation, system reset causes -monitoring, select operation and version info. - -Signed-off-by: Vadim Pasternak ---- - drivers/leds/leds-mlxreg.c | 10 +- - drivers/platform/mellanox/Kconfig | 11 ++ - drivers/platform/mellanox/Makefile | 1 + - drivers/platform/mellanox/mlxreg-io.c | 211 ++++++++++++++++++++++++++++++++++ - drivers/platform/x86/mlx-platform.c | 193 +++++++++++++++++++++++++++++-- - include/linux/platform_data/mlxreg.h | 6 +- - 6 files changed, 418 insertions(+), 14 deletions(-) - create mode 100644 drivers/platform/mellanox/mlxreg-io.c - -diff --git a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c -index a932f20..036c214 100644 ---- a/drivers/leds/leds-mlxreg.c -+++ b/drivers/leds/leds-mlxreg.c -@@ -79,7 +79,7 @@ struct mlxreg_led_data { - */ - struct mlxreg_led_priv_data { - struct platform_device *pdev; -- struct mlxreg_core_led_platform_data *pdata; -+ struct mlxreg_core_platform_data *pdata; - struct mutex access_lock; /* protect IO operations */ - }; - -@@ -87,7 +87,7 @@ static int - mlxreg_led_store_hw(struct mlxreg_led_data *led_data, u8 vset) - { - struct mlxreg_led_priv_data *priv = led_data->data_parent; -- struct mlxreg_core_led_platform_data *led_pdata = priv->pdata; -+ struct mlxreg_core_platform_data *led_pdata = priv->pdata; - struct mlxreg_core_data *data = led_data->data; - u32 regval; - u32 nib; -@@ -125,7 +125,7 @@ static enum led_brightness - mlxreg_led_get_hw(struct mlxreg_led_data *led_data) - { - struct mlxreg_led_priv_data *priv = led_data->data_parent; -- struct mlxreg_core_led_platform_data *led_pdata = priv->pdata; -+ struct mlxreg_core_platform_data *led_pdata = priv->pdata; - struct mlxreg_core_data *data = led_data->data; - u32 regval; - int ret; -@@ -212,7 +212,7 @@ mlxreg_led_blink_set(struct led_classdev *cled, unsigned long *delay_on, - - static int mlxreg_led_config(struct mlxreg_led_priv_data *priv) - { -- struct mlxreg_core_led_platform_data *led_pdata = priv->pdata; -+ struct mlxreg_core_platform_data *led_pdata = priv->pdata; - struct mlxreg_core_data *data = led_pdata->data; - struct mlxreg_led_data *led_data; - struct led_classdev *led_cdev; -@@ -266,7 +266,7 @@ static int mlxreg_led_config(struct mlxreg_led_priv_data *priv) - - static int mlxreg_led_probe(struct platform_device *pdev) - { -- struct mlxreg_core_led_platform_data *led_pdata; -+ struct mlxreg_core_platform_data *led_pdata; - struct mlxreg_led_priv_data *priv; - - led_pdata = dev_get_platdata(&pdev->dev); -diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig -index b197cc1..5c6dc29 100644 ---- a/drivers/platform/mellanox/Kconfig -+++ b/drivers/platform/mellanox/Kconfig -@@ -22,4 +22,15 @@ config MLXREG_HOTPLUG - This driver handles hot-plug events for the power suppliers, power - cables and fans on the wide range Mellanox IB and Ethernet systems. - -+config MLXREG_IO -+ tristate "Mellanox platform register driver support" -+ depends on REGMAP -+ depends on HWMON -+ ---help--- -+ This driver allows access to Mellanox programmable device register -+ space trough sysfs interface. The set of registers for sysfs access -+ are defined per system type bases and includes the registers related -+ to system resets operation, system reset causes monitoring and some -+ kinds of mux selection. -+ - endif # MELLANOX_PLATFORM -diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile -index f58d089..b9a2692 100644 ---- a/drivers/platform/mellanox/Makefile -+++ b/drivers/platform/mellanox/Makefile -@@ -1 +1,2 @@ - obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o -+obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o -diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c -new file mode 100644 -index 0000000..f7434ca ---- /dev/null -+++ b/drivers/platform/mellanox/mlxreg-io.c -@@ -0,0 +1,211 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Attribute parameters. */ -+#define MLXREG_IO_ATT_SIZE 10 -+#define MLXREG_IO_ATT_NUM 48 -+ -+/** -+ * struct mlxreg_io_priv_data - driver's private data: -+ * -+ * @pdev: platform device; -+ * @pdata: platform data; -+ * @hwmon: hwmon device; -+ * @mlxreg_io_attr: sysfs attributes array; -+ * @mlxreg_io_dev_attr: sysfs sensor device attribute array; -+ * @group: sysfs attribute group; -+ * @groups: list of sysfs attribute group for hwmon registration; -+ */ -+struct mlxreg_io_priv_data { -+ struct platform_device *pdev; -+ struct mlxreg_core_platform_data *pdata; -+ struct device *hwmon; -+ struct attribute *mlxreg_io_attr[MLXREG_IO_ATT_NUM + 1]; -+ struct sensor_device_attribute mlxreg_io_dev_attr[MLXREG_IO_ATT_NUM]; -+ struct attribute_group group; -+ const struct attribute_group *groups[2]; -+}; -+ -+static ssize_t -+mlxreg_io_attr_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev); -+ int index = to_sensor_dev_attr(attr)->index; -+ struct mlxreg_core_data *data = priv->pdata->data + index; -+ u32 regval = 0; -+ int ret; -+ -+ ret = regmap_read(priv->pdata->regmap, data->reg, ®val); -+ if (ret) -+ goto access_error; -+ -+ if (!data->bit) -+ regval = !!(regval & ~data->mask); -+ -+ return sprintf(buf, "%u\n", regval); -+ -+access_error: -+ return ret; -+} -+ -+static ssize_t -+mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev); -+ int index = to_sensor_dev_attr(attr)->index; -+ struct mlxreg_core_data *data = priv->pdata->data + index; -+ u32 val, regval; -+ int ret; -+ -+ ret = kstrtou32(buf, MLXREG_IO_ATT_SIZE, &val); -+ if (ret) -+ return ret; -+ -+ ret = regmap_read(priv->pdata->regmap, data->reg, ®val); -+ if (ret) -+ goto access_error; -+ -+ regval &= data->mask; -+ -+ val = !!val; -+ if (val) -+ regval |= ~data->mask; -+ else -+ regval &= data->mask; -+ -+ ret = regmap_write(priv->pdata->regmap, data->reg, regval); -+ if (ret) -+ goto access_error; -+ -+ return len; -+ -+access_error: -+ dev_err(&priv->pdev->dev, "Bus access error\n"); -+ return ret; -+} -+ -+static int mlxreg_io_attr_init(struct mlxreg_io_priv_data *priv) -+{ -+ int i; -+ -+ priv->group.attrs = devm_kzalloc(&priv->pdev->dev, -+ priv->pdata->counter * -+ sizeof(struct attribute *), -+ GFP_KERNEL); -+ if (!priv->group.attrs) -+ return -ENOMEM; -+ -+ for (i = 0; i < priv->pdata->counter; i++) { -+ priv->mlxreg_io_attr[i] = -+ &priv->mlxreg_io_dev_attr[i].dev_attr.attr; -+ -+ /* Set attribute name as a label. */ -+ priv->mlxreg_io_attr[i]->name = -+ devm_kasprintf(&priv->pdev->dev, GFP_KERNEL, -+ priv->pdata->data[i].label); -+ -+ if (!priv->mlxreg_io_attr[i]->name) { -+ dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n", -+ i + 1); -+ return -ENOMEM; -+ } -+ -+ priv->mlxreg_io_dev_attr[i].dev_attr.attr.mode = -+ priv->pdata->data[i].mode; -+ switch (priv->pdata->data[i].mode) { -+ case 0200: -+ priv->mlxreg_io_dev_attr[i].dev_attr.store = -+ mlxreg_io_attr_store; -+ break; -+ -+ case 0444: -+ priv->mlxreg_io_dev_attr[i].dev_attr.show = -+ mlxreg_io_attr_show; -+ break; -+ -+ case 0644: -+ priv->mlxreg_io_dev_attr[i].dev_attr.show = -+ mlxreg_io_attr_show; -+ priv->mlxreg_io_dev_attr[i].dev_attr.store = -+ mlxreg_io_attr_store; -+ break; -+ -+ default: -+ dev_err(&priv->pdev->dev, "Bad access mode %u for attribute %s.\n", -+ priv->pdata->data[i].mode, -+ priv->mlxreg_io_attr[i]->name); -+ return -EINVAL; -+ } -+ -+ priv->mlxreg_io_dev_attr[i].dev_attr.attr.name = -+ priv->mlxreg_io_attr[i]->name; -+ priv->mlxreg_io_dev_attr[i].index = i; -+ sysfs_attr_init(&priv->mlxreg_io_dev_attr[i].dev_attr.attr); -+ } -+ -+ priv->group.attrs = priv->mlxreg_io_attr; -+ priv->groups[0] = &priv->group; -+ priv->groups[1] = NULL; -+ -+ return 0; -+} -+ -+static int mlxreg_io_probe(struct platform_device *pdev) -+{ -+ struct mlxreg_io_priv_data *priv; -+ int err; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->pdata = dev_get_platdata(&pdev->dev); -+ if (!priv->pdata) { -+ dev_err(&pdev->dev, "Failed to get platform data.\n"); -+ return -EINVAL; -+ } -+ -+ priv->pdev = pdev; -+ -+ err = mlxreg_io_attr_init(priv); -+ if (err) { -+ dev_err(&priv->pdev->dev, "Failed to allocate attributes: %d\n", -+ err); -+ return err; -+ } -+ -+ priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, -+ "mlxreg_io", priv, priv->groups); -+ if (IS_ERR(priv->hwmon)) { -+ dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", -+ PTR_ERR(priv->hwmon)); -+ return PTR_ERR(priv->hwmon); -+ } -+ -+ dev_set_drvdata(&pdev->dev, priv); -+ -+ return 0; -+} -+ -+static struct platform_driver mlxreg_io_driver = { -+ .driver = { -+ .name = "mlxreg-io", -+ }, -+ .probe = mlxreg_io_probe, -+}; -+ -+module_platform_driver(mlxreg_io_driver); -+ -+MODULE_AUTHOR("Vadim Pasternak "); -+MODULE_DESCRIPTION("Mellanox regmap I/O access driver"); -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_ALIAS("platform:mlxreg-io"); -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index 49721c2..61cbe35 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -47,16 +47,31 @@ - /* LPC bus IO offsets */ - #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 - #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 -+#define MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF 0x00 -+#define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF 0x01 -+#define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF 0x1d - #define MLXPLAT_CPLD_LPC_REG_LED1_OFF 0x20 - #define MLXPLAT_CPLD_LPC_REG_LED2_OFF 0x21 - #define MLXPLAT_CPLD_LPC_REG_LED3_OFF 0x22 - #define MLXPLAT_CPLD_LPC_REG_LED4_OFF 0x23 - #define MLXPLAT_CPLD_LPC_REG_LED5_OFF 0x24 -+#define MLXPLAT_CPLD_LPC_REG_GP1_OFF 0x30 -+#define MLXPLAT_CPLD_LPC_REG_WP1_OFF 0x31 -+#define MLXPLAT_CPLD_LPC_REG_GP2_OFF 0x32 -+#define MLXPLAT_CPLD_LPC_REG_WP2_OFF 0x33 - #define MLXPLAT_CPLD_LPC_REG_AGGR_OFF 0x3a -+#define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF 0x3b - #define MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF 0x40 -+#define MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF 0x41 - #define MLXPLAT_CPLD_LPC_REG_PSU_OFF 0x58 -+#define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF 0x59 -+#define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF 0x5a - #define MLXPLAT_CPLD_LPC_REG_PWR_OFF 0x64 -+#define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF 0x65 -+#define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF 0x66 - #define MLXPLAT_CPLD_LPC_REG_FAN_OFF 0x88 -+#define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF 0x89 -+#define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF 0x8a - #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 - #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb - #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda -@@ -100,12 +115,14 @@ - * @pdev_mux - array of mux platform devices - * @pdev_hotplug - hotplug platform devices - * @pdev_led - led platform devices -+ * @pdev_io_regs - register access platform devices - */ - struct mlxplat_priv { - struct platform_device *pdev_i2c; - struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS]; - struct platform_device *pdev_hotplug; - struct platform_device *pdev_led; -+ struct platform_device *pdev_io_regs; - }; - - /* Regions for LPC I2C controller and LPC base register space */ -@@ -643,7 +660,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { - }, - }; - --static struct mlxreg_core_led_platform_data mlxplat_default_led_data = { -+static struct mlxreg_core_platform_data mlxplat_default_led_data = { - .data = mlxplat_mlxcpld_default_led_data, - .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_data), - }; -@@ -697,7 +714,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_led_data[] = { - }, - }; - --static struct mlxreg_core_led_platform_data mlxplat_msn21xx_led_data = { -+static struct mlxreg_core_platform_data mlxplat_msn21xx_led_data = { - .data = mlxplat_mlxcpld_msn21xx_led_data, - .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_led_data), - }; -@@ -786,11 +803,105 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_led_data[] = { - }, - }; - --static struct mlxreg_core_led_platform_data mlxplat_default_ng_led_data = { -+static struct mlxreg_core_platform_data mlxplat_default_ng_led_data = { - .data = mlxplat_mlxcpld_default_ng_led_data, - .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data), - }; - -+static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case MLXPLAT_CPLD_LPC_REG_LED1_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED2_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED3_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED4_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED5_OFF: -+ case MLXPLAT_CPLD_LPC_REG_GP1_OFF: -+ case MLXPLAT_CPLD_LPC_REG_WP1_OFF: -+ case MLXPLAT_CPLD_LPC_REG_GP2_OFF: -+ case MLXPLAT_CPLD_LPC_REG_WP2_OFF: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF: -+ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF: -+ return true; -+ } -+ return false; -+} -+ -+static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF: -+ case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF: -+ case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED1_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED2_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED3_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED4_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED5_OFF: -+ case MLXPLAT_CPLD_LPC_REG_GP1_OFF: -+ case MLXPLAT_CPLD_LPC_REG_WP1_OFF: -+ case MLXPLAT_CPLD_LPC_REG_GP2_OFF: -+ case MLXPLAT_CPLD_LPC_REG_WP2_OFF: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_OFF: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PSU_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PWR_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_FAN_OFF: -+ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF: -+ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF: -+ return true; -+ } -+ return false; -+} -+ -+static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF: -+ case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF: -+ case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED1_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED2_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED3_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED4_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED5_OFF: -+ case MLXPLAT_CPLD_LPC_REG_GP1_OFF: -+ case MLXPLAT_CPLD_LPC_REG_GP2_OFF: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_OFF: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PSU_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PWR_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF: -+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_FAN_OFF: -+ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF: -+ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF: -+ return true; -+ } -+ return false; -+} -+ -+static const struct reg_default mlxplat_mlxcpld_regmap_default[] = { -+ { MLXPLAT_CPLD_LPC_REG_WP1_OFF, 0x00 }, -+ { MLXPLAT_CPLD_LPC_REG_WP2_OFF, 0x00 }, -+}; -+ - static int - mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val) - { -@@ -809,6 +920,12 @@ const struct regmap_config mlxplat_mlxcpld_regmap_config = { - .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_default, -+ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_default), - .reg_read = mlxplat_mlxcpld_reg_read, - .reg_write = mlxplat_mlxcpld_reg_write, - }; -@@ -817,9 +934,38 @@ static struct resource mlxplat_mlxcpld_resources[] = { - [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"), - }; - --struct platform_device *mlxplat_dev; --struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; --struct mlxreg_core_led_platform_data *mlxplat_led; -+static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { -+ { "cpld1_version", MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF, 0x00, -+ GENMASK(7, 0), 0444 }, -+ { "cpld2_version", MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF, 0x00, -+ GENMASK(7, 0), 0444 }, -+ { "cause_long_pb", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -+ GENMASK(7, 0) & ~BIT(0), 0x00, 0444 }, -+ { "cause_short_pb", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -+ GENMASK(7, 0) & ~BIT(1), 0x00, 0444 }, -+ { "cause_pwr_aux", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -+ GENMASK(7, 0) & ~BIT(2), 0x00, 0444 }, -+ { "cause_pwr_fail", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -+ GENMASK(7, 0) & ~BIT(3), 0x00, 0444 }, -+ { "psu1_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(0), -+ 0x00, 0200 }, -+ { "psu2_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(1), -+ 0x00, 0200 }, -+ { "pwr_cycle", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(2), -+ 0x00, 0200 }, -+ { "select_iio", MLXPLAT_CPLD_LPC_REG_GP2_OFF, GENMASK(7, 0) & ~BIT(6), -+ 0x00, 0644 }, -+}; -+ -+static struct mlxreg_core_platform_data mlxplat_default_regs_io_data = { -+ .data = mlxplat_mlxcpld_default_regs_io_data, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_regs_io_data), -+}; -+ -+static struct platform_device *mlxplat_dev; -+static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; -+static struct mlxreg_core_platform_data *mlxplat_led; -+static struct mlxreg_core_platform_data *mlxplat_regs_io; - - static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) - { -@@ -832,6 +978,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) - } - mlxplat_hotplug = &mlxplat_mlxcpld_default_data; - mlxplat_led = &mlxplat_default_led_data; -+ mlxplat_regs_io = &mlxplat_default_regs_io_data; - - return 1; - }; -@@ -847,6 +994,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) - } - mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data; - mlxplat_led = &mlxplat_msn21xx_led_data; -+ mlxplat_regs_io = &mlxplat_default_regs_io_data; - - return 1; - }; -@@ -862,6 +1010,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) - } - mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data; - mlxplat_led = &mlxplat_default_led_data; -+ mlxplat_regs_io = &mlxplat_default_regs_io_data; - - return 1; - }; -@@ -877,6 +1026,7 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) - } - mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data; - mlxplat_led = &mlxplat_default_ng_led_data; -+ mlxplat_regs_io = &mlxplat_default_regs_io_data; - - return 1; - }; -@@ -892,6 +1042,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) - } - mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data; - mlxplat_led = &mlxplat_msn21xx_led_data; -+ mlxplat_regs_io = &mlxplat_default_regs_io_data; - - return 1; - }; -@@ -974,7 +1125,7 @@ static int __init mlxplat_init(void) - { - struct mlxplat_priv *priv; - void __iomem *base; -- int i, err = 0; -+ int i, j, err = 0; - - if (!dmi_check_system(mlxplat_dmi_table)) - return -ENODEV; -@@ -1023,6 +1174,15 @@ static int __init mlxplat_init(void) - if (IS_ERR(mlxplat_hotplug->regmap)) - goto fail_platform_mux_register; - -+ /* Set default registers. */ -+ for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) { -+ err = regmap_write(mlxplat_hotplug->regmap, -+ mlxplat_mlxcpld_regmap_default[j].reg, -+ mlxplat_mlxcpld_regmap_default[j].def); -+ if (err) -+ goto fail_platform_mux_register; -+ } -+ - priv->pdev_hotplug = platform_device_register_resndata( - &mlxplat_dev->dev, "mlxreg-hotplug", - PLATFORM_DEVID_NONE, -@@ -1044,8 +1204,26 @@ static int __init mlxplat_init(void) - goto fail_platform_hotplug_register; - } - -+ mlxplat_regs_io->regmap = mlxplat_hotplug->regmap; -+ priv->pdev_io_regs = platform_device_register_resndata( -+ &mlxplat_dev->dev, "mlxreg-io", -+ PLATFORM_DEVID_NONE, NULL, 0, -+ mlxplat_regs_io, sizeof(*mlxplat_regs_io)); -+ if (IS_ERR(priv->pdev_io_regs)) { -+ err = PTR_ERR(priv->pdev_io_regs); -+ goto fail_platform_led_register; -+ } -+ -+ /* Sync registers with hardware. */ -+ regcache_mark_dirty(mlxplat_hotplug->regmap); -+ err = regcache_sync(mlxplat_hotplug->regmap); -+ if (err) -+ goto fail_platform_led_register; -+ - return 0; - -+fail_platform_led_register: -+ platform_device_unregister(priv->pdev_led); - fail_platform_hotplug_register: - platform_device_unregister(priv->pdev_hotplug); - fail_platform_mux_register: -@@ -1064,6 +1242,7 @@ static void __exit mlxplat_exit(void) - struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); - int i; - -+ platform_device_unregister(priv->pdev_io_regs); - platform_device_unregister(priv->pdev_led); - platform_device_unregister(priv->pdev_hotplug); - -diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h -index dd471c5..c25623b 100644 ---- a/include/linux/platform_data/mlxreg.h -+++ b/include/linux/platform_data/mlxreg.h -@@ -61,6 +61,7 @@ struct mlxreg_hotplug_device { - * @label: attribute register offset; - * @reg: attribute register; - * @mask: attribute access mask; -+ * @mode: access mode; - * @bit: attribute effective bit; - * @np - pointer to node platform associated with attribute; - * @hpdev - hotplug device data; -@@ -72,6 +73,7 @@ struct mlxreg_core_data { - u32 reg; - u32 mask; - u32 bit; -+ umode_t mode; - struct device_node *np; - struct mlxreg_hotplug_device hpdev; - u8 health_cntr; -@@ -104,13 +106,13 @@ struct mlxreg_core_item { - }; - - /** -- * struct mlxreg_core_led_platform_data - led platform data: -+ * struct mlxreg_core_platform_data - platform data: - * - * @led_data: led private data; - * @regmap: register map of parent device; - * @counter: number of led instances; - */ --struct mlxreg_core_led_platform_data { -+struct mlxreg_core_platform_data { - struct mlxreg_core_data *data; - void *regmap; - int counter; --- -2.1.4 - diff --git a/patch/0010-config-mellanox-configuration.patch b/patch/0010-config-mellanox-configuration.patch deleted file mode 100644 index e61028056b0a..000000000000 --- a/patch/0010-config-mellanox-configuration.patch +++ /dev/null @@ -1,140 +0,0 @@ -From c951dd6c826de2dbcb1d239743448bb56753ef96 Mon Sep 17 00:00:00 2001 - -From: root - -Subject: [v4.9 backport 10/10] config: mellanox configuration - -It adds the next configuration flags, used by Mellanox systems: - -CONFIG_MLXSW_CORE=m -CONFIG_MLXSW_CORE_HWMON=y -CONFIG_MLXSW_CORE_THERMAL=y -CONFIG_MLXSW_CORE_QSFP=y -CONFIG_MLXSW_PCI=m -CONFIG_MLXSW_I2C=m -CONFIG_MLXSW_MINIMAL=m -CONFIG_I2C_MUX_REG=y -CONFIG_I2C_MUX_MLXCPLD=m -CONFIG_I2C_MLXCPLD=m -CONFIG_SENSORS_IIO_HWMON=y -CONFIG_PMBUS=y -CONFIG_SENSORS_PMBUS=y -CONFIG_SENSORS_LM25066=m -CONFIG_SENSORS_TPS53679=m -CONFIG_SENSORS_UCD9000=m -CONFIG_SENSORS_UCD9200=m -CONFIG_LEDS_MLXREG=m -CONFIG_MLX_PLATFORM=m -CONFIG_MELLANOX_PLATFORM=y -CONFIG_MLXREG_HOTPLUG=m -CONFIG_MLXREG_IO=m -CONFIG_MAX1363=y - -Signed-off-by: Vadim Pastrenak ---- - debian/build/build_amd64_none_amd64/.config | 39 ++++++++++++++++++++++++--- - 1 file changed, 34 insertions(+), 5 deletions(-) - -diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index 88a71ef..e927c8d 100644 ---- a/debian/build/build_amd64_none_amd64/.config -+++ b/debian/build/build_amd64_none_amd64/.config -@@ -2632,7 +2632,13 @@ CONFIG_MLX4_DEBUG=y - CONFIG_MLX5_CORE=m - CONFIG_MLX5_CORE_EN=y - CONFIG_MLX5_CORE_EN_DCB=y --# CONFIG_MLXSW_CORE is not set -+CONFIG_MLXSW_CORE=m -+CONFIG_MLXSW_CORE_HWMON=y -+CONFIG_MLXSW_CORE_THERMAL=y -+CONFIG_MLXSW_CORE_QSFP=y -+CONFIG_MLXSW_PCI=m -+CONFIG_MLXSW_I2C=m -+CONFIG_MLXSW_MINIMAL=m - CONFIG_NET_VENDOR_MICREL=y - # CONFIG_KS8842 is not set - # CONFIG_KS8851 is not set -@@ -3565,7 +3571,8 @@ CONFIG_I2C_MUX=m - # CONFIG_I2C_MUX_PCA9541 is not set - # CONFIG_I2C_MUX_PCA954x is not set - # CONFIG_I2C_MUX_PINCTRL is not set --# CONFIG_I2C_MUX_REG is not set -+CONFIG_I2C_MUX_REG=m -+CONFIG_I2C_MUX_MLXCPLD=m - CONFIG_I2C_HELPER_AUTO=y - CONFIG_I2C_SMBUS=m - CONFIG_I2C_ALGOBIT=m -@@ -3632,6 +3639,7 @@ CONFIG_I2C_VIPERBOARD=m - # - # Other I2C/SMBus bus drivers - # -+CONFIG_I2C_MLXCPLD=m - CONFIG_I2C_STUB=m - # CONFIG_I2C_SLAVE is not set - # CONFIG_I2C_DEBUG_CORE is not set -@@ -3879,7 +3887,7 @@ CONFIG_SENSORS_G760A=m - # CONFIG_SENSORS_HIH6130 is not set - CONFIG_SENSORS_IBMAEM=m - CONFIG_SENSORS_IBMPEX=m --# CONFIG_SENSORS_IIO_HWMON is not set -+CONFIG_SENSORS_IIO_HWMON=m - CONFIG_SENSORS_I5500=m - CONFIG_SENSORS_CORETEMP=m - CONFIG_SENSORS_IT87=m -@@ -3932,7 +3940,21 @@ CONFIG_SENSORS_NCT6775=m - # CONFIG_SENSORS_NCT7802 is not set - # CONFIG_SENSORS_NCT7904 is not set - CONFIG_SENSORS_PCF8591=m --# CONFIG_PMBUS is not set -+CONFIG_PMBUS=m -+CONFIG_SENSORS_PMBUS=m -+# CONFIG_SENSORS_ADM1275 is not set -+CONFIG_SENSORS_LM25066=m -+# CONFIG_SENSORS_LTC2978 is not set -+# CONFIG_SENSORS_LTC3815 is not set -+# CONFIG_SENSORS_MAX16064 is not set -+# CONFIG_SENSORS_MAX20751 is not set -+# CONFIG_SENSORS_MAX34440 is not set -+# CONFIG_SENSORS_MAX8688 is not set -+# CONFIG_SENSORS_TPS40422 is not set -+CONFIG_SENSORS_TPS53679=m -+CONFIG_SENSORS_UCD9000=m -+CONFIG_SENSORS_UCD9200=m -+# CONFIG_SENSORS_ZL6100 is not set - # CONFIG_SENSORS_SHT15 is not set - CONFIG_SENSORS_SHT21=m - # CONFIG_SENSORS_SHT3x is not set -@@ -5904,6 +5926,9 @@ CONFIG_LEDS_MENF21BMC=m - # - # CONFIG_LEDS_BLINKM is not set - # CONFIG_LEDS_MLXCPLD is not set -+CONFIG_LEDS_MLXREG=m -+# CONFIG_LEDS_USER is not set -+# CONFIG_LEDS_NIC78BX is not set - - # - # LED Triggers -@@ -6483,10 +6508,14 @@ CONFIG_PVPANIC=m - CONFIG_INTEL_PMC_IPC=m - CONFIG_SURFACE_PRO3_BUTTON=m - # CONFIG_INTEL_PUNIT_IPC is not set -+CONFIG_MLX_PLATFORM=m - CONFIG_CHROME_PLATFORMS=y - CONFIG_CHROMEOS_LAPTOP=m - CONFIG_CHROMEOS_PSTORE=m - CONFIG_CROS_KBD_LED_BACKLIGHT=m -+CONFIG_MELLANOX_PLATFORM=y -+CONFIG_MLXREG_HOTPLUG=m -+CONFIG_MLXREG_IO=m - CONFIG_CLKDEV_LOOKUP=y - CONFIG_HAVE_CLK_PREPARE=y - CONFIG_COMMON_CLK=y -@@ -6621,7 +6650,7 @@ CONFIG_MMA9553=m - # CONFIG_INA2XX_ADC is not set - # CONFIG_LTC2485 is not set - # CONFIG_MAX1027 is not set --# CONFIG_MAX1363 is not set -+CONFIG_MAX1363=m - # CONFIG_MCP320X is not set - # CONFIG_MCP3422 is not set - # CONFIG_NAU7802 is not set diff --git a/patch/0011-support-Broadcom-54616-Phy-for-Intel-igb-driver.patch b/patch/0011-support-Broadcom-54616-Phy-for-Intel-igb-driver.patch deleted file mode 100644 index 721065dc2c85..000000000000 --- a/patch/0011-support-Broadcom-54616-Phy-for-Intel-igb-driver.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 6d396497162d143ff7476bdcdffa29923ff7a49e Mon Sep 17 00:00:00 2001 -From: Guohan Lu -Date: Tue, 5 Dec 2017 13:41:45 +0000 -Subject: [PATCH] Support Broadcom 54616 Phy for Intel igb driver - ---- - drivers/net/ethernet/intel/igb/e1000_82575.c | 5 +++++ - drivers/net/ethernet/intel/igb/e1000_defines.h | 1 + - drivers/net/ethernet/intel/igb/e1000_hw.h | 1 + - 3 files changed, 7 insertions(+) - -diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c -index a61447f..394ecd8 100644 ---- a/drivers/net/ethernet/intel/igb/e1000_82575.c -+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c -@@ -328,6 +328,9 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw) - phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580; - phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88; - break; -+ case BCM54616_E_PHY_ID: -+ phy->type = e1000_phy_bcm54616; -+ break; - default: - ret_val = -E1000_ERR_PHY; - goto out; -@@ -1647,6 +1650,8 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) - case e1000_phy_82580: - ret_val = igb_copper_link_setup_82580(hw); - break; -+ case e1000_phy_bcm54616: -+ break; - default: - ret_val = -E1000_ERR_PHY; - break; -diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h -index 2688180..ce95b7e 100644 ---- a/drivers/net/ethernet/intel/igb/e1000_defines.h -+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h -@@ -867,6 +867,7 @@ - #define I210_I_PHY_ID 0x01410C00 - #define M88E1543_E_PHY_ID 0x01410EA0 - #define M88E1512_E_PHY_ID 0x01410DD0 -+#define BCM54616_E_PHY_ID 0x03625D10 - - /* M88E1000 Specific Registers */ - #define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ -diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h -index 2fb2213..644d8f5 100644 ---- a/drivers/net/ethernet/intel/igb/e1000_hw.h -+++ b/drivers/net/ethernet/intel/igb/e1000_hw.h -@@ -128,6 +128,7 @@ enum e1000_phy_type { - e1000_phy_ife, - e1000_phy_82580, - e1000_phy_i210, -+ e1000_phy_bcm54616, - }; - - enum e1000_bus_type { --- -2.7.4 - diff --git a/patch/0012-platform-mellanox-mlxreg-hotplug-driver-add-check-fo.patch b/patch/0012-platform-mellanox-mlxreg-hotplug-driver-add-check-fo.patch deleted file mode 100644 index ef29d13420d1..000000000000 --- a/patch/0012-platform-mellanox-mlxreg-hotplug-driver-add-check-fo.patch +++ /dev/null @@ -1,53 +0,0 @@ -From c794f8ffa6521c47bfbff813e7f713561d7da7bd Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Mon, 11 Dec 2017 19:02:19 +0000 -Subject: [v4.9 backport 09/29] platform/mellanox: mlxreg-hotplug driver add - check for low aggregation register mask - -It adds verification for low aggregation register mask offset. Only -non-zero offset is considered as valid. - -Signed-off-by: Vadim Pasternak ---- - drivers/platform/mellanox/mlxreg-hotplug.c | 18 +++++++++++------- - 1 file changed, 11 insertions(+), 7 deletions(-) - -diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c -index 94fdb6b..ba9241e 100644 ---- a/drivers/platform/mellanox/mlxreg-hotplug.c -+++ b/drivers/platform/mellanox/mlxreg-hotplug.c -@@ -550,10 +550,13 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) - goto access_error; - - /* Keep low aggregation initial status as zero and unmask events. */ -- ret = regmap_write(priv->regmap, pdata->cell_low + -- MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask_low); -- if (ret) -- goto access_error; -+ if (pdata->cell_low) { -+ ret = regmap_write(priv->regmap, pdata->cell_low + -+ MLXREG_HOTPLUG_AGGR_MASK_OFF, -+ pdata->mask_low); -+ if (ret) -+ goto access_error; -+ } - - /* Invoke work handler for initializing hot plug devices setting. */ - mlxreg_hotplug_work_handler(&priv->dwork_irq.work); -@@ -582,9 +585,10 @@ static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv) - disable_irq(priv->irq); - cancel_delayed_work_sync(&priv->dwork_irq); - -- /* Mask low aggregation event. */ -- regmap_write(priv->regmap, pdata->cell_low + -- MLXREG_HOTPLUG_AGGR_MASK_OFF, 0); -+ /* Mask low aggregation event, if defined. */ -+ if (pdata->cell_low) -+ regmap_write(priv->regmap, pdata->cell_low + -+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0); - - /* Mask aggregation event. */ - regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF, --- -2.1.4 - diff --git a/patch/0014-mlxsw-qsfp_sysfs-Support-CPLD-version-reading-based-.patch b/patch/0014-mlxsw-qsfp_sysfs-Support-CPLD-version-reading-based-.patch deleted file mode 100644 index f1bba43ef6eb..000000000000 --- a/patch/0014-mlxsw-qsfp_sysfs-Support-CPLD-version-reading-based-.patch +++ /dev/null @@ -1,123 +0,0 @@ -From 7b3d375e329256d70df1552c210f81867ea285bd Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Sun, 18 Feb 2018 11:08:22 +0000 -Subject: [backport 4.9 14/20] mlxsw: qsfp_sysfs: Support CPLD version reading - based on DMI system type - -Add system type detection through DMI table in order to distinct between -the systems supporting reading only one CPLD version and capable of reading -the versions of three CPLDs. - -Signed-off-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c | 42 +++++++++++++++++++++--- - 1 file changed, 37 insertions(+), 5 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -index 3bc6cf8..07cc7ea 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -@@ -33,6 +33,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -49,7 +50,8 @@ - #define MLXSW_QSFP_MAX_NUM 64 - #define MLXSW_QSFP_MIN_REQ_LEN 4 - #define MLXSW_QSFP_STATUS_VALID_TIME (120 * HZ) --#define MLXSW_QSFP_MAX_CPLD_NUM 1 -+#define MLXSW_QSFP_MAX_CPLD_NUM 3 -+#define MLXSW_QSFP_MIN_CPLD_NUM 1 - - static const u8 mlxsw_qsfp_page_number[] = { 0xa0, 0x00, 0x01, 0x02, 0x03 }; - static const u16 mlxsw_qsfp_page_shift[] = { 0x00, 0x80, 0x80, 0x80, 0x80 }; -@@ -85,6 +87,8 @@ struct mlxsw_qsfp { - struct device_attribute *cpld_dev_attrs; - }; - -+static int mlxsw_qsfp_cpld_num = MLXSW_QSFP_MIN_CPLD_NUM; -+ - static int - mlxsw_qsfp_query_module_eeprom(struct mlxsw_qsfp *mlxsw_qsfp, u8 index, - loff_t off, size_t count, int page, char *buf) -@@ -210,11 +214,11 @@ mlxsw_qsfp_cpld_show(struct device *dev, struct device_attribute *attr, - u32 version, i; - int err; - -- for (i = 0; i < MLXSW_QSFP_MAX_CPLD_NUM; i++) { -+ for (i = 0; i < mlxsw_qsfp_cpld_num; i++) { - if ((mlxsw_qsfp->cpld_dev_attrs + i) == attr) - break; - } -- if (i == MLXSW_QSFP_MAX_CPLD_NUM) -+ if (i == mlxsw_qsfp_cpld_num) - return -EINVAL; - - mlxsw_reg_msci_pack(msci_pl, i); -@@ -227,6 +231,32 @@ mlxsw_qsfp_cpld_show(struct device *dev, struct device_attribute *attr, - return sprintf(buf, "%u\n", version); - } - -+static int mlxsw_qsfp_dmi_set_cpld_num(const struct dmi_system_id *dmi) -+{ -+ mlxsw_qsfp_cpld_num = MLXSW_QSFP_MAX_CPLD_NUM; -+ -+ return 1; -+}; -+ -+static const struct dmi_system_id mlxsw_qsfp_dmi_table[] = { -+ { -+ .callback = mlxsw_qsfp_dmi_set_cpld_num, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"), -+ }, -+ }, -+ { -+ .callback = mlxsw_qsfp_dmi_set_cpld_num, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"), -+ }, -+ }, -+ { } -+}; -+MODULE_DEVICE_TABLE(dmi, mlxsw_qsfp_dmi_table); -+ - int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info, - struct mlxsw_qsfp **p_qsfp) -@@ -242,6 +272,8 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, - if (!strcmp(mlxsw_bus_info->device_kind, "i2c")) - return 0; - -+ dmi_check_system(mlxsw_qsfp_dmi_table); -+ - mlxsw_qsfp = devm_kzalloc(mlxsw_bus_info->dev, sizeof(*mlxsw_qsfp), - GFP_KERNEL); - if (!mlxsw_qsfp) -@@ -285,7 +317,7 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, - return -ENOMEM; - - mlxsw_qsfp->cpld_dev_attrs = devm_kzalloc(mlxsw_bus_info->dev, -- MLXSW_QSFP_MAX_CPLD_NUM * -+ mlxsw_qsfp_cpld_num * - sizeof(*mlxsw_qsfp->cpld_dev_attrs), - GFP_KERNEL); - if (!mlxsw_qsfp->cpld_dev_attrs) -@@ -323,7 +355,7 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, - } - - cpld_dev_attr = mlxsw_qsfp->cpld_dev_attrs; -- for (i = 0; i < MLXSW_QSFP_MAX_CPLD_NUM; i++, cpld_dev_attr++) { -+ for (i = 0; i < mlxsw_qsfp_cpld_num; i++, cpld_dev_attr++) { - cpld_dev_attr->show = mlxsw_qsfp_cpld_show; - cpld_dev_attr->attr.mode = 0444; - cpld_dev_attr->attr.name = devm_kasprintf(mlxsw_bus_info->dev, --- -2.1.4 - diff --git a/patch/0015-platform-x86-mlx-platform-Add-support-for-new-msn201.patch b/patch/0015-platform-x86-mlx-platform-Add-support-for-new-msn201.patch deleted file mode 100644 index b6119ab53caa..000000000000 --- a/patch/0015-platform-x86-mlx-platform-Add-support-for-new-msn201.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 1dff5178538466037b40edfb074ec2233b69b7d6 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Sun, 18 Feb 2018 11:44:19 +0000 -Subject: [backport 4.9 15/20] platform/x86: mlx-platform: Add support for new - msn201x system type - -Patch contains: -- Additional reset causes fields for mlxreg-io. -- Fix for devm_ioport_map return value: - devm_ioport_map() returns NULL on error but we accidentally check for - error pointers instead. -- Fix for fan5 and fan6 mask bits. - -Signed-off-by: Vadim Pasternak ---- - drivers/platform/x86/mlx-platform.c | 24 ++++++++++++++++++------ - 1 file changed, 18 insertions(+), 6 deletions(-) - -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index 61cbe35..33fece8 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -472,14 +472,14 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = { - { - .label = "fan5", - .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -- .mask = BIT(3), -+ .mask = BIT(4), - .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, - .hpdev.nr = 15, - }, - { - .label = "fan6", - .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -- .mask = BIT(3), -+ .mask = BIT(5), - .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, - .hpdev.nr = 16, - }, -@@ -943,10 +943,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { - GENMASK(7, 0) & ~BIT(0), 0x00, 0444 }, - { "cause_short_pb", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, - GENMASK(7, 0) & ~BIT(1), 0x00, 0444 }, -- { "cause_pwr_aux", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -+ { "cause_aux_pwr_or_refresh", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, - GENMASK(7, 0) & ~BIT(2), 0x00, 0444 }, -- { "cause_pwr_fail", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -+ { "cause_main_pwr_fail", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, - GENMASK(7, 0) & ~BIT(3), 0x00, 0444 }, -+ { "cause_sw_reset", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -+ GENMASK(7, 0) & ~BIT(4), 0x00, 0444 }, -+ { "cause_fw_reset", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -+ GENMASK(7, 0) & ~BIT(5), 0x00, 0444 }, -+ { "cause_hotswap_or_wd", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -+ GENMASK(7, 0) & ~BIT(6), 0x00, 0444 }, -+ { "cause_asic_thermal", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -+ GENMASK(7, 0) & ~BIT(7), 0x00, 0444 }, - { "psu1_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(0), - 0x00, 0200 }, - { "psu2_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(1), -@@ -1166,13 +1174,17 @@ static int __init mlxplat_init(void) - - base = devm_ioport_map(&mlxplat_dev->dev, - mlxplat_lpc_resources[1].start, 1); -- if (IS_ERR(base)) -+ if (!base) { -+ err = -ENOMEM; - goto fail_platform_mux_register; -+ } - - mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, - base, &mlxplat_mlxcpld_regmap_config); -- if (IS_ERR(mlxplat_hotplug->regmap)) -+ if (IS_ERR(mlxplat_hotplug->regmap)) { -+ err = PTR_ERR(mlxplat_hotplug->regmap); - goto fail_platform_mux_register; -+ } - - /* Set default registers. */ - for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) { --- -2.1.4 - diff --git a/patch/0016-platform-mellanox-mlxreg-hotplug-add-extra-run-cycle.patch b/patch/0016-platform-mellanox-mlxreg-hotplug-add-extra-run-cycle.patch deleted file mode 100644 index 0c995135d5be..000000000000 --- a/patch/0016-platform-mellanox-mlxreg-hotplug-add-extra-run-cycle.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 487a2e6ffeb26d3ed36d68a472d15dc7894d9df9 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Thu, 15 Mar 2018 14:01:03 +0000 -Subject: [backport 4.9 16/20] platform/mellanox: mlxreg-hotplug: add extra run - cycle for hotplug work queue - -It adds missed logic for signal acknowledge, by adding an extra run for -work queue in case no signal assertion is detected. This extra run will -allow to acknowlede the missed signal, which can happen for example in -case several units are remover or inserted at the same time. - -Fixes: 1f976f6978bf ("platform/x86: Move Mellanox platform hotplug driver to platform/mellanox") -Signed-off-by: Vadim Pasternak ---- - drivers/platform/mellanox/mlxreg-hotplug.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c -index ba9241e..57fe24d 100644 ---- a/drivers/platform/mellanox/mlxreg-hotplug.c -+++ b/drivers/platform/mellanox/mlxreg-hotplug.c -@@ -58,6 +58,7 @@ - #define MLXREG_HOTPLUG_PROP_STATUS "status" - - #define MLXREG_HOTPLUG_ATTRS_MAX 24 -+#define MLXREG_HOTPLUG_NOT_ASSERT 3 - - /** - * struct mlxreg_hotplug_priv_data - platform private data: -@@ -74,6 +75,7 @@ - * @cell: location of top aggregation interrupt register; - * @mask: top aggregation interrupt common mask; - * @aggr_cache: last value of aggregation register status; -+ * @not_asserted: number of entries in workqueue with no signal assertion; - */ - struct mlxreg_hotplug_priv_data { - int irq; -@@ -94,6 +96,7 @@ struct mlxreg_hotplug_priv_data { - u32 mask; - u32 aggr_cache; - bool after_probe; -+ u8 not_asserted; - }; - - #if defined(CONFIG_OF_DYNAMIC) -@@ -472,6 +475,13 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work) - aggr_asserted = priv->aggr_cache ^ regval; - priv->aggr_cache = regval; - -+ if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) { -+ priv->not_asserted = 0; -+ aggr_asserted = pdata->mask; -+ } -+ if (!aggr_asserted) -+ goto unmask_event; -+ - /* Handle topology and health configuration changes. */ - for (i = 0; i < pdata->counter; i++, item++) { - if (aggr_asserted & item->aggr_mask) { -@@ -503,6 +513,8 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work) - return; - } - -+unmask_event: -+ priv->not_asserted++; - /* Unmask aggregation event (no need acknowledge). */ - ret = regmap_write(priv->regmap, pdata->cell + - MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); --- -2.1.4 - diff --git a/patch/0017-platform-mellanox-add-new-OEM-system-types-to-mlx-pl.patch b/patch/0017-platform-mellanox-add-new-OEM-system-types-to-mlx-pl.patch deleted file mode 100644 index 4d284fc5923b..000000000000 --- a/patch/0017-platform-mellanox-add-new-OEM-system-types-to-mlx-pl.patch +++ /dev/null @@ -1,73 +0,0 @@ -From cfb83680ddb2c14dcb2dd5d855ec0c4d73bd89a3 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Thu, 15 Mar 2018 17:46:38 +0000 -Subject: [backport 4.9 17/20] platform: mellanox: add new OEM system types to - mlx-platform - -Patch adds new OEM systems, matched according to DMI_BOARD_NAME. -The supported OEM Ids are: VMOD0001, VMOD0002, VMOD0003, VMOD0004, -VMOD0005. - -Signed-off-by: Vadim Pasternak ---- - drivers/platform/x86/mlx-platform.c | 34 +++++++++++++++++++++++++++++++++- - 1 file changed, 33 insertions(+), 1 deletion(-) - -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index 33fece8..2a2d00c 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -1055,7 +1055,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) - return 1; - }; - --static struct dmi_system_id mlxplat_dmi_table[] __initdata = { -+static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { - { - .callback = mlxplat_dmi_msn274x_matched, - .matches = { -@@ -1126,9 +1126,41 @@ static struct dmi_system_id mlxplat_dmi_table[] __initdata = { - DMI_MATCH(DMI_PRODUCT_NAME, "SN34"), - }, - }, -+ { -+ .callback = mlxplat_dmi_default_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_msn21xx_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_msn274x_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_msn201x_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_qmb7xx_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), -+ }, -+ }, - { } - }; - -+MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table); -+ - static int __init mlxplat_init(void) - { - struct mlxplat_priv *priv; --- -2.1.4 - diff --git a/patch/0018-platform-x86-mlx-platform-fix-module-aliases.patch b/patch/0018-platform-x86-mlx-platform-fix-module-aliases.patch deleted file mode 100644 index 7edced19cff0..000000000000 --- a/patch/0018-platform-x86-mlx-platform-fix-module-aliases.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 1958bec50c3c98a2e964ada753de6020c1b461f6 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Thu, 15 Mar 2018 18:02:40 +0000 -Subject: [backport 4.9 18/20] platform/x86: mlx-platform: fix module aliases - -Missing prefix 'pn' in MODULE_ALIAS lines causes the module to -not load automatically. The driver should use MODULE_DEVICE_TABLE -together with existing mlxplat_dmi_table instead. - -commit 580d834fe166c695f37c942e9cd92d1743bdc5d4 -Author: Ivan Vecera -Fixes: 6613d18e9038 ("platform/x86: mlx-platform: Move module from arch/x86") - -Signed-off-by: Vadim Pasternak ---- - drivers/platform/x86/mlx-platform.c | 10 ---------- - 1 file changed, 10 deletions(-) - -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index 2a2d00c..9ad1fc9 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -1301,13 +1301,3 @@ module_exit(mlxplat_exit); - MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); - MODULE_DESCRIPTION("Mellanox platform driver"); - MODULE_LICENSE("Dual BSD/GPL"); --MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:"); --MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:"); --MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:"); --MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:"); --MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:"); --MODULE_ALIAS("dmi:*:*Mellanox*MSN274*:"); --MODULE_ALIAS("dmi:*:*Mellanox*MSN201*:"); --MODULE_ALIAS("dmi:*:*Mellanox*QMB7*:"); --MODULE_ALIAS("dmi:*:*Mellanox*SN37*:"); --MODULE_ALIAS("dmi:*:*Mellanox*QM34*:"); --- -2.1.4 - diff --git a/patch/0019-platform-x86-mlx-platform-Add-bus-detection-and-diff.patch b/patch/0019-platform-x86-mlx-platform-Add-bus-detection-and-diff.patch deleted file mode 100644 index 40e6f6c299d6..000000000000 --- a/patch/0019-platform-x86-mlx-platform-Add-bus-detection-and-diff.patch +++ /dev/null @@ -1,266 +0,0 @@ -From b428a16bb35bfe6ddf8260dc6462a82d44a28486 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Thu, 15 Mar 2018 18:10:02 +0000 -Subject: [backport 4.9 19/20] platform/x86: mlx-platform: Add bus detection - and differed bus functionality - -The patch contains two below commits for platform-next. - -platform/x86: mlx-platform: Add physical bus number auto detection - -Add physical bus number auto detection mechanism in order to avoid a -possible collision with I2C physical bus allocation. The mlx-platform -driver activates i2c-mlxcpld driver with no bus number specification. It -based on an assumption that on all Mellanox systems physical bus number is -supposed to be number one. On some X86 systems other I2C drivers, which -even are not used for Mellanox systems, could come up before i2c-mlxcpld, -for example i2c_i801, i2c_ismt, i2c-kempld. And in such case a pre-defined -I2C bus number one, could be busy. In order to avoid such situation, -with no having special kernel config file disabling unwanted modules or -with no putting anything to a blacklist, the logic for I2C available bus -number auto detection is added. To ensure it, mlx-platform driver verifies -which adapter number is free prior activation of i2c-mlxcpld driver. In -case numbered adapter one is busy, it shifts to the available number. This -shift is passed to i2c-mlxcpld driver, the mux base numbers are -incremented by the this shift value and passed to i2c-mux-reg driver, and -also this value is passed to mlxreg-hotplug driver. - -commit cffc7c0a124ee600b4f162685ce79256fb8a7ba9 for platform-next -Author: Vadim Pasternak - -platform/x86: mlx-platform: Add differed bus functionality - -Add deferred bus functionality in order to enforce probing flow execution -order. Driver mlx-platform activates platform driver i2c-mux-reg, which -creates busses infrastructure, after that it activates mlxreg-hotplug -driver, which uses these busses, for connecting devices. The possible -miss-ordering can happened, for example in case the probing routine of -mlxreg-hotplug is already started execution, while i2c-mux-reg probing -routine is not completed yet. In such situation the first one could -attempt to connect device to adapter number, which is not created yet. -And as a result this connection will fail. In order to ensure the order of -probing execution on mlxreg-hotplug probe routine will be deferred until -all the busses is not created by probe routine of i2c-mux-reg. -In order to ensure the flow order, mlx-platform driver passes the highest -bus number to the mlxreg-hotplug platform data, which in their turn could -wait in the deferred state, until all the necessary buses topology is not -exist. - -commit 7d5bd2e82ed4202cc8898b7513eb9474e3c1d874 -Author: Vadim Pasternak - -Signed-off-by: Vadim Pasternak ---- - drivers/platform/mellanox/mlxreg-hotplug.c | 9 +++- - drivers/platform/x86/mlx-platform.c | 71 ++++++++++++++++++++++++++++-- - include/linux/platform_data/mlxreg.h | 4 ++ - 3 files changed, 79 insertions(+), 5 deletions(-) - -diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c -index 57fe24d..5c13591 100644 ---- a/drivers/platform/mellanox/mlxreg-hotplug.c -+++ b/drivers/platform/mellanox/mlxreg-hotplug.c -@@ -444,7 +444,7 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, - * *---* - * - * In case some system changed are detected: FAN in/out, PSU in/out, power -- * cable attached/detached, ASIC helath good/bad, relevant device is created -+ * cable attached/detached, ASIC health good/bad, relevant device is created - * or destroyed. - */ - static void mlxreg_hotplug_work_handler(struct work_struct *work) -@@ -638,6 +638,7 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) - { - struct mlxreg_core_hotplug_platform_data *pdata; - struct mlxreg_hotplug_priv_data *priv; -+ struct i2c_adapter *deferred_adap; - int err; - - pdata = dev_get_platdata(&pdev->dev); -@@ -646,6 +647,12 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) - return -EINVAL; - } - -+ /* Defer probing if the necessary adapter is not configured yet. */ -+ deferred_adap = i2c_get_adapter(pdata->deferred_nr); -+ if (!deferred_adap) -+ return -EPROBE_DEFER; -+ i2c_put_adapter(deferred_adap); -+ - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index 9ad1fc9..e03f03f 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -99,6 +99,15 @@ - #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) - #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) - -+/* Default I2C parent bus number */ -+#define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1 -+ -+/* Maximum number of possible physical buses equipped on system */ -+#define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16 -+ -+/* Number of channels in group */ -+#define MLXPLAT_CPLD_GRP_CHNL_NUM 8 -+ - /* Start channel numbers */ - #define MLXPLAT_CPLD_CH1 2 - #define MLXPLAT_CPLD_CH2 10 -@@ -106,7 +115,8 @@ - /* Number of LPC attached MUX platform devices */ - #define MLXPLAT_CPLD_LPC_MUX_DEVS 2 - --/* PSU adapter numbers */ -+/* Hotplug devices adapter numbers */ -+#define MLXPLAT_CPLD_NR_NONE -1 - #define MLXPLAT_CPLD_PSU_DEFAULT_NR 10 - #define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4 - -@@ -137,7 +147,7 @@ static const struct resource mlxplat_lpc_resources[] = { - }; - - /* Platform default channels */ --static const int mlxplat_default_channels[][8] = { -+static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = { - { - MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2, - MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 + -@@ -985,6 +995,8 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) - ARRAY_SIZE(mlxplat_default_channels[i]); - } - mlxplat_hotplug = &mlxplat_mlxcpld_default_data; -+ mlxplat_hotplug->deferred_nr = -+ mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; - mlxplat_led = &mlxplat_default_led_data; - mlxplat_regs_io = &mlxplat_default_regs_io_data; - -@@ -1001,6 +1013,8 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) - ARRAY_SIZE(mlxplat_msn21xx_channels); - } - mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data; -+ mlxplat_hotplug->deferred_nr = -+ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; - mlxplat_led = &mlxplat_msn21xx_led_data; - mlxplat_regs_io = &mlxplat_default_regs_io_data; - -@@ -1017,6 +1031,8 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) - ARRAY_SIZE(mlxplat_msn21xx_channels); - } - mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data; -+ mlxplat_hotplug->deferred_nr = -+ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; - mlxplat_led = &mlxplat_default_led_data; - mlxplat_regs_io = &mlxplat_default_regs_io_data; - -@@ -1033,6 +1049,8 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) - ARRAY_SIZE(mlxplat_msn21xx_channels); - } - mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data; -+ mlxplat_hotplug->deferred_nr = -+ mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; - mlxplat_led = &mlxplat_default_ng_led_data; - mlxplat_regs_io = &mlxplat_default_regs_io_data; - -@@ -1049,6 +1067,8 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) - ARRAY_SIZE(mlxplat_msn21xx_channels); - } - mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data; -+ mlxplat_hotplug->deferred_nr = -+ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; - mlxplat_led = &mlxplat_msn21xx_led_data; - mlxplat_regs_io = &mlxplat_default_regs_io_data; - -@@ -1161,11 +1181,49 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { - - MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table); - -+static int mlxplat_mlxcpld_verify_bus_topology(int *nr) -+{ -+ struct i2c_adapter *search_adap; -+ int shift, i; -+ -+ /* Scan adapters from expected id to verify it is free. */ -+ *nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; -+ for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i < -+ MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) { -+ search_adap = i2c_get_adapter(i); -+ if (search_adap) { -+ i2c_put_adapter(search_adap); -+ continue; -+ } -+ -+ /* Return if expected parent adapter is free. */ -+ if (i == MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR) -+ return 0; -+ break; -+ } -+ -+ /* Return with error if free id for adapter is not found. */ -+ if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) -+ return -ENODEV; -+ -+ /* Shift adapter ids, since expected parent adapter is not free. */ -+ *nr = i; -+ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -+ shift = *nr - mlxplat_mux_data[i].parent; -+ mlxplat_mux_data[i].parent = *nr; -+ mlxplat_mux_data[i].base_nr += shift; -+ if (shift > 0) -+ mlxplat_hotplug->shift_nr = shift; -+ } -+ -+ return 0; -+} -+ - static int __init mlxplat_init(void) - { - struct mlxplat_priv *priv; - void __iomem *base; -- int i, j, err = 0; -+ int i, j, nr, err = 0; - - if (!dmi_check_system(mlxplat_dmi_table)) - return -ENODEV; -@@ -1185,7 +1243,12 @@ static int __init mlxplat_init(void) - } - platform_set_drvdata(mlxplat_dev, priv); - -- priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1, -+ err = mlxplat_mlxcpld_verify_bus_topology(&nr); -+ if (nr < 0) -+ goto fail_alloc; -+ -+ nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr; -+ priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr, - NULL, 0); - if (IS_ERR(priv->pdev_i2c)) { - err = PTR_ERR(priv->pdev_i2c); -diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h -index c25623b..b77c7a5 100644 ---- a/include/linux/platform_data/mlxreg.h -+++ b/include/linux/platform_data/mlxreg.h -@@ -129,6 +129,8 @@ struct mlxreg_core_platform_data { - * @mask: top aggregation interrupt common mask; - * @cell_low: location of low aggregation interrupt register; - * @mask_low: low aggregation interrupt common mask; -+ * @deferred_nr: I2C adapter number must be exist prior probing execution; -+ * @shift_nr: I2C adapter numbers must be incremented by this value; - */ - struct mlxreg_core_hotplug_platform_data { - struct mlxreg_core_item *items; -@@ -139,6 +141,8 @@ struct mlxreg_core_hotplug_platform_data { - u32 mask; - u32 cell_low; - u32 mask_low; -+ int deferred_nr; -+ int shift_nr; - }; - - #endif /* __LINUX_PLATFORM_DATA_MLXREG_H */ --- -2.1.4 - diff --git a/patch/0020-i2c-busses-Add-capabilities-to-i2c-mlxcpld.patch b/patch/0020-i2c-busses-Add-capabilities-to-i2c-mlxcpld.patch deleted file mode 100644 index 956542502d81..000000000000 --- a/patch/0020-i2c-busses-Add-capabilities-to-i2c-mlxcpld.patch +++ /dev/null @@ -1,199 +0,0 @@ -From 23c8535af1dd9dcaecb5aaf4097129bfb7e24570 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Thu, 15 Mar 2018 18:38:18 +0000 -Subject: [backport 4.9 20/20] i2c: busses: Add capabilities to i2c-mlxcpld - -It adds support for extended length of read and write transactions. -New CPLD logic allows double size of the read and write transactions -length. This feature is verified through capability register, which is -renamed from unclear LPF_REG to CPBLTY_REG. Two bits 5 and 6 of these -register are used for length capability detection, while only 01 -combination indicates support of extended transaction length. Others mean -lack of such support. - -It adds support for smbus block read transaction. CPLD smbus block read -bit of capability register is verified during driver initialization, and -driver data is updated if such capability is available. In case an upper -layer requests a read transaction of length one and expects that length -will be the first received byte, driver will notify CPLD about SMBus block -read transaction flavor, so CPLD will know to execute such kind of -transaction. - -It fixes report about supported functionality. -Functionality can be different up to CPLD capability. - -It allows mlxcpld driver to be connected to pre-defined adapter number -equal or greater than one, in order to avoid current limitation, assuming -usage of id number one only. - -Author: Michael Shych -Patches are sent to i2c-next. - -Signed-off-by: Vadim Pasternak ---- - drivers/i2c/busses/i2c-mlxcpld.c | 70 ++++++++++++++++++++++++++++++++++------ - 1 file changed, 60 insertions(+), 10 deletions(-) - -diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c -index d271e6a..745ed43 100644 ---- a/drivers/i2c/busses/i2c-mlxcpld.c -+++ b/drivers/i2c/busses/i2c-mlxcpld.c -@@ -45,13 +45,16 @@ - #define MLXCPLD_I2C_VALID_FLAG (I2C_M_RECV_LEN | I2C_M_RD) - #define MLXCPLD_I2C_BUS_NUM 1 - #define MLXCPLD_I2C_DATA_REG_SZ 36 -+#define MLXCPLD_I2C_DATA_SZ_BIT BIT(5) -+#define MLXCPLD_I2C_DATA_SZ_MASK GENMASK(6, 5) -+#define MLXCPLD_I2C_SMBUS_BLK_BIT BIT(7) - #define MLXCPLD_I2C_MAX_ADDR_LEN 4 - #define MLXCPLD_I2C_RETR_NUM 2 - #define MLXCPLD_I2C_XFER_TO 500000 /* usec */ - #define MLXCPLD_I2C_POLL_TIME 2000 /* usec */ - - /* LPC I2C registers */ --#define MLXCPLD_LPCI2C_LPF_REG 0x0 -+#define MLXCPLD_LPCI2C_CPBLTY_REG 0x0 - #define MLXCPLD_LPCI2C_CTRL_REG 0x1 - #define MLXCPLD_LPCI2C_HALF_CYC_REG 0x4 - #define MLXCPLD_LPCI2C_I2C_HOLD_REG 0x5 -@@ -83,6 +86,7 @@ struct mlxcpld_i2c_priv { - struct mutex lock; - struct mlxcpld_i2c_curr_xfer xfer; - struct device *dev; -+ bool smbus_block; - }; - - static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr) -@@ -230,7 +234,7 @@ static void mlxcpld_i2c_set_transf_data(struct mlxcpld_i2c_priv *priv, - * All upper layers currently are never use transfer with more than - * 2 messages. Actually, it's also not so relevant in Mellanox systems - * because of HW limitation. Max size of transfer is not more than 32 -- * bytes in the current x86 LPCI2C bridge. -+ * or 68 bytes in the current x86 LPCI2C bridge. - */ - priv->xfer.cmd = msgs[num - 1].flags & I2C_M_RD; - -@@ -295,7 +299,7 @@ static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv) - static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) - { - int status, i, timeout = 0; -- u8 datalen; -+ u8 datalen, val; - - do { - usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME); -@@ -324,9 +328,22 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) - * Actual read data len will be always the same as - * requested len. 0xff (line pull-up) will be returned - * if slave has no data to return. Thus don't read -- * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. -+ * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. Only in case of -+ * SMBus block read transaction data len can be different, -+ * check this case. - */ -- datalen = priv->xfer.data_len; -+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, -+ 1); -+ if (priv->smbus_block && (val & MLXCPLD_I2C_SMBUS_BLK_BIT)) { -+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG, -+ &datalen, 1); -+ if (unlikely(datalen > (I2C_SMBUS_BLOCK_MAX + 1))) { -+ dev_err(priv->dev, "Incorrect smbus block read message len\n"); -+ return -E2BIG; -+ } -+ } else { -+ datalen = priv->xfer.data_len; -+ } - - mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG, - priv->xfer.msg[i].buf, datalen); -@@ -344,12 +361,20 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) - static void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv) - { - int i, len = 0; -- u8 cmd; -+ u8 cmd, val; - - mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG, - &priv->xfer.data_len, 1); -- mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, -- &priv->xfer.addr_width, 1); -+ -+ val = priv->xfer.addr_width; -+ /* Notify HW about SMBus block read transaction */ -+ if (priv->smbus_block && priv->xfer.msg_num >= 2 && -+ priv->xfer.msg[1].len == 1 && -+ (priv->xfer.msg[1].flags & I2C_M_RECV_LEN) && -+ (priv->xfer.msg[1].flags & I2C_M_RD)) -+ val |= MLXCPLD_I2C_SMBUS_BLK_BIT; -+ -+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, 1); - - for (i = 0; i < priv->xfer.msg_num; i++) { - if ((priv->xfer.msg[i].flags & I2C_M_RD) != I2C_M_RD) { -@@ -425,7 +450,14 @@ static int mlxcpld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - - static u32 mlxcpld_i2c_func(struct i2c_adapter *adap) - { -- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; -+ struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap); -+ -+ if (priv->smbus_block) -+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | -+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_BLOCK_DATA; -+ else -+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | -+ I2C_FUNC_SMBUS_I2C_BLOCK; - } - - static const struct i2c_algorithm mlxcpld_i2c_algo = { -@@ -433,13 +465,20 @@ static const struct i2c_algorithm mlxcpld_i2c_algo = { - .functionality = mlxcpld_i2c_func - }; - --static struct i2c_adapter_quirks mlxcpld_i2c_quirks = { -+static const struct i2c_adapter_quirks mlxcpld_i2c_quirks = { - .flags = I2C_AQ_COMB_WRITE_THEN_READ, - .max_read_len = MLXCPLD_I2C_DATA_REG_SZ - MLXCPLD_I2C_MAX_ADDR_LEN, - .max_write_len = MLXCPLD_I2C_DATA_REG_SZ, - .max_comb_1st_msg_len = 4, - }; - -+static const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext = { -+ .flags = I2C_AQ_COMB_WRITE_THEN_READ, -+ .max_read_len = MLXCPLD_I2C_DATA_REG_SZ * 2 - MLXCPLD_I2C_MAX_ADDR_LEN, -+ .max_write_len = MLXCPLD_I2C_DATA_REG_SZ * 2, -+ .max_comb_1st_msg_len = 4, -+}; -+ - static struct i2c_adapter mlxcpld_i2c_adapter = { - .owner = THIS_MODULE, - .name = "i2c-mlxcpld", -@@ -454,6 +493,7 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) - { - struct mlxcpld_i2c_priv *priv; - int err; -+ u8 val; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) -@@ -466,6 +506,16 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) - - /* Register with i2c layer */ - mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO); -+ /* Read capability register */ -+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CPBLTY_REG, &val, 1); -+ /* Check support for extended transaction length */ -+ if ((val & MLXCPLD_I2C_DATA_SZ_MASK) == MLXCPLD_I2C_DATA_SZ_BIT) -+ mlxcpld_i2c_adapter.quirks = &mlxcpld_i2c_quirks_ext; -+ /* Check support for smbus block transaction */ -+ if (val & MLXCPLD_I2C_SMBUS_BLK_BIT) -+ priv->smbus_block = true; -+ if (pdev->id >= -1) -+ mlxcpld_i2c_adapter.nr = pdev->id; - priv->adap = mlxcpld_i2c_adapter; - priv->adap.dev.parent = &pdev->dev; - priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; --- -2.1.4 - diff --git a/patch/0021-Mellanox-backport-patchwork-from-kernels-4.17-4.19.patch b/patch/0021-Mellanox-backport-patchwork-from-kernels-4.17-4.19.patch deleted file mode 100644 index 5c0c5d91974a..000000000000 --- a/patch/0021-Mellanox-backport-patchwork-from-kernels-4.17-4.19.patch +++ /dev/null @@ -1,3063 +0,0 @@ -From 54f7d08c9337a82e79142fcdab2b6fa5bcf5843e Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Wed, 18 Jul 2018 16:27:08 +0000 -Subject: [patch bacport patchwork 1/1] Mellanox backport patchwork from - kerenls 4.17-4.19 - -Signed-off-by: Vadim Pasternak ---- - drivers/hwmon/Kconfig | 12 + - drivers/hwmon/Makefile | 1 + - drivers/hwmon/mlxreg-fan.c | 489 ++++++++++++ - drivers/platform/mellanox/Kconfig | 9 +- - drivers/platform/mellanox/Makefile | 7 +- - drivers/platform/mellanox/mlxreg-hotplug.c | 306 ++++---- - drivers/platform/mellanox/mlxreg-io.c | 118 +-- - drivers/platform/x86/mlx-platform.c | 1106 +++++++++++++++++++--------- - 8 files changed, 1482 insertions(+), 566 deletions(-) - create mode 100644 drivers/hwmon/mlxreg-fan.c - -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 45cef3d..9014151 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -907,6 +907,18 @@ config SENSORS_MCP3021 - This driver can also be built as a module. If so, the module - will be called mcp3021. - -+config SENSORS_MLXREG_FAN -+ tristate "Mellanox Mellanox FAN driver" -+ depends on MELLANOX_PLATFORM -+ select THERMAL -+ select REGMAP -+ help -+ This option enables support for the FAN control on the Mellanox -+ Ethernet and InfiniBand switches. The driver can be activated by the -+ platform device add call. Say Y to enable these. To compile this -+ driver as a module, choose 'M' here: the module will be called -+ mlxreg-fan. -+ - config SENSORS_MENF21BMC_HWMON - tristate "MEN 14F021P00 BMC Hardware Monitoring" - depends on MFD_MENF21BMC -diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index aecf4ba..4ff1b63 100644 ---- a/drivers/hwmon/Makefile -+++ b/drivers/hwmon/Makefile -@@ -122,6 +122,7 @@ obj-$(CONFIG_SENSORS_MAX6697) += max6697.o - obj-$(CONFIG_SENSORS_MAX31790) += max31790.o - obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o - obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o -+obj-$(CONFIG_SENSORS_MLXREG_FAN) += mlxreg-fan.o - obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o - obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o - obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o -diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c -new file mode 100644 -index 0000000..de46577 ---- /dev/null -+++ b/drivers/hwmon/mlxreg-fan.c -@@ -0,0 +1,489 @@ -+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -+// -+// Copyright (c) 2018 Mellanox Technologies. All rights reserved. -+// Copyright (c) 2018 Vadim Pasternak -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MLXREG_FAN_MAX_TACHO 12 -+#define MLXREG_FAN_MAX_STATE 10 -+#define MLXREG_FAN_MIN_DUTY 51 /* 20% */ -+#define MLXREG_FAN_MAX_DUTY 255 /* 100% */ -+/* -+ * Minimum and maximum FAN allowed speed in percent: from 20% to 100%. Values -+ * MLXREG_FAN_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 MLXREG_FAN_SPEED_MIN (MLXREG_FAN_MAX_STATE + 2) -+#define MLXREG_FAN_SPEED_MAX (MLXREG_FAN_MAX_STATE * 2) -+#define MLXREG_FAN_SPEED_MIN_LEVEL 2 /* 20 percent */ -+#define MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF 44 -+#define MLXREG_FAN_TACHO_DIVIDER_DEF 1132 -+/* -+ * FAN datasheet defines the formula for RPM calculations as RPM = 15/t-high. -+ * The logic in a programmable device measures the time t-high by sampling the -+ * tachometer every t-sample (with the default value 11.32 uS) and increment -+ * a counter (N) as long as the pulse has not change: -+ * RPM = 15 / (t-sample * (K + Regval)), where: -+ * Regval: is the value read from the programmable device register; -+ * - 0xff - represents tachometer fault; -+ * - 0xfe - represents tachometer minimum value , which is 4444 RPM; -+ * - 0x00 - represents tachometer maximum value , which is 300000 RPM; -+ * K: is 44 and it represents the minimum allowed samples per pulse; -+ * N: is equal K + Regval; -+ * In order to calculate RPM from the register value the following formula is -+ * used: RPM = 15 / ((Regval + K) * 11.32) * 10^(-6)), which in the -+ * default case is modified to: -+ * RPM = 15000000 * 100 / ((Regval + 44) * 1132); -+ * - for Regval 0x00, RPM will be 15000000 * 100 / (44 * 1132) = 30115; -+ * - for Regval 0xfe, RPM will be 15000000 * 100 / ((254 + 44) * 1132) = 4446; -+ * In common case the formula is modified to: -+ * RPM = 15000000 * 100 / ((Regval + samples) * divider). -+ */ -+#define MLXREG_FAN_GET_RPM(rval, d, s) (DIV_ROUND_CLOSEST(15000000 * 100, \ -+ ((rval) + (s)) * (d))) -+#define MLXREG_FAN_GET_FAULT(val, mask) (!!((val) ^ (mask))) -+#define MLXREG_FAN_PWM_DUTY2STATE(duty) (DIV_ROUND_CLOSEST((duty) * \ -+ MLXREG_FAN_MAX_STATE, \ -+ MLXREG_FAN_MAX_DUTY)) -+#define MLXREG_FAN_PWM_STATE2DUTY(stat) (DIV_ROUND_CLOSEST((stat) * \ -+ MLXREG_FAN_MAX_DUTY, \ -+ MLXREG_FAN_MAX_STATE)) -+ -+/* -+ * struct mlxreg_fan_tacho - tachometer data (internal use): -+ * -+ * @connected: indicates if tachometer is connected; -+ * @reg: register offset; -+ * @mask: fault mask; -+ */ -+struct mlxreg_fan_tacho { -+ bool connected; -+ u32 reg; -+ u32 mask; -+}; -+ -+/* -+ * struct mlxreg_fan_pwm - PWM data (internal use): -+ * -+ * @connected: indicates if PWM is connected; -+ * @reg: register offset; -+ */ -+struct mlxreg_fan_pwm { -+ bool connected; -+ u32 reg; -+}; -+ -+/* -+ * struct mlxreg_fan - private data (internal use): -+ * -+ * @dev: basic device; -+ * @regmap: register map of parent device; -+ * @tacho: tachometer data; -+ * @pwm: PWM data; -+ * @samples: minimum allowed samples per pulse; -+ * @divider: divider value for tachometer RPM calculation; -+ * @cooling: cooling device levels; -+ * @cdev: cooling device; -+ */ -+struct mlxreg_fan { -+ struct device *dev; -+ void *regmap; -+ struct mlxreg_core_platform_data *pdata; -+ struct mlxreg_fan_tacho tacho[MLXREG_FAN_MAX_TACHO]; -+ struct mlxreg_fan_pwm pwm; -+ int samples; -+ int divider; -+ u8 cooling_levels[MLXREG_FAN_MAX_STATE + 1]; -+ struct thermal_cooling_device *cdev; -+}; -+ -+static int -+mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, -+ int channel, long *val) -+{ -+ struct mlxreg_fan *fan = dev_get_drvdata(dev); -+ struct mlxreg_fan_tacho *tacho; -+ u32 regval; -+ int err; -+ -+ switch (type) { -+ case hwmon_fan: -+ tacho = &fan->tacho[channel]; -+ switch (attr) { -+ case hwmon_fan_input: -+ err = regmap_read(fan->regmap, tacho->reg, ®val); -+ if (err) -+ return err; -+ -+ *val = MLXREG_FAN_GET_RPM(regval, fan->divider, -+ fan->samples); -+ break; -+ -+ case hwmon_fan_fault: -+ err = regmap_read(fan->regmap, tacho->reg, ®val); -+ if (err) -+ return err; -+ -+ *val = MLXREG_FAN_GET_FAULT(regval, tacho->mask); -+ break; -+ -+ default: -+ return -EOPNOTSUPP; -+ } -+ break; -+ -+ case hwmon_pwm: -+ switch (attr) { -+ case hwmon_pwm_input: -+ err = regmap_read(fan->regmap, fan->pwm.reg, ®val); -+ if (err) -+ return err; -+ -+ *val = regval; -+ break; -+ -+ default: -+ return -EOPNOTSUPP; -+ } -+ break; -+ -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ return 0; -+} -+ -+static int -+mlxreg_fan_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, -+ int channel, long val) -+{ -+ struct mlxreg_fan *fan = dev_get_drvdata(dev); -+ -+ switch (type) { -+ case hwmon_pwm: -+ switch (attr) { -+ case hwmon_pwm_input: -+ if (val < MLXREG_FAN_MIN_DUTY || -+ val > MLXREG_FAN_MAX_DUTY) -+ return -EINVAL; -+ return regmap_write(fan->regmap, fan->pwm.reg, val); -+ default: -+ return -EOPNOTSUPP; -+ } -+ break; -+ -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ return -EOPNOTSUPP; -+} -+ -+static umode_t -+mlxreg_fan_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, -+ int channel) -+{ -+ switch (type) { -+ case hwmon_fan: -+ if (!(((struct mlxreg_fan *)data)->tacho[channel].connected)) -+ return 0; -+ -+ switch (attr) { -+ case hwmon_fan_input: -+ case hwmon_fan_fault: -+ return 0444; -+ default: -+ break; -+ } -+ break; -+ -+ case hwmon_pwm: -+ if (!(((struct mlxreg_fan *)data)->pwm.connected)) -+ return 0; -+ -+ switch (attr) { -+ case hwmon_pwm_input: -+ return 0644; -+ default: -+ break; -+ } -+ break; -+ -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+static const u32 mlxreg_fan_hwmon_fan_config[] = { -+ 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_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, -+ 0 -+}; -+ -+static const struct hwmon_channel_info mlxreg_fan_hwmon_fan = { -+ .type = hwmon_fan, -+ .config = mlxreg_fan_hwmon_fan_config, -+}; -+ -+static const u32 mlxreg_fan_hwmon_pwm_config[] = { -+ HWMON_PWM_INPUT, -+ 0 -+}; -+ -+static const struct hwmon_channel_info mlxreg_fan_hwmon_pwm = { -+ .type = hwmon_pwm, -+ .config = mlxreg_fan_hwmon_pwm_config, -+}; -+ -+static const struct hwmon_channel_info *mlxreg_fan_hwmon_info[] = { -+ &mlxreg_fan_hwmon_fan, -+ &mlxreg_fan_hwmon_pwm, -+ NULL -+}; -+ -+static const struct hwmon_ops mlxreg_fan_hwmon_hwmon_ops = { -+ .is_visible = mlxreg_fan_is_visible, -+ .read = mlxreg_fan_read, -+ .write = mlxreg_fan_write, -+}; -+ -+static const struct hwmon_chip_info mlxreg_fan_hwmon_chip_info = { -+ .ops = &mlxreg_fan_hwmon_hwmon_ops, -+ .info = mlxreg_fan_hwmon_info, -+}; -+ -+static int mlxreg_fan_get_max_state(struct thermal_cooling_device *cdev, -+ unsigned long *state) -+{ -+ *state = MLXREG_FAN_MAX_STATE; -+ return 0; -+} -+ -+static int mlxreg_fan_get_cur_state(struct thermal_cooling_device *cdev, -+ unsigned long *state) -+ -+{ -+ struct mlxreg_fan *fan = cdev->devdata; -+ u32 regval; -+ int err; -+ -+ err = regmap_read(fan->regmap, fan->pwm.reg, ®val); -+ if (err) { -+ dev_err(fan->dev, "Failed to query PWM duty\n"); -+ return err; -+ } -+ -+ *state = MLXREG_FAN_PWM_DUTY2STATE(regval); -+ -+ return 0; -+} -+ -+static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev, -+ unsigned long state) -+ -+{ -+ struct mlxreg_fan *fan = cdev->devdata; -+ unsigned long cur_state; -+ u32 regval; -+ int i; -+ int err; -+ -+ /* -+ * 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, fan->cooling_levels[0 to 5] will be changed all -+ * from 4 to 6. And state 5 (fan->cooling_levels[4]) should be -+ * overwritten. -+ */ -+ if (state >= MLXREG_FAN_SPEED_MIN && state <= MLXREG_FAN_SPEED_MAX) { -+ state -= MLXREG_FAN_MAX_STATE; -+ for (i = 0; i < state; i++) -+ fan->cooling_levels[i] = state; -+ for (i = state; i <= MLXREG_FAN_MAX_STATE; i++) -+ fan->cooling_levels[i] = i; -+ -+ err = regmap_read(fan->regmap, fan->pwm.reg, ®val); -+ if (err) { -+ dev_err(fan->dev, "Failed to query PWM duty\n"); -+ return err; -+ } -+ -+ cur_state = MLXREG_FAN_PWM_DUTY2STATE(regval); -+ if (state < cur_state) -+ return 0; -+ -+ state = cur_state; -+ } -+ -+ if (state > MLXREG_FAN_MAX_STATE) -+ return -EINVAL; -+ -+ /* Normalize the state to the valid speed range. */ -+ state = fan->cooling_levels[state]; -+ err = regmap_write(fan->regmap, fan->pwm.reg, -+ MLXREG_FAN_PWM_STATE2DUTY(state)); -+ if (err) { -+ dev_err(fan->dev, "Failed to write PWM duty\n"); -+ return err; -+ } -+ return 0; -+} -+ -+static const struct thermal_cooling_device_ops mlxreg_fan_cooling_ops = { -+ .get_max_state = mlxreg_fan_get_max_state, -+ .get_cur_state = mlxreg_fan_get_cur_state, -+ .set_cur_state = mlxreg_fan_set_cur_state, -+}; -+ -+static int mlxreg_fan_config(struct mlxreg_fan *fan, -+ struct mlxreg_core_platform_data *pdata) -+{ -+ struct mlxreg_core_data *data = pdata->data; -+ bool configured = false; -+ int tacho_num = 0, i; -+ -+ fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF; -+ fan->divider = MLXREG_FAN_TACHO_DIVIDER_DEF; -+ for (i = 0; i < pdata->counter; i++, data++) { -+ if (strnstr(data->label, "tacho", sizeof(data->label))) { -+ if (tacho_num == MLXREG_FAN_MAX_TACHO) { -+ dev_err(fan->dev, "too many tacho entries: %s\n", -+ data->label); -+ return -EINVAL; -+ } -+ fan->tacho[tacho_num].reg = data->reg; -+ fan->tacho[tacho_num].mask = data->mask; -+ fan->tacho[tacho_num++].connected = true; -+ } else if (strnstr(data->label, "pwm", sizeof(data->label))) { -+ if (fan->pwm.connected) { -+ dev_err(fan->dev, "duplicate pwm entry: %s\n", -+ data->label); -+ return -EINVAL; -+ } -+ fan->pwm.reg = data->reg; -+ fan->pwm.connected = true; -+ } else if (strnstr(data->label, "conf", sizeof(data->label))) { -+ if (configured) { -+ dev_err(fan->dev, "duplicate conf entry: %s\n", -+ data->label); -+ return -EINVAL; -+ } -+ /* Validate that conf parameters are not zeros. */ -+ if (!data->mask || !data->bit) { -+ dev_err(fan->dev, "invalid conf entry params: %s\n", -+ data->label); -+ return -EINVAL; -+ } -+ fan->samples = data->mask; -+ fan->divider = data->bit; -+ configured = true; -+ } else { -+ dev_err(fan->dev, "invalid label: %s\n", data->label); -+ return -EINVAL; -+ } -+ } -+ -+ /* Init cooling levels per PWM state. */ -+ for (i = 0; i < MLXREG_FAN_SPEED_MIN_LEVEL; i++) -+ fan->cooling_levels[i] = MLXREG_FAN_SPEED_MIN_LEVEL; -+ for (i = MLXREG_FAN_SPEED_MIN_LEVEL; i <= MLXREG_FAN_MAX_STATE; i++) -+ fan->cooling_levels[i] = i; -+ -+ return 0; -+} -+ -+static int mlxreg_fan_probe(struct platform_device *pdev) -+{ -+ struct mlxreg_core_platform_data *pdata; -+ struct mlxreg_fan *fan; -+ struct device *hwm; -+ int err; -+ -+ pdata = dev_get_platdata(&pdev->dev); -+ if (!pdata) { -+ dev_err(&pdev->dev, "Failed to get platform data.\n"); -+ return -EINVAL; -+ } -+ -+ fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL); -+ if (!fan) -+ return -ENOMEM; -+ -+ fan->dev = &pdev->dev; -+ fan->regmap = pdata->regmap; -+ platform_set_drvdata(pdev, fan); -+ -+ err = mlxreg_fan_config(fan, pdata); -+ if (err) -+ return err; -+ -+ hwm = devm_hwmon_device_register_with_info(&pdev->dev, "mlxreg_fan", -+ fan, -+ &mlxreg_fan_hwmon_chip_info, -+ NULL); -+ if (IS_ERR(hwm)) { -+ dev_err(&pdev->dev, "Failed to register hwmon device\n"); -+ return PTR_ERR(hwm); -+ } -+ -+ if (IS_REACHABLE(CONFIG_THERMAL)) { -+ fan->cdev = thermal_cooling_device_register("mlxreg_fan", fan, -+ &mlxreg_fan_cooling_ops); -+ if (IS_ERR(fan->cdev)) { -+ dev_err(&pdev->dev, "Failed to register cooling device\n"); -+ return PTR_ERR(fan->cdev); -+ } -+ } -+ -+ return 0; -+} -+ -+static int mlxreg_fan_remove(struct platform_device *pdev) -+{ -+ struct mlxreg_fan *fan = platform_get_drvdata(pdev); -+ -+ if (IS_REACHABLE(CONFIG_THERMAL)) -+ thermal_cooling_device_unregister(fan->cdev); -+ -+ return 0; -+} -+ -+static struct platform_driver mlxreg_fan_driver = { -+ .driver = { -+ .name = "mlxreg-fan", -+ }, -+ .probe = mlxreg_fan_probe, -+ .remove = mlxreg_fan_remove, -+}; -+ -+module_platform_driver(mlxreg_fan_driver); -+ -+MODULE_AUTHOR("Vadim Pasternak "); -+MODULE_DESCRIPTION("Mellanox FAN driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:mlxreg-fan"); -diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig -index 5c6dc29..cd8a908 100644 ---- a/drivers/platform/mellanox/Kconfig -+++ b/drivers/platform/mellanox/Kconfig -@@ -1,3 +1,4 @@ -+# SPDX-License-Identifier: GPL-2.0 - # - # Platform support for Mellanox hardware - # -@@ -23,13 +24,13 @@ config MLXREG_HOTPLUG - cables and fans on the wide range Mellanox IB and Ethernet systems. - - config MLXREG_IO -- tristate "Mellanox platform register driver support" -+ tristate "Mellanox platform register access driver support" - depends on REGMAP - depends on HWMON -- ---help--- -+ help - This driver allows access to Mellanox programmable device register -- space trough sysfs interface. The set of registers for sysfs access -- are defined per system type bases and includes the registers related -+ space through sysfs interface. The sets of registers for sysfs access -+ are defined per system type bases and include the registers related - to system resets operation, system reset causes monitoring and some - kinds of mux selection. - -diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile -index b9a2692..57074d9c 100644 ---- a/drivers/platform/mellanox/Makefile -+++ b/drivers/platform/mellanox/Makefile -@@ -1,2 +1,7 @@ -+# SPDX-License-Identifier: GPL-2.0 -+# -+# Makefile for linux/drivers/platform/mellanox -+# Mellanox Platform-Specific Drivers -+# - obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o --obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o -+obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o -diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c -index 5c13591..4761211 100644 ---- a/drivers/platform/mellanox/mlxreg-hotplug.c -+++ b/drivers/platform/mellanox/mlxreg-hotplug.c -@@ -1,6 +1,6 @@ - /* -- * Copyright (c) 2017 Mellanox Technologies. All rights reserved. -- * Copyright (c) 2017 Vadim Pasternak -+ * Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved. -+ * Copyright (c) 2016-2018 Vadim Pasternak - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: -@@ -41,6 +41,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -50,12 +51,9 @@ - #define MLXREG_HOTPLUG_AGGR_MASK_OFF 1 - - /* ASIC health parameters. */ -+#define MLXREG_HOTPLUG_DOWN_MASK 0x00 - #define MLXREG_HOTPLUG_HEALTH_MASK 0x02 --#define MLXREG_HOTPLUG_RST_CNTR 3 -- --#define MLXREG_HOTPLUG_PROP_OKAY "okay" --#define MLXREG_HOTPLUG_PROP_DISABLED "disabled" --#define MLXREG_HOTPLUG_PROP_STATUS "status" -+#define MLXREG_HOTPLUG_RST_CNTR 2 - - #define MLXREG_HOTPLUG_ATTRS_MAX 24 - #define MLXREG_HOTPLUG_NOT_ASSERT 3 -@@ -63,11 +61,14 @@ - /** - * struct mlxreg_hotplug_priv_data - platform private data: - * @irq: platform device interrupt number; -+ * @dev: basic device; - * @pdev: platform device; - * @plat: platform data; -- * @dwork: delayed work template; -+ * @regmap: register map handle; -+ * @dwork_irq: delayed work template; - * @lock: spin lock; - * @hwmon: hwmon device; -+ * @kobj: hwmon kobject for notification; - * @mlxreg_hotplug_attr: sysfs attributes array; - * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array; - * @group: sysfs attribute group; -@@ -75,6 +76,7 @@ - * @cell: location of top aggregation interrupt register; - * @mask: top aggregation interrupt common mask; - * @aggr_cache: last value of aggregation register status; -+ * @after_probe: flag indication probing completion; - * @not_asserted: number of entries in workqueue with no signal assertion; - */ - struct mlxreg_hotplug_priv_data { -@@ -84,9 +86,9 @@ struct mlxreg_hotplug_priv_data { - struct mlxreg_hotplug_platform_data *plat; - struct regmap *regmap; - struct delayed_work dwork_irq; -- struct delayed_work dwork; - spinlock_t lock; /* sync with interrupt */ - struct device *hwmon; -+ struct kobject *kobj; - struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1]; - struct sensor_device_attribute_2 - mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX]; -@@ -99,70 +101,37 @@ struct mlxreg_hotplug_priv_data { - u8 not_asserted; - }; - --#if defined(CONFIG_OF_DYNAMIC) --/** -- * struct mlxreg_hotplug_device_en - Open Firmware property for enabling device -- * -- * @name - property name; -- * @value - property value string; -- * @length - length of proprty value string; -- * -- * The structure is used for the devices, which require some dynamic -- * selection operation allowing access to them. -- */ --static struct property mlxreg_hotplug_device_en = { -- .name = MLXREG_HOTPLUG_PROP_STATUS, -- .value = MLXREG_HOTPLUG_PROP_OKAY, -- .length = sizeof(MLXREG_HOTPLUG_PROP_OKAY), --}; -- --/** -- * struct mlxreg_hotplug_device_dis - Open Firmware property for disabling -- * device -- * -- * @name - property name; -- * @value - property value string; -- * @length - length of proprty value string; -- * -- * The structure is used for the devices, which require some dynamic -- * selection operation disallowing access to them. -- */ --static struct property mlxreg_hotplug_device_dis = { -- .name = MLXREG_HOTPLUG_PROP_STATUS, -- .value = MLXREG_HOTPLUG_PROP_DISABLED, -- .length = sizeof(MLXREG_HOTPLUG_PROP_DISABLED), --}; -- --static int mlxreg_hotplug_of_device_create(struct mlxreg_core_data *data) -+static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, -+ struct mlxreg_core_data *data) - { -- return of_update_property(data->np, &mlxreg_hotplug_device_en); --} -+ struct mlxreg_core_hotplug_platform_data *pdata; - --static void mlxreg_hotplug_of_device_destroy(struct mlxreg_core_data *data) --{ -- of_update_property(data->np, &mlxreg_hotplug_device_dis); -- of_node_clear_flag(data->np, OF_POPULATED); --} --#else --static int mlxreg_hotplug_of_device_create(struct mlxreg_core_data *data) --{ -- return 0; --} -+ /* Notify user by sending hwmon uevent. */ -+ kobject_uevent(priv->kobj, KOBJ_CHANGE); - --static void mlxreg_hotplug_of_device_destroy(struct mlxreg_core_data *data) --{ --} --#endif -+ /* -+ * Return if adapter number is negative. It could be in case hotplug -+ * event is not associated with hotplug device. -+ */ -+ if (data->hpdev.nr < 0) -+ return 0; - --static int mlxreg_hotplug_device_create(struct mlxreg_core_data *data) --{ -- data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr); -- if (!data->hpdev.adapter) -+ pdata = dev_get_platdata(&priv->pdev->dev); -+ data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr + -+ pdata->shift_nr); -+ if (!data->hpdev.adapter) { -+ dev_err(priv->dev, "Failed to get adapter for bus %d\n", -+ data->hpdev.nr + pdata->shift_nr); - return -EFAULT; -+ } - - data->hpdev.client = i2c_new_device(data->hpdev.adapter, - data->hpdev.brdinfo); - if (!data->hpdev.client) { -+ dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", -+ data->hpdev.brdinfo->type, data->hpdev.nr + -+ pdata->shift_nr, data->hpdev.brdinfo->addr); -+ - i2c_put_adapter(data->hpdev.adapter); - data->hpdev.adapter = NULL; - return -EFAULT; -@@ -171,8 +140,13 @@ static int mlxreg_hotplug_device_create(struct mlxreg_core_data *data) - return 0; - } - --static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data) -+static void -+mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv, -+ struct mlxreg_core_data *data) - { -+ /* Notify user by sending hwmon uevent. */ -+ kobject_uevent(priv->kobj, KOBJ_CHANGE); -+ - if (data->hpdev.client) { - i2c_unregister_device(data->hpdev.client); - data->hpdev.client = NULL; -@@ -184,28 +158,6 @@ static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data) - } - } - --static int mlxreg_hotplug_dev_enable(struct mlxreg_core_data *data) --{ -- int err; -- -- /* Enable and create device. */ -- if (data->np) -- err = mlxreg_hotplug_of_device_create(data); -- else -- err = mlxreg_hotplug_device_create(data); -- -- return err; --} -- --static void mlxreg_hotplug_dev_disable(struct mlxreg_core_data *data) --{ -- /* Disable and unregister platform device. */ -- if (data->np) -- mlxreg_hotplug_of_device_destroy(data); -- else -- mlxreg_hotplug_device_destroy(data); --} -- - static ssize_t mlxreg_hotplug_attr_show(struct device *dev, - struct device_attribute *attr, - char *buf) -@@ -281,7 +233,8 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) - } - } - -- priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs * -+ priv->group.attrs = devm_kcalloc(&priv->pdev->dev, -+ num_attrs, - sizeof(struct attribute *), - GFP_KERNEL); - if (!priv->group.attrs) -@@ -320,12 +273,12 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, - ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, - 0); - if (ret) -- goto access_error; -+ goto out; - - /* Read status. */ - ret = regmap_read(priv->regmap, item->reg, ®val); - if (ret) -- goto access_error; -+ goto out; - - /* Set asserted bits and save last status. */ - regval &= item->mask; -@@ -336,14 +289,14 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, - data = item->data + bit; - if (regval & BIT(bit)) { - if (item->inversed) -- mlxreg_hotplug_dev_disable(data); -+ mlxreg_hotplug_device_destroy(priv, data); - else -- mlxreg_hotplug_dev_enable(data); -+ mlxreg_hotplug_device_create(priv, data); - } else { - if (item->inversed) -- mlxreg_hotplug_dev_enable(data); -+ mlxreg_hotplug_device_create(priv, data); - else -- mlxreg_hotplug_dev_disable(data); -+ mlxreg_hotplug_device_destroy(priv, data); - } - } - -@@ -351,18 +304,15 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, - ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF, - 0); - if (ret) -- goto access_error; -+ goto out; - - /* Unmask event. */ - ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, - item->mask); -- if (ret) -- goto access_error; - -- return; -- --access_error: -- dev_err(priv->dev, "Failed to complete workqueue.\n"); -+ out: -+ if (ret) -+ dev_err(priv->dev, "Failed to complete workqueue.\n"); - } - - static void -@@ -371,53 +321,83 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, - { - struct mlxreg_core_data *data = item->data; - u32 regval; -- int i, ret; -+ int i, ret = 0; - - for (i = 0; i < item->count; i++, data++) { - /* Mask event. */ - ret = regmap_write(priv->regmap, data->reg + - MLXREG_HOTPLUG_MASK_OFF, 0); - if (ret) -- goto access_error; -+ goto out; - - /* Read status. */ - ret = regmap_read(priv->regmap, data->reg, ®val); - if (ret) -- goto access_error; -+ goto out; - - regval &= data->mask; -- item->cache = regval; -+ /* -+ * ASIC health indication is provided through two bits. Bits -+ * value 0x2 indicates that ASIC reached the good health, value -+ * 0x0 indicates ASIC the bad health or dormant state and value -+ * 0x2 indicates the booting state. During ASIC reset it should -+ * pass the following states: dormant -> booting -> good. -+ * The transition from dormant to booting state and from -+ * booting to good state are indicated by ASIC twice, so actual -+ * sequence for getting to the steady state after reset is: -+ * dormant -> booting -> booting -> good -> good. It is -+ * possible that due to some hardware noise, the transition -+ * sequence will look like: dormant -> booting -> [ booting -> -+ * good -> dormant -> booting ] -> good -> good. -+ */ - if (regval == MLXREG_HOTPLUG_HEALTH_MASK) { -- if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) || -+ if ((++data->health_cntr == MLXREG_HOTPLUG_RST_CNTR) || - !priv->after_probe) { -- mlxreg_hotplug_dev_enable(data); -+ /* -+ * ASIC is in steady state. Connect associated -+ * device, if configured. -+ */ -+ mlxreg_hotplug_device_create(priv, data); - data->attached = true; - } - } else { - if (data->attached) { -- mlxreg_hotplug_dev_disable(data); -+ /* -+ * ASIC health is dropped after ASIC has been -+ * in steady state. Disconnect associated -+ * device, if it has been connected. -+ */ -+ mlxreg_hotplug_device_destroy(priv, data); - data->attached = false; - data->health_cntr = 0; -+ } else if (regval == MLXREG_HOTPLUG_DOWN_MASK && -+ item->cache == MLXREG_HOTPLUG_HEALTH_MASK) { -+ /* -+ * Decrease counter, if health has been dropped -+ * before ASIC reaches the steady state, like: -+ * good -> dormant -> booting. -+ */ -+ data->health_cntr--; - } - } -+ item->cache = regval; - - /* Acknowledge event. */ - ret = regmap_write(priv->regmap, data->reg + - MLXREG_HOTPLUG_EVENT_OFF, 0); - if (ret) -- goto access_error; -+ goto out; - - /* Unmask event. */ - ret = regmap_write(priv->regmap, data->reg + - MLXREG_HOTPLUG_MASK_OFF, data->mask); - if (ret) -- goto access_error; -+ goto out; - } - -- return; -- --access_error: -- dev_err(priv->dev, "Failed to complete workqueue.\n"); -+ out: -+ if (ret) -+ dev_err(priv->dev, "Failed to complete workqueue.\n"); - } - - /* -@@ -449,32 +429,38 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, - */ - static void mlxreg_hotplug_work_handler(struct work_struct *work) - { -- struct mlxreg_hotplug_priv_data *priv = container_of(work, -- struct mlxreg_hotplug_priv_data, dwork_irq.work); - struct mlxreg_core_hotplug_platform_data *pdata; -+ struct mlxreg_hotplug_priv_data *priv; - struct mlxreg_core_item *item; -- unsigned long flags; - u32 regval, aggr_asserted; -- int i; -- int ret; -+ unsigned long flags; -+ int i, ret; - -+ priv = container_of(work, struct mlxreg_hotplug_priv_data, -+ dwork_irq.work); - pdata = dev_get_platdata(&priv->pdev->dev); - item = pdata->items; -+ - /* Mask aggregation event. */ - ret = regmap_write(priv->regmap, pdata->cell + - MLXREG_HOTPLUG_AGGR_MASK_OFF, 0); - if (ret < 0) -- goto access_error; -+ goto out; - - /* Read aggregation status. */ - ret = regmap_read(priv->regmap, pdata->cell, ®val); - if (ret) -- goto access_error; -+ goto out; - - regval &= pdata->mask; - aggr_asserted = priv->aggr_cache ^ regval; - priv->aggr_cache = regval; - -+ /* -+ * Handler is invoked, but no assertion is detected at top aggregation -+ * status level. Set aggr_asserted to mask value to allow handler extra -+ * run over all relevant signals to recover any missed signal. -+ */ - if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) { - priv->not_asserted = 0; - aggr_asserted = pdata->mask; -@@ -492,47 +478,40 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work) - } - } - -- if (aggr_asserted) { -- spin_lock_irqsave(&priv->lock, flags); -+ spin_lock_irqsave(&priv->lock, flags); - -- /* -- * It is possible, that some signals have been inserted, while -- * interrupt has been masked by mlxreg_hotplug_work_handler. -- * In this case such signals will 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(&priv->dwork_irq); -- schedule_delayed_work(&priv->dwork_irq, 0); -+ /* -+ * It is possible, that some signals have been inserted, while -+ * interrupt has been masked by mlxreg_hotplug_work_handler. In this -+ * case such signals will 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(&priv->dwork_irq); -+ schedule_delayed_work(&priv->dwork_irq, 0); - -- spin_unlock_irqrestore(&priv->lock, flags); -+ spin_unlock_irqrestore(&priv->lock, flags); - -- return; -- } -+ return; - - unmask_event: - priv->not_asserted++; - /* Unmask aggregation event (no need acknowledge). */ - ret = regmap_write(priv->regmap, pdata->cell + - MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); -- if (ret) -- goto access_error; - -- return; -- --access_error: -- dev_err(priv->dev, "Failed to complete workqueue.\n"); -+ out: -+ if (ret) -+ dev_err(priv->dev, "Failed to complete workqueue.\n"); - } - - static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) - { - struct mlxreg_core_hotplug_platform_data *pdata; - struct mlxreg_core_item *item; -- int i; -- int ret; -+ int i, ret; - - pdata = dev_get_platdata(&priv->pdev->dev); - item = pdata->items; -@@ -542,7 +521,7 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) - ret = regmap_write(priv->regmap, item->reg + - MLXREG_HOTPLUG_EVENT_OFF, 0); - if (ret) -- goto access_error; -+ goto out; - - /* Set group initial status as mask and unmask group event. */ - if (item->inversed) { -@@ -551,7 +530,7 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) - MLXREG_HOTPLUG_MASK_OFF, - item->mask); - if (ret) -- goto access_error; -+ goto out; - } - } - -@@ -559,7 +538,7 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) - ret = regmap_write(priv->regmap, pdata->cell + - MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); - if (ret) -- goto access_error; -+ goto out; - - /* Keep low aggregation initial status as zero and unmask events. */ - if (pdata->cell_low) { -@@ -567,21 +546,16 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) - MLXREG_HOTPLUG_AGGR_MASK_OFF, - pdata->mask_low); - if (ret) -- goto access_error; -+ goto out; - } - - /* Invoke work handler for initializing hot plug devices setting. */ - mlxreg_hotplug_work_handler(&priv->dwork_irq.work); - -+ out: -+ if (ret) -+ dev_err(priv->dev, "Failed to set interrupts.\n"); - enable_irq(priv->irq); -- -- return 0; -- --access_error: -- dev_err(priv->dev, "Failed to set interrupts.\n"); -- -- enable_irq(priv->irq); -- - return ret; - } - -@@ -619,14 +593,15 @@ static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv) - /* Remove all the attached devices in group. */ - count = item->count; - for (j = 0; j < count; j++, data++) -- mlxreg_hotplug_dev_disable(data); -+ mlxreg_hotplug_device_destroy(priv, data); - } - } - - static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev) - { -- struct mlxreg_hotplug_priv_data *priv = -- (struct mlxreg_hotplug_priv_data *)dev; -+ struct mlxreg_hotplug_priv_data *priv; -+ -+ priv = (struct mlxreg_hotplug_priv_data *)dev; - - /* Schedule work task for immediate execution.*/ - schedule_delayed_work(&priv->dwork_irq, 0); -@@ -683,10 +658,6 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) - disable_irq(priv->irq); - spin_lock_init(&priv->lock); - INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler); -- /* Perform initial interrupts setup. */ -- mlxreg_hotplug_set_irq(priv); -- -- priv->after_probe = true; - dev_set_drvdata(&pdev->dev, priv); - - err = mlxreg_hotplug_attr_init(priv); -@@ -703,6 +674,11 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) - PTR_ERR(priv->hwmon)); - return PTR_ERR(priv->hwmon); - } -+ priv->kobj = &priv->hwmon->kobj; -+ -+ /* Perform initial interrupts setup. */ -+ mlxreg_hotplug_set_irq(priv); -+ priv->after_probe = true; - - return 0; - } -diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c -index f7434ca..c192dfe 100644 ---- a/drivers/platform/mellanox/mlxreg-io.c -+++ b/drivers/platform/mellanox/mlxreg-io.c -@@ -1,3 +1,11 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Mellanox register access driver -+ * -+ * Copyright (C) 2018 Mellanox Technologies -+ * Copyright (C) 2018 Vadim Pasternak -+ */ -+ - #include - #include - #include -@@ -33,6 +41,54 @@ struct mlxreg_io_priv_data { - const struct attribute_group *groups[2]; - }; - -+static int -+mlxreg_io_get_reg(void *regmap, struct mlxreg_core_data *data, u32 in_val, -+ bool rw_flag, u32 *regval) -+{ -+ int ret; -+ -+ ret = regmap_read(regmap, data->reg, regval); -+ if (ret) -+ goto access_error; -+ -+ /* -+ * There are three kinds of attributes: single bit, full register's -+ * bits and bit sequence. For the first kind field mask indicates which -+ * bits are not related and field bit is set zero. For the second kind -+ * field mask is set to zero and field bit is set with all bits one. -+ * No special handling for such kind of attributes - pass value as is. -+ * For the third kind, field mask indicates which bits are related and -+ * field bit is set to the first bit number (from 1 to 32) is the bit -+ * sequence. -+ */ -+ if (!data->bit) { -+ /* Single bit. */ -+ if (rw_flag) { -+ /* For show: expose effective bit value as 0 or 1. */ -+ *regval = !!(*regval & ~data->mask); -+ } else { -+ /* For store: set effective bit value. */ -+ *regval &= data->mask; -+ if (in_val) -+ *regval |= ~data->mask; -+ } -+ } else if (data->mask) { -+ /* Bit sequence. */ -+ if (rw_flag) { -+ /* For show: mask and shift right. */ -+ *regval = ror32(*regval & data->mask, (data->bit - 1)); -+ } else { -+ /* For store: shift to the position and mask. */ -+ in_val = rol32(in_val, data->bit - 1) & data->mask; -+ /* Clear relevant bits and set them to new value. */ -+ *regval = (*regval & ~data->mask) | in_val; -+ } -+ } -+ -+access_error: -+ return ret; -+} -+ - static ssize_t - mlxreg_io_attr_show(struct device *dev, struct device_attribute *attr, - char *buf) -@@ -43,13 +99,10 @@ mlxreg_io_attr_show(struct device *dev, struct device_attribute *attr, - u32 regval = 0; - int ret; - -- ret = regmap_read(priv->pdata->regmap, data->reg, ®val); -+ ret = mlxreg_io_get_reg(priv->pdata->regmap, data, 0, true, ®val); - if (ret) - goto access_error; - -- if (!data->bit) -- regval = !!(regval & ~data->mask); -- - return sprintf(buf, "%u\n", regval); - - access_error: -@@ -63,25 +116,22 @@ mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr, - struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev); - int index = to_sensor_dev_attr(attr)->index; - struct mlxreg_core_data *data = priv->pdata->data + index; -- u32 val, regval; -+ u32 input_val, regval; - int ret; - -- ret = kstrtou32(buf, MLXREG_IO_ATT_SIZE, &val); -+ if (len > MLXREG_IO_ATT_SIZE) -+ return -EINVAL; -+ -+ /* Convert buffer to input value. */ -+ ret = kstrtou32(buf, len, &input_val); - if (ret) - return ret; - -- ret = regmap_read(priv->pdata->regmap, data->reg, ®val); -+ ret = mlxreg_io_get_reg(priv->pdata->regmap, data, input_val, false, -+ ®val); - if (ret) - goto access_error; - -- regval &= data->mask; -- -- val = !!val; -- if (val) -- regval |= ~data->mask; -- else -- regval &= data->mask; -- - ret = regmap_write(priv->pdata->regmap, data->reg, regval); - if (ret) - goto access_error; -@@ -93,6 +143,11 @@ mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr, - return ret; - } - -+static struct device_attribute mlxreg_io_devattr_rw = { -+ .show = mlxreg_io_attr_show, -+ .store = mlxreg_io_attr_store, -+}; -+ - static int mlxreg_io_attr_init(struct mlxreg_io_priv_data *priv) - { - int i; -@@ -107,6 +162,8 @@ static int mlxreg_io_attr_init(struct mlxreg_io_priv_data *priv) - for (i = 0; i < priv->pdata->counter; i++) { - priv->mlxreg_io_attr[i] = - &priv->mlxreg_io_dev_attr[i].dev_attr.attr; -+ memcpy(&priv->mlxreg_io_dev_attr[i].dev_attr, -+ &mlxreg_io_devattr_rw, sizeof(struct device_attribute)); - - /* Set attribute name as a label. */ - priv->mlxreg_io_attr[i]->name = -@@ -121,31 +178,6 @@ static int mlxreg_io_attr_init(struct mlxreg_io_priv_data *priv) - - priv->mlxreg_io_dev_attr[i].dev_attr.attr.mode = - priv->pdata->data[i].mode; -- switch (priv->pdata->data[i].mode) { -- case 0200: -- priv->mlxreg_io_dev_attr[i].dev_attr.store = -- mlxreg_io_attr_store; -- break; -- -- case 0444: -- priv->mlxreg_io_dev_attr[i].dev_attr.show = -- mlxreg_io_attr_show; -- break; -- -- case 0644: -- priv->mlxreg_io_dev_attr[i].dev_attr.show = -- mlxreg_io_attr_show; -- priv->mlxreg_io_dev_attr[i].dev_attr.store = -- mlxreg_io_attr_store; -- break; -- -- default: -- dev_err(&priv->pdev->dev, "Bad access mode %u for attribute %s.\n", -- priv->pdata->data[i].mode, -- priv->mlxreg_io_attr[i]->name); -- return -EINVAL; -- } -- - priv->mlxreg_io_dev_attr[i].dev_attr.attr.name = - priv->mlxreg_io_attr[i]->name; - priv->mlxreg_io_dev_attr[i].index = i; -@@ -184,7 +216,9 @@ static int mlxreg_io_probe(struct platform_device *pdev) - } - - priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, -- "mlxreg_io", priv, priv->groups); -+ "mlxreg_io", -+ priv, -+ priv->groups); - if (IS_ERR(priv->hwmon)) { - dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", - PTR_ERR(priv->hwmon)); -@@ -207,5 +241,5 @@ module_platform_driver(mlxreg_io_driver); - - MODULE_AUTHOR("Vadim Pasternak "); - MODULE_DESCRIPTION("Mellanox regmap I/O access driver"); --MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_LICENSE("GPL"); - MODULE_ALIAS("platform:mlxreg-io"); -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index e03f03f..e1f9fce 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -47,34 +47,52 @@ - /* LPC bus IO offsets */ - #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 - #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 --#define MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF 0x00 --#define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF 0x01 --#define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF 0x1d --#define MLXPLAT_CPLD_LPC_REG_LED1_OFF 0x20 --#define MLXPLAT_CPLD_LPC_REG_LED2_OFF 0x21 --#define MLXPLAT_CPLD_LPC_REG_LED3_OFF 0x22 --#define MLXPLAT_CPLD_LPC_REG_LED4_OFF 0x23 --#define MLXPLAT_CPLD_LPC_REG_LED5_OFF 0x24 --#define MLXPLAT_CPLD_LPC_REG_GP1_OFF 0x30 --#define MLXPLAT_CPLD_LPC_REG_WP1_OFF 0x31 --#define MLXPLAT_CPLD_LPC_REG_GP2_OFF 0x32 --#define MLXPLAT_CPLD_LPC_REG_WP2_OFF 0x33 --#define MLXPLAT_CPLD_LPC_REG_AGGR_OFF 0x3a --#define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF 0x3b --#define MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF 0x40 --#define MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF 0x41 --#define MLXPLAT_CPLD_LPC_REG_PSU_OFF 0x58 --#define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF 0x59 --#define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF 0x5a --#define MLXPLAT_CPLD_LPC_REG_PWR_OFF 0x64 --#define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF 0x65 --#define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF 0x66 --#define MLXPLAT_CPLD_LPC_REG_FAN_OFF 0x88 --#define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF 0x89 --#define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF 0x8a -+#define MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET 0x00 -+#define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET 0x01 -+#define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET 0x1d -+#define MLXPLAT_CPLD_LPC_REG_LED1_OFFSET 0x20 -+#define MLXPLAT_CPLD_LPC_REG_LED2_OFFSET 0x21 -+#define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET 0x22 -+#define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET 0x23 -+#define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET 0x24 -+#define MLXPLAT_CPLD_LPC_REG_GP1_OFFSET 0x30 -+#define MLXPLAT_CPLD_LPC_REG_WP1_OFFSET 0x31 -+#define MLXPLAT_CPLD_LPC_REG_GP2_OFFSET 0x32 -+#define MLXPLAT_CPLD_LPC_REG_WP2_OFFSET 0x33 -+#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_AGGRLO_OFFSET 0x40 -+#define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 -+#define MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET 0x50 -+#define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51 -+#define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52 -+#define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58 -+#define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59 -+#define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a -+#define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64 -+#define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET 0x65 -+#define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET 0x66 -+#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_PWM1_OFFSET 0xe3 -+#define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4 -+#define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5 -+#define MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET 0xe6 -+#define MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET 0xe7 -+#define MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET 0xe8 -+#define MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET 0xe9 -+#define MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET 0xea -+#define MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET 0xeb -+#define MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET 0xec -+#define MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET 0xed -+#define MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET 0xee -+#define MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET 0xef - #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_PIO_OFFSET 0x10000UL - #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ - MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \ -@@ -84,17 +102,20 @@ - MLXPLAT_CPLD_LPC_PIO_OFFSET) - - /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ -+#define MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF 0x04 - #define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08 - #define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08 - #define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40 --#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ -+#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF | \ -+ MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ - MLXPLAT_CPLD_AGGR_FAN_MASK_DEF) -+#define MLXPLAT_CPLD_AGGR_ASIC_MASK_NG 0x01 - #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04 --#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc0 --#define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04 -+#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 - #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) - #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) - #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) -+#define MLXPLAT_CPLD_ASIC_MASK GENMASK(1, 0) - #define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0) - #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) - #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) -@@ -119,6 +140,10 @@ - #define MLXPLAT_CPLD_NR_NONE -1 - #define MLXPLAT_CPLD_PSU_DEFAULT_NR 10 - #define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4 -+#define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11 -+#define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12 -+#define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13 -+#define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14 - - /* mlxplat_priv - platform private data - * @pdev_i2c - i2c controller platform device -@@ -126,6 +151,7 @@ - * @pdev_hotplug - hotplug platform devices - * @pdev_led - led platform devices - * @pdev_io_regs - register access platform devices -+ * @pdev_fan - FAN platform devices - */ - struct mlxplat_priv { - struct platform_device *pdev_i2c; -@@ -133,6 +159,7 @@ struct mlxplat_priv { - struct platform_device *pdev_hotplug; - struct platform_device *pdev_led; - struct platform_device *pdev_io_regs; -+ struct platform_device *pdev_fan; - }; - - /* Regions for LPC I2C controller and LPC base register space */ -@@ -194,6 +221,15 @@ static struct i2c_board_info mlxplat_mlxcpld_psu[] = { - }, - }; - -+static struct i2c_board_info mlxplat_mlxcpld_ng_psu[] = { -+ { -+ I2C_BOARD_INFO("24c32", 0x51), -+ }, -+ { -+ I2C_BOARD_INFO("24c32", 0x50), -+ }, -+}; -+ - static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { - { - I2C_BOARD_INFO("dps460", 0x59), -@@ -222,14 +258,14 @@ static struct i2c_board_info mlxplat_mlxcpld_fan[] = { - static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = { - { - .label = "psu1", -- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, - .mask = BIT(0), - .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0], - .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, - }, - { - .label = "psu2", -- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, - .mask = BIT(1), - .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1], - .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, -@@ -239,14 +275,14 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = { - static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = { - { - .label = "pwr1", -- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, - .mask = BIT(0), - .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], - .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, - }, - { - .label = "pwr2", -- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, - .mask = BIT(1), - .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], - .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, -@@ -256,31 +292,40 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = { - static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { - { - .label = "fan1", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = BIT(0), - .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0], -- .hpdev.nr = 11, -+ .hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR, - }, - { - .label = "fan2", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = BIT(1), - .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1], -- .hpdev.nr = 12, -+ .hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR, - }, - { - .label = "fan3", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = BIT(2), - .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2], -- .hpdev.nr = 13, -+ .hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR, - }, - { - .label = "fan4", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = BIT(3), - .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3], -- .hpdev.nr = 14, -+ .hpdev.nr = MLXPLAT_CPLD_FAN4_DEFAULT_NR, -+ }, -+}; -+ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_asic_items_data[] = { -+ { -+ .label = "asic1", -+ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, -+ .mask = MLXPLAT_CPLD_ASIC_MASK, -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, - }, - }; - -@@ -288,7 +333,7 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { - { - .data = mlxplat_mlxcpld_default_psu_items_data, - .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, -- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, - .mask = MLXPLAT_CPLD_PSU_MASK, - .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), - .inversed = 1, -@@ -297,7 +342,7 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { - { - .data = mlxplat_mlxcpld_default_pwr_items_data, - .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, -- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, - .mask = MLXPLAT_CPLD_PWR_MASK, - .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), - .inversed = 0, -@@ -306,127 +351,92 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { - { - .data = mlxplat_mlxcpld_default_fan_items_data, - .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF, -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = MLXPLAT_CPLD_FAN_MASK, - .count = ARRAY_SIZE(mlxplat_mlxcpld_fan), - .inversed = 1, - .health = false, - }, -+ { -+ .data = mlxplat_mlxcpld_default_asic_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_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_data = { - .items = mlxplat_mlxcpld_default_items, - .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items), -- .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, -+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, - .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, --}; -- --/* Platform hotplug MSN21xx system family data */ --static struct i2c_board_info mlxplat_mlxcpld_msn21xx_pwr[] = { -- { -- I2C_BOARD_INFO("holder", 0x59), -- }, -- { -- I2C_BOARD_INFO("holder", 0x58), -- }, -+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, -+ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, - }; - - static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = { - { - .label = "pwr1", -- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, - .mask = BIT(0), -- .hpdev.brdinfo = &mlxplat_mlxcpld_msn21xx_pwr[0], -- .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, - }, - { - .label = "pwr2", -- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, - .mask = BIT(1), -- .hpdev.brdinfo = &mlxplat_mlxcpld_msn21xx_pwr[1], -- .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, - }, - }; - -+/* Platform hotplug MSN21xx system family data */ - static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = { - { - .data = mlxplat_mlxcpld_msn21xx_pwr_items_data, - .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, -- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, - .mask = MLXPLAT_CPLD_PWR_MASK, - .count = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data), - .inversed = 0, - .health = false, - }, --}; -- --static --struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { -- .items = mlxplat_mlxcpld_msn21xx_items, -- .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items), -- .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, -- .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, -- .cell_low = MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF, -- .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, --}; -- --/* Platform hotplug MSN201x system family data */ --static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data[] = { -- { -- .label = "pwr1", -- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -- .mask = BIT(0), -- .hpdev.brdinfo = &mlxplat_mlxcpld_msn21xx_pwr[0], -- .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, -- }, -- { -- .label = "pwr2", -- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -- .mask = BIT(1), -- .hpdev.brdinfo = &mlxplat_mlxcpld_msn21xx_pwr[1], -- .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, -- }, --}; -- --static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = { - { -- .data = mlxplat_mlxcpld_msn201x_pwr_items_data, -- .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, -- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -- .mask = MLXPLAT_CPLD_PWR_MASK, -- .count = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_pwr_items_data), -+ .data = mlxplat_mlxcpld_default_asic_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_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 = false, -+ .health = true, - }, - }; - - static --struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = { -+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { - .items = mlxplat_mlxcpld_msn21xx_items, -- .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items), -- .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items), -+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, - .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, -- .cell_low = MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF, -+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, - .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, - }; - --/* Platform hotplug next generation system family data */ --static struct i2c_board_info mlxplat_mlxcpld_ng_fan = { -- I2C_BOARD_INFO("holder", 0x50), --}; -- --static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = { -+/* Platform hotplug msn274x system family data */ -+static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data[] = { - { - .label = "psu1", -- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, - .mask = BIT(0), - .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0], - .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, - }, - { - .label = "psu2", -- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, - .mask = BIT(1), - .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1], - .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, -@@ -436,173 +446,246 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = { - static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data[] = { - { - .label = "pwr1", -- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, - .mask = BIT(0), - .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], - .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, - }, - { - .label = "pwr2", -- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, - .mask = BIT(1), - .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], - .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, - }, - }; - --static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = { -+static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = { - { - .label = "fan1", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = BIT(0), -- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -- .hpdev.nr = 11, -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, - }, - { - .label = "fan2", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = BIT(1), -- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -- .hpdev.nr = 12, -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, - }, - { - .label = "fan3", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = BIT(2), -- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -- .hpdev.nr = 13, -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, - }, - { - .label = "fan4", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = BIT(3), -- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -- .hpdev.nr = 14, -- }, -- { -- .label = "fan5", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -- .mask = BIT(4), -- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -- .hpdev.nr = 15, -- }, -- { -- .label = "fan6", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -- .mask = BIT(5), -- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -- .hpdev.nr = 16, -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, - }, - }; - --static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = { -+static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = { - { -- .data = mlxplat_mlxcpld_default_ng_psu_items_data, -+ .data = mlxplat_mlxcpld_msn274x_psu_items_data, - .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, -- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, - .mask = MLXPLAT_CPLD_PSU_MASK, -- .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_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_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, - .mask = MLXPLAT_CPLD_PWR_MASK, -- .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data), - .inversed = 0, - .health = false, - }, - { -- .data = mlxplat_mlxcpld_default_ng_fan_items_data, -+ .data = mlxplat_mlxcpld_msn274x_fan_items_data, - .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = MLXPLAT_CPLD_FAN_MASK, -- .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_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, -- .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items), -- .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, -+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = { -+ .items = mlxplat_mlxcpld_msn274x_items, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items), -+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, - .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, -- .cell_low = MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF, -+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, - .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, - }; - --static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = { -+/* Platform hotplug MSN201x system family data */ -+static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data[] = { -+ { -+ .label = "pwr1", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, -+ .mask = BIT(0), -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, -+ }, -+ { -+ .label = "pwr2", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, -+ .mask = BIT(1), -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, -+ }, -+}; -+ -+static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = { -+ { -+ .data = mlxplat_mlxcpld_msn201x_pwr_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, -+ .mask = MLXPLAT_CPLD_PWR_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_pwr_items_data), -+ .inversed = 0, -+ .health = false, -+ }, -+ { -+ .data = mlxplat_mlxcpld_default_asic_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_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_msn201x_data = { -+ .items = mlxplat_mlxcpld_msn21xx_items, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items), -+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, -+ .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, -+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, -+ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, -+}; -+ -+/* Platform hotplug next generation system family data */ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = { -+ { -+ .label = "psu1", -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, -+ .mask = BIT(0), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[0], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, -+ }, -+ { -+ .label = "psu2", -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, -+ .mask = BIT(1), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[1], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, -+ }, -+}; -+ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = { - { - .label = "fan1", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = BIT(0), -- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -- .hpdev.nr = 11, -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, - }, - { - .label = "fan2", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = BIT(1), -- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -- .hpdev.nr = 12, -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, - }, - { - .label = "fan3", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = BIT(2), -- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -- .hpdev.nr = 13, -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, - }, - { - .label = "fan4", -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, - .mask = BIT(3), -- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, -- .hpdev.nr = 14, -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, -+ }, -+ { -+ .label = "fan5", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, -+ .mask = BIT(4), -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, -+ }, -+ { -+ .label = "fan6", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, -+ .mask = BIT(5), -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, - }, - }; - --static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = { -+static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = { - { - .data = mlxplat_mlxcpld_default_ng_psu_items_data, - .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, -- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, - .mask = MLXPLAT_CPLD_PSU_MASK, -- .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), -+ .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_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, - .mask = MLXPLAT_CPLD_PWR_MASK, -- .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data), - .inversed = 0, - .health = false, - }, - { -- .data = mlxplat_mlxcpld_msn274x_fan_items_data, -+ .data = mlxplat_mlxcpld_default_ng_fan_items_data, - .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, -- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, -- .mask = MLXPLAT_CPLD_FAN_MASK, -- .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data), -+ .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_msn274x_data = { -- .items = mlxplat_mlxcpld_msn274x_items, -+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { -+ .items = mlxplat_mlxcpld_default_ng_items, - .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items), -- .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, -+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, - .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, -- .cell_low = MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF, -+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, - .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, - }; - -@@ -610,62 +693,62 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = { - static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { - { - .label = "status:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "status:red", -- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK - }, - { - .label = "psu:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "psu:red", -- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "fan1:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "fan1:red", -- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "fan2:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "fan2:red", -- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "fan3:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "fan3:red", -- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "fan4:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "fan4:red", -- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - }; -@@ -679,47 +762,47 @@ static struct mlxreg_core_platform_data mlxplat_default_led_data = { - static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_led_data[] = { - { - .label = "status:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "status:red", -- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK - }, - { - .label = "fan:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "fan:red", -- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "psu1:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "psu1:red", -- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "psu2:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "psu2:red", -- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "uid:blue", -- .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - }; -@@ -733,82 +816,82 @@ static struct mlxreg_core_platform_data mlxplat_msn21xx_led_data = { - static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_led_data[] = { - { - .label = "status:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "status:orange", -- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK - }, - { - .label = "psu:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "psu:orange", -- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "fan1:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "fan1:orange", -- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "fan2:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "fan2:orange", -- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "fan3:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "fan3:orange", -- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "fan4:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "fan4:orange", -- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "fan5:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "fan5:orange", -- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, - .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, - }, - { - .label = "fan6:green", -- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - { - .label = "fan6:orange", -- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, -+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, - .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, - }, - }; -@@ -818,26 +901,303 @@ static struct mlxreg_core_platform_data mlxplat_default_ng_led_data = { - .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data), - }; - -+/* Platform register access default */ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { -+ { -+ .label = "cpld1_version", -+ .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, -+ .bit = GENMASK(7, 0), -+ .mode = 0444, -+ }, -+ { -+ .label = "cpld2_version", -+ .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, -+ .bit = GENMASK(7, 0), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_long_pb", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(0), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_short_pb", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(1), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_aux_pwr_or_ref", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(2), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_main_pwr_fail", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(3), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_sw_reset", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(4), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_fw_reset", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(5), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_hotswap_or_wd", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(6), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_asic_thermal", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(7), -+ .mode = 0444, -+ }, -+ { -+ .label = "psu1_on", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(0), -+ .mode = 0200, -+ }, -+ { -+ .label = "psu2_on", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(1), -+ .mode = 0200, -+ }, -+ { -+ .label = "pwr_cycle", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(2), -+ .mode = 0200, -+ }, -+ { -+ .label = "pwr_down", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(3), -+ .mode = 0200, -+ }, -+ { -+ .label = "select_iio", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(6), -+ .mode = 0644, -+ }, -+ { -+ .label = "asic_health", -+ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, -+ .mask = MLXPLAT_CPLD_ASIC_MASK, -+ .bit = 1, -+ .mode = 0444, -+ }, -+}; -+ -+static struct mlxreg_core_platform_data mlxplat_default_regs_io_data = { -+ .data = mlxplat_mlxcpld_default_regs_io_data, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_regs_io_data), -+}; -+ -+/* Platform register access MSN21xx, MSN201x, MSN274x systems families data */ -+static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_regs_io_data[] = { -+ { -+ .label = "cpld1_version", -+ .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, -+ .bit = GENMASK(7, 0), -+ .mode = 0444, -+ }, -+ { -+ .label = "cpld2_version", -+ .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, -+ .bit = GENMASK(7, 0), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_long_pb", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(0), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_short_pb", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(1), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_aux_pwr_or_ref", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(2), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_sw_reset", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(3), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_main_pwr_fail", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(4), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_asic_thermal", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(5), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_hotswap_or_halt", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(6), -+ .mode = 0444, -+ }, -+ { -+ .label = "psu1_on", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(0), -+ .mode = 0200, -+ }, -+ { -+ .label = "psu2_on", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(1), -+ .mode = 0200, -+ }, -+ { -+ .label = "pwr_cycle", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(2), -+ .mode = 0200, -+ }, -+ { -+ .label = "pwr_down", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(3), -+ .mode = 0200, -+ }, -+ { -+ .label = "asic_health", -+ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, -+ .mask = MLXPLAT_CPLD_ASIC_MASK, -+ .bit = 1, -+ .mode = 0444, -+ }, -+}; -+ -+static struct mlxreg_core_platform_data mlxplat_msn21xx_regs_io_data = { -+ .data = mlxplat_mlxcpld_msn21xx_regs_io_data, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_regs_io_data), -+}; -+ -+/* Platform FAN default */ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { -+ { -+ .label = "pwm1", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET, -+ }, -+ { -+ .label = "tacho1", -+ .reg = MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET, -+ .mask = GENMASK(7, 0), -+ }, -+ { -+ .label = "tacho2", -+ .reg = MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET, -+ .mask = GENMASK(7, 0), -+ }, -+ { -+ .label = "tacho3", -+ .reg = MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET, -+ .mask = GENMASK(7, 0), -+ }, -+ { -+ .label = "tacho4", -+ .reg = MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET, -+ .mask = GENMASK(7, 0), -+ }, -+ { -+ .label = "tacho5", -+ .reg = MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET, -+ .mask = GENMASK(7, 0), -+ }, -+ { -+ .label = "tacho6", -+ .reg = MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET, -+ .mask = GENMASK(7, 0), -+ }, -+ { -+ .label = "tacho7", -+ .reg = MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET, -+ .mask = GENMASK(7, 0), -+ }, -+ { -+ .label = "tacho8", -+ .reg = MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET, -+ .mask = GENMASK(7, 0), -+ }, -+ { -+ .label = "tacho9", -+ .reg = MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET, -+ .mask = GENMASK(7, 0), -+ }, -+ { -+ .label = "tacho10", -+ .reg = MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET, -+ .mask = GENMASK(7, 0), -+ }, -+ { -+ .label = "tacho11", -+ .reg = MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET, -+ .mask = GENMASK(7, 0), -+ }, -+ { -+ .label = "tacho12", -+ .reg = MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET, -+ .mask = GENMASK(7, 0), -+ }, -+}; -+ -+static struct mlxreg_core_platform_data mlxplat_default_fan_data = { -+ .data = mlxplat_mlxcpld_default_fan_data, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data), -+}; -+ - static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) - { - switch (reg) { -- case MLXPLAT_CPLD_LPC_REG_LED1_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED2_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED3_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED4_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED5_OFF: -- case MLXPLAT_CPLD_LPC_REG_GP1_OFF: -- case MLXPLAT_CPLD_LPC_REG_WP1_OFF: -- case MLXPLAT_CPLD_LPC_REG_GP2_OFF: -- case MLXPLAT_CPLD_LPC_REG_WP2_OFF: -- case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF: -- case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF: -- case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF: -- case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF: -- case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF: -- case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF: -- case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF: -- case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: -+ 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_PWM1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: - return true; - } - return false; -@@ -846,31 +1206,48 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) - static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) - { - switch (reg) { -- case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF: -- case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF: -- case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED1_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED2_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED3_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED4_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED5_OFF: -- case MLXPLAT_CPLD_LPC_REG_GP1_OFF: -- case MLXPLAT_CPLD_LPC_REG_WP1_OFF: -- case MLXPLAT_CPLD_LPC_REG_GP2_OFF: -- case MLXPLAT_CPLD_LPC_REG_WP2_OFF: -- case MLXPLAT_CPLD_LPC_REG_AGGR_OFF: -- case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF: -- case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF: -- case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF: -- case MLXPLAT_CPLD_LPC_REG_PSU_OFF: -- case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF: -- case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF: -- case MLXPLAT_CPLD_LPC_REG_PWR_OFF: -- case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF: -- case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF: -- case MLXPLAT_CPLD_LPC_REG_FAN_OFF: -- case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF: -- case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_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: -+ case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: -+ 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_PWM1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: - return true; - } - return false; -@@ -879,54 +1256,82 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) - static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) - { - switch (reg) { -- case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF: -- case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF: -- case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED1_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED2_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED3_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED4_OFF: -- case MLXPLAT_CPLD_LPC_REG_LED5_OFF: -- case MLXPLAT_CPLD_LPC_REG_GP1_OFF: -- case MLXPLAT_CPLD_LPC_REG_GP2_OFF: -- case MLXPLAT_CPLD_LPC_REG_AGGR_OFF: -- case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF: -- case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF: -- case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF: -- case MLXPLAT_CPLD_LPC_REG_PSU_OFF: -- case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF: -- case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF: -- case MLXPLAT_CPLD_LPC_REG_PWR_OFF: -- case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF: -- case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF: -- case MLXPLAT_CPLD_LPC_REG_FAN_OFF: -- case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF: -- case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF: -+ case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRLO_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: -+ case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: -+ 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_PWM1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: - return true; - } - return false; - } - - static const struct reg_default mlxplat_mlxcpld_regmap_default[] = { -- { MLXPLAT_CPLD_LPC_REG_WP1_OFF, 0x00 }, -- { MLXPLAT_CPLD_LPC_REG_WP2_OFF, 0x00 }, -+ { MLXPLAT_CPLD_LPC_REG_WP1_OFFSET, 0x00 }, -+ { MLXPLAT_CPLD_LPC_REG_WP2_OFFSET, 0x00 }, -+ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, -+}; -+ -+struct mlxplat_mlxcpld_regmap_context { -+ void __iomem *base; - }; - -+static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx; -+ - static int - mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val) - { -- *val = ioread8(context + reg); -+ struct mlxplat_mlxcpld_regmap_context *ctx = context; -+ -+ *val = ioread8(ctx->base + reg); - return 0; - } - - static int - mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val) - { -- iowrite8(val, context + reg); -+ struct mlxplat_mlxcpld_regmap_context *ctx = context; -+ -+ iowrite8(val, ctx->base + reg); - return 0; - } - --const struct regmap_config mlxplat_mlxcpld_regmap_config = { -+static const struct regmap_config mlxplat_mlxcpld_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 255, -@@ -944,46 +1349,11 @@ static struct resource mlxplat_mlxcpld_resources[] = { - [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"), - }; - --static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { -- { "cpld1_version", MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF, 0x00, -- GENMASK(7, 0), 0444 }, -- { "cpld2_version", MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF, 0x00, -- GENMASK(7, 0), 0444 }, -- { "cause_long_pb", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -- GENMASK(7, 0) & ~BIT(0), 0x00, 0444 }, -- { "cause_short_pb", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -- GENMASK(7, 0) & ~BIT(1), 0x00, 0444 }, -- { "cause_aux_pwr_or_refresh", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -- GENMASK(7, 0) & ~BIT(2), 0x00, 0444 }, -- { "cause_main_pwr_fail", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -- GENMASK(7, 0) & ~BIT(3), 0x00, 0444 }, -- { "cause_sw_reset", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -- GENMASK(7, 0) & ~BIT(4), 0x00, 0444 }, -- { "cause_fw_reset", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -- GENMASK(7, 0) & ~BIT(5), 0x00, 0444 }, -- { "cause_hotswap_or_wd", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -- GENMASK(7, 0) & ~BIT(6), 0x00, 0444 }, -- { "cause_asic_thermal", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, -- GENMASK(7, 0) & ~BIT(7), 0x00, 0444 }, -- { "psu1_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(0), -- 0x00, 0200 }, -- { "psu2_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(1), -- 0x00, 0200 }, -- { "pwr_cycle", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(2), -- 0x00, 0200 }, -- { "select_iio", MLXPLAT_CPLD_LPC_REG_GP2_OFF, GENMASK(7, 0) & ~BIT(6), -- 0x00, 0644 }, --}; -- --static struct mlxreg_core_platform_data mlxplat_default_regs_io_data = { -- .data = mlxplat_mlxcpld_default_regs_io_data, -- .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_regs_io_data), --}; -- - static struct platform_device *mlxplat_dev; - static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; - static struct mlxreg_core_platform_data *mlxplat_led; - static struct mlxreg_core_platform_data *mlxplat_regs_io; -+static struct mlxreg_core_platform_data *mlxplat_fan; - - static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) - { -@@ -1016,7 +1386,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) - mlxplat_hotplug->deferred_nr = - mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; - mlxplat_led = &mlxplat_msn21xx_led_data; -- mlxplat_regs_io = &mlxplat_default_regs_io_data; -+ mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; - - return 1; - }; -@@ -1034,12 +1404,12 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) - mlxplat_hotplug->deferred_nr = - mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; - mlxplat_led = &mlxplat_default_led_data; -- mlxplat_regs_io = &mlxplat_default_regs_io_data; -+ mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; - - return 1; - }; - --static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) -+static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) - { - int i; - -@@ -1048,16 +1418,16 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) - mlxplat_mux_data[i].n_values = - ARRAY_SIZE(mlxplat_msn21xx_channels); - } -- mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data; -+ mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data; - mlxplat_hotplug->deferred_nr = - mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; - mlxplat_led = &mlxplat_default_ng_led_data; -- mlxplat_regs_io = &mlxplat_default_regs_io_data; -+ mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; - - return 1; - }; - --static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) -+static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) - { - int i; - -@@ -1066,11 +1436,11 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) - mlxplat_mux_data[i].n_values = - ARRAY_SIZE(mlxplat_msn21xx_channels); - } -- mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data; -+ mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data; - mlxplat_hotplug->deferred_nr = - mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; - mlxplat_led = &mlxplat_msn21xx_led_data; -- mlxplat_regs_io = &mlxplat_default_regs_io_data; -+ mlxplat_fan = &mlxplat_default_fan_data; - - return 1; - }; -@@ -1222,8 +1592,7 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr) - static int __init mlxplat_init(void) - { - struct mlxplat_priv *priv; -- void __iomem *base; -- int i, j, nr, err = 0; -+ int i, j, nr, err; - - if (!dmi_check_system(mlxplat_dmi_table)) - return -ENODEV; -@@ -1267,29 +1636,21 @@ static int __init mlxplat_init(void) - } - } - -- base = devm_ioport_map(&mlxplat_dev->dev, -+ mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev, - mlxplat_lpc_resources[1].start, 1); -- if (!base) { -+ if (!mlxplat_mlxcpld_regmap_ctx.base) { - err = -ENOMEM; - goto fail_platform_mux_register; - } - - mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, -- base, &mlxplat_mlxcpld_regmap_config); -+ &mlxplat_mlxcpld_regmap_ctx, -+ &mlxplat_mlxcpld_regmap_config); - if (IS_ERR(mlxplat_hotplug->regmap)) { - err = PTR_ERR(mlxplat_hotplug->regmap); - goto fail_platform_mux_register; - } - -- /* Set default registers. */ -- for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) { -- err = regmap_write(mlxplat_hotplug->regmap, -- mlxplat_mlxcpld_regmap_default[j].reg, -- mlxplat_mlxcpld_regmap_default[j].def); -- if (err) -- goto fail_platform_mux_register; -- } -- - priv->pdev_hotplug = platform_device_register_resndata( - &mlxplat_dev->dev, "mlxreg-hotplug", - PLATFORM_DEVID_NONE, -@@ -1301,6 +1662,16 @@ static int __init mlxplat_init(void) - goto fail_platform_mux_register; - } - -+ /* Set default registers. */ -+ for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) { -+ err = regmap_write(mlxplat_hotplug->regmap, -+ mlxplat_mlxcpld_regmap_default[j].reg, -+ mlxplat_mlxcpld_regmap_default[j].def); -+ if (err) -+ goto fail_platform_mux_register; -+ } -+ -+ /* Add LED driver. */ - mlxplat_led->regmap = mlxplat_hotplug->regmap; - priv->pdev_led = platform_device_register_resndata( - &mlxplat_dev->dev, "leds-mlxreg", -@@ -1311,24 +1682,48 @@ static int __init mlxplat_init(void) - goto fail_platform_hotplug_register; - } - -- mlxplat_regs_io->regmap = mlxplat_hotplug->regmap; -- priv->pdev_io_regs = platform_device_register_resndata( -- &mlxplat_dev->dev, "mlxreg-io", -- PLATFORM_DEVID_NONE, NULL, 0, -- mlxplat_regs_io, sizeof(*mlxplat_regs_io)); -- if (IS_ERR(priv->pdev_io_regs)) { -- err = PTR_ERR(priv->pdev_io_regs); -- goto fail_platform_led_register; -+ /* Add registers io access driver. */ -+ if (mlxplat_regs_io) { -+ mlxplat_regs_io->regmap = mlxplat_hotplug->regmap; -+ priv->pdev_io_regs = platform_device_register_resndata( -+ &mlxplat_dev->dev, "mlxreg-io", -+ PLATFORM_DEVID_NONE, NULL, 0, -+ mlxplat_regs_io, -+ sizeof(*mlxplat_regs_io)); -+ if (IS_ERR(priv->pdev_io_regs)) { -+ err = PTR_ERR(priv->pdev_io_regs); -+ goto fail_platform_led_register; -+ } -+ } -+ -+ /* Add FAN driver. */ -+ if (mlxplat_fan) { -+ mlxplat_fan->regmap = mlxplat_hotplug->regmap; -+ priv->pdev_fan = platform_device_register_resndata( -+ &mlxplat_dev->dev, "mlxreg-fan", -+ PLATFORM_DEVID_NONE, NULL, 0, -+ mlxplat_fan, -+ sizeof(*mlxplat_fan)); -+ if (IS_ERR(priv->pdev_io_regs)) { -+ err = PTR_ERR(priv->pdev_io_regs); -+ goto fail_platform_io_regs_register; -+ } - } - - /* Sync registers with hardware. */ - regcache_mark_dirty(mlxplat_hotplug->regmap); - err = regcache_sync(mlxplat_hotplug->regmap); - if (err) -- goto fail_platform_led_register; -+ goto fail_platform_fan_register; - - return 0; - -+fail_platform_fan_register: -+ if (mlxplat_fan) -+ platform_device_unregister(priv->pdev_fan); -+fail_platform_io_regs_register: -+ if (mlxplat_regs_io) -+ platform_device_unregister(priv->pdev_io_regs); - fail_platform_led_register: - platform_device_unregister(priv->pdev_led); - fail_platform_hotplug_register: -@@ -1349,7 +1744,10 @@ static void __exit mlxplat_exit(void) - struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); - int i; - -- platform_device_unregister(priv->pdev_io_regs); -+ if (priv->pdev_fan) -+ platform_device_unregister(priv->pdev_fan); -+ if (priv->pdev_io_regs) -+ platform_device_unregister(priv->pdev_io_regs); - platform_device_unregister(priv->pdev_led); - platform_device_unregister(priv->pdev_hotplug); - --- -2.1.4 - diff --git a/patch/0022-platform-x86-mlx-platform-backport-from-4.19.patch b/patch/0022-platform-x86-mlx-platform-backport-from-4.19.patch deleted file mode 100644 index d5caf06c4824..000000000000 --- a/patch/0022-platform-x86-mlx-platform-backport-from-4.19.patch +++ /dev/null @@ -1,215 +0,0 @@ -From 4674fe003c7b71aff4f14bb4fdb723f066cf398b Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Thu, 9 Aug 2018 16:41:16 +0000 -Subject: [patch backport from 4.19 1/1] platform/x86: mlx-platform: backport - from 4.19 - -Signed-off-by: Vadim Pasternak ---- - drivers/platform/mellanox/mlxreg-hotplug.c | 43 +++++++++--------------------- - drivers/platform/x86/mlx-platform.c | 22 +++++++-------- - include/linux/platform_data/mlxreg.h | 5 ++-- - 3 files changed, 26 insertions(+), 44 deletions(-) - -diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c -index 4761211..b6d4455 100644 ---- a/drivers/platform/mellanox/mlxreg-hotplug.c -+++ b/drivers/platform/mellanox/mlxreg-hotplug.c -@@ -50,10 +50,8 @@ - #define MLXREG_HOTPLUG_MASK_OFF 2 - #define MLXREG_HOTPLUG_AGGR_MASK_OFF 1 - --/* ASIC health parameters. */ --#define MLXREG_HOTPLUG_DOWN_MASK 0x00 --#define MLXREG_HOTPLUG_HEALTH_MASK 0x02 --#define MLXREG_HOTPLUG_RST_CNTR 2 -+/* ASIC good health mask. */ -+#define MLXREG_HOTPLUG_GOOD_HEALTH_MASK 0x02 - - #define MLXREG_HOTPLUG_ATTRS_MAX 24 - #define MLXREG_HOTPLUG_NOT_ASSERT 3 -@@ -68,7 +66,6 @@ - * @dwork_irq: delayed work template; - * @lock: spin lock; - * @hwmon: hwmon device; -- * @kobj: hwmon kobject for notification; - * @mlxreg_hotplug_attr: sysfs attributes array; - * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array; - * @group: sysfs attribute group; -@@ -88,7 +85,6 @@ struct mlxreg_hotplug_priv_data { - struct delayed_work dwork_irq; - spinlock_t lock; /* sync with interrupt */ - struct device *hwmon; -- struct kobject *kobj; - struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1]; - struct sensor_device_attribute_2 - mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX]; -@@ -107,7 +103,7 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, - struct mlxreg_core_hotplug_platform_data *pdata; - - /* Notify user by sending hwmon uevent. */ -- kobject_uevent(priv->kobj, KOBJ_CHANGE); -+ kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE); - - /* - * Return if adapter number is negative. It could be in case hotplug -@@ -145,7 +141,7 @@ mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv, - struct mlxreg_core_data *data) - { - /* Notify user by sending hwmon uevent. */ -- kobject_uevent(priv->kobj, KOBJ_CHANGE); -+ kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE); - - if (data->hpdev.client) { - i2c_unregister_device(data->hpdev.client); -@@ -336,23 +332,19 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, - goto out; - - regval &= data->mask; -+ -+ if (item->cache == regval) -+ goto ack_event; -+ - /* - * ASIC health indication is provided through two bits. Bits - * value 0x2 indicates that ASIC reached the good health, value - * 0x0 indicates ASIC the bad health or dormant state and value -- * 0x2 indicates the booting state. During ASIC reset it should -+ * 0x3 indicates the booting state. During ASIC reset it should - * pass the following states: dormant -> booting -> good. -- * The transition from dormant to booting state and from -- * booting to good state are indicated by ASIC twice, so actual -- * sequence for getting to the steady state after reset is: -- * dormant -> booting -> booting -> good -> good. It is -- * possible that due to some hardware noise, the transition -- * sequence will look like: dormant -> booting -> [ booting -> -- * good -> dormant -> booting ] -> good -> good. - */ -- if (regval == MLXREG_HOTPLUG_HEALTH_MASK) { -- if ((++data->health_cntr == MLXREG_HOTPLUG_RST_CNTR) || -- !priv->after_probe) { -+ if (regval == MLXREG_HOTPLUG_GOOD_HEALTH_MASK) { -+ if (!data->attached) { - /* - * ASIC is in steady state. Connect associated - * device, if configured. -@@ -363,25 +355,17 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, - } else { - if (data->attached) { - /* -- * ASIC health is dropped after ASIC has been -+ * ASIC health is failed after ASIC has been - * in steady state. Disconnect associated - * device, if it has been connected. - */ - mlxreg_hotplug_device_destroy(priv, data); - data->attached = false; - data->health_cntr = 0; -- } else if (regval == MLXREG_HOTPLUG_DOWN_MASK && -- item->cache == MLXREG_HOTPLUG_HEALTH_MASK) { -- /* -- * Decrease counter, if health has been dropped -- * before ASIC reaches the steady state, like: -- * good -> dormant -> booting. -- */ -- data->health_cntr--; - } - } - item->cache = regval; -- -+ack_event: - /* Acknowledge event. */ - ret = regmap_write(priv->regmap, data->reg + - MLXREG_HOTPLUG_EVENT_OFF, 0); -@@ -674,7 +658,6 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) - PTR_ERR(priv->hwmon)); - return PTR_ERR(priv->hwmon); - } -- priv->kobj = &priv->hwmon->kobj; - - /* Perform initial interrupts setup. */ - mlxreg_hotplug_set_irq(priv); -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index e1f9fce..84e17cd 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -83,12 +83,12 @@ - #define MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET 0xe7 - #define MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET 0xe8 - #define MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET 0xe9 --#define MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET 0xea --#define MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET 0xeb --#define MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET 0xec --#define MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET 0xed --#define MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET 0xee --#define MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET 0xef -+#define MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET 0xeb -+#define MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET 0xec -+#define MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET 0xed -+#define MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET 0xee -+#define MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET 0xef -+#define MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET 0xf0 - #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 - #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb - #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda -@@ -1499,21 +1499,21 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { - .callback = mlxplat_dmi_qmb7xx_matched, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -- DMI_MATCH(DMI_PRODUCT_NAME, "QMB7"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MQM87"), - }, - }, - { - .callback = mlxplat_dmi_qmb7xx_matched, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -- DMI_MATCH(DMI_PRODUCT_NAME, "SN37"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN37"), - }, - }, - { - .callback = mlxplat_dmi_qmb7xx_matched, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -- DMI_MATCH(DMI_PRODUCT_NAME, "SN34"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN34"), - }, - }, - { -@@ -1704,8 +1704,8 @@ static int __init mlxplat_init(void) - PLATFORM_DEVID_NONE, NULL, 0, - mlxplat_fan, - sizeof(*mlxplat_fan)); -- if (IS_ERR(priv->pdev_io_regs)) { -- err = PTR_ERR(priv->pdev_io_regs); -+ if (IS_ERR(priv->pdev_fan)) { -+ err = PTR_ERR(priv->pdev_fan); - goto fail_platform_io_regs_register; - } - } -diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h -index b77c7a5..19f5cb61 100644 ---- a/include/linux/platform_data/mlxreg.h -+++ b/include/linux/platform_data/mlxreg.h -@@ -58,15 +58,14 @@ struct mlxreg_hotplug_device { - * struct mlxreg_core_data - attributes control data: - * - * @label: attribute label; -- * @label: attribute register offset; - * @reg: attribute register; - * @mask: attribute access mask; -- * @mode: access mode; - * @bit: attribute effective bit; -+ * @mode: access mode; - * @np - pointer to node platform associated with attribute; - * @hpdev - hotplug device data; - * @health_cntr: dynamic device health indication counter; -- * @attached: true if device has been attached after good helath indication; -+ * @attached: true if device has been attached after good health indication; - */ - struct mlxreg_core_data { - char label[MLXREG_CORE_LABEL_MAX_SIZE]; --- -2.1.4 - diff --git a/patch/0023-platform-x86-mlx-platform-Add-support-for-register-a.patch b/patch/0023-platform-x86-mlx-platform-Add-support-for-register-a.patch deleted file mode 100644 index 19c36a92d8ed..000000000000 --- a/patch/0023-platform-x86-mlx-platform-Add-support-for-register-a.patch +++ /dev/null @@ -1,203 +0,0 @@ -From d73a1884eeb2107b4803650c3dce511bc951ce3e Mon Sep 17 00:00:00 2001 -From: Oleksandr Shamray -Date: Tue, 14 Aug 2018 13:32:40 +0000 -Subject: [PATCH] platform/x86: mlx-platform: Add support for register - CPLD3_VER, RST_CUSE Add NG system type support - -Signed-off-by: Oleksandr Shamray ---- - drivers/hwmon/mlxreg-fan.c | 2 +- - drivers/platform/x86/mlx-platform.c | 126 +++++++++++++++++++++++++++++++++++- - 2 files changed, 125 insertions(+), 3 deletions(-) - -diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c -index de46577..d8fa4be 100644 ---- a/drivers/hwmon/mlxreg-fan.c -+++ b/drivers/hwmon/mlxreg-fan.c -@@ -51,7 +51,7 @@ - */ - #define MLXREG_FAN_GET_RPM(rval, d, s) (DIV_ROUND_CLOSEST(15000000 * 100, \ - ((rval) + (s)) * (d))) --#define MLXREG_FAN_GET_FAULT(val, mask) (!!((val) ^ (mask))) -+#define MLXREG_FAN_GET_FAULT(val, mask) (!((val) ^ (mask))) - #define MLXREG_FAN_PWM_DUTY2STATE(duty) (DIV_ROUND_CLOSEST((duty) * \ - MLXREG_FAN_MAX_STATE, \ - MLXREG_FAN_MAX_DUTY)) -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index 84e17cd..e8782f5 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -49,7 +49,10 @@ - #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 - #define MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET 0x00 - #define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET 0x01 -+#define MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET 0x02 - #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_LED1_OFFSET 0x20 - #define MLXPLAT_CPLD_LPC_REG_LED2_OFFSET 0x21 - #define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET 0x22 -@@ -1101,6 +1104,118 @@ static struct mlxreg_core_platform_data mlxplat_msn21xx_regs_io_data = { - .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_regs_io_data), - }; - -+/* Platform register access for next generation systems families data */ -+static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { -+ { -+ .label = "cpld1_version", -+ .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, -+ .bit = GENMASK(7, 0), -+ .mode = 0444, -+ }, -+ { -+ .label = "cpld2_version", -+ .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, -+ .bit = GENMASK(7, 0), -+ .mode = 0444, -+ }, -+ { -+ .label = "cpld3_version", -+ .reg = MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET, -+ .bit = GENMASK(7, 0), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_long_pb", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(0), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_short_pb", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(1), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_aux_pwr_or_ref", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .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_asic_thermal", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(7), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_comex_pwr_fail", -+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(3), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_voltmon_upgrade_fail", -+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(0), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_system", -+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(1), -+ .mode = 0444, -+ }, -+ { -+ .label = "psu1_on", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(0), -+ .mode = 0200, -+ }, -+ { -+ .label = "psu2_on", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(1), -+ .mode = 0200, -+ }, -+ { -+ .label = "pwr_cycle", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(2), -+ .mode = 0200, -+ }, -+ { -+ .label = "pwr_down", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(3), -+ .mode = 0200, -+ }, -+ { -+ .label = "jtag_enable", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(4), -+ .mode = 0644, -+ }, -+ { -+ .label = "asic_health", -+ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, -+ .mask = MLXPLAT_CPLD_ASIC_MASK, -+ .bit = 1, -+ .mode = 0444, -+ }, -+}; -+ -+static struct mlxreg_core_platform_data mlxplat_default_ng_regs_io_data = { -+ .data = mlxplat_mlxcpld_default_ng_regs_io_data, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_regs_io_data), -+}; -+ - /* Platform FAN default */ - static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { - { -@@ -1208,7 +1323,10 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) - switch (reg) { - case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: - case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET: - case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: -+ 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_LED2_OFFSET: - case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: -@@ -1258,7 +1376,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) - switch (reg) { - case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: - case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET: - case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: -+ 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_LED2_OFFSET: - case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: -@@ -1421,7 +1542,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) - mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data; - mlxplat_hotplug->deferred_nr = - mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; -- mlxplat_led = &mlxplat_default_ng_led_data; -+ mlxplat_led = &mlxplat_msn21xx_led_data; - mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; - - return 1; -@@ -1439,7 +1560,8 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) - mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data; - mlxplat_hotplug->deferred_nr = - mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; -- mlxplat_led = &mlxplat_msn21xx_led_data; -+ mlxplat_led = &mlxplat_default_ng_led_data; -+ mlxplat_regs_io = &mlxplat_default_ng_regs_io_data; - mlxplat_fan = &mlxplat_default_fan_data; - - return 1; --- -2.1.4 - diff --git a/patch/0024-config-mellanox-fan-configuration.patch b/patch/0024-config-mellanox-fan-configuration.patch deleted file mode 100644 index 416916583cfb..000000000000 --- a/patch/0024-config-mellanox-fan-configuration.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 204cb504381c07a62c8a2829f1d3107eed0c133b Mon Sep 17 00:00:00 2001 -From: Oleksandr Shamray -Date: Thu, 13 Sep 2018 14:50:45 +0300 -Subject: [patchV1] config: mellanox fan configuration It adds configuration - flag, used by Mellanox systems: - -SENSORS_MLXREG_FAN=m - -Signed-off-by: Oleksandr Shamray ---- - debian/build/build_amd64_none_amd64/.config | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index 7473276..f39f782 100644 ---- a/debian/build/build_amd64_none_amd64/.config -+++ b/debian/build/build_amd64_none_amd64/.config -@@ -701,6 +701,7 @@ CONFIG_ACPI_EXTLOG=y - # CONFIG_PMIC_OPREGION is not set - # CONFIG_ACPI_CONFIGFS is not set - CONFIG_SFI=y -+CONFIG_SENSORS_MLXREG_FAN=m - - # - # CPU Frequency scaling --- -1.9.1 - diff --git a/patch/0025-net-udp_l3mdev_accept-support.patch b/patch/0025-net-udp_l3mdev_accept-support.patch deleted file mode 100644 index 0c0c4db76a5b..000000000000 --- a/patch/0025-net-udp_l3mdev_accept-support.patch +++ /dev/null @@ -1,306 +0,0 @@ -From 58be55eb5de3a319c0740ba8071440d972c821c3 Mon Sep 17 00:00:00 2001 -From: Harish Venkatraman -Date: Tue, 25 Sep 2018 09:56:25 -0700 -Subject: [PATCH] net: udp_l3mdev_accept support - -From 63a6fff353d01da5a22b72670c434bf12fa0e3b8 Mon Sep 17 00:00:00 2001 -From: Robert Shearman -Date: Thu, 26 Jan 2017 18:02:24 +0000 -Subject: [PATCH] net: Avoid receiving packets with an l3mdev on unbound UDP - sockets - -Packets arriving in a VRF currently are delivered to UDP sockets that -aren't bound to any interface. TCP defaults to not delivering packets -arriving in a VRF to unbound sockets. IP route lookup and socket -transmit both assume that unbound means using the default table and -UDP applications that haven't been changed to be aware of VRFs may not -function correctly in this case since they may not be able to handle -overlapping IP address ranges, or be able to send packets back to the -original sender if required. - -So add a sysctl, udp_l3mdev_accept, to control this behaviour with it -being analgous to the existing tcp_l3mdev_accept, namely to allow a -process to have a VRF-global listen socket. Have this default to off -as this is the behaviour that users will expect, given that there is -no explicit mechanism to set unmodified VRF-unaware application into a -default VRF. - -Signed-off-by: Robert Shearman -Acked-by: David Ahern -Tested-by: David Ahern -Signed-off-by: David S. Miller - ---- - Documentation/networking/ip-sysctl.txt | 7 +++++++ - Documentation/networking/vrf.txt | 7 ++++--- - include/net/netns/ipv4.h | 4 ++++ - net/ipv4/sysctl_net_ipv4.c | 11 +++++++++++ - net/ipv4/udp.c | 27 ++++++++++++++++++++------- - net/ipv6/udp.c | 27 ++++++++++++++++++++------- - 6 files changed, 66 insertions(+), 17 deletions(-) - -diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt -index 3db8c67..7ceeff3 100644 ---- a/Documentation/networking/ip-sysctl.txt -+++ b/Documentation/networking/ip-sysctl.txt -@@ -737,6 +737,13 @@ tcp_challenge_ack_limit - INTEGER - - UDP variables: - -+udp_l3mdev_accept - BOOLEAN -+ Enabling this option allows a "global" bound socket to work -+ across L3 master domains (e.g., VRFs) with packets capable of -+ being received regardless of the L3 domain in which they -+ originated. Only valid when the kernel was compiled with -+ CONFIG_NET_L3_MASTER_DEV. -+ - udp_mem - vector of 3 INTEGERs: min, pressure, max - Number of pages allowed for queueing by all UDP sockets. - -diff --git a/Documentation/networking/vrf.txt b/Documentation/networking/vrf.txt -index 755dab8..3918dae 100644 ---- a/Documentation/networking/vrf.txt -+++ b/Documentation/networking/vrf.txt -@@ -98,10 +98,11 @@ VRF device: - - or to specify the output device using cmsg and IP_PKTINFO. - --TCP services running in the default VRF context (ie., not bound to any VRF --device) can work across all VRF domains by enabling the tcp_l3mdev_accept --sysctl option: -+TCP & UDP services running in the default VRF context (ie., not bound -+to any VRF device) can work across all VRF domains by enabling the -+tcp_l3mdev_accept and udp_l3mdev_accept sysctl options: - sysctl -w net.ipv4.tcp_l3mdev_accept=1 -+ sysctl -w net.ipv4.udp_l3mdev_accept=1 - - netfilter rules on the VRF device can be used to limit access to services - running in the default VRF context as well. -diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h -index 7adf438..3917764 100644 ---- a/include/net/netns/ipv4.h -+++ b/include/net/netns/ipv4.h -@@ -111,6 +111,10 @@ struct netns_ipv4 { - int sysctl_tcp_fin_timeout; - unsigned int sysctl_tcp_notsent_lowat; - -+#ifdef CONFIG_NET_L3_MASTER_DEV -+ int sysctl_udp_l3mdev_accept; -+#endif -+ - int sysctl_igmp_max_memberships; - int sysctl_igmp_max_msf; - int sysctl_igmp_llm_reports; -diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c -index 566cfc5..2006032 100644 ---- a/net/ipv4/sysctl_net_ipv4.c -+++ b/net/ipv4/sysctl_net_ipv4.c -@@ -971,6 +971,17 @@ static struct ctl_table ipv4_net_table[] = { - .extra2 = &one, - }, - #endif -+#ifdef CONFIG_NET_L3_MASTER_DEV -+ { -+ .procname = "udp_l3mdev_accept", -+ .data = &init_net.ipv4.sysctl_udp_l3mdev_accept, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec_minmax, -+ .extra1 = &zero, -+ .extra2 = &one, -+ }, -+#endif - { } - }; - -diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c -index aa2a20e..7229028 100644 ---- a/net/ipv4/udp.c -+++ b/net/ipv4/udp.c -@@ -134,6 +134,17 @@ EXPORT_SYMBOL(udp_memory_allocated); - #define MAX_UDP_PORTS 65536 - #define PORTS_PER_CHAIN (MAX_UDP_PORTS / UDP_HTABLE_SIZE_MIN) - -+/* IPCB reference means this can not be used from early demux */ -+static bool udp_lib_exact_dif_match(struct net *net, struct sk_buff *skb) -+{ -+#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) -+ if (!net->ipv4.sysctl_udp_l3mdev_accept && -+ skb && ipv4_l3mdev_skb(IPCB(skb)->flags)) -+ return true; -+#endif -+ return false; -+} -+ - static int udp_lib_lport_inuse(struct net *net, __u16 num, - const struct udp_hslot *hslot, - unsigned long *bitmap, -@@ -391,7 +402,8 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum) - - static int compute_score(struct sock *sk, struct net *net, - __be32 saddr, __be16 sport, -- __be32 daddr, unsigned short hnum, int dif) -+ __be32 daddr, unsigned short hnum, int dif, -+ bool exact_dif) - { - int score; - struct inet_sock *inet; -@@ -422,7 +434,7 @@ static int compute_score(struct sock *sk, struct net *net, - score += 4; - } - -- if (sk->sk_bound_dev_if) { -+ if (sk->sk_bound_dev_if || exact_dif) { - if (sk->sk_bound_dev_if != dif) - return -1; - score += 4; -@@ -447,7 +459,7 @@ static u32 udp_ehashfn(const struct net *net, const __be32 laddr, - /* called with rcu_read_lock() */ - static struct sock *udp4_lib_lookup2(struct net *net, - __be32 saddr, __be16 sport, -- __be32 daddr, unsigned int hnum, int dif, -+ __be32 daddr, unsigned int hnum, int dif, bool exact_dif, - struct udp_hslot *hslot2, - struct sk_buff *skb) - { -@@ -459,7 +471,7 @@ static struct sock *udp4_lib_lookup2(struct net *net, - badness = 0; - udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { - score = compute_score(sk, net, saddr, sport, -- daddr, hnum, dif); -+ daddr, hnum, dif, exact_dif); - if (score > badness) { - reuseport = sk->sk_reuseport; - if (reuseport) { -@@ -494,6 +506,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, - unsigned short hnum = ntohs(dport); - unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); - struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; -+ bool exact_dif = udp_lib_exact_dif_match(net, skb); - int score, badness, matches = 0, reuseport = 0; - u32 hash = 0; - -@@ -506,7 +519,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, - - result = udp4_lib_lookup2(net, saddr, sport, - daddr, hnum, dif, -- hslot2, skb); -+ exact_dif, hslot2, skb); - if (!result) { - unsigned int old_slot2 = slot2; - hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum); -@@ -521,7 +534,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, - - result = udp4_lib_lookup2(net, saddr, sport, - daddr, hnum, dif, -- hslot2, skb); -+ exact_dif, hslot2, skb); - } - return result; - } -@@ -530,7 +543,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, - badness = 0; - sk_for_each_rcu(sk, &hslot->head) { - score = compute_score(sk, net, saddr, sport, -- daddr, hnum, dif); -+ daddr, hnum, dif, exact_dif); - if (score > badness) { - reuseport = sk->sk_reuseport; - if (reuseport) { -diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c -index 4db5f54..1317d2f 100644 ---- a/net/ipv6/udp.c -+++ b/net/ipv6/udp.c -@@ -55,6 +55,16 @@ - #include - #include "udp_impl.h" - -+static bool udp6_lib_exact_dif_match(struct net *net, struct sk_buff *skb) -+{ -+#if defined(CONFIG_NET_L3_MASTER_DEV) -+ if (!net->ipv4.sysctl_udp_l3mdev_accept && -+ skb && ipv6_l3mdev_skb(IP6CB(skb)->flags)) -+ return true; -+#endif -+ return false; -+} -+ - static u32 udp6_ehashfn(const struct net *net, - const struct in6_addr *laddr, - const u16 lport, -@@ -118,7 +128,7 @@ static void udp_v6_rehash(struct sock *sk) - static int compute_score(struct sock *sk, struct net *net, - const struct in6_addr *saddr, __be16 sport, - const struct in6_addr *daddr, unsigned short hnum, -- int dif) -+ int dif, bool exact_dif) - { - int score; - struct inet_sock *inet; -@@ -149,7 +159,7 @@ static int compute_score(struct sock *sk, struct net *net, - score++; - } - -- if (sk->sk_bound_dev_if) { -+ if (sk->sk_bound_dev_if || exact_dif) { - if (sk->sk_bound_dev_if != dif) - return -1; - score++; -@@ -165,7 +175,7 @@ static int compute_score(struct sock *sk, struct net *net, - static struct sock *udp6_lib_lookup2(struct net *net, - const struct in6_addr *saddr, __be16 sport, - const struct in6_addr *daddr, unsigned int hnum, int dif, -- struct udp_hslot *hslot2, -+ bool exact_dif, struct udp_hslot *hslot2, - struct sk_buff *skb) - { - struct sock *sk, *result; -@@ -176,7 +186,7 @@ static struct sock *udp6_lib_lookup2(struct net *net, - badness = -1; - udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { - score = compute_score(sk, net, saddr, sport, -- daddr, hnum, dif); -+ daddr, hnum, dif, exact_dif); - if (score > badness) { - reuseport = sk->sk_reuseport; - if (reuseport) { -@@ -212,6 +222,7 @@ struct sock *__udp6_lib_lookup(struct net *net, - unsigned short hnum = ntohs(dport); - unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); - struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; -+ bool exact_dif = udp6_lib_exact_dif_match(net, skb); - int score, badness, matches = 0, reuseport = 0; - u32 hash = 0; - -@@ -223,7 +234,7 @@ struct sock *__udp6_lib_lookup(struct net *net, - goto begin; - - result = udp6_lib_lookup2(net, saddr, sport, -- daddr, hnum, dif, -+ daddr, hnum, dif, exact_dif, - hslot2, skb); - if (!result) { - unsigned int old_slot2 = slot2; -@@ -239,7 +250,8 @@ struct sock *__udp6_lib_lookup(struct net *net, - - result = udp6_lib_lookup2(net, saddr, sport, - daddr, hnum, dif, -- hslot2, skb); -+ exact_dif, hslot2, -+ skb); - } - return result; - } -@@ -247,7 +259,8 @@ struct sock *__udp6_lib_lookup(struct net *net, - result = NULL; - badness = -1; - sk_for_each_rcu(sk, &hslot->head) { -- score = compute_score(sk, net, saddr, sport, daddr, hnum, dif); -+ score = compute_score(sk, net, saddr, sport, daddr, hnum, dif, -+ exact_dif); - if (score > badness) { - reuseport = sk->sk_reuseport; - if (reuseport) { --- -2.7.4 - diff --git a/patch/0026-mlxsw-qsfp_sysfs-Support-extended-port-numbers-for-S.patch b/patch/0026-mlxsw-qsfp_sysfs-Support-extended-port-numbers-for-S.patch deleted file mode 100644 index 0783cffb8efa..000000000000 --- a/patch/0026-mlxsw-qsfp_sysfs-Support-extended-port-numbers-for-S.patch +++ /dev/null @@ -1,75 +0,0 @@ -From c6a95c1ea4518a19cf46e8d0c844ae980df4c5da Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Thu, 3 Jan 2019 18:05:01 +0000 -Subject: [PATCH v1] mlxsw: qsfp_sysfs: Support extended port numbers for - Spectrume2 chip - -Add system type detection through DMI table in order to distinct between -the systems supporting up to 64 and up to 128 ports. - -Signed-off-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c | 19 +++++++++++++++++-- - 1 file changed, 17 insertions(+), 2 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -index c072b91..bee2a08 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -@@ -47,7 +47,7 @@ - #define MLXSW_QSFP_SUB_PAGE_NUM 3 - #define MLXSW_QSFP_SUB_PAGE_SIZE 48 - #define MLXSW_QSFP_LAST_SUB_PAGE_SIZE 32 --#define MLXSW_QSFP_MAX_NUM 64 -+#define MLXSW_QSFP_MAX_NUM 128 - #define MLXSW_QSFP_MIN_REQ_LEN 4 - #define MLXSW_QSFP_STATUS_VALID_TIME (120 * HZ) - #define MLXSW_QSFP_MAX_CPLD_NUM 3 -@@ -88,6 +88,7 @@ struct mlxsw_qsfp { - }; - - static int mlxsw_qsfp_cpld_num = MLXSW_QSFP_MIN_CPLD_NUM; -+static int mlxsw_qsfp_num = MLXSW_QSFP_MAX_NUM / 2; - - static int - mlxsw_qsfp_query_module_eeprom(struct mlxsw_qsfp *mlxsw_qsfp, u8 index, -@@ -238,6 +239,13 @@ static int mlxsw_qsfp_dmi_set_cpld_num(const struct dmi_system_id *dmi) - return 1; - }; - -+static int mlxsw_qsfp_dmi_set_qsfp_num(const struct dmi_system_id *dmi) -+{ -+ mlxsw_qsfp_num = MLXSW_QSFP_MAX_NUM; -+ -+ return 1; -+}; -+ - static const struct dmi_system_id mlxsw_qsfp_dmi_table[] = { - { - .callback = mlxsw_qsfp_dmi_set_cpld_num, -@@ -253,6 +261,13 @@ static const struct dmi_system_id mlxsw_qsfp_dmi_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"), - }, - }, -+ { -+ .callback = mlxsw_qsfp_dmi_set_qsfp_num, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN37"), -+ }, -+ }, - { } - }; - MODULE_DEVICE_TABLE(dmi, mlxsw_qsfp_dmi_table); -@@ -283,7 +298,7 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, - mlxsw_qsfp->bus_info = mlxsw_bus_info; - mlxsw_bus_info->dev->platform_data = mlxsw_qsfp; - -- for (i = 1; i <= MLXSW_QSFP_MAX_NUM; i++) { -+ for (i = 1; i <= mlxsw_qsfp_num; i++) { - mlxsw_reg_pmlp_pack(pmlp_pl, i); - err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(pmlp), - pmlp_pl); --- -2.1.4 - diff --git a/patch/0027-mlxsw-thermal-monitoring-amendments.patch b/patch/0027-mlxsw-thermal-monitoring-amendments.patch deleted file mode 100644 index 9abbc574e9c6..000000000000 --- a/patch/0027-mlxsw-thermal-monitoring-amendments.patch +++ /dev/null @@ -1,4072 +0,0 @@ -From e663de0d7c184c605db27519e3f23e9ec835d845 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Fri, 14 Dec 2018 01:38:16 +0000 -Subject: [PATCH mellanox 4.20-4.21 backport] mlxsw thermal monitoring - amendments - -This patchset extends mlxsw hwmon and thermal with module temperature -attributes (input, fault, critical and emergency thresholds) and adds -hwmon fault for FAN. - -New hwmon attributes, such as FAN faults, port temperature fault will -improve system monitoring abilities. - -Introduction of per QSFP module thermal zones - -The motivation is: -- To support multiport network switch equipped with a big number of - temperature sensors (128+) and with a single cooling device. -- Provide a user interface that will allow it to optimize thermal - monitoring flow. - -When multiple sensors are mapped to the same cooling device, the -cooling device should be set according the worst sensor from the -sensors associated with this cooling device. The system shall implement -cooling control based on thermal monitoring of the critical temperature -sensors. In many cases, in order to achieve an optimal thermal -solution, the user involvement is reqiered. - -Add support for ethtool interface to allow reading QSFP/SFP modules -content through 'ethtool -m' command. - -It adds to sysfs the next additional attributes: -per each port: -- tempX_crit (reading from Management Cable Info Access Register); -- tempX_fault (reading Management Temperature Bulk Register); -- tempX_emergency (reading from Management Cable Info Access Register); -- tempX_input (reading Management Temperature Bulk Register); - where X is from 2 (1 is for ASIC ambient temperature) to the number - of ports equipped within the system. -per each tachometer: -- fanY_fault (reading from Fan Out of Range Event Register); - where Y is from 1 to the number of rotors (FANs) equipped within the - system. -Temperature input, critical and emergency attributes are supposed to be -exposed from sensors utilities of lm-sensors package, like: -front panel 001: +51.0C (highest = +52.0C) -front panel 002: +62.0C (crit = +70.0C, emerg = +80.0C) -... -front panel 055: +60.0C (crit = +70.0C, emerg = +80.0C) - -Add definitions for new registers: -- CPLD3 version - next generation systems are equipped with three CPLD; -- Two reset cause registers, which store the system reset reason (like - system failures, upgrade failures and so on; - -The below are the list of the commits included in patchset. - -mlxsw: spectrum: Move QSFP EEPROM definitons to common location - -Move QSFP EEPROM definitions to common location from the spectrum driver -in order to make them available for other mlxsw modules. They are common -for all kind of chips and have relation to SFF specifications 8024, 8436, -8472, 8636, rather than to chip type. - -Signed-off-by: Vadim Pasternak -Reviewed-by: Jiri Pirko ---- - -mlxsw: reg: Add Management Temperature Bulk Register - -Add MTBR (Management Temperature Bulk Register), which is used for port -temperature reading in a bulk mode. - -Signed-off-by: Vadim Pasternak -Reviewed-by: Jiri Pirko ---- - -mlxsw: reg: Add Fan Out of Range Event Register - -Add FORE (Fan Out of Range Event Register), which is used for Fan fault -reading. - -Signed-off-by: Vadim Pasternak ---- - -mlxsw: core: Add core environment module for QSFP module temperature thresholds reading - -Add new core_env module to allow module temperature warning and critical -thresholds reading. - -New internal API reads the temperature thresholds from the modules, which -are equipped with the thermal sensor. These thresholds are to be exposed -by hwmon module and to be used by thermal module. - -Signed-off-by: Vadim Pasternak -Reviewed-by: Jiri Pirko ---- - -mlxsw: core: Set different thermal polling time based on bus frequency capability - -Add low frequency bus capability in order to allow core functionality -separation based on bus type. Driver could run over PCIe, which is -considered as high frequency bus or I2C , which is considered as low -frequency bus. In the last case time setting, for example, for thermal -polling interval, should be increased. - -Use different thermal monitoring based on bus type. -For I2C bus time is set to 20 seconds, while for PCIe 1 second polling -interval is used. - -Signed-off-by: Vadim Pasternak -Reviewed-by: Jiri Pirko ---- - -mlxsw: core: Modify thermal zone definition - -Modify thermal zone trip points setting for better alignment with -system thermal requirement. -Add hysteresis thresholds for thermal trips are added in order to avoid -throttling around thermal trip point. If hysteresis temperature is not -considered PWM can have side effect of flip up/down on thermal trip -point boundary. - -Signed-off-by: Vadim Pasternak -Reviewed-by: Jiri Pirko ---- - -mlxsw: core: Replace thermal temperature trips with defines - -Replace thermal hardcoded temperature trips values with defines. - -Signed-off-by: Vadim Pasternak -Reviewed-by: Jiri Pirko ---- - -mlxsw: core: Extend cooling device with cooling levels - -Extend cooling device with cooling levels vector to allow more -flexibility of PWM setting. -Thermal zone algorithm operates with the numerical states for PWM -setting. Each state is the index, defined in range from 0 to 10 and -it's mapped to the relevant duty cycle value, which is written to PWM -controller. With the current definition fan speed is set to 0% for -state 0, 10% for state 1, and so on up to 100% for the maximum state -10. -Some systems have limitation for the PWM speed minimum. For such -systems PWM setting speed to 0% will just disable the ability to -increase speed anymore and such device will be stall on zero speed. -Cooling levels allow to configure state vector according to the -particular system requirements. For example, if PWM speed is not -allowed to be below 30%, cooling levels could be configured as 30%, -30%, 30%, 30%, 40%, 50% and so on. - -Signed-off-by: Vadim Pasternak -Reviewed-by: Jiri Pirko ---- - -mlxsw: core: Rename cooling device - -Rename cooling device from "Fan" to "mlxsw_fan". -Name "Fan" is too common name, and such name is misleading, while it's -interpreted by user. -For example name "Fan" could be used by ACPI. - -Signed-off-by: Vadim Pasternak -Reviewed-by: Jiri Pirko ---- - -mlxsw: core: Extend hwmon interface with fan fault attribute - -Add new fan hwmon attribute for exposing fan faults (fault indication -is reading from Fan Out of Range Event Register). - -Signed-off-by: Vadim Pasternak -Reviewed-by: Jiri Pirko ---- - -mlxsw: core: Extend hwmon interface with QSFP module temperature attributes - -Add new attributes to hwmon object for exposing QSFP module temperature -input, fault indication, critical and emergency thresholds. -Temperature input and fault indication are reading from Management -Temperature Bulk Register. Temperature thresholds are reading from -Management Cable Info Access Register. - -Signed-off-by: Vadim Pasternak -Reviewed-by: Jiri Pirko ---- - -mlxsw: core: thermal zone binding to an external cooling device - -Allow thermal zone binding to an external cooling device from the -cooling devices white list. -It provides support for Mellanox next generation systems on which -cooling device logic is not controlled through the switch registers. - -Signed-off-by: Vadim Pasternak -Reviewed-by: Jiri Pirko ---- - -mlxsw: core: Add QSFP module temperature label attribute to hwmon - -Add label attribute to hwmon object for exposing QSFP module's -temperature sensors name. Modules are labeld as "front panel xxx". -It will be exposed by utilities sensors as: -front panel 001: +0.0C (crit = +0.0C, emerg = +0.0C) -.. -front panel 020: +31.0C (crit = +70.0C, emerg = +80.0C) -.. -front panel 056: +41.0C (crit = +70.0C, emerg = +80.0C) - -Signed-off-by: Vadim Pasternak -Reviewed-by: Jiri Pirko - -mlxsw: core: Extend thermal module with per QSFP module thermal zones - -Add a dedicated thermal zone for each QSFP/SFP module. -Implement per QSFP/SFP module thermal zone for mlxsw based hardware. -Use module temperature sensor and module warning and critical -temperature thresholds, obtained through the mlxsw hardware for the -thermal zone current and trips temperatures. -Bind a cooling device to all of these thermal zones for fan speed -control. -Set thermal zone governor to user space. -Since all these zones share the same cooling device, it will allow to -user to take most suitable thermal control decision and to avoid -competing between the thermal zones for the cooling device control -and to avoid collisions between thermal zones, when one of them could -require increasing of the cooling device speed, while another one could -require its reducing. - -Signed-off-by: Vadim Pasternak ---- - -mlxsw: core: Extend thermal module with highest thermal zone detection - -Add the detection of highest thermal zone and user notification about -which thermal zone currently has a highest score. It'll allow to user -to make an optimal decision about the thermal control management, in -case user intends to be involved in thermal monitoring process. -Otherwise the thermal flow is not affected. - -Thermal zone score is represented by 32 bits unsigned integer and -calculated according to the next formula: -For T < TZ, where t from {normal trip = 0, high trip = 1, hot -trip = 2, critical = 3}: -TZ score = (T + (TZ - T) / 2) / (TZ - T) * 256 ** j; -Highest thermal zone score s is set as MAX(TZscore); -Following this formula, if TZ is in trip point higher than TZ, -the higher score is to be always assigned to TZ. - -For two thermal zones located at the same kind of trip point, the higher -score will be assigned to the zone, which closer to the next trip point. -Thus, the highest score will always be assigned objectively to the hottest -thermal zone. - -User is notified through udev event in case new thermal zone is reached -the highest score. - -Signed-off-by: Vadim Pasternak ---- - -mlxsw: minimal: Add support for ethtool interface - -Add support for ethtool interface to allow reading QSFP/SFP modules -content through 'ethtool -m' command. -The minimal driver is chip independent, uses I2C bus for chip access. -Its purpose is to support chassis management on the systems equipped -with Mellanox network switch device. For example from BMC (Board -Management Controller) device. -The patch allows to obtain QSFP/SFP module info through ethtool. - -Signed-off-by: Vadim Pasternak ---- - -platform/x86: mlx-platform: Add support for fan direction register - -Provide support for the fan direction register. -This register shows configuration for system fans direction, which could -be forward or reversed. -For forward direction - relevant bit is set 0; -For reversed direction - relevant bit is set 1. - -Signed-off-by: Vadim Pasternak ---- - -platform_data/mlxreg: Document fixes for core platform data - -Remove "led" from the description, since the structure -"mlxreg_core_platform_data" is used not only for led data. - -Signed-off-by: Vadim Pasternak ---- - -platform_data/mlxreg: Add capability field to core platform data - -Add capability field to "mlxreg_core_platform_data" structure. -The purpose of this register is to provide additional info to platform -driver through the atribute related capability register. - -Signed-off-by: Vadim Pasternak ---- - -platform/x86: mlx-platform: Add support for fan capability registers - -Provide support for the fan capability registers for next generation -systems of types MQM87xx, MSN34xx, MSN37xx. These new registers -provide configuration for tachometers connectivity, fan drawers -connectvivity and tachometer speed divider. -Use these registers for next generation led, fan and hotplug structures -in order to distinct between the systems which have minor configuration -differences. This reduces the amount of code used to describe such -systems. - -Signed-off-by: Vadim Pasternak ---- - -platform/x86: mlx-platform: Add support for new VMOD0007 board name - -Add support for new Mellanox system type MSN3700C, which is -a cost reduction flavor of MSN37 system?s class. - -Signed-off-by: Vadim Pasternak ---- - -hwmon: (mlxreg-fan) Add support for fan capability registers - -Add support for fan capability registers in order to distinct between -the systems which have minor fan configuration differences. This -reduces the amount of code used to describe such systems. -The capability registers provides system specific information about the -number of physically connected tachometers and system specific fan -speed scale parameter. -For example one system can be equipped with twelve fan tachometers, -while the other with for example, eight or six. Or one system should -use default fan speed divider value, while the other has a scale -parameter defined in hardware, which should be used for divider -setting. -Reading this information from the capability registers allows to use the -same fan structure for the systems with the such differences. - -Signed-off-by: Vadim Pasternak ---- - -leds: mlxreg: Add support for capability register - -Add support for capability register in order to distinct between the -systems which have minor LED configuration differences. This reduces -the amount of code used to describe such systems. -For example one system can be equipped with six LED, while the other -with only four. Reading this information from the capability registers -allows to use the same LED structure for such systems. - -Signed-off-by: Vadim Pasternak ---- ---- - drivers/hwmon/mlxreg-fan.c | 78 ++- - drivers/leds/leds-mlxreg.c | 55 +- - drivers/net/ethernet/mellanox/mlxsw/Makefile | 2 +- - drivers/net/ethernet/mellanox/mlxsw/core.h | 14 + - drivers/net/ethernet/mellanox/mlxsw/core_env.c | 238 +++++++ - drivers/net/ethernet/mellanox/mlxsw/core_env.h | 17 + - drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 337 +++++++-- - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 761 +++++++++++++++++++-- - drivers/net/ethernet/mellanox/mlxsw/i2c.c | 43 +- - drivers/net/ethernet/mellanox/mlxsw/i2c.h | 35 +- - drivers/net/ethernet/mellanox/mlxsw/minimal.c | 356 ++++++++-- - drivers/net/ethernet/mellanox/mlxsw/reg.h | 139 +++- - drivers/platform/mellanox/mlxreg-hotplug.c | 23 +- - drivers/platform/mellanox/mlxreg-io.c | 4 +- - drivers/platform/x86/mlx-platform.c | 138 +++- - include/linux/platform_data/mlxreg.h | 6 +- - include/linux/sfp.h | 564 +++++++++++++++ - 17 files changed, 2506 insertions(+), 304 deletions(-) - create mode 100644 drivers/net/ethernet/mellanox/mlxsw/core_env.c - create mode 100644 drivers/net/ethernet/mellanox/mlxsw/core_env.h - create mode 100644 include/linux/sfp.h - -diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c -index d8fa4be..11388c5 100644 ---- a/drivers/hwmon/mlxreg-fan.c -+++ b/drivers/hwmon/mlxreg-fan.c -@@ -27,7 +27,10 @@ - #define MLXREG_FAN_SPEED_MAX (MLXREG_FAN_MAX_STATE * 2) - #define MLXREG_FAN_SPEED_MIN_LEVEL 2 /* 20 percent */ - #define MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF 44 --#define MLXREG_FAN_TACHO_DIVIDER_DEF 1132 -+#define MLXREG_FAN_TACHO_DIVIDER_MIN 283 -+#define MLXREG_FAN_TACHO_DIVIDER_DEF (MLXREG_FAN_TACHO_DIVIDER_MIN \ -+ * 4) -+#define MLXREG_FAN_TACHO_DIVIDER_SCALE_MAX 32 - /* - * FAN datasheet defines the formula for RPM calculations as RPM = 15/t-high. - * The logic in a programmable device measures the time t-high by sampling the -@@ -51,7 +54,7 @@ - */ - #define MLXREG_FAN_GET_RPM(rval, d, s) (DIV_ROUND_CLOSEST(15000000 * 100, \ - ((rval) + (s)) * (d))) --#define MLXREG_FAN_GET_FAULT(val, mask) (!((val) ^ (mask))) -+#define MLXREG_FAN_GET_FAULT(val, mask) ((val) == (mask)) - #define MLXREG_FAN_PWM_DUTY2STATE(duty) (DIV_ROUND_CLOSEST((duty) * \ - MLXREG_FAN_MAX_STATE, \ - MLXREG_FAN_MAX_DUTY)) -@@ -360,12 +363,57 @@ static const struct thermal_cooling_device_ops mlxreg_fan_cooling_ops = { - .set_cur_state = mlxreg_fan_set_cur_state, - }; - -+static int mlxreg_fan_connect_verify(struct mlxreg_fan *fan, -+ struct mlxreg_core_data *data, -+ bool *connected) -+{ -+ u32 regval; -+ int err; -+ -+ err = regmap_read(fan->regmap, data->capability, ®val); -+ if (err) { -+ dev_err(fan->dev, "Failed to query capability register 0x%08x\n", -+ data->capability); -+ return err; -+ } -+ -+ *connected = (regval & data->bit) ? true : false; -+ -+ return 0; -+} -+ -+static int mlxreg_fan_speed_divider_get(struct mlxreg_fan *fan, -+ struct mlxreg_core_data *data) -+{ -+ u32 regval; -+ int err; -+ -+ err = regmap_read(fan->regmap, data->capability, ®val); -+ if (err) { -+ dev_err(fan->dev, "Failed to query capability register 0x%08x\n", -+ data->capability); -+ return err; -+ } -+ -+ /* -+ * Set divider value according to the capability register, in case it -+ * contains valid value. Otherwise use default value. The purpose of -+ * this validation is to protect against the old hardware, in which -+ * this register can be un-initialized. -+ */ -+ if (regval > 0 && regval <= MLXREG_FAN_TACHO_DIVIDER_SCALE_MAX) -+ fan->divider = regval * MLXREG_FAN_TACHO_DIVIDER_MIN; -+ -+ return 0; -+} -+ - static int mlxreg_fan_config(struct mlxreg_fan *fan, - struct mlxreg_core_platform_data *pdata) - { - struct mlxreg_core_data *data = pdata->data; -- bool configured = false; -+ bool configured = false, connected = false; - int tacho_num = 0, i; -+ int err; - - fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF; - fan->divider = MLXREG_FAN_TACHO_DIVIDER_DEF; -@@ -376,6 +424,18 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, - data->label); - return -EINVAL; - } -+ -+ if (data->capability) { -+ err = mlxreg_fan_connect_verify(fan, data, -+ &connected); -+ if (err) -+ return err; -+ if (!connected) { -+ tacho_num++; -+ continue; -+ } -+ } -+ - fan->tacho[tacho_num].reg = data->reg; - fan->tacho[tacho_num].mask = data->mask; - fan->tacho[tacho_num++].connected = true; -@@ -394,13 +454,19 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, - return -EINVAL; - } - /* Validate that conf parameters are not zeros. */ -- if (!data->mask || !data->bit) { -+ if (!data->mask && !data->bit && !data->capability) { - dev_err(fan->dev, "invalid conf entry params: %s\n", - data->label); - return -EINVAL; - } -- fan->samples = data->mask; -- fan->divider = data->bit; -+ if (data->capability) { -+ err = mlxreg_fan_speed_divider_get(fan, data); -+ if (err) -+ return err; -+ } else { -+ fan->samples = data->mask; -+ fan->divider = data->bit; -+ } - configured = true; - } else { - dev_err(fan->dev, "invalid label: %s\n", data->label); -diff --git a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c -index 036c214..2db2000 100644 ---- a/drivers/leds/leds-mlxreg.c -+++ b/drivers/leds/leds-mlxreg.c -@@ -1,35 +1,7 @@ --/* -- * Copyright (c) 2017 Mellanox Technologies. All rights reserved. -- * Copyright (c) 2017 Vadim Pasternak -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. 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. -- * 3. Neither the names of the copyright holders nor the names of its -- * contributors may be used to endorse or promote products derived from -- * this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * 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. -- */ -+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -+// -+// Copyright (c) 2018 Mellanox Technologies. All rights reserved. -+// Copyright (c) 2018 Vadim Pasternak - - #include - #include -@@ -217,6 +189,7 @@ static int mlxreg_led_config(struct mlxreg_led_priv_data *priv) - struct mlxreg_led_data *led_data; - struct led_classdev *led_cdev; - int brightness; -+ u32 regval; - int i; - int err; - -@@ -226,6 +199,17 @@ static int mlxreg_led_config(struct mlxreg_led_priv_data *priv) - if (!led_data) - return -ENOMEM; - -+ if (data->capability) { -+ err = regmap_read(led_pdata->regmap, data->capability, -+ ®val); -+ if (err) { -+ dev_err(&priv->pdev->dev, "Failed to query capability register\n"); -+ return err; -+ } -+ if (!(regval & data->bit)) -+ continue; -+ } -+ - led_cdev = &led_data->led_cdev; - led_data->data_parent = priv; - if (strstr(data->label, "red") || -@@ -295,16 +279,9 @@ static int mlxreg_led_remove(struct platform_device *pdev) - return 0; - } - --static const struct of_device_id mlxreg_led_dt_match[] = { -- { .compatible = "mellanox,leds-mlxreg" }, -- { }, --}; --MODULE_DEVICE_TABLE(of, mlxreg_led_dt_match); -- - static struct platform_driver mlxreg_led_driver = { - .driver = { - .name = "leds-mlxreg", -- .of_match_table = of_match_ptr(mlxreg_led_dt_match), - }, - .probe = mlxreg_led_probe, - .remove = mlxreg_led_remove, -diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile -index b58ea1b..c62ba64 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/Makefile -+++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile -@@ -1,5 +1,5 @@ - obj-$(CONFIG_MLXSW_CORE) += mlxsw_core.o --mlxsw_core-objs := core.o -+mlxsw_core-objs := core.o core_env.o - mlxsw_core-$(CONFIG_MLXSW_CORE_HWMON) += core_hwmon.o - mlxsw_core-$(CONFIG_MLXSW_CORE_THERMAL) += core_thermal.o - mlxsw_core-$(CONFIG_MLXSW_CORE_QSFP) += qsfp_sysfs.o -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h -index ffaacc9..4fb104e 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h -@@ -63,6 +63,13 @@ struct mlxsw_driver; - struct mlxsw_bus; - struct mlxsw_bus_info; - -+#define MLXSW_PORT_MAX_PORTS_DEFAULT 0x40 -+static inline unsigned int -+mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core) -+{ -+ return MLXSW_PORT_MAX_PORTS_DEFAULT; -+} -+ - void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core); - - int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver); -@@ -161,6 +168,8 @@ mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port) - return mlxsw_core_port; - } - -+int mlxsw_core_port_get_phys_port_name(struct mlxsw_core *mlxsw_core, -+ u8 local_port, char *name, size_t len); - int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, - struct mlxsw_core_port *mlxsw_core_port, u8 local_port, - struct net_device *dev, bool split, u32 split_group); -@@ -331,6 +340,7 @@ struct mlxsw_bus_info { - } fw_rev; - u8 vsd[MLXSW_CMD_BOARDINFO_VSD_LEN]; - u8 psid[MLXSW_CMD_BOARDINFO_PSID_LEN]; -+ u8 low_frequency; - }; - - struct mlxsw_hwmon; -@@ -351,6 +361,10 @@ static inline int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, - return 0; - } - -+static inline void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon) -+{ -+} -+ - #endif - - struct mlxsw_thermal; -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c -new file mode 100644 -index 0000000..7a15e93 ---- /dev/null -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c -@@ -0,0 +1,238 @@ -+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 -+/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ -+ -+#include -+#include -+ -+#include "core.h" -+#include "core_env.h" -+#include "item.h" -+#include "reg.h" -+ -+static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id, -+ bool *qsfp) -+{ -+ char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE]; -+ char mcia_pl[MLXSW_REG_MCIA_LEN]; -+ 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); -+ err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); -+ if (err) -+ return err; -+ mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp); -+ ident = eeprom_tmp[0]; -+ switch (ident) { -+ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: -+ *qsfp = false; -+ break; -+ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: /* fall-through */ -+ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */ -+ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: /* fall-through */ -+ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD: -+ *qsfp = true; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int -+mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, -+ u16 offset, u16 size, void *data, -+ unsigned int *p_read_size) -+{ -+ char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE]; -+ char mcia_pl[MLXSW_REG_MCIA_LEN]; -+ u16 i2c_addr; -+ int status; -+ int err; -+ -+ size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE); -+ -+ if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH && -+ offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) -+ /* Cross pages read, read until offset 256 in low page */ -+ size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset; -+ -+ i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW; -+ if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) { -+ i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH; -+ offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH; -+ } -+ -+ mlxsw_reg_mcia_pack(mcia_pl, module, 0, 0, offset, size, i2c_addr); -+ -+ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); -+ if (err) -+ return err; -+ -+ status = mlxsw_reg_mcia_status_get(mcia_pl); -+ if (status) -+ return -EIO; -+ -+ mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp); -+ memcpy(data, eeprom_tmp, size); -+ *p_read_size = size; -+ -+ return 0; -+} -+ -+int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, -+ int off, int *temp) -+{ -+ char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE]; -+ union { -+ u8 buf[MLXSW_REG_MCIA_TH_ITEM_SIZE]; -+ u16 temp; -+ } temp_thresh; -+ char mcia_pl[MLXSW_REG_MCIA_LEN] = {0}; -+ char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; -+ u16 module_temp; -+ bool qsfp; -+ int err; -+ -+ mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, -+ 1); -+ err = mlxsw_reg_query(core, MLXSW_REG(mtbr), mtbr_pl); -+ if (err) -+ return err; -+ -+ /* Don't read temperature thresholds for module with no valid info. */ -+ mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &module_temp, NULL); -+ switch (module_temp) { -+ case MLXSW_REG_MTBR_BAD_SENS_INFO: /* fall-through */ -+ case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ -+ case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ -+ case MLXSW_REG_MTBR_INDEX_NA: -+ *temp = 0; -+ return 0; -+ default: -+ /* Do not consider thresholds for zero temperature. */ -+ if (!MLXSW_REG_MTMP_TEMP_TO_MC(module_temp)) { -+ *temp = 0; -+ return 0; -+ } -+ break; -+ } -+ -+ /* Read Free Side Device Temperature Thresholds from page 03h -+ * (MSB at lower byte address). -+ * Bytes: -+ * 128-129 - Temp High Alarm (SFP_TEMP_HIGH_ALARM); -+ * 130-131 - Temp Low Alarm (SFP_TEMP_LOW_ALARM); -+ * 132-133 - Temp High Warning (SFP_TEMP_HIGH_WARN); -+ * 134-135 - Temp Low Warning (SFP_TEMP_LOW_WARN); -+ */ -+ -+ /* Validate module identifier value. */ -+ err = mlxsw_env_validate_cable_ident(core, module, &qsfp); -+ if (err) -+ return err; -+ -+ if (qsfp) -+ mlxsw_reg_mcia_pack(mcia_pl, module, 0, -+ MLXSW_REG_MCIA_TH_PAGE_NUM, -+ 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_PAGE0_LO, -+ off, MLXSW_REG_MCIA_TH_ITEM_SIZE, -+ MLXSW_REG_MCIA_I2C_ADDR_HIGH); -+ -+ err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); -+ if (err) -+ return err; -+ -+ mlxsw_reg_mcia_eeprom_memcpy_from(mcia_pl, eeprom_tmp); -+ memcpy(temp_thresh.buf, eeprom_tmp, MLXSW_REG_MCIA_TH_ITEM_SIZE); -+ *temp = temp_thresh.temp * 1000; -+ -+ return 0; -+} -+ -+int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, 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; -+ u8 module_rev_id, module_id; -+ unsigned int read_size; -+ int err; -+ -+ err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset, -+ module_info, &read_size); -+ if (err) -+ return err; -+ -+ if (read_size < offset) -+ return -EIO; -+ -+ module_rev_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID]; -+ module_id = module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID]; -+ -+ switch (module_id) { -+ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: -+ modinfo->type = ETH_MODULE_SFF_8436; -+ modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; -+ break; -+ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */ -+ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: -+ if (module_id == MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 || -+ module_rev_id >= -+ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) { -+ modinfo->type = ETH_MODULE_SFF_8636; -+ modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; -+ } else { -+ modinfo->type = ETH_MODULE_SFF_8436; -+ modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; -+ } -+ break; -+ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: -+ modinfo->type = ETH_MODULE_SFF_8472; -+ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+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) -+{ -+ int offset = ee->offset; -+ unsigned int read_size; -+ int i = 0; -+ int err; -+ -+ if (!ee->len) -+ return -EINVAL; -+ -+ memset(data, 0, ee->len); -+ -+ while (i < ee->len) { -+ err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset, -+ ee->len - i, data + i, -+ &read_size); -+ if (err) { -+ netdev_err(netdev, "Eeprom query failed\n"); -+ return err; -+ } -+ -+ i += read_size; -+ offset += read_size; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(mlxsw_env_get_module_eeprom); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.h b/drivers/net/ethernet/mellanox/mlxsw/core_env.h -new file mode 100644 -index 0000000..064d0e7 ---- /dev/null -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.h -@@ -0,0 +1,17 @@ -+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ -+/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ -+ -+#ifndef _MLXSW_CORE_ENV_H -+#define _MLXSW_CORE_ENV_H -+ -+int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, 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_eeprom(struct net_device *netdev, -+ struct mlxsw_core *mlxsw_core, int module, -+ struct ethtool_eeprom *ee, u8 *data); -+ -+#endif -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -index ab710e3..f1ada4cd 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -@@ -1,36 +1,5 @@ --/* -- * drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -- * Copyright (c) 2015 Mellanox Technologies. All rights reserved. -- * Copyright (c) 2015 Jiri Pirko -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. 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. -- * 3. Neither the names of the copyright holders nor the names of its -- * contributors may be used to endorse or promote products derived from -- * this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * 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. -- */ -+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 -+/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ - - #include - #include -@@ -38,8 +7,10 @@ - #include - #include - #include -+#include - - #include "core.h" -+#include "core_env.h" - - #define MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT 127 - #define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT * 4 + \ -@@ -61,6 +32,7 @@ struct mlxsw_hwmon { - struct attribute *attrs[MLXSW_HWMON_ATTR_COUNT + 1]; - struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT]; - unsigned int attrs_count; -+ u8 sensor_count; - }; - - static ssize_t mlxsw_hwmon_temp_show(struct device *dev, -@@ -152,6 +124,27 @@ static ssize_t mlxsw_hwmon_fan_rpm_show(struct device *dev, - return sprintf(buf, "%u\n", mlxsw_reg_mfsm_rpm_get(mfsm_pl)); - } - -+static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = -+ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); -+ struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; -+ char fore_pl[MLXSW_REG_FORE_LEN]; -+ bool fault; -+ int err; -+ -+ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(fore), fore_pl); -+ if (err) { -+ 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); -+ -+ return sprintf(buf, "%u\n", fault); -+} -+ - static ssize_t mlxsw_hwmon_pwm_show(struct device *dev, - struct device_attribute *attr, - char *buf) -@@ -198,12 +191,160 @@ static ssize_t mlxsw_hwmon_pwm_store(struct device *dev, - return len; - } - -+static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = -+ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); -+ struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; -+ char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; -+ u16 temp; -+ u8 module; -+ int err; -+ -+ module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; -+ mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, -+ 1); -+ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); -+ if (err) { -+ dev_err(dev, "Failed to query module temprature sensor\n"); -+ return err; -+ } -+ -+ mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); -+ /* Update status and temperature cache. */ -+ switch (temp) { -+ case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ -+ case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ -+ case MLXSW_REG_MTBR_INDEX_NA: -+ temp = 0; -+ break; -+ case MLXSW_REG_MTBR_BAD_SENS_INFO: -+ /* Untrusted cable is connected. Reading temperature from its -+ * sensor is faulty. -+ */ -+ temp = 0; -+ break; -+ default: -+ temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp); -+ break; -+ } -+ -+ return sprintf(buf, "%u\n", temp); -+} -+ -+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 = -+ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); -+ struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; -+ char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; -+ u8 module, fault; -+ u16 temp; -+ int err; -+ -+ module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; -+ mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, -+ 1); -+ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); -+ if (err) { -+ dev_err(dev, "Failed to query module temprature sensor\n"); -+ return err; -+ } -+ -+ mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); -+ -+ /* Update status and temperature cache. */ -+ switch (temp) { -+ case MLXSW_REG_MTBR_BAD_SENS_INFO: -+ /* Untrusted cable is connected. Reading temperature from its -+ * sensor is faulty. -+ */ -+ fault = 1; -+ break; -+ case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ -+ case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ -+ case MLXSW_REG_MTBR_INDEX_NA: -+ default: -+ fault = 0; -+ break; -+ } -+ -+ return sprintf(buf, "%u\n", fault); -+} -+ -+static ssize_t -+mlxsw_hwmon_module_temp_critical_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = -+ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); -+ struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; -+ int temp; -+ u8 module; -+ int err; -+ -+ module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; -+ err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, -+ SFP_TEMP_HIGH_WARN, &temp); -+ if (err) { -+ dev_err(dev, "Failed to query module temprature thresholds\n"); -+ return err; -+ } -+ -+ return sprintf(buf, "%u\n", temp); -+} -+ -+static ssize_t -+mlxsw_hwmon_module_temp_emergency_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = -+ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); -+ struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; -+ u8 module; -+ int temp; -+ int err; -+ -+ module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; -+ err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, -+ SFP_TEMP_HIGH_ALARM, &temp); -+ if (err) { -+ dev_err(dev, "Failed to query module temprature thresholds\n"); -+ return err; -+ } -+ -+ return sprintf(buf, "%u\n", temp); -+} -+ -+static ssize_t -+mlxsw_hwmon_module_temp_label_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = -+ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); -+ -+ return sprintf(buf, "front panel %03u\n", -+ mlwsw_hwmon_attr->type_index); -+} -+ - enum mlxsw_hwmon_attr_type { - MLXSW_HWMON_ATTR_TYPE_TEMP, - MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, - MLXSW_HWMON_ATTR_TYPE_TEMP_RST, - MLXSW_HWMON_ATTR_TYPE_FAN_RPM, -+ MLXSW_HWMON_ATTR_TYPE_FAN_FAULT, - MLXSW_HWMON_ATTR_TYPE_PWM, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL, - }; - - static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon, -@@ -218,35 +359,75 @@ static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon, - switch (attr_type) { - case MLXSW_HWMON_ATTR_TYPE_TEMP: - mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_temp_show; -- mlxsw_hwmon_attr->dev_attr.attr.mode = S_IRUGO; -+ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; - snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), - "temp%u_input", num + 1); - break; - case MLXSW_HWMON_ATTR_TYPE_TEMP_MAX: - mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_temp_max_show; -- mlxsw_hwmon_attr->dev_attr.attr.mode = S_IRUGO; -+ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; - snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), - "temp%u_highest", num + 1); - break; - case MLXSW_HWMON_ATTR_TYPE_TEMP_RST: - mlxsw_hwmon_attr->dev_attr.store = mlxsw_hwmon_temp_rst_store; -- mlxsw_hwmon_attr->dev_attr.attr.mode = S_IWUSR; -+ mlxsw_hwmon_attr->dev_attr.attr.mode = 0200; - snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), - "temp%u_reset_history", num + 1); - break; - case MLXSW_HWMON_ATTR_TYPE_FAN_RPM: - mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_fan_rpm_show; -- mlxsw_hwmon_attr->dev_attr.attr.mode = S_IRUGO; -+ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; - snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), - "fan%u_input", num + 1); - break; -+ case MLXSW_HWMON_ATTR_TYPE_FAN_FAULT: -+ mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_fan_fault_show; -+ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; -+ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), -+ "fan%u_fault", num + 1); -+ break; - case MLXSW_HWMON_ATTR_TYPE_PWM: - mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_pwm_show; - mlxsw_hwmon_attr->dev_attr.store = mlxsw_hwmon_pwm_store; -- mlxsw_hwmon_attr->dev_attr.attr.mode = S_IWUSR | S_IRUGO; -+ mlxsw_hwmon_attr->dev_attr.attr.mode = 0644; - snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), - "pwm%u", num + 1); - break; -+ case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE: -+ mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_module_temp_show; -+ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; -+ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), -+ "temp%u_input", num + 1); -+ break; -+ case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT: -+ mlxsw_hwmon_attr->dev_attr.show = -+ mlxsw_hwmon_module_temp_fault_show; -+ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; -+ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), -+ "temp%u_fault", num + 1); -+ break; -+ case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT: -+ mlxsw_hwmon_attr->dev_attr.show = -+ mlxsw_hwmon_module_temp_critical_show; -+ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; -+ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), -+ "temp%u_crit", num + 1); -+ break; -+ case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG: -+ mlxsw_hwmon_attr->dev_attr.show = -+ mlxsw_hwmon_module_temp_emergency_show; -+ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; -+ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), -+ "temp%u_emergency", num + 1); -+ break; -+ case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL: -+ mlxsw_hwmon_attr->dev_attr.show = -+ mlxsw_hwmon_module_temp_label_show; -+ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; -+ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), -+ "temp%u_label", num + 1); -+ break; - default: - WARN_ON(1); - } -@@ -264,7 +445,6 @@ static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon) - { - char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0}; - char mtmp_pl[MLXSW_REG_MTMP_LEN]; -- u8 sensor_count; - int i; - int err; - -@@ -273,8 +453,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; - } -- sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl); -- for (i = 0; i < sensor_count; i++) { -+ mlxsw_hwmon->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl); -+ for (i = 0; i < mlxsw_hwmon->sensor_count; i++) { - mlxsw_reg_mtmp_pack(mtmp_pl, i, true, true); - err = mlxsw_reg_write(mlxsw_hwmon->core, - MLXSW_REG(mtmp), mtmp_pl); -@@ -311,10 +491,14 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) - mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active); - num = 0; - for (type_index = 0; type_index < MLXSW_MFCR_TACHOS_MAX; type_index++) { -- if (tacho_active & BIT(type_index)) -+ if (tacho_active & BIT(type_index)) { - mlxsw_hwmon_attr_add(mlxsw_hwmon, - MLXSW_HWMON_ATTR_TYPE_FAN_RPM, -+ type_index, num); -+ mlxsw_hwmon_attr_add(mlxsw_hwmon, -+ MLXSW_HWMON_ATTR_TYPE_FAN_FAULT, - type_index, num++); -+ } - } - num = 0; - for (type_index = 0; type_index < MLXSW_MFCR_PWMS_MAX; type_index++) { -@@ -326,6 +510,53 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) - return 0; - } - -+static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) -+{ -+ unsigned int module_count = mlxsw_core_max_ports(mlxsw_hwmon->core); -+ char pmlp_pl[MLXSW_REG_PMLP_LEN] = {0}; -+ int i, index; -+ u8 width; -+ int err; -+ -+ /* Add extra attributes for module temperature. Sensor index is -+ * assigned to sensor_count value, while all indexed before -+ * sensor_count are already utilized by the sensors connected through -+ * mtmp register by mlxsw_hwmon_temp_init(). -+ */ -+ index = mlxsw_hwmon->sensor_count; -+ for (i = 1; i < module_count; i++) { -+ mlxsw_reg_pmlp_pack(pmlp_pl, i); -+ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(pmlp), -+ pmlp_pl); -+ if (err) { -+ dev_err(mlxsw_hwmon->bus_info->dev, "Failed to read module index %d\n", -+ i); -+ return err; -+ } -+ width = mlxsw_reg_pmlp_width_get(pmlp_pl); -+ if (!width) -+ continue; -+ mlxsw_hwmon_attr_add(mlxsw_hwmon, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, index, -+ index); -+ mlxsw_hwmon_attr_add(mlxsw_hwmon, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT, -+ index, index); -+ mlxsw_hwmon_attr_add(mlxsw_hwmon, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, -+ index, index); -+ mlxsw_hwmon_attr_add(mlxsw_hwmon, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG, -+ index, index); -+ mlxsw_hwmon_attr_add(mlxsw_hwmon, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL, -+ index, index); -+ index++; -+ } -+ -+ return 0; -+} -+ - int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info, - struct mlxsw_hwmon **p_hwmon) -@@ -334,8 +565,7 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, - struct device *hwmon_dev; - int err; - -- mlxsw_hwmon = devm_kzalloc(mlxsw_bus_info->dev, sizeof(*mlxsw_hwmon), -- GFP_KERNEL); -+ mlxsw_hwmon = kzalloc(sizeof(*mlxsw_hwmon), GFP_KERNEL); - if (!mlxsw_hwmon) - return -ENOMEM; - mlxsw_hwmon->core = mlxsw_core; -@@ -349,13 +579,16 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, - if (err) - goto err_fans_init; - -+ err = mlxsw_hwmon_module_init(mlxsw_hwmon); -+ if (err) -+ goto err_temp_module_init; -+ - mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group; - mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs; - -- hwmon_dev = devm_hwmon_device_register_with_groups(mlxsw_bus_info->dev, -- "mlxsw", -- mlxsw_hwmon, -- mlxsw_hwmon->groups); -+ hwmon_dev = hwmon_device_register_with_groups(mlxsw_bus_info->dev, -+ "mlxsw", mlxsw_hwmon, -+ mlxsw_hwmon->groups); - if (IS_ERR(hwmon_dev)) { - err = PTR_ERR(hwmon_dev); - goto err_hwmon_register; -@@ -366,7 +599,15 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, - return 0; - - err_hwmon_register: -+err_temp_module_init: - err_fans_init: - err_temp_init: -+ kfree(mlxsw_hwmon); - return err; - } -+ -+void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon) -+{ -+ hwmon_device_unregister(mlxsw_hwmon->hwmon_dev); -+ kfree(mlxsw_hwmon); -+} -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index 8047556..c047b61 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -1,34 +1,6 @@ --/* -- * drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 -+/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved - * Copyright (c) 2016 Ivan Vecera -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. 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. -- * 3. Neither the names of the copyright holders nor the names of its -- * contributors may be used to endorse or promote products derived from -- * this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * 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 -@@ -37,44 +9,79 @@ - #include - #include - #include -+#include - - #include "core.h" -+#include "core_env.h" - - #define MLXSW_THERMAL_POLL_INT 1000 /* ms */ --#define MLXSW_THERMAL_MAX_TEMP 110000 /* 110C */ -+#define MLXSW_THERMAL_SLOW_POLL_INT 20000 /* ms */ -+#define MLXSW_THERMAL_ASIC_TEMP_NORM 75000 /* 75C */ -+#define MLXSW_THERMAL_ASIC_TEMP_HIGH 85000 /* 85C */ -+#define MLXSW_THERMAL_ASIC_TEMP_HOT 105000 /* 105C */ -+#define MLXSW_THERMAL_ASIC_TEMP_CRIT 110000 /* 110C */ -+#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 0xffffffff - #define MLXSW_THERMAL_MAX_STATE 10 - #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[] = { -+ "mlxreg_fan", -+}; -+ -+enum mlxsw_thermal_trips { -+ MLXSW_THERMAL_TEMP_TRIP_NORM, -+ MLXSW_THERMAL_TEMP_TRIP_HIGH, -+ MLXSW_THERMAL_TEMP_TRIP_HOT, -+ MLXSW_THERMAL_TEMP_TRIP_CRIT, -+}; - - struct mlxsw_thermal_trip { - int type; - int temp; -+ int hyst; - int min_state; - int max_state; - }; - - static const struct mlxsw_thermal_trip default_thermal_trips[] = { -- { /* Above normal - 60%-100% PWM */ -+ { /* In range - 0-40% PWM */ - .type = THERMAL_TRIP_ACTIVE, -- .temp = 75000, -- .min_state = (6 * MLXSW_THERMAL_MAX_STATE) / 10, -- .max_state = MLXSW_THERMAL_MAX_STATE, -+ .temp = MLXSW_THERMAL_ASIC_TEMP_NORM, -+ .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP, -+ .min_state = 0, -+ .max_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10, - }, - { -- /* Very high - 100% PWM */ -+ /* In range - 40-100% PWM */ - .type = THERMAL_TRIP_ACTIVE, -- .temp = 85000, -- .min_state = MLXSW_THERMAL_MAX_STATE, -+ .temp = MLXSW_THERMAL_ASIC_TEMP_HIGH, -+ .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP, -+ .min_state = (4 * MLXSW_THERMAL_MAX_STATE) / 10, - .max_state = MLXSW_THERMAL_MAX_STATE, - }, - { /* Warning */ - .type = THERMAL_TRIP_HOT, -- .temp = 105000, -+ .temp = MLXSW_THERMAL_ASIC_TEMP_HOT, -+ .hyst = MLXSW_THERMAL_HYSTERESIS_TEMP, - .min_state = MLXSW_THERMAL_MAX_STATE, - .max_state = MLXSW_THERMAL_MAX_STATE, - }, - { /* Critical - soft poweroff */ - .type = THERMAL_TRIP_CRITICAL, -- .temp = MLXSW_THERMAL_MAX_TEMP, -+ .temp = MLXSW_THERMAL_ASIC_TEMP_CRIT, - .min_state = MLXSW_THERMAL_MAX_STATE, - .max_state = MLXSW_THERMAL_MAX_STATE, - } -@@ -85,13 +92,29 @@ static const struct mlxsw_thermal_trip default_thermal_trips[] = { - /* Make sure all trips are writable */ - #define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1) - -+struct mlxsw_thermal; -+ -+struct mlxsw_thermal_module { -+ struct mlxsw_thermal *parent; -+ struct thermal_zone_device *tzdev; -+ struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; -+ enum thermal_device_mode mode; -+ int module; -+}; -+ - struct mlxsw_thermal { - struct mlxsw_core *core; - const struct mlxsw_bus_info *bus_info; - struct thermal_zone_device *tzdev; -+ int polling_delay; - 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]; - enum thermal_device_mode mode; -+ struct mlxsw_thermal_module *tz_module_arr; -+ unsigned int tz_module_num; -+ int tz_highest; -+ struct mutex tz_update_lock; - }; - - static inline u8 mlxsw_state_to_duty(int state) -@@ -115,9 +138,201 @@ static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal, - if (thermal->cdevs[i] == cdev) - return i; - -+ /* 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], -+ sizeof(cdev->type))) -+ return 0; -+ } -+ - return -ENODEV; - } - -+static void -+mlxsw_thermal_module_trips_reset(struct mlxsw_thermal_module *tz) -+{ -+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = 0; -+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = 0; -+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = 0; -+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = 0; -+} -+ -+static int -+mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core, -+ struct mlxsw_thermal_module *tz) -+{ -+ int crit_temp, emerg_temp; -+ int err; -+ -+ err = mlxsw_env_module_temp_thresholds_get(core, tz->module, -+ SFP_TEMP_HIGH_WARN, -+ &crit_temp); -+ if (err) -+ return err; -+ -+ err = mlxsw_env_module_temp_thresholds_get(core, tz->module, -+ SFP_TEMP_HIGH_ALARM, -+ &emerg_temp); -+ if (err) -+ return err; -+ -+ /* According to the system thermal requirements, the thermal zones are -+ * defined with four trip points. The critical and emergency -+ * temperature thresholds, provided by QSFP module are set as "active" -+ * and "hot" trip points, "normal" and "critical" trip points ar -+ * derived from "active" and "hot" by subtracting or adding double -+ * hysteresis value. -+ */ -+ if (crit_temp >= MLXSW_THERMAL_MODULE_TEMP_SHIFT) -+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp - -+ MLXSW_THERMAL_MODULE_TEMP_SHIFT; -+ else -+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp = crit_temp; -+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp = crit_temp; -+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_HOT].temp = emerg_temp; -+ if (emerg_temp > crit_temp) -+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = emerg_temp + -+ MLXSW_THERMAL_MODULE_TEMP_SHIFT; -+ else -+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp = emerg_temp; -+ -+ return 0; -+} -+ -+static void mlxsw_thermal_tz_score_get(struct mlxsw_thermal_trip *trips, -+ int temp, int *score) -+{ -+ struct mlxsw_thermal_trip *trip = trips; -+ int delta, i, shift = 1; -+ -+ /* Calculate thermal zone score, if temperature is above the critical -+ * threshold score is set to MLXSW_THERMAL_TEMP_SCORE_MAX. -+ */ -+ *score = MLXSW_THERMAL_TEMP_SCORE_MAX; -+ for (i = MLXSW_THERMAL_TEMP_TRIP_NORM; i < MLXSW_THERMAL_NUM_TRIPS; -+ i++, trip++) { -+ if (temp < trip->temp) { -+ delta = DIV_ROUND_CLOSEST(temp, trip->temp - temp); -+ *score = delta * shift; -+ break; -+ } -+ shift *= 256; -+ } -+} -+ -+static int -+mlxsw_thermal_highest_tz_get(struct device *dev, struct mlxsw_thermal *thermal, -+ int module_count, unsigned int seed_temp, -+ int *max_tz, int *max_score) -+{ -+ char mtbr_pl[MLXSW_REG_MTBR_LEN]; -+ struct mlxsw_thermal_module *tz; -+ int i, j, index, off, score; -+ u16 temp; -+ int err; -+ -+ mlxsw_thermal_tz_score_get(thermal->trips, seed_temp, max_score); -+ /* Read modules temperature. */ -+ index = 0; -+ while (index < module_count) { -+ off = min_t(u8, MLXSW_REG_MTBR_REC_MAX_COUNT, -+ module_count - index); -+ mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + -+ index, off); -+ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtbr), mtbr_pl); -+ if (err) { -+ dev_err(dev, "Failed to get temp from index %d\n", -+ off); -+ return err; -+ } -+ -+ for (i = 0, j = index; i < off; i++, j++) { -+ mlxsw_reg_mtbr_temp_unpack(mtbr_pl, i, &temp, NULL); -+ /* Update status and temperature cache. */ -+ switch (temp) { -+ case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ -+ case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ -+ case MLXSW_REG_MTBR_INDEX_NA: /* fall-through */ -+ case MLXSW_REG_MTBR_BAD_SENS_INFO: -+ temp = 0; -+ break; -+ default: -+ tz = &thermal->tz_module_arr[j]; -+ if (!tz) -+ break; -+ /* Reset all trip point. */ -+ mlxsw_thermal_module_trips_reset(tz); -+ temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp); -+ /* Do not consider zero temperature. */ -+ if (!temp) -+ break; -+ -+ err = mlxsw_thermal_module_trips_update(dev, -+ thermal->core, -+ tz); -+ if (err) { -+ dev_err(dev, "Failed to update trips for %s\n", -+ tz->tzdev->type); -+ return err; -+ } -+ -+ score = 0; -+ mlxsw_thermal_tz_score_get(tz->trips, temp, -+ &score); -+ if (score > *max_score) { -+ *max_score = score; -+ *max_tz = j + 1; -+ } -+ break; -+ } -+ } -+ index += off; -+ } -+ -+ return 0; -+} -+ -+static int -+mlxsw_thermal_highest_tz_notify(struct device *dev, -+ struct thermal_zone_device *tzdev, -+ struct mlxsw_thermal *thermal, -+ int module_count, unsigned int temp) -+{ -+ char env_record[24]; -+ char *envp[2] = { env_record, NULL }; -+ struct mlxsw_thermal_module *tz_module; -+ struct thermal_zone_device *tz; -+ int max_tz = 0, max_score = 0; -+ int err; -+ -+ err = mlxsw_thermal_highest_tz_get(dev, thermal, -+ thermal->tz_module_num, temp, -+ &max_tz, &max_score); -+ if (err) { -+ dev_err(dev, "Failed to query module temp sensor\n"); -+ return err; -+ } -+ -+ if (thermal->tz_highest != max_tz) { -+ sprintf(env_record, "TZ_HIGHEST==%u", max_score); -+ if (max_tz && (&thermal->tz_module_arr[max_tz - 1])) { -+ tz_module = &thermal->tz_module_arr[max_tz - 1]; -+ tz = tz_module->tzdev; -+ err = kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE, -+ envp); -+ } else { -+ err = kobject_uevent_env(&tzdev->device.kobj, -+ KOBJ_CHANGE, envp); -+ } -+ if (err) -+ dev_err(dev, "Error sending uevent %s\n", envp[0]); -+ else -+ thermal->tz_highest = max_tz; -+ } -+ -+ return 0; -+} -+ - static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev, - struct thermal_cooling_device *cdev) - { -@@ -183,15 +398,20 @@ static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev, - - mutex_lock(&tzdev->lock); - -- if (mode == THERMAL_DEVICE_ENABLED) -- tzdev->polling_delay = MLXSW_THERMAL_POLL_INT; -- else -+ if (mode == THERMAL_DEVICE_ENABLED) { -+ thermal->tz_highest = 0; -+ tzdev->polling_delay = thermal->polling_delay; -+ } else { - tzdev->polling_delay = 0; -+ } - - mutex_unlock(&tzdev->lock); - - thermal->mode = mode; -+ -+ mutex_lock(&thermal->tz_update_lock); - thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED); -+ mutex_unlock(&thermal->tz_update_lock); - - return 0; - } -@@ -214,6 +434,14 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, - } - mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); - -+ if (thermal->tz_module_arr) { -+ err = mlxsw_thermal_highest_tz_notify(dev, tzdev, thermal, -+ thermal->tz_module_num, -+ temp); -+ if (err) -+ dev_err(dev, "Failed to query module temp sensor\n"); -+ } -+ - *p_temp = (int) temp; - return 0; - } -@@ -249,13 +477,31 @@ static int mlxsw_thermal_set_trip_temp(struct thermal_zone_device *tzdev, - struct mlxsw_thermal *thermal = tzdev->devdata; - - if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS || -- temp > MLXSW_THERMAL_MAX_TEMP) -+ temp > MLXSW_THERMAL_ASIC_TEMP_CRIT) - return -EINVAL; - - thermal->trips[trip].temp = temp; - return 0; - } - -+static int mlxsw_thermal_get_trip_hyst(struct thermal_zone_device *tzdev, -+ int trip, int *p_hyst) -+{ -+ struct mlxsw_thermal *thermal = tzdev->devdata; -+ -+ *p_hyst = thermal->trips[trip].hyst; -+ return 0; -+} -+ -+static int mlxsw_thermal_set_trip_hyst(struct thermal_zone_device *tzdev, -+ int trip, int hyst) -+{ -+ struct mlxsw_thermal *thermal = tzdev->devdata; -+ -+ thermal->trips[trip].hyst = hyst; -+ return 0; -+} -+ - static struct thermal_zone_device_ops mlxsw_thermal_ops = { - .bind = mlxsw_thermal_bind, - .unbind = mlxsw_thermal_unbind, -@@ -265,6 +511,250 @@ static struct thermal_zone_device_ops mlxsw_thermal_ops = { - .get_trip_type = mlxsw_thermal_get_trip_type, - .get_trip_temp = mlxsw_thermal_get_trip_temp, - .set_trip_temp = mlxsw_thermal_set_trip_temp, -+ .get_trip_hyst = mlxsw_thermal_get_trip_hyst, -+ .set_trip_hyst = mlxsw_thermal_set_trip_hyst, -+}; -+ -+static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev, -+ struct thermal_cooling_device *cdev) -+{ -+ struct mlxsw_thermal_module *tz = tzdev->devdata; -+ struct mlxsw_thermal *thermal = tz->parent; -+ int i, j, err; -+ -+ /* If the cooling device is one of ours bind it */ -+ if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0) -+ return 0; -+ -+ for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) { -+ const struct mlxsw_thermal_trip *trip = &tz->trips[i]; -+ -+ err = thermal_zone_bind_cooling_device(tzdev, i, cdev, -+ trip->max_state, -+ trip->min_state, -+ THERMAL_WEIGHT_DEFAULT); -+ if (err < 0) -+ goto err_bind_cooling_device; -+ } -+ return 0; -+ -+err_bind_cooling_device: -+ for (j = i - 1; j >= 0; j--) -+ thermal_zone_unbind_cooling_device(tzdev, j, cdev); -+ return err; -+} -+ -+static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev, -+ struct thermal_cooling_device *cdev) -+{ -+ struct mlxsw_thermal_module *tz = tzdev->devdata; -+ struct mlxsw_thermal *thermal = tz->parent; -+ int i; -+ int err; -+ -+ /* If the cooling device is one of ours unbind it */ -+ if (mlxsw_get_cooling_device_idx(thermal, cdev) < 0) -+ return 0; -+ -+ for (i = 0; i < MLXSW_THERMAL_NUM_TRIPS; i++) { -+ err = thermal_zone_unbind_cooling_device(tzdev, i, cdev); -+ WARN_ON(err); -+ } -+ return err; -+} -+ -+static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev, -+ enum thermal_device_mode *mode) -+{ -+ struct mlxsw_thermal_module *tz = tzdev->devdata; -+ -+ *mode = tz->mode; -+ -+ return 0; -+} -+ -+static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev, -+ enum thermal_device_mode mode) -+{ -+ struct mlxsw_thermal_module *tz = tzdev->devdata; -+ struct mlxsw_thermal *thermal = tz->parent; -+ -+ mutex_lock(&tzdev->lock); -+ -+ if (mode == THERMAL_DEVICE_ENABLED) -+ tzdev->polling_delay = thermal->polling_delay; -+ else -+ tzdev->polling_delay = 0; -+ -+ mutex_unlock(&tzdev->lock); -+ -+ tz->mode = mode; -+ -+ mutex_lock(&thermal->tz_update_lock); -+ thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED); -+ mutex_unlock(&thermal->tz_update_lock); -+ -+ return 0; -+} -+ -+static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, -+ int *p_temp) -+{ -+ struct mlxsw_thermal_module *tz = tzdev->devdata; -+ struct mlxsw_thermal *thermal = tz->parent; -+ struct device *dev = thermal->bus_info->dev; -+ char mtbr_pl[MLXSW_REG_MTBR_LEN]; -+ u16 temp; -+ int err; -+ -+ /* Read module temperature. */ -+ mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + -+ tz->module, 1); -+ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtbr), mtbr_pl); -+ if (err) -+ return err; -+ -+ mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); -+ /* Update temperature. */ -+ switch (temp) { -+ case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ -+ case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ -+ case MLXSW_REG_MTBR_INDEX_NA: /* fall-through */ -+ case MLXSW_REG_MTBR_BAD_SENS_INFO: -+ temp = 0; -+ break; -+ default: -+ temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp); -+ /* Reset all trip point. */ -+ mlxsw_thermal_module_trips_reset(tz); -+ /* Update trip points. */ -+ err = mlxsw_thermal_module_trips_update(dev, thermal->core, -+ tz); -+ if (err) -+ return err; -+ break; -+ } -+ -+ *p_temp = (int) temp; -+ return 0; -+} -+ -+static int -+mlxsw_thermal_module_trip_type_get(struct thermal_zone_device *tzdev, int trip, -+ enum thermal_trip_type *p_type) -+{ -+ struct mlxsw_thermal_module *tz = tzdev->devdata; -+ -+ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) -+ return -EINVAL; -+ -+ *p_type = tz->trips[trip].type; -+ return 0; -+} -+ -+static int -+mlxsw_thermal_module_trip_temp_get(struct thermal_zone_device *tzdev, -+ int trip, int *p_temp) -+{ -+ struct mlxsw_thermal_module *tz = tzdev->devdata; -+ -+ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) -+ return -EINVAL; -+ -+ *p_temp = tz->trips[trip].temp; -+ return 0; -+} -+ -+static int -+mlxsw_thermal_module_trip_temp_set(struct thermal_zone_device *tzdev, -+ int trip, int temp) -+{ -+ struct mlxsw_thermal_module *tz = tzdev->devdata; -+ -+ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS || -+ temp > tz->trips[MLXSW_THERMAL_TEMP_TRIP_CRIT].temp) -+ return -EINVAL; -+ -+ tz->trips[trip].temp = temp; -+ return 0; -+} -+ -+static int -+mlxsw_thermal_module_trip_hyst_get(struct thermal_zone_device *tzdev, int trip, -+ int *p_hyst) -+{ -+ struct mlxsw_thermal_module *tz = tzdev->devdata; -+ -+ *p_hyst = tz->trips[trip].hyst; -+ return 0; -+} -+ -+static int -+mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip, -+ int hyst) -+{ -+ struct mlxsw_thermal_module *tz = tzdev->devdata; -+ -+ tz->trips[trip].hyst = hyst; -+ return 0; -+} -+ -+static int mlxsw_thermal_module_trend_get(struct thermal_zone_device *tzdev, -+ int trip, enum thermal_trend *trend) -+{ -+ struct mlxsw_thermal_module *tz = tzdev->devdata; -+ struct mlxsw_thermal *thermal = tz->parent; -+ struct device *dev = thermal->bus_info->dev; -+ char *envp[2] = { "TZ_DOWN=1", NULL }; -+ int delta, window; -+ int err; -+ -+ if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) -+ return -EINVAL; -+ -+ delta = tzdev->last_temperature - tzdev->temperature; -+ window = tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp - -+ tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp; -+ if (delta > window && !window && !tzdev->last_temperature) { -+ /* Notify user about fast temperature decreasing by sending -+ * hwmon uevent. Fast decreasing could happen when some hot -+ * module is removed. In this situation temperature trend could -+ * go down once, and then stay in a stable state. -+ * Notification will allow user to handle such case, if user -+ * supposes to optimize PWM state. -+ */ -+ err = kobject_uevent_env(&tzdev->device.kobj, KOBJ_CHANGE, -+ envp); -+ if (err) -+ dev_err(dev, "Error sending uevent %s\n", envp[0]); -+ } -+ -+ if (tzdev->temperature > tzdev->last_temperature) -+ *trend = THERMAL_TREND_RAISING; -+ else if (tzdev->temperature < tzdev->last_temperature) -+ *trend = THERMAL_TREND_DROPPING; -+ else -+ *trend = THERMAL_TREND_STABLE; -+ -+ return 0; -+} -+ -+static struct thermal_zone_params mlxsw_thermal_module_params = { -+ .governor_name = "user_space", -+}; -+ -+static struct thermal_zone_device_ops mlxsw_thermal_module_ops = { -+ .bind = mlxsw_thermal_module_bind, -+ .unbind = mlxsw_thermal_module_unbind, -+ .get_mode = mlxsw_thermal_module_mode_get, -+ .set_mode = mlxsw_thermal_module_mode_set, -+ .get_temp = mlxsw_thermal_module_temp_get, -+ .get_trip_type = mlxsw_thermal_module_trip_type_get, -+ .get_trip_temp = mlxsw_thermal_module_trip_temp_get, -+ .set_trip_temp = mlxsw_thermal_module_trip_temp_set, -+ .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get, -+ .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set, -+ .get_trend = mlxsw_thermal_module_trend_get, - }; - - static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev, -@@ -307,12 +797,51 @@ 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]; -- int err, idx; -+ unsigned long cur_state, i; -+ int idx; -+ u8 duty; -+ int err; - - 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)); - err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsc), mfsc_pl); - if (err) { -@@ -328,6 +857,122 @@ static const struct thermal_cooling_device_ops mlxsw_cooling_ops = { - .set_cur_state = mlxsw_thermal_set_cur_state, - }; - -+static int -+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); -+ module_tz->tzdev = thermal_zone_device_register(tz_name, -+ MLXSW_THERMAL_NUM_TRIPS, -+ MLXSW_THERMAL_TRIP_MASK, -+ module_tz, -+ &mlxsw_thermal_module_ops, -+ &mlxsw_thermal_module_params, -+ 0, 0); -+ if (IS_ERR(module_tz->tzdev)) { -+ err = PTR_ERR(module_tz); -+ return err; -+ } -+ -+ return 0; -+} -+ -+static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev) -+{ -+ thermal_zone_device_unregister(tzdev); -+} -+ -+static int -+mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, -+ struct mlxsw_thermal *thermal, u8 local_port) -+{ -+ struct mlxsw_thermal_module *module_tz; -+ char pmlp_pl[MLXSW_REG_PMLP_LEN]; -+ u8 width, module; -+ int err; -+ -+ mlxsw_reg_pmlp_pack(pmlp_pl, local_port); -+ err = mlxsw_reg_query(core, MLXSW_REG(pmlp), pmlp_pl); -+ if (err) -+ return err; -+ -+ width = mlxsw_reg_pmlp_width_get(pmlp_pl); -+ if (!width) -+ return 0; -+ -+ module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); -+ module_tz = &thermal->tz_module_arr[module]; -+ module_tz->module = module; -+ 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); -+ /* Update trip point according to the module data. */ -+ err = mlxsw_thermal_module_trips_update(dev, core, module_tz); -+ if (err) -+ return err; -+ -+ thermal->tz_module_num++; -+ -+ return 0; -+} -+ -+static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz) -+{ -+ if (module_tz && module_tz->tzdev) { -+ mlxsw_thermal_module_tz_fini(module_tz->tzdev); -+ module_tz->tzdev = NULL; -+ } -+} -+ -+static int -+mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, -+ struct mlxsw_thermal *thermal) -+{ -+ unsigned int module_count = mlxsw_core_max_ports(core); -+ int i, err; -+ -+ thermal->tz_module_arr = kcalloc(module_count, -+ sizeof(*thermal->tz_module_arr), -+ GFP_KERNEL); -+ if (!thermal->tz_module_arr) -+ return -ENOMEM; -+ -+ for (i = 1; i <= module_count; i++) { -+ err = mlxsw_thermal_module_init(dev, core, thermal, i); -+ if (err) -+ goto err_unreg_tz_module_arr; -+ } -+ -+ for (i = 0; i < thermal->tz_module_num; i++) { -+ err = mlxsw_thermal_module_tz_init(&thermal->tz_module_arr[i]); -+ if (err) -+ goto err_unreg_tz_module_arr; -+ } -+ -+ return 0; -+ -+err_unreg_tz_module_arr: -+ for (i = thermal->tz_module_num - 1; i >= 0; i--) -+ mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); -+ kfree(thermal->tz_module_arr); -+ return err; -+} -+ -+static void -+mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal) -+{ -+ 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); -+} -+ - int mlxsw_thermal_init(struct mlxsw_core *core, - const struct mlxsw_bus_info *bus_info, - struct mlxsw_thermal **p_thermal) -@@ -347,6 +992,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core, - - thermal->core = core; - thermal->bus_info = bus_info; -+ mutex_init(&thermal->tz_update_lock); - memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips)); - - err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl); -@@ -380,7 +1026,8 @@ int mlxsw_thermal_init(struct mlxsw_core *core, - if (pwm_active & BIT(i)) { - struct thermal_cooling_device *cdev; - -- cdev = thermal_cooling_device_register("Fan", thermal, -+ cdev = thermal_cooling_device_register("mlxsw_fan", -+ thermal, - &mlxsw_cooling_ops); - if (IS_ERR(cdev)) { - err = PTR_ERR(cdev); -@@ -391,22 +1038,41 @@ 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_SPEED_MIN_LEVEL, -+ i); -+ -+ thermal->polling_delay = bus_info->low_frequency ? -+ MLXSW_THERMAL_SLOW_POLL_INT : -+ MLXSW_THERMAL_POLL_INT; -+ - thermal->tzdev = thermal_zone_device_register("mlxsw", - MLXSW_THERMAL_NUM_TRIPS, - MLXSW_THERMAL_TRIP_MASK, - thermal, - &mlxsw_thermal_ops, - NULL, 0, -- MLXSW_THERMAL_POLL_INT); -+ thermal->polling_delay); - if (IS_ERR(thermal->tzdev)) { - err = PTR_ERR(thermal->tzdev); - dev_err(dev, "Failed to register thermal zone\n"); - goto err_unreg_cdevs; - } - -+ err = mlxsw_thermal_modules_init(dev, core, thermal); -+ if (err) -+ goto err_unreg_tzdev; -+ - thermal->mode = THERMAL_DEVICE_ENABLED; - *p_thermal = thermal; - return 0; -+ -+err_unreg_tzdev: -+ if (thermal->tzdev) { -+ thermal_zone_device_unregister(thermal->tzdev); -+ thermal->tzdev = NULL; -+ } - err_unreg_cdevs: - for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) - if (thermal->cdevs[i]) -@@ -420,6 +1086,7 @@ void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) - { - int i; - -+ mlxsw_thermal_modules_fini(thermal); - if (thermal->tzdev) { - thermal_zone_device_unregister(thermal->tzdev); - thermal->tzdev = NULL; -diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c -index 5c31665..f1b95d5 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c -@@ -1,36 +1,5 @@ --/* -- * drivers/net/ethernet/mellanox/mlxsw/i2c.c -- * Copyright (c) 2016 Mellanox Technologies. All rights reserved. -- * Copyright (c) 2016 Vadim Pasternak -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. 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. -- * 3. Neither the names of the copyright holders nor the names of its -- * contributors may be used to endorse or promote products derived from -- * this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * 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. -- */ -+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 -+/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */ - - #include - #include -@@ -46,8 +15,6 @@ - #include "core.h" - #include "i2c.h" - --static const char mlxsw_i2c_driver_name[] = "mlxsw_i2c"; -- - #define MLXSW_I2C_CIR2_BASE 0x72000 - #define MLXSW_I2C_CIR_STATUS_OFF 0x18 - #define MLXSW_I2C_CIR2_OFF_STATUS (MLXSW_I2C_CIR2_BASE + \ -@@ -364,10 +331,7 @@ mlxsw_i2c_cmd(struct device *dev, size_t in_mbox_size, u8 *in_mbox, - if (reg_size % MLXSW_I2C_BLK_MAX) - num++; - -- if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { -- dev_err(&client->dev, "Could not acquire lock"); -- return -EINVAL; -- } -+ mutex_lock(&mlxsw_i2c->cmd.lock); - - err = mlxsw_i2c_write(dev, reg_size, in_mbox, num, status); - if (err) -@@ -536,6 +500,7 @@ static int mlxsw_i2c_probe(struct i2c_client *client, - mlxsw_i2c->bus_info.device_kind = id->name; - mlxsw_i2c->bus_info.device_name = client->name; - mlxsw_i2c->bus_info.dev = &client->dev; -+ mlxsw_i2c->bus_info.low_frequency = true; - mlxsw_i2c->dev = &client->dev; - - err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info, -diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.h b/drivers/net/ethernet/mellanox/mlxsw/i2c.h -index daa24b2..17e059d 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/i2c.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.h -@@ -1,36 +1,5 @@ --/* -- * drivers/net/ethernet/mellanox/mlxsw/i2c.h -- * Copyright (c) 2016 Mellanox Technologies. All rights reserved. -- * Copyright (c) 2016 Vadim Pasternak -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. 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. -- * 3. Neither the names of the copyright holders nor the names of its -- * contributors may be used to endorse or promote products derived from -- * this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * 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. -- */ -+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ -+/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */ - - #ifndef _MLXSW_I2C_H - #define _MLXSW_I2C_H -diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -index 3dd1626..c47949c 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -@@ -1,37 +1,9 @@ --/* -- * drivers/net/ethernet/mellanox/mlxsw/minimal.c -- * Copyright (c) 2016 Mellanox Technologies. All rights reserved. -- * Copyright (c) 2016 Vadim Pasternak -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. 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. -- * 3. Neither the names of the copyright holders nor the names of its -- * contributors may be used to endorse or promote products derived from -- * this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * 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. -- */ -+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 -+/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */ - -+#include -+#include -+#include - #include - #include - #include -@@ -39,59 +11,339 @@ - #include - - #include "core.h" -+#include "core_env.h" - #include "i2c.h" - --static const char mlxsw_minimal_driver_name[] = "mlxsw_minimal"; -+static const char mlxsw_m_driver_name[] = "mlxsw_minimal"; - --static const struct mlxsw_config_profile mlxsw_minimal_config_profile; -+struct mlxsw_m_port; - --static struct mlxsw_driver mlxsw_minimal_driver = { -- .kind = mlxsw_minimal_driver_name, -- .priv_size = 1, -- .profile = &mlxsw_minimal_config_profile, -+struct mlxsw_m { -+ struct mlxsw_m_port **modules; -+ int *module_to_port; -+ struct mlxsw_core *core; -+ const struct mlxsw_bus_info *bus_info; -+ u8 base_mac[ETH_ALEN]; -+ u8 max_modules; - }; - --static const struct i2c_device_id mlxsw_minimal_i2c_id[] = { -+struct mlxsw_m_port { -+ struct mlxsw_core_port core_port; /* must be first */ -+ struct net_device *dev; -+ struct mlxsw_m *mlxsw_m; -+ u8 local_port; -+ u8 module; -+}; -+ -+static int mlxsw_m_port_dummy_open_stop(struct net_device *dev) -+{ -+ return 0; -+} -+ -+static const struct net_device_ops mlxsw_m_port_netdev_ops = { -+ .ndo_open = mlxsw_m_port_dummy_open_stop, -+ .ndo_stop = mlxsw_m_port_dummy_open_stop, -+}; -+ -+static int mlxsw_m_get_module_info(struct net_device *netdev, -+ struct ethtool_modinfo *modinfo) -+{ -+ struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); -+ struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; -+ int err; -+ -+ err = mlxsw_env_get_module_info(core, mlxsw_m_port->module, modinfo); -+ -+ return err; -+} -+ -+static int -+mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee, -+ u8 *data) -+{ -+ struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); -+ struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; -+ int err; -+ -+ err = mlxsw_env_get_module_eeprom(netdev, core, -+ mlxsw_m_port->module, ee, data); -+ -+ return err; -+} -+ -+static const struct ethtool_ops mlxsw_m_port_ethtool_ops = { -+ .get_module_info = mlxsw_m_get_module_info, -+ .get_module_eeprom = mlxsw_m_get_module_eeprom, -+}; -+ -+static int -+mlxsw_m_port_module_info_get(struct mlxsw_m *mlxsw_m, u8 local_port, -+ u8 *p_module, u8 *p_width) -+{ -+ char pmlp_pl[MLXSW_REG_PMLP_LEN]; -+ int err; -+ -+ mlxsw_reg_pmlp_pack(pmlp_pl, local_port); -+ err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(pmlp), pmlp_pl); -+ if (err) -+ return err; -+ *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); -+ *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl); -+ -+ return 0; -+} -+ -+static int -+mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port) -+{ -+ struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; -+ struct net_device *dev = mlxsw_m_port->dev; -+ char ppad_pl[MLXSW_REG_PPAD_LEN]; -+ int err; -+ -+ mlxsw_reg_ppad_pack(ppad_pl, false, 0); -+ err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(ppad), ppad_pl); -+ if (err) -+ return err; -+ mlxsw_reg_ppad_mac_memcpy_from(ppad_pl, dev->dev_addr); -+ /* The last byte value in base mac address is guaranteed -+ * to be such it does not overflow when adding local_port -+ * value. -+ */ -+ dev->dev_addr[ETH_ALEN - 1] += mlxsw_m_port->module + 1; -+ return 0; -+} -+ -+static int -+mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) -+{ -+ struct mlxsw_m_port *mlxsw_m_port; -+ struct net_device *dev; -+ int err; -+ -+ dev = alloc_etherdev(sizeof(struct mlxsw_m_port)); -+ if (!dev) { -+ err = -ENOMEM; -+ goto err_alloc_etherdev; -+ } -+ -+ SET_NETDEV_DEV(dev, mlxsw_m->bus_info->dev); -+ mlxsw_m_port = netdev_priv(dev); -+ mlxsw_m_port->dev = dev; -+ mlxsw_m_port->mlxsw_m = mlxsw_m; -+ mlxsw_m_port->local_port = local_port; -+ mlxsw_m_port->module = module; -+ -+ mlxsw_m->modules[local_port] = mlxsw_m_port; -+ -+ dev->netdev_ops = &mlxsw_m_port_netdev_ops; -+ dev->ethtool_ops = &mlxsw_m_port_ethtool_ops; -+ -+ err = mlxsw_core_port_init(mlxsw_m->core, -+ &mlxsw_m_port->core_port, local_port, -+ dev, false, module); -+ if (err) { -+ dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to init core port\n", -+ local_port); -+ goto err_alloc_etherdev; -+ } -+ -+ err = mlxsw_m_port_dev_addr_get(mlxsw_m_port); -+ if (err) { -+ dev_err(mlxsw_m->bus_info->dev, "Port %d: Unable to get port mac address\n", -+ mlxsw_m_port->local_port); -+ goto err_dev_addr_get; -+ } -+ -+ netif_carrier_off(dev); -+ -+ err = register_netdev(dev); -+ if (err) { -+ dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to register netdev\n", -+ mlxsw_m_port->local_port); -+ goto err_register_netdev; -+ } -+ -+ return 0; -+ -+err_register_netdev: -+ free_netdev(dev); -+err_dev_addr_get: -+err_alloc_etherdev: -+ mlxsw_m->modules[local_port] = NULL; -+ return err; -+} -+ -+static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 local_port) -+{ -+ struct mlxsw_m_port *mlxsw_m_port = mlxsw_m->modules[local_port]; -+ -+ unregister_netdev(mlxsw_m_port->dev); /* This calls ndo_stop */ -+ free_netdev(mlxsw_m_port->dev); -+ mlxsw_core_port_fini(&mlxsw_m_port->core_port); -+} -+ -+static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) -+{ -+ int i; -+ -+ for (i = 0; i < mlxsw_m->max_modules; i++) { -+ if (mlxsw_m->module_to_port[i] > 0) -+ mlxsw_m_port_remove(mlxsw_m, -+ mlxsw_m->module_to_port[i]); -+ } -+ -+ kfree(mlxsw_m->module_to_port); -+ kfree(mlxsw_m->modules); -+} -+ -+static int mlxsw_m_port_mapping_create(struct mlxsw_m *mlxsw_m, u8 local_port, -+ u8 *last_module) -+{ -+ u8 module, width; -+ int err; -+ -+ /* Fill out to local port mapping array */ -+ err = mlxsw_m_port_module_info_get(mlxsw_m, local_port, &module, -+ &width); -+ if (err) -+ return err; -+ -+ if (!width) -+ return 0; -+ /* Skip, if port belongs to the cluster */ -+ if (module == *last_module) -+ return 0; -+ *last_module = module; -+ mlxsw_m->module_to_port[module] = ++mlxsw_m->max_modules; -+ -+ return 0; -+} -+ -+static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) -+{ -+ unsigned int max_port = mlxsw_core_max_ports(mlxsw_m->core); -+ u8 last_module = max_port; -+ int i; -+ int err; -+ -+ mlxsw_m->modules = kcalloc(max_port, sizeof(*mlxsw_m->modules), -+ GFP_KERNEL); -+ if (!mlxsw_m->modules) -+ return -ENOMEM; -+ -+ mlxsw_m->module_to_port = kmalloc_array(max_port, sizeof(int), -+ GFP_KERNEL); -+ if (!mlxsw_m->module_to_port) { -+ err = -ENOMEM; -+ goto err_port_create; -+ } -+ -+ /* Invalidate the entries of module to local port mapping array */ -+ for (i = 0; i < max_port; i++) -+ mlxsw_m->module_to_port[i] = -1; -+ -+ /* Fill out module to local port mapping array */ -+ for (i = 1; i <= max_port; i++) { -+ err = mlxsw_m_port_mapping_create(mlxsw_m, i, &last_module); -+ if (err) -+ goto err_port_create; -+ } -+ -+ /* Create port objects for each valid entry */ -+ for (i = 0; i < mlxsw_m->max_modules; i++) { -+ if (mlxsw_m->module_to_port[i] > 0) { -+ err = mlxsw_m_port_create(mlxsw_m, -+ mlxsw_m->module_to_port[i], -+ i); -+ if (err) -+ goto err_port_create; -+ } -+ } -+ -+ return 0; -+ -+err_port_create: -+ mlxsw_m_ports_remove(mlxsw_m); -+ return err; -+} -+ -+static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_bus_info *mlxsw_bus_info) -+{ -+ struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); -+ int err; -+ -+ mlxsw_m->core = mlxsw_core; -+ mlxsw_m->bus_info = mlxsw_bus_info; -+ -+ err = mlxsw_m_ports_create(mlxsw_m); -+ if (err) { -+ dev_err(mlxsw_m->bus_info->dev, "Failed to create modules\n"); -+ return err; -+ } -+ -+ return 0; -+} -+ -+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); -+} -+ -+static const struct mlxsw_config_profile mlxsw_m_config_profile; -+ -+static struct mlxsw_driver mlxsw_m_driver = { -+ .kind = mlxsw_m_driver_name, -+ .priv_size = sizeof(struct mlxsw_m), -+ .init = mlxsw_m_init, -+ .fini = mlxsw_m_fini, -+ .profile = &mlxsw_m_config_profile, -+}; -+ -+static const struct i2c_device_id mlxsw_m_i2c_id[] = { - { "mlxsw_minimal", 0}, - { }, - }; - --static struct i2c_driver mlxsw_minimal_i2c_driver = { -+static struct i2c_driver mlxsw_m_i2c_driver = { - .driver.name = "mlxsw_minimal", - .class = I2C_CLASS_HWMON, -- .id_table = mlxsw_minimal_i2c_id, -+ .id_table = mlxsw_m_i2c_id, - }; - --static int __init mlxsw_minimal_module_init(void) -+static int __init mlxsw_m_module_init(void) - { - int err; - -- err = mlxsw_core_driver_register(&mlxsw_minimal_driver); -+ err = mlxsw_core_driver_register(&mlxsw_m_driver); - if (err) - return err; - -- err = mlxsw_i2c_driver_register(&mlxsw_minimal_i2c_driver); -+ err = mlxsw_i2c_driver_register(&mlxsw_m_i2c_driver); - if (err) - goto err_i2c_driver_register; - - return 0; - - err_i2c_driver_register: -- mlxsw_core_driver_unregister(&mlxsw_minimal_driver); -+ mlxsw_core_driver_unregister(&mlxsw_m_driver); - - return err; - } - --static void __exit mlxsw_minimal_module_exit(void) -+static void __exit mlxsw_m_module_exit(void) - { -- mlxsw_i2c_driver_unregister(&mlxsw_minimal_i2c_driver); -- mlxsw_core_driver_unregister(&mlxsw_minimal_driver); -+ mlxsw_i2c_driver_unregister(&mlxsw_m_i2c_driver); -+ mlxsw_core_driver_unregister(&mlxsw_m_driver); - } - --module_init(mlxsw_minimal_module_init); --module_exit(mlxsw_minimal_module_exit); -+module_init(mlxsw_m_module_init); -+module_exit(mlxsw_m_module_exit); - - MODULE_LICENSE("Dual BSD/GPL"); - MODULE_AUTHOR("Vadim Pasternak "); - MODULE_DESCRIPTION("Mellanox minimal driver"); --MODULE_DEVICE_TABLE(i2c, mlxsw_minimal_i2c_id); -+MODULE_DEVICE_TABLE(i2c, mlxsw_m_i2c_id); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h -index 2c0c331..20f01bb 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/reg.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h -@@ -4618,6 +4618,35 @@ static inline void mlxsw_reg_mfsl_unpack(char *payload, u8 tacho, - *p_tach_max = mlxsw_reg_mfsl_tach_max_get(payload); - } - -+/* FORE - Fan Out of Range Event Register -+ * -------------------------------------- -+ * This register reports the status of the controlled fans compared to the -+ * range defined by the MFSL register. -+ */ -+#define MLXSW_REG_FORE_ID 0x9007 -+#define MLXSW_REG_FORE_LEN 0x0C -+ -+MLXSW_REG_DEFINE(fore, MLXSW_REG_FORE_ID, MLXSW_REG_FORE_LEN); -+ -+/* fan_under_limit -+ * Fan speed is below the low limit defined in MFSL register. Each bit relates -+ * to a single tachometer and indicates the specific tachometer reading is -+ * below the threshold. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, fore, fan_under_limit, 0x00, 16, 10); -+ -+static inline void mlxsw_reg_fore_unpack(char *payload, u8 tacho, -+ bool *fan_under_limit) -+{ -+ u16 limit; -+ -+ if (fan_under_limit) { -+ limit = mlxsw_reg_fore_fan_under_limit_get(payload); -+ *fan_under_limit = !!(limit & BIT(tacho)); -+ } -+} -+ - /* MTCAP - Management Temperature Capabilities - * ------------------------------------------- - * This register exposes the capabilities of the device and -@@ -4750,6 +4779,80 @@ static inline void mlxsw_reg_mtmp_unpack(char *payload, unsigned int *p_temp, - mlxsw_reg_mtmp_sensor_name_memcpy_from(payload, sensor_name); - } - -+/* MTBR - Management Temperature Bulk Register -+ * ------------------------------------------- -+ * This register is used for bulk temperature reading. -+ */ -+#define MLXSW_REG_MTBR_ID 0x900F -+#define MLXSW_REG_MTBR_BASE_LEN 0x10 /* base length, without records */ -+#define MLXSW_REG_MTBR_REC_LEN 0x04 /* record length */ -+#define MLXSW_REG_MTBR_REC_MAX_COUNT 47 /* firmware limitation */ -+#define MLXSW_REG_MTBR_LEN (MLXSW_REG_MTBR_BASE_LEN + \ -+ MLXSW_REG_MTBR_REC_LEN * \ -+ MLXSW_REG_MTBR_REC_MAX_COUNT) -+ -+MLXSW_REG_DEFINE(mtbr, MLXSW_REG_MTBR_ID, MLXSW_REG_MTBR_LEN); -+ -+/* 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). -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, mtbr, base_sensor_index, 0x00, 0, 7); -+ -+/* reg_mtbr_num_rec -+ * Request: Number of records to read -+ * Response: Number of records read -+ * See above description for more details. -+ * Range 1..255 -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mtbr, num_rec, 0x04, 0, 8); -+ -+/* reg_mtbr_rec_max_temp -+ * The highest measured temperature from the sensor. -+ * When the bit mte is cleared, the field max_temperature is reserved. -+ * Access: RO -+ */ -+MLXSW_ITEM32_INDEXED(reg, mtbr, rec_max_temp, MLXSW_REG_MTBR_BASE_LEN, 16, -+ 16, MLXSW_REG_MTBR_REC_LEN, 0x00, false); -+ -+/* reg_mtbr_rec_temp -+ * Temperature reading from the sensor. Reading is in 0..125 Celsius -+ * degrees units. -+ * Access: RO -+ */ -+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, u8 base_sensor_index, -+ u8 num_rec) -+{ -+ MLXSW_REG_ZERO(mtbr, payload); -+ mlxsw_reg_mtbr_base_sensor_index_set(payload, base_sensor_index); -+ mlxsw_reg_mtbr_num_rec_set(payload, num_rec); -+} -+ -+/* Error codes from temperatute reading */ -+enum mlxsw_reg_mtbr_temp_status { -+ MLXSW_REG_MTBR_NO_CONN = 0x8000, -+ MLXSW_REG_MTBR_NO_TEMP_SENS = 0x8001, -+ MLXSW_REG_MTBR_INDEX_NA = 0x8002, -+ MLXSW_REG_MTBR_BAD_SENS_INFO = 0x8003, -+}; -+ -+/* Base index for reading modules temperature */ -+#define MLXSW_REG_MTBR_BASE_MODULE_INDEX 64 -+ -+static inline void mlxsw_reg_mtbr_temp_unpack(char *payload, int rec_ind, -+ u16 *p_temp, u16 *p_max_temp) -+{ -+ if (p_temp) -+ *p_temp = mlxsw_reg_mtbr_rec_temp_get(payload, rec_ind); -+ if (p_max_temp) -+ *p_max_temp = mlxsw_reg_mtbr_rec_max_temp_get(payload, rec_ind); -+} -+ - /* MCIA - Management Cable Info Access - * ----------------------------------- - * MCIA register is used to access the SFP+ and QSFP connector's EPROM. -@@ -4804,13 +4907,41 @@ MLXSW_ITEM32(reg, mcia, device_address, 0x04, 0, 16); - */ - MLXSW_ITEM32(reg, mcia, size, 0x08, 0, 16); - --#define MLXSW_SP_REG_MCIA_EEPROM_SIZE 48 -+#define MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH 256 -+#define MLXSW_REG_MCIA_EEPROM_SIZE 48 -+#define MLXSW_REG_MCIA_I2C_ADDR_LOW 0x50 -+#define MLXSW_REG_MCIA_I2C_ADDR_HIGH 0x51 -+#define MLXSW_REG_MCIA_PAGE0_LO_OFF 0xa0 -+#define MLXSW_REG_MCIA_TH_ITEM_SIZE 2 -+#define MLXSW_REG_MCIA_TH_PAGE_NUM 3 -+#define MLXSW_REG_MCIA_PAGE0_LO 0 -+#define MLXSW_REG_MCIA_TH_PAGE_OFF 0x80 -+ -+enum mlxsw_reg_mcia_eeprom_module_info_rev_id { -+ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_UNSPC = 0x00, -+ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8436 = 0x01, -+ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636 = 0x03, -+}; -+ -+enum mlxsw_reg_mcia_eeprom_module_info_id { -+ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP = 0x03, -+ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP = 0x0C, -+ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS = 0x0D, -+ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 = 0x11, -+ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD = 0x18, -+}; -+ -+enum mlxsw_reg_mcia_eeprom_module_info { -+ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID, -+ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID, -+ MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE, -+}; - - /* reg_mcia_eeprom - * Bytes to read/write. - * Access: RW - */ --MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_SP_REG_MCIA_EEPROM_SIZE); -+MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE); - - static inline void mlxsw_reg_mcia_pack(char *payload, u8 module, u8 lock, - u8 page_number, u16 device_addr, -@@ -5548,6 +5679,8 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id) - return "MFSC"; - case MLXSW_REG_MFSM_ID: - return "MFSM"; -+ case MLXSW_REG_FORE_ID: -+ return "FORE"; - case MLXSW_REG_MTCAP_ID: - return "MTCAP"; - case MLXSW_REG_MPAT_ID: -@@ -5556,6 +5689,8 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id) - return "MPAR"; - case MLXSW_REG_MTMP_ID: - return "MTMP"; -+ case MLXSW_REG_MTBR_ID: -+ return "MTBR"; - case MLXSW_REG_MLCR_ID: - return "MLCR"; - case MLXSW_REG_SBPR_ID: -diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c -index b6d4455..52314a1 100644 ---- a/drivers/platform/mellanox/mlxreg-hotplug.c -+++ b/drivers/platform/mellanox/mlxreg-hotplug.c -@@ -495,7 +495,9 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) - { - struct mlxreg_core_hotplug_platform_data *pdata; - struct mlxreg_core_item *item; -- int i, ret; -+ struct mlxreg_core_data *data; -+ u32 regval; -+ int i, j, ret; - - pdata = dev_get_platdata(&priv->pdev->dev); - item = pdata->items; -@@ -507,6 +509,25 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) - if (ret) - goto out; - -+ /* -+ * Verify if hardware configuration requires to disable -+ * interrupt capability for some of components. -+ */ -+ data = item->data; -+ for (j = 0; j < item->count; j++, data++) { -+ /* Verify if the attribute has capability register. */ -+ if (data->capability) { -+ /* Read capability register. */ -+ ret = regmap_read(priv->regmap, -+ data->capability, ®val); -+ if (ret) -+ goto out; -+ -+ if (!(regval & data->bit)) -+ item->mask &= ~BIT(j); -+ } -+ } -+ - /* Set group initial status as mask and unmask group event. */ - if (item->inversed) { - item->cache = item->mask; -diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c -index c192dfe..acfaf64 100644 ---- a/drivers/platform/mellanox/mlxreg-io.c -+++ b/drivers/platform/mellanox/mlxreg-io.c -@@ -152,8 +152,8 @@ static int mlxreg_io_attr_init(struct mlxreg_io_priv_data *priv) - { - int i; - -- priv->group.attrs = devm_kzalloc(&priv->pdev->dev, -- priv->pdata->counter * -+ priv->group.attrs = devm_kcalloc(&priv->pdev->dev, -+ priv->pdata->counter, - sizeof(struct attribute *), - GFP_KERNEL); - if (!priv->group.attrs) -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index e8782f5..6e150b4 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -1,34 +1,9 @@ -+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 - /* -- * Copyright (c) 2016 Mellanox Technologies. All rights reserved. -- * Copyright (c) 2016 Vadim Pasternak -+ * Mellanox platform driver - * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. 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. -- * 3. Neither the names of the copyright holders nor the names of its -- * contributors may be used to endorse or promote products derived from -- * this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * 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. -+ * Copyright (C) 2016-2018 Mellanox Technologies -+ * Copyright (C) 2016-2018 Vadim Pasternak - */ - - #include -@@ -49,7 +24,7 @@ - #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 - #define MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET 0x00 - #define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET 0x01 --#define MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET 0x02 -+#define MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET 0x02 - #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 -@@ -58,6 +33,7 @@ - #define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET 0x22 - #define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET 0x23 - #define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET 0x24 -+#define MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION 0x2a - #define MLXPLAT_CPLD_LPC_REG_GP1_OFFSET 0x30 - #define MLXPLAT_CPLD_LPC_REG_WP1_OFFSET 0x31 - #define MLXPLAT_CPLD_LPC_REG_GP2_OFFSET 0x32 -@@ -92,6 +68,10 @@ - #define MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET 0xee - #define MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET 0xef - #define MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET 0xf0 -+#define MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET 0xf5 -+#define MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET 0xf6 -+#define MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET 0xf7 -+#define MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET 0xf8 - #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 - #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb - #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda -@@ -578,7 +558,7 @@ static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = { - - static - struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = { -- .items = mlxplat_mlxcpld_msn21xx_items, -+ .items = mlxplat_mlxcpld_msn201x_items, - .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items), - .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, - .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, -@@ -609,36 +589,48 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_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, - }, - }; -@@ -841,61 +833,85 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_led_data[] = { - .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), - }, - }; - -@@ -1123,7 +1139,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { - .reg = MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET, - .bit = GENMASK(7, 0), - .mode = 0444, -- }, -+ }, - { - .label = "reset_long_pb", - .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -@@ -1209,6 +1225,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { - .bit = 1, - .mode = 0444, - }, -+ { -+ .label = "fan_dir", -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION, -+ .bit = GENMASK(7, 0), -+ .mode = 0200, -+ }, - }; - - static struct mlxreg_core_platform_data mlxplat_default_ng_regs_io_data = { -@@ -1226,61 +1248,90 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { - .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", -+ .reg = MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET, -+ .capability = MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET, - }, - }; - -@@ -1332,6 +1383,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: - case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: - case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION: - case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: -@@ -1366,6 +1418,10 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: - case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: - case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET: - return true; - } - return false; -@@ -1385,6 +1441,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: - case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: - case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION: - case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: - case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: -@@ -1417,6 +1474,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: - case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: - case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET: - return true; - } - return false; -@@ -1639,6 +1700,13 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { - }, - }, - { -+ .callback = mlxplat_dmi_qmb7xx_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN38"), -+ }, -+ }, -+ { - .callback = mlxplat_dmi_default_matched, - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"), -@@ -1668,6 +1736,12 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { - DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), - }, - }, -+ { -+ .callback = mlxplat_dmi_qmb7xx_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0007"), -+ }, -+ }, - { } - }; - -diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h -index 19f5cb61..1b2f86f 100644 ---- a/include/linux/platform_data/mlxreg.h -+++ b/include/linux/platform_data/mlxreg.h -@@ -61,6 +61,7 @@ struct mlxreg_hotplug_device { - * @reg: attribute register; - * @mask: attribute access mask; - * @bit: attribute effective bit; -+ * @capability: attribute capability register; - * @mode: access mode; - * @np - pointer to node platform associated with attribute; - * @hpdev - hotplug device data; -@@ -72,6 +73,7 @@ struct mlxreg_core_data { - u32 reg; - u32 mask; - u32 bit; -+ u32 capability; - umode_t mode; - struct device_node *np; - struct mlxreg_hotplug_device hpdev; -@@ -107,9 +109,9 @@ struct mlxreg_core_item { - /** - * struct mlxreg_core_platform_data - platform data: - * -- * @led_data: led private data; -+ * @data: instance private data; - * @regmap: register map of parent device; -- * @counter: number of led instances; -+ * @counter: number of instances; - */ - struct mlxreg_core_platform_data { - struct mlxreg_core_data *data; -diff --git a/include/linux/sfp.h b/include/linux/sfp.h -new file mode 100644 -index 0000000..d37518e ---- /dev/null -+++ b/include/linux/sfp.h -@@ -0,0 +1,564 @@ -+#ifndef LINUX_SFP_H -+#define LINUX_SFP_H -+ -+#include -+ -+struct sfp_eeprom_base { -+ u8 phys_id; -+ u8 phys_ext_id; -+ u8 connector; -+#if defined __BIG_ENDIAN_BITFIELD -+ u8 e10g_base_er:1; -+ u8 e10g_base_lrm:1; -+ u8 e10g_base_lr:1; -+ u8 e10g_base_sr:1; -+ u8 if_1x_sx:1; -+ u8 if_1x_lx:1; -+ u8 if_1x_copper_active:1; -+ u8 if_1x_copper_passive:1; -+ -+ u8 escon_mmf_1310_led:1; -+ u8 escon_smf_1310_laser:1; -+ u8 sonet_oc192_short_reach:1; -+ u8 sonet_reach_bit1:1; -+ u8 sonet_reach_bit2:1; -+ u8 sonet_oc48_long_reach:1; -+ u8 sonet_oc48_intermediate_reach:1; -+ u8 sonet_oc48_short_reach:1; -+ -+ u8 unallocated_5_7:1; -+ u8 sonet_oc12_smf_long_reach:1; -+ u8 sonet_oc12_smf_intermediate_reach:1; -+ u8 sonet_oc12_short_reach:1; -+ u8 unallocated_5_3:1; -+ u8 sonet_oc3_smf_long_reach:1; -+ u8 sonet_oc3_smf_intermediate_reach:1; -+ u8 sonet_oc3_short_reach:1; -+ -+ u8 e_base_px:1; -+ u8 e_base_bx10:1; -+ u8 e100_base_fx:1; -+ u8 e100_base_lx:1; -+ u8 e1000_base_t:1; -+ u8 e1000_base_cx:1; -+ u8 e1000_base_lx:1; -+ u8 e1000_base_sx:1; -+ -+ u8 fc_ll_v:1; -+ u8 fc_ll_s:1; -+ u8 fc_ll_i:1; -+ u8 fc_ll_l:1; -+ u8 fc_ll_m:1; -+ u8 fc_tech_sa:1; -+ u8 fc_tech_lc:1; -+ u8 fc_tech_electrical_inter_enclosure:1; -+ -+ u8 fc_tech_electrical_intra_enclosure:1; -+ u8 fc_tech_sn:1; -+ u8 fc_tech_sl:1; -+ u8 fc_tech_ll:1; -+ u8 sfp_ct_active:1; -+ u8 sfp_ct_passive:1; -+ u8 unallocated_8_1:1; -+ u8 unallocated_8_0:1; -+ -+ u8 fc_media_tw:1; -+ u8 fc_media_tp:1; -+ u8 fc_media_mi:1; -+ u8 fc_media_tv:1; -+ u8 fc_media_m6:1; -+ u8 fc_media_m5:1; -+ u8 unallocated_9_1:1; -+ u8 fc_media_sm:1; -+ -+ u8 fc_speed_1200:1; -+ u8 fc_speed_800:1; -+ u8 fc_speed_1600:1; -+ u8 fc_speed_400:1; -+ u8 fc_speed_3200:1; -+ u8 fc_speed_200:1; -+ u8 unallocated_10_1:1; -+ u8 fc_speed_100:1; -+#elif defined __LITTLE_ENDIAN_BITFIELD -+ u8 if_1x_copper_passive:1; -+ u8 if_1x_copper_active:1; -+ u8 if_1x_lx:1; -+ u8 if_1x_sx:1; -+ u8 e10g_base_sr:1; -+ u8 e10g_base_lr:1; -+ u8 e10g_base_lrm:1; -+ u8 e10g_base_er:1; -+ -+ u8 sonet_oc3_short_reach:1; -+ u8 sonet_oc3_smf_intermediate_reach:1; -+ u8 sonet_oc3_smf_long_reach:1; -+ u8 unallocated_5_3:1; -+ u8 sonet_oc12_short_reach:1; -+ u8 sonet_oc12_smf_intermediate_reach:1; -+ u8 sonet_oc12_smf_long_reach:1; -+ u8 unallocated_5_7:1; -+ -+ u8 sonet_oc48_short_reach:1; -+ u8 sonet_oc48_intermediate_reach:1; -+ u8 sonet_oc48_long_reach:1; -+ u8 sonet_reach_bit2:1; -+ u8 sonet_reach_bit1:1; -+ u8 sonet_oc192_short_reach:1; -+ u8 escon_smf_1310_laser:1; -+ u8 escon_mmf_1310_led:1; -+ -+ u8 e1000_base_sx:1; -+ u8 e1000_base_lx:1; -+ u8 e1000_base_cx:1; -+ u8 e1000_base_t:1; -+ u8 e100_base_lx:1; -+ u8 e100_base_fx:1; -+ u8 e_base_bx10:1; -+ u8 e_base_px:1; -+ -+ u8 fc_tech_electrical_inter_enclosure:1; -+ u8 fc_tech_lc:1; -+ u8 fc_tech_sa:1; -+ u8 fc_ll_m:1; -+ u8 fc_ll_l:1; -+ u8 fc_ll_i:1; -+ u8 fc_ll_s:1; -+ u8 fc_ll_v:1; -+ -+ u8 unallocated_8_0:1; -+ u8 unallocated_8_1:1; -+ u8 sfp_ct_passive:1; -+ u8 sfp_ct_active:1; -+ u8 fc_tech_ll:1; -+ u8 fc_tech_sl:1; -+ u8 fc_tech_sn:1; -+ u8 fc_tech_electrical_intra_enclosure:1; -+ -+ u8 fc_media_sm:1; -+ u8 unallocated_9_1:1; -+ u8 fc_media_m5:1; -+ u8 fc_media_m6:1; -+ u8 fc_media_tv:1; -+ u8 fc_media_mi:1; -+ u8 fc_media_tp:1; -+ u8 fc_media_tw:1; -+ -+ u8 fc_speed_100:1; -+ u8 unallocated_10_1:1; -+ u8 fc_speed_200:1; -+ u8 fc_speed_3200:1; -+ u8 fc_speed_400:1; -+ u8 fc_speed_1600:1; -+ u8 fc_speed_800:1; -+ u8 fc_speed_1200:1; -+#else -+#error Unknown Endian -+#endif -+ u8 encoding; -+ u8 br_nominal; -+ u8 rate_id; -+ u8 link_len[6]; -+ char vendor_name[16]; -+ u8 extended_cc; -+ char vendor_oui[3]; -+ char vendor_pn[16]; -+ char vendor_rev[4]; -+ union { -+ __be16 optical_wavelength; -+ __be16 cable_compliance; -+ struct { -+#if defined __BIG_ENDIAN_BITFIELD -+ u8 reserved60_2:6; -+ u8 fc_pi_4_app_h:1; -+ u8 sff8431_app_e:1; -+ u8 reserved61:8; -+#elif defined __LITTLE_ENDIAN_BITFIELD -+ u8 sff8431_app_e:1; -+ u8 fc_pi_4_app_h:1; -+ u8 reserved60_2:6; -+ u8 reserved61:8; -+#else -+#error Unknown Endian -+#endif -+ } __packed passive; -+ struct { -+#if defined __BIG_ENDIAN_BITFIELD -+ u8 reserved60_4:4; -+ u8 fc_pi_4_lim:1; -+ u8 sff8431_lim:1; -+ u8 fc_pi_4_app_h:1; -+ u8 sff8431_app_e:1; -+ u8 reserved61:8; -+#elif defined __LITTLE_ENDIAN_BITFIELD -+ u8 sff8431_app_e:1; -+ u8 fc_pi_4_app_h:1; -+ u8 sff8431_lim:1; -+ u8 fc_pi_4_lim:1; -+ u8 reserved60_4:4; -+ u8 reserved61:8; -+#else -+#error Unknown Endian -+#endif -+ } __packed active; -+ } __packed; -+ u8 reserved62; -+ u8 cc_base; -+} __packed; -+ -+struct sfp_eeprom_ext { -+ __be16 options; -+ u8 br_max; -+ u8 br_min; -+ char vendor_sn[16]; -+ char datecode[8]; -+ u8 diagmon; -+ u8 enhopts; -+ u8 sff8472_compliance; -+ u8 cc_ext; -+} __packed; -+ -+/** -+ * struct sfp_eeprom_id - raw SFP module identification information -+ * @base: base SFP module identification structure -+ * @ext: extended SFP module identification structure -+ * -+ * See the SFF-8472 specification and related documents for the definition -+ * of these structure members. This can be obtained from -+ * ftp://ftp.seagate.com/sff -+ */ -+struct sfp_eeprom_id { -+ struct sfp_eeprom_base base; -+ struct sfp_eeprom_ext ext; -+} __packed; -+ -+struct sfp_diag { -+ __be16 temp_high_alarm; -+ __be16 temp_low_alarm; -+ __be16 temp_high_warn; -+ __be16 temp_low_warn; -+ __be16 volt_high_alarm; -+ __be16 volt_low_alarm; -+ __be16 volt_high_warn; -+ __be16 volt_low_warn; -+ __be16 bias_high_alarm; -+ __be16 bias_low_alarm; -+ __be16 bias_high_warn; -+ __be16 bias_low_warn; -+ __be16 txpwr_high_alarm; -+ __be16 txpwr_low_alarm; -+ __be16 txpwr_high_warn; -+ __be16 txpwr_low_warn; -+ __be16 rxpwr_high_alarm; -+ __be16 rxpwr_low_alarm; -+ __be16 rxpwr_high_warn; -+ __be16 rxpwr_low_warn; -+ __be16 laser_temp_high_alarm; -+ __be16 laser_temp_low_alarm; -+ __be16 laser_temp_high_warn; -+ __be16 laser_temp_low_warn; -+ __be16 tec_cur_high_alarm; -+ __be16 tec_cur_low_alarm; -+ __be16 tec_cur_high_warn; -+ __be16 tec_cur_low_warn; -+ __be32 cal_rxpwr4; -+ __be32 cal_rxpwr3; -+ __be32 cal_rxpwr2; -+ __be32 cal_rxpwr1; -+ __be32 cal_rxpwr0; -+ __be16 cal_txi_slope; -+ __be16 cal_txi_offset; -+ __be16 cal_txpwr_slope; -+ __be16 cal_txpwr_offset; -+ __be16 cal_t_slope; -+ __be16 cal_t_offset; -+ __be16 cal_v_slope; -+ __be16 cal_v_offset; -+} __packed; -+ -+/* SFP EEPROM registers */ -+enum { -+ SFP_PHYS_ID = 0x00, -+ SFP_PHYS_EXT_ID = 0x01, -+ SFP_CONNECTOR = 0x02, -+ SFP_COMPLIANCE = 0x03, -+ SFP_ENCODING = 0x0b, -+ SFP_BR_NOMINAL = 0x0c, -+ SFP_RATE_ID = 0x0d, -+ SFP_LINK_LEN_SM_KM = 0x0e, -+ SFP_LINK_LEN_SM_100M = 0x0f, -+ SFP_LINK_LEN_50UM_OM2_10M = 0x10, -+ SFP_LINK_LEN_62_5UM_OM1_10M = 0x11, -+ SFP_LINK_LEN_COPPER_1M = 0x12, -+ SFP_LINK_LEN_50UM_OM4_10M = 0x12, -+ SFP_LINK_LEN_50UM_OM3_10M = 0x13, -+ SFP_VENDOR_NAME = 0x14, -+ SFP_VENDOR_OUI = 0x25, -+ SFP_VENDOR_PN = 0x28, -+ SFP_VENDOR_REV = 0x38, -+ SFP_OPTICAL_WAVELENGTH_MSB = 0x3c, -+ SFP_OPTICAL_WAVELENGTH_LSB = 0x3d, -+ SFP_CABLE_SPEC = 0x3c, -+ SFP_CC_BASE = 0x3f, -+ SFP_OPTIONS = 0x40, /* 2 bytes, MSB, LSB */ -+ SFP_BR_MAX = 0x42, -+ SFP_BR_MIN = 0x43, -+ SFP_VENDOR_SN = 0x44, -+ SFP_DATECODE = 0x54, -+ SFP_DIAGMON = 0x5c, -+ SFP_ENHOPTS = 0x5d, -+ SFP_SFF8472_COMPLIANCE = 0x5e, -+ SFP_CC_EXT = 0x5f, -+ -+ SFP_PHYS_ID_SFF = 0x02, -+ SFP_PHYS_ID_SFP = 0x03, -+ SFP_PHYS_EXT_ID_SFP = 0x04, -+ SFP_CONNECTOR_UNSPEC = 0x00, -+ /* codes 01-05 not supportable on SFP, but some modules have single SC */ -+ SFP_CONNECTOR_SC = 0x01, -+ SFP_CONNECTOR_FIBERJACK = 0x06, -+ SFP_CONNECTOR_LC = 0x07, -+ SFP_CONNECTOR_MT_RJ = 0x08, -+ SFP_CONNECTOR_MU = 0x09, -+ SFP_CONNECTOR_SG = 0x0a, -+ SFP_CONNECTOR_OPTICAL_PIGTAIL = 0x0b, -+ SFP_CONNECTOR_MPO_1X12 = 0x0c, -+ SFP_CONNECTOR_MPO_2X16 = 0x0d, -+ SFP_CONNECTOR_HSSDC_II = 0x20, -+ SFP_CONNECTOR_COPPER_PIGTAIL = 0x21, -+ SFP_CONNECTOR_RJ45 = 0x22, -+ SFP_CONNECTOR_NOSEPARATE = 0x23, -+ SFP_CONNECTOR_MXC_2X16 = 0x24, -+ SFP_ENCODING_UNSPEC = 0x00, -+ SFP_ENCODING_8B10B = 0x01, -+ SFP_ENCODING_4B5B = 0x02, -+ SFP_ENCODING_NRZ = 0x03, -+ SFP_ENCODING_8472_MANCHESTER = 0x04, -+ SFP_ENCODING_8472_SONET = 0x05, -+ SFP_ENCODING_8472_64B66B = 0x06, -+ SFP_ENCODING_256B257B = 0x07, -+ SFP_ENCODING_PAM4 = 0x08, -+ SFP_OPTIONS_HIGH_POWER_LEVEL = BIT(13), -+ SFP_OPTIONS_PAGING_A2 = BIT(12), -+ SFP_OPTIONS_RETIMER = BIT(11), -+ SFP_OPTIONS_COOLED_XCVR = BIT(10), -+ SFP_OPTIONS_POWER_DECL = BIT(9), -+ SFP_OPTIONS_RX_LINEAR_OUT = BIT(8), -+ SFP_OPTIONS_RX_DECISION_THRESH = BIT(7), -+ SFP_OPTIONS_TUNABLE_TX = BIT(6), -+ SFP_OPTIONS_RATE_SELECT = BIT(5), -+ SFP_OPTIONS_TX_DISABLE = BIT(4), -+ SFP_OPTIONS_TX_FAULT = BIT(3), -+ SFP_OPTIONS_LOS_INVERTED = BIT(2), -+ SFP_OPTIONS_LOS_NORMAL = BIT(1), -+ SFP_DIAGMON_DDM = BIT(6), -+ SFP_DIAGMON_INT_CAL = BIT(5), -+ SFP_DIAGMON_EXT_CAL = BIT(4), -+ SFP_DIAGMON_RXPWR_AVG = BIT(3), -+ SFP_DIAGMON_ADDRMODE = BIT(2), -+ SFP_ENHOPTS_ALARMWARN = BIT(7), -+ SFP_ENHOPTS_SOFT_TX_DISABLE = BIT(6), -+ SFP_ENHOPTS_SOFT_TX_FAULT = BIT(5), -+ SFP_ENHOPTS_SOFT_RX_LOS = BIT(4), -+ SFP_ENHOPTS_SOFT_RATE_SELECT = BIT(3), -+ SFP_ENHOPTS_APP_SELECT_SFF8079 = BIT(2), -+ SFP_ENHOPTS_SOFT_RATE_SFF8431 = BIT(1), -+ SFP_SFF8472_COMPLIANCE_NONE = 0x00, -+ SFP_SFF8472_COMPLIANCE_REV9_3 = 0x01, -+ SFP_SFF8472_COMPLIANCE_REV9_5 = 0x02, -+ SFP_SFF8472_COMPLIANCE_REV10_2 = 0x03, -+ SFP_SFF8472_COMPLIANCE_REV10_4 = 0x04, -+ SFP_SFF8472_COMPLIANCE_REV11_0 = 0x05, -+ SFP_SFF8472_COMPLIANCE_REV11_3 = 0x06, -+ SFP_SFF8472_COMPLIANCE_REV11_4 = 0x07, -+ SFP_SFF8472_COMPLIANCE_REV12_0 = 0x08, -+}; -+ -+/* SFP Diagnostics */ -+enum { -+ /* Alarm and warnings stored MSB at lower address then LSB */ -+ SFP_TEMP_HIGH_ALARM = 0x00, -+ SFP_TEMP_LOW_ALARM = 0x02, -+ SFP_TEMP_HIGH_WARN = 0x04, -+ SFP_TEMP_LOW_WARN = 0x06, -+ SFP_VOLT_HIGH_ALARM = 0x08, -+ SFP_VOLT_LOW_ALARM = 0x0a, -+ SFP_VOLT_HIGH_WARN = 0x0c, -+ SFP_VOLT_LOW_WARN = 0x0e, -+ SFP_BIAS_HIGH_ALARM = 0x10, -+ SFP_BIAS_LOW_ALARM = 0x12, -+ SFP_BIAS_HIGH_WARN = 0x14, -+ SFP_BIAS_LOW_WARN = 0x16, -+ SFP_TXPWR_HIGH_ALARM = 0x18, -+ SFP_TXPWR_LOW_ALARM = 0x1a, -+ SFP_TXPWR_HIGH_WARN = 0x1c, -+ SFP_TXPWR_LOW_WARN = 0x1e, -+ SFP_RXPWR_HIGH_ALARM = 0x20, -+ SFP_RXPWR_LOW_ALARM = 0x22, -+ SFP_RXPWR_HIGH_WARN = 0x24, -+ SFP_RXPWR_LOW_WARN = 0x26, -+ SFP_LASER_TEMP_HIGH_ALARM = 0x28, -+ SFP_LASER_TEMP_LOW_ALARM = 0x2a, -+ SFP_LASER_TEMP_HIGH_WARN = 0x2c, -+ SFP_LASER_TEMP_LOW_WARN = 0x2e, -+ SFP_TEC_CUR_HIGH_ALARM = 0x30, -+ SFP_TEC_CUR_LOW_ALARM = 0x32, -+ SFP_TEC_CUR_HIGH_WARN = 0x34, -+ SFP_TEC_CUR_LOW_WARN = 0x36, -+ SFP_CAL_RXPWR4 = 0x38, -+ SFP_CAL_RXPWR3 = 0x3c, -+ SFP_CAL_RXPWR2 = 0x40, -+ SFP_CAL_RXPWR1 = 0x44, -+ SFP_CAL_RXPWR0 = 0x48, -+ SFP_CAL_TXI_SLOPE = 0x4c, -+ SFP_CAL_TXI_OFFSET = 0x4e, -+ SFP_CAL_TXPWR_SLOPE = 0x50, -+ SFP_CAL_TXPWR_OFFSET = 0x52, -+ SFP_CAL_T_SLOPE = 0x54, -+ SFP_CAL_T_OFFSET = 0x56, -+ SFP_CAL_V_SLOPE = 0x58, -+ SFP_CAL_V_OFFSET = 0x5a, -+ SFP_CHKSUM = 0x5f, -+ -+ SFP_TEMP = 0x60, -+ SFP_VCC = 0x62, -+ SFP_TX_BIAS = 0x64, -+ SFP_TX_POWER = 0x66, -+ SFP_RX_POWER = 0x68, -+ SFP_LASER_TEMP = 0x6a, -+ SFP_TEC_CUR = 0x6c, -+ -+ SFP_STATUS = 0x6e, -+ SFP_ALARM0 = 0x70, -+ SFP_ALARM0_TEMP_HIGH = BIT(7), -+ SFP_ALARM0_TEMP_LOW = BIT(6), -+ SFP_ALARM0_VCC_HIGH = BIT(5), -+ SFP_ALARM0_VCC_LOW = BIT(4), -+ SFP_ALARM0_TX_BIAS_HIGH = BIT(3), -+ SFP_ALARM0_TX_BIAS_LOW = BIT(2), -+ SFP_ALARM0_TXPWR_HIGH = BIT(1), -+ SFP_ALARM0_TXPWR_LOW = BIT(0), -+ -+ SFP_ALARM1 = 0x71, -+ SFP_ALARM1_RXPWR_HIGH = BIT(7), -+ SFP_ALARM1_RXPWR_LOW = BIT(6), -+ -+ SFP_WARN0 = 0x74, -+ SFP_WARN0_TEMP_HIGH = BIT(7), -+ SFP_WARN0_TEMP_LOW = BIT(6), -+ SFP_WARN0_VCC_HIGH = BIT(5), -+ SFP_WARN0_VCC_LOW = BIT(4), -+ SFP_WARN0_TX_BIAS_HIGH = BIT(3), -+ SFP_WARN0_TX_BIAS_LOW = BIT(2), -+ SFP_WARN0_TXPWR_HIGH = BIT(1), -+ SFP_WARN0_TXPWR_LOW = BIT(0), -+ -+ SFP_WARN1 = 0x75, -+ SFP_WARN1_RXPWR_HIGH = BIT(7), -+ SFP_WARN1_RXPWR_LOW = BIT(6), -+ -+ SFP_EXT_STATUS = 0x76, -+ SFP_VSL = 0x78, -+ SFP_PAGE = 0x7f, -+}; -+ -+struct fwnode_handle; -+struct ethtool_eeprom; -+struct ethtool_modinfo; -+struct net_device; -+struct sfp_bus; -+ -+/** -+ * struct sfp_upstream_ops - upstream operations structure -+ * @module_insert: called after a module has been detected to determine -+ * whether the module is supported for the upstream device. -+ * @module_remove: called after the module has been removed. -+ * @link_down: called when the link is non-operational for whatever -+ * reason. -+ * @link_up: called when the link is operational. -+ * @connect_phy: called when an I2C accessible PHY has been detected -+ * on the module. -+ * @disconnect_phy: called when a module with an I2C accessible PHY has -+ * been removed. -+ */ -+struct sfp_upstream_ops { -+ int (*module_insert)(void *priv, const struct sfp_eeprom_id *id); -+ void (*module_remove)(void *priv); -+ void (*link_down)(void *priv); -+ void (*link_up)(void *priv); -+ int (*connect_phy)(void *priv, struct phy_device *); -+ void (*disconnect_phy)(void *priv); -+}; -+ -+#if IS_ENABLED(CONFIG_SFP) -+int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id, -+ unsigned long *support); -+void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, -+ unsigned long *support); -+phy_interface_t sfp_select_interface(struct sfp_bus *bus, -+ const struct sfp_eeprom_id *id, -+ unsigned long *link_modes); -+ -+int sfp_get_module_info(struct sfp_bus *bus, struct ethtool_modinfo *modinfo); -+int sfp_get_module_eeprom(struct sfp_bus *bus, struct ethtool_eeprom *ee, -+ u8 *data); -+void sfp_upstream_start(struct sfp_bus *bus); -+void sfp_upstream_stop(struct sfp_bus *bus); -+struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode, -+ struct net_device *ndev, void *upstream, -+ const struct sfp_upstream_ops *ops); -+void sfp_unregister_upstream(struct sfp_bus *bus); -+#else -+static inline int sfp_parse_port(struct sfp_bus *bus, -+ const struct sfp_eeprom_id *id, -+ unsigned long *support) -+{ -+ return PORT_OTHER; -+} -+ -+static inline void sfp_parse_support(struct sfp_bus *bus, -+ const struct sfp_eeprom_id *id, -+ unsigned long *support) -+{ -+} -+ -+static inline phy_interface_t sfp_select_interface(struct sfp_bus *bus, -+ const struct sfp_eeprom_id *id, -+ unsigned long *link_modes) -+{ -+ return PHY_INTERFACE_MODE_NA; -+} -+ -+static inline int sfp_get_module_info(struct sfp_bus *bus, -+ struct ethtool_modinfo *modinfo) -+{ -+ return -EOPNOTSUPP; -+} -+ -+static inline int sfp_get_module_eeprom(struct sfp_bus *bus, -+ struct ethtool_eeprom *ee, u8 *data) -+{ -+ return -EOPNOTSUPP; -+} -+ -+static inline void sfp_upstream_start(struct sfp_bus *bus) -+{ -+} -+ -+static inline void sfp_upstream_stop(struct sfp_bus *bus) -+{ -+} -+ -+static inline struct sfp_bus *sfp_register_upstream( -+ struct fwnode_handle *fwnode, -+ struct net_device *ndev, void *upstream, -+ const struct sfp_upstream_ops *ops) -+{ -+ return (struct sfp_bus *)-1; -+} -+ -+static inline void sfp_unregister_upstream(struct sfp_bus *bus) -+{ -+} -+#endif -+ -+#endif --- -2.1.4 - diff --git a/patch/0028-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch b/patch/0028-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch deleted file mode 100644 index d29b5c5cc918..000000000000 --- a/patch/0028-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch +++ /dev/null @@ -1,839 +0,0 @@ -From a648f2856518f8884a7798469faf755d0f5dcd50 Mon Sep 17 00:00:00 2001 -From: Michael Shych -Date: Mon, 17 Dec 2018 12:32:45 +0000 -Subject: [PATCH v1 mlx-wdt 1/1] watchdog: mlx-wdt: introduce watchdog driver - for Mellanox systems - -Watchdog driver for Mellanox watchdog devices, implemented in -programmable logic device. - -Main and auxiliary watchdog devices can exist on the same system. -There are several actions that can be defined in the watchdog: -system reset, start fans on full speed and increase counter. -The last 2 actions are performed without system reset. -Actions without reset are provided for auxiliary watchdog devices, -which is optional. -Access to CPLD registers is performed through generic -regmap interface. - -There are 2 types of HW CPLD watchdog implementations. -Type 1: actual HW timeout can be defined as power of 2 msec. -e.g. timeout 20 sec will be rounded up to 32768 msec.; -maximum timeout period is 32 sec (32768 msec.); -get time-left isn't supported -Type 2: actual HW timeout is defined in sec. and it's a same as -user defined timeout; -maximum timeout is 255 sec; -get time-left is supported; - -Watchdog driver is probed from common mlx_platform driver. - -Signed-off-by: Michael Shych ---- - drivers/platform/x86/mlx-platform.c | 202 +++++++++++++++++- - drivers/watchdog/Kconfig | 15 ++ - drivers/watchdog/Makefile | 1 + - drivers/watchdog/mlx_wdt.c | 391 +++++++++++++++++++++++++++++++++++ - include/linux/platform_data/mlxreg.h | 6 + - 5 files changed, 612 insertions(+), 3 deletions(-) - create mode 100644 drivers/watchdog/mlx_wdt.c - -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index 6e150b4..fc8d655 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -55,6 +55,14 @@ - #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 - #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 - #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a -+#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET 0xc7 -+#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET 0xc8 -+#define MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET 0xc9 -+#define MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET 0xcb -+#define MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET 0xcd -+#define MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET 0xcf -+#define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET 0xd1 -+#define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd2 - #define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3 - #define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4 - #define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5 -@@ -128,6 +136,18 @@ - #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13 - #define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14 - -+/* Masks and default values for watchdogs */ -+#define MLXPLAT_CPLD_WD1_CLEAR_MASK GENMASK(7, 1) -+#define MLXPLAT_CPLD_WD2_CLEAR_MASK (GENMASK(7, 0) & ~BIT(1)) -+ -+#define MLXPLAT_CPLD_WD_TYPE1_TO_MASK GENMASK(7, 4) -+#define MLXPLAT_CPLD_WD_TYPE2_TO_MASK 0 -+#define MLXPLAT_CPLD_WD_RESET_ACT_MASK GENMASK(7, 1) -+#define MLXPLAT_CPLD_WD_FAN_ACT_MASK (GENMASK(7, 0) & ~BIT(4)) -+#define MLXPLAT_CPLD_WD_COUNT_ACT_MASK (GENMASK(7, 0) & ~BIT(7)) -+#define MLXPLAT_CPLD_WD_DFLT_TIMEOUT 30 -+#define MLXPLAT_CPLD_WD_MAX_DEVS 2 -+ - /* mlxplat_priv - platform private data - * @pdev_i2c - i2c controller platform device - * @pdev_mux - array of mux platform devices -@@ -135,6 +155,7 @@ - * @pdev_led - led platform devices - * @pdev_io_regs - register access platform devices - * @pdev_fan - FAN platform devices -+ * @pdev_wd - array of watchdog platform devices - */ - struct mlxplat_priv { - struct platform_device *pdev_i2c; -@@ -143,6 +164,7 @@ struct mlxplat_priv { - struct platform_device *pdev_led; - struct platform_device *pdev_io_regs; - struct platform_device *pdev_fan; -+ struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS]; - }; - - /* Regions for LPC I2C controller and LPC base register space */ -@@ -1340,6 +1362,132 @@ static struct mlxreg_core_platform_data mlxplat_default_fan_data = { - .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data), - }; - -+/* Type1 watchdog implementation on MSN2700, MSN2100 and MSN2140 systems */ -+static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type1[] = { -+ { -+ .label = "action", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, -+ .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK, -+ .bit = 0, -+ }, -+ { -+ .label = "timeout", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET, -+ .mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK, -+ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, -+ }, -+ { -+ .label = "ping", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET, -+ .mask = MLXPLAT_CPLD_WD1_CLEAR_MASK, -+ .bit = 0, -+ }, -+ { -+ .label = "reset", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(6), -+ .bit = 6, -+ }, -+}; -+ -+static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type1[] = { -+ { -+ .label = "action", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, -+ .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK, -+ .bit = 4, -+ }, -+ { -+ .label = "timeout", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET, -+ .mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK, -+ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, -+ }, -+ { -+ .label = "ping", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET, -+ .mask = MLXPLAT_CPLD_WD1_CLEAR_MASK, -+ .bit = 1, -+ }, -+}; -+ -+static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type1[] = { -+ { -+ .data = mlxplat_mlxcpld_wd_main_regs_type1, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type1), -+ .identity = "mlx-wdt-main", -+ }, -+ { -+ .data = mlxplat_mlxcpld_wd_aux_regs_type1, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type1), -+ .identity = "mlx-wdt-aux", -+ }, -+}; -+ -+/* Type2 watchdog implementation on MSB8700 and up systems -+ * To differentiate: ping reg == action reg -+ */ -+static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type2[] = { -+ { -+ .label = "action", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, -+ .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK, -+ .bit = 0, -+ }, -+ { -+ .label = "timeout", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET, -+ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, -+ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, -+ }, -+ { -+ .label = "ping", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, -+ .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK, -+ .bit = 0, -+ }, -+ { -+ .label = "reset", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(6), -+ .bit = 6, -+ }, -+}; -+ -+static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type2[] = { -+ { -+ .label = "action", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, -+ .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK, -+ .bit = 4, -+ }, -+ { -+ .label = "timeout", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET, -+ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, -+ .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, -+ }, -+ { -+ .label = "ping", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, -+ .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK, -+ .bit = 4, -+ }, -+}; -+ -+static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type2[] = { -+ { -+ .data = mlxplat_mlxcpld_wd_main_regs_type2, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type2), -+ .identity = "mlx-wdt-main", -+ }, -+ { -+ .data = mlxplat_mlxcpld_wd_aux_regs_type2, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type2), -+ .identity = "mlx-wdt-aux", -+ }, -+}; -+ - static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) - { - switch (reg) { -@@ -1362,6 +1510,14 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: - case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: - case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: - case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: - return true; -@@ -1404,6 +1560,14 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: - case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: - case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: - case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: -@@ -1460,6 +1624,8 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: - case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: - case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: - case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: -@@ -1487,6 +1653,7 @@ static const struct reg_default mlxplat_mlxcpld_regmap_default[] = { - { MLXPLAT_CPLD_LPC_REG_WP1_OFFSET, 0x00 }, - { MLXPLAT_CPLD_LPC_REG_WP2_OFFSET, 0x00 }, - { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, -+ { MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 }, - }; - - struct mlxplat_mlxcpld_regmap_context { -@@ -1536,6 +1703,8 @@ static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; - static struct mlxreg_core_platform_data *mlxplat_led; - static struct mlxreg_core_platform_data *mlxplat_regs_io; - static struct mlxreg_core_platform_data *mlxplat_fan; -+static struct mlxreg_core_platform_data -+ *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS]; - - static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) - { -@@ -1551,6 +1720,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) - mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; - mlxplat_led = &mlxplat_default_led_data; - mlxplat_regs_io = &mlxplat_default_regs_io_data; -+ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; - - return 1; - }; -@@ -1569,6 +1739,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) - mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; - mlxplat_led = &mlxplat_msn21xx_led_data; - mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; -+ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; - - return 1; - }; -@@ -1587,6 +1758,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) - mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; - mlxplat_led = &mlxplat_default_led_data; - mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; -+ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; - - return 1; - }; -@@ -1605,6 +1777,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) - mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; - mlxplat_led = &mlxplat_msn21xx_led_data; - mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; -+ mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; - - return 1; - }; -@@ -1624,6 +1797,8 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) - mlxplat_led = &mlxplat_default_ng_led_data; - mlxplat_regs_io = &mlxplat_default_ng_regs_io_data; - mlxplat_fan = &mlxplat_default_fan_data; -+ for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) -+ mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; - - return 1; - }; -@@ -1906,15 +2081,33 @@ static int __init mlxplat_init(void) - } - } - -+ /* Add WD drivers. */ -+ for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) { -+ if (mlxplat_wd_data[j]) { -+ mlxplat_wd_data[j]->regmap = mlxplat_hotplug->regmap; -+ priv->pdev_wd[j] = platform_device_register_resndata( -+ &mlxplat_dev->dev, -+ "mlx-wdt", j, NULL, 0, -+ mlxplat_wd_data[j], -+ sizeof(*mlxplat_wd_data[j])); -+ if (IS_ERR(priv->pdev_wd[j])) { -+ err = PTR_ERR(priv->pdev_wd[j]); -+ goto fail_platform_wd_register; -+ } -+ } -+ } -+ - /* Sync registers with hardware. */ - regcache_mark_dirty(mlxplat_hotplug->regmap); - err = regcache_sync(mlxplat_hotplug->regmap); - if (err) -- goto fail_platform_fan_register; -+ goto fail_platform_wd_register; - - return 0; - --fail_platform_fan_register: -+fail_platform_wd_register: -+ while (--j >= 0) -+ platform_device_unregister(priv->pdev_wd[j]); - if (mlxplat_fan) - platform_device_unregister(priv->pdev_fan); - fail_platform_io_regs_register: -@@ -1946,7 +2139,10 @@ static void __exit mlxplat_exit(void) - platform_device_unregister(priv->pdev_io_regs); - platform_device_unregister(priv->pdev_led); - platform_device_unregister(priv->pdev_hotplug); -- -+ for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) { -+ if (mlxplat_wd_data[i]) -+ platform_device_unregister(priv->pdev_wd[i]); -+ } - for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) - platform_device_unregister(priv->pdev_mux[i]); - -diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig -index 3eb58cb..ada5a33 100644 ---- a/drivers/watchdog/Kconfig -+++ b/drivers/watchdog/Kconfig -@@ -141,6 +141,21 @@ config MENF21BMC_WATCHDOG - This driver can also be built as a module. If so the module - will be called menf21bmc_wdt. - -+config MLX_WDT -+ tristate "Mellanox Watchdog" -+ select WATCHDOG_CORE -+ select REGMAP -+ ---help--- -+ This is the driver for the hardware watchdog on Mellanox systems. -+ If you are going to use it, say Y here, otherwise N. -+ This driver can be used together with the watchdog daemon. -+ It can also watch your kernel to make sure it doesn't freeze, -+ and if it does, it reboots your system after a certain amount of -+ time. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mlx-wdt. -+ - config TANGOX_WATCHDOG - tristate "Sigma Designs SMP86xx/SMP87xx watchdog" - select WATCHDOG_CORE -diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile -index caa9f4a..50494df 100644 ---- a/drivers/watchdog/Makefile -+++ b/drivers/watchdog/Makefile -@@ -139,6 +139,7 @@ obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o - obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o - obj-$(CONFIG_INTEL_MEI_WDT) += mei_wdt.o - obj-$(CONFIG_NI903X_WDT) += ni903x_wdt.o -+obj-$(CONFIG_MLX_WDT) += mlx_wdt.o - - # M32R Architecture - -diff --git a/drivers/watchdog/mlx_wdt.c b/drivers/watchdog/mlx_wdt.c -new file mode 100644 -index 0000000..7effe8c ---- /dev/null -+++ b/drivers/watchdog/mlx_wdt.c -@@ -0,0 +1,391 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Mellanox watchdog driver -+ * -+ * Copyright (C) 2018 Mellanox Technologies -+ * Copyright (C) 2018 Michael Shych -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MLXREG_WDT_CLOCK_SCALE 1000 -+#define MLXREG_WDT_MAX_TIMEOUT_TYPE1 32 -+#define MLXREG_WDT_MAX_TIMEOUT_TYPE2 255 -+#define MLXREG_WDT_MIN_TIMEOUT 1 -+#define MLXREG_WDT_HW_TIMEOUT_CONVERT(hw_timeout) ((1 << (hw_timeout)) \ -+ / MLXREG_WDT_CLOCK_SCALE) -+ -+/** -+ * enum mlxreg_wdt_type - type of HW watchdog -+ * -+ * TYPE1 can be differentiated by different register/mask -+ * for WD action set and ping. -+ */ -+enum mlxreg_wdt_type { -+ MLX_WDT_TYPE1, -+ MLX_WDT_TYPE2, -+}; -+ -+/** -+ * struct mlxreg_wdt - wd private data: -+ * -+ * @wdd: watchdog device; -+ * @device: basic device; -+ * @pdata: data received from platform driver; -+ * @regmap: register map of parent device; -+ * @timeout: defined timeout in sec.; -+ * @hw_timeout: real timeout set in hw; -+ * It will be roundup base of 2 in WD type 1, -+ * in WD type 2 it will be same number of sec as timeout; -+ * @action_idx: index for direct access to action register; -+ * @timeout_idx:index for direct access to TO register; -+ * @ping_idx: index for direct access to ping register; -+ * @reset_idx: index for direct access to reset cause register; -+ * @wd_type: watchdog HW type; -+ * @hw_timeout: actual HW timeout; -+ * @io_lock: spinlock for io access; -+ */ -+struct mlxreg_wdt { -+ struct watchdog_device wdd; -+ struct mlxreg_core_platform_data *pdata; -+ void *regmap; -+ int action_idx; -+ int timeout_idx; -+ int ping_idx; -+ int reset_idx; -+ enum mlxreg_wdt_type wdt_type; -+ u8 hw_timeout; -+ spinlock_t io_lock; /* the lock for io operations */ -+}; -+ -+static int mlxreg_wdt_roundup_to_base_2(struct mlxreg_wdt *wdt, int timeout) -+{ -+ timeout *= MLXREG_WDT_CLOCK_SCALE; -+ -+ wdt->hw_timeout = order_base_2(timeout); -+ dev_info(wdt->wdd.parent, -+ "watchdog %s timeout %d was rounded up to %lu (msec)\n", -+ wdt->wdd.info->identity, timeout, roundup_pow_of_two(timeout)); -+ -+ return 0; -+} -+ -+static enum mlxreg_wdt_type -+mlxreg_wdt_check_watchdog_type(struct mlxreg_wdt *wdt, -+ struct mlxreg_core_platform_data *pdata) -+{ -+ if ((pdata->data[wdt->action_idx].reg == -+ pdata->data[wdt->ping_idx].reg) && -+ (pdata->data[wdt->action_idx].mask == -+ pdata->data[wdt->ping_idx].mask)) -+ return MLX_WDT_TYPE2; -+ else -+ return MLX_WDT_TYPE1; -+} -+ -+static int mlxreg_wdt_check_card_reset(struct mlxreg_wdt *wdt) -+{ -+ struct mlxreg_core_data *reg_data; -+ u32 regval; -+ int rc; -+ -+ if (wdt->reset_idx == -EINVAL) -+ return -EINVAL; -+ -+ if (!(wdt->wdd.info->options & WDIOF_CARDRESET)) -+ return 0; -+ -+ spin_lock(&wdt->io_lock); -+ reg_data = &wdt->pdata->data[wdt->reset_idx]; -+ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); -+ spin_unlock(&wdt->io_lock); -+ if (rc) -+ goto read_error; -+ -+ if (regval & ~reg_data->mask) { -+ wdt->wdd.bootstatus = WDIOF_CARDRESET; -+ dev_info(wdt->wdd.parent, -+ "watchdog previously reset the CPU\n"); -+ } -+ -+read_error: -+ return rc; -+} -+ -+static int mlxreg_wdt_start(struct watchdog_device *wdd) -+{ -+ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); -+ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->action_idx]; -+ u32 regval; -+ int rc; -+ -+ spin_lock(&wdt->io_lock); -+ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); -+ if (rc) { -+ spin_unlock(&wdt->io_lock); -+ goto read_error; -+ } -+ -+ regval = (regval & reg_data->mask) | BIT(reg_data->bit); -+ rc = regmap_write(wdt->regmap, reg_data->reg, regval); -+ spin_unlock(&wdt->io_lock); -+ if (!rc) { -+ set_bit(WDOG_HW_RUNNING, &wdt->wdd.status); -+ dev_info(wdt->wdd.parent, "watchdog %s started\n", -+ wdd->info->identity); -+ } -+ -+read_error: -+ return rc; -+} -+ -+static int mlxreg_wdt_stop(struct watchdog_device *wdd) -+{ -+ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); -+ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->action_idx]; -+ u32 regval; -+ int rc; -+ -+ spin_lock(&wdt->io_lock); -+ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); -+ if (rc) { -+ spin_unlock(&wdt->io_lock); -+ goto read_error; -+ } -+ -+ regval = (regval & reg_data->mask) & ~BIT(reg_data->bit); -+ rc = regmap_write(wdt->regmap, reg_data->reg, regval); -+ spin_unlock(&wdt->io_lock); -+ if (!rc) -+ dev_info(wdt->wdd.parent, "watchdog %s stopped\n", -+ wdd->info->identity); -+ -+read_error: -+ return rc; -+} -+ -+static int mlxreg_wdt_ping(struct watchdog_device *wdd) -+{ -+ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); -+ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->ping_idx]; -+ u32 regval; -+ int rc; -+ -+ spin_lock(&wdt->io_lock); -+ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); -+ if (rc) -+ goto read_error; -+ -+ regval = (regval & reg_data->mask) | BIT(reg_data->bit); -+ rc = regmap_write(wdt->regmap, reg_data->reg, regval); -+ -+read_error: -+ spin_unlock(&wdt->io_lock); -+ -+ return rc; -+} -+ -+static int mlxreg_wdt_set_timeout(struct watchdog_device *wdd, -+ unsigned int timeout) -+{ -+ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); -+ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->timeout_idx]; -+ u32 regval; -+ int rc; -+ -+ spin_lock(&wdt->io_lock); -+ -+ if (wdt->wdt_type == MLX_WDT_TYPE1) { -+ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); -+ if (rc) -+ goto read_error; -+ regval = (regval & reg_data->mask) | wdt->hw_timeout; -+ } else { -+ wdt->hw_timeout = timeout; -+ regval = timeout; -+ } -+ -+ rc = regmap_write(wdt->regmap, reg_data->reg, regval); -+ -+read_error: -+ spin_unlock(&wdt->io_lock); -+ -+ return rc; -+} -+ -+static unsigned int mlxreg_wdt_get_timeleft(struct watchdog_device *wdd) -+{ -+ struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); -+ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->timeout_idx]; -+ u32 regval; -+ int rc; -+ -+ if (wdt->wdt_type == MLX_WDT_TYPE1) -+ return 0; -+ -+ spin_lock(&wdt->io_lock); -+ rc = regmap_read(wdt->regmap, reg_data->reg, ®val); -+ if (rc) -+ rc = 0; -+ else -+ rc = regval; -+ -+ spin_unlock(&wdt->io_lock); -+ -+ return rc; -+} -+ -+static const struct watchdog_ops mlxreg_wdt_ops_type1 = { -+ .start = mlxreg_wdt_start, -+ .stop = mlxreg_wdt_stop, -+ .ping = mlxreg_wdt_ping, -+ .set_timeout = mlxreg_wdt_set_timeout, -+ .owner = THIS_MODULE, -+}; -+ -+static const struct watchdog_ops mlxreg_wdt_ops_type2 = { -+ .start = mlxreg_wdt_start, -+ .stop = mlxreg_wdt_stop, -+ .ping = mlxreg_wdt_ping, -+ .set_timeout = mlxreg_wdt_set_timeout, -+ .get_timeleft = mlxreg_wdt_get_timeleft, -+ .owner = THIS_MODULE, -+}; -+ -+static const struct watchdog_info mlxreg_wdt_main_info = { -+ .options = WDIOF_KEEPALIVEPING -+ | WDIOF_MAGICCLOSE -+ | WDIOF_SETTIMEOUT -+ | WDIOF_CARDRESET, -+ .identity = "mlx-wdt-main", -+}; -+ -+static const struct watchdog_info mlxreg_wdt_aux_info = { -+ .options = WDIOF_KEEPALIVEPING -+ | WDIOF_MAGICCLOSE -+ | WDIOF_SETTIMEOUT -+ | WDIOF_ALARMONLY, -+ .identity = "mlx-wdt-aux", -+}; -+ -+static int mlxreg_wdt_config(struct mlxreg_wdt *wdt, -+ struct mlxreg_core_platform_data *pdata) -+{ -+ struct mlxreg_core_data *data = pdata->data; -+ int i, timeout; -+ -+ wdt->reset_idx = -EINVAL; -+ for (i = 0; i < pdata->counter; i++, data++) { -+ if (strnstr(data->label, "action", sizeof(data->label))) -+ wdt->action_idx = i; -+ else if (strnstr(data->label, "timeout", sizeof(data->label))) -+ wdt->timeout_idx = i; -+ else if (strnstr(data->label, "ping", sizeof(data->label))) -+ wdt->ping_idx = i; -+ else if (strnstr(data->label, "reset", sizeof(data->label))) -+ wdt->reset_idx = i; -+ } -+ -+ wdt->pdata = pdata; -+ if (strnstr(pdata->identity, mlxreg_wdt_main_info.identity, -+ sizeof(mlxreg_wdt_main_info.identity))) -+ wdt->wdd.info = &mlxreg_wdt_main_info; -+ else -+ wdt->wdd.info = &mlxreg_wdt_aux_info; -+ -+ timeout = pdata->data[wdt->timeout_idx].health_cntr; -+ wdt->wdt_type = mlxreg_wdt_check_watchdog_type(wdt, pdata); -+ if (wdt->wdt_type == MLX_WDT_TYPE2) { -+ wdt->hw_timeout = timeout; -+ wdt->wdd.ops = &mlxreg_wdt_ops_type2; -+ wdt->wdd.timeout = wdt->hw_timeout; -+ wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE2; -+ } else { -+ mlxreg_wdt_roundup_to_base_2(wdt, timeout); -+ wdt->wdd.ops = &mlxreg_wdt_ops_type1; -+ /* Rowndown to actual closest number of sec. */ -+ wdt->wdd.timeout = -+ MLXREG_WDT_HW_TIMEOUT_CONVERT(wdt->hw_timeout); -+ wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE1; -+ } -+ wdt->wdd.min_timeout = MLXREG_WDT_MIN_TIMEOUT; -+ -+ return -EINVAL; -+} -+ -+static int mlxreg_wdt_probe(struct platform_device *pdev) -+{ -+ struct mlxreg_core_platform_data *pdata; -+ struct mlxreg_wdt *wdt; -+ int rc; -+ -+ pdata = dev_get_platdata(&pdev->dev); -+ if (!pdata) { -+ dev_err(&pdev->dev, "Failed to get platform data.\n"); -+ return -EINVAL; -+ } -+ wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); -+ if (!wdt) -+ return -ENOMEM; -+ -+ spin_lock_init(&wdt->io_lock); -+ -+ wdt->wdd.parent = &pdev->dev; -+ wdt->regmap = pdata->regmap; -+ mlxreg_wdt_config(wdt, pdata); -+ -+ if ((pdata->features & MLXREG_CORE_WD_FEATURE_NOSTOP_AFTER_START)) -+ watchdog_set_nowayout(&wdt->wdd, WATCHDOG_NOWAYOUT); -+ watchdog_stop_on_reboot(&wdt->wdd); -+ watchdog_init_timeout(&wdt->wdd, 0, &pdev->dev); -+ watchdog_set_drvdata(&wdt->wdd, wdt); -+ -+ mlxreg_wdt_check_card_reset(wdt); -+ rc = devm_watchdog_register_device(&pdev->dev, &wdt->wdd); -+ if (rc) { -+ dev_err(&pdev->dev, -+ "Cannot register watchdog device (err=%d)\n", rc); -+ return rc; -+ } -+ -+ mlxreg_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout); -+ if ((pdata->features & MLXREG_CORE_WD_FEATURE_START_AT_BOOT)) -+ mlxreg_wdt_start(&wdt->wdd); -+ -+ return rc; -+} -+ -+static int mlxreg_wdt_remove(struct platform_device *pdev) -+{ -+ struct mlxreg_wdt *wdt = dev_get_platdata(&pdev->dev); -+ -+ mlxreg_wdt_stop(&wdt->wdd); -+ watchdog_unregister_device(&wdt->wdd); -+ -+ return 0; -+} -+ -+static struct platform_driver mlxreg_wdt_driver = { -+ .probe = mlxreg_wdt_probe, -+ .remove = mlxreg_wdt_remove, -+ .driver = { -+ .name = "mlx-wdt", -+ }, -+}; -+ -+module_platform_driver(mlxreg_wdt_driver); -+ -+MODULE_AUTHOR("Michael Shych "); -+MODULE_DESCRIPTION("Mellanox watchdog driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:mlx-wdt"); -diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h -index 1b2f86f..4d70c00 100644 ---- a/include/linux/platform_data/mlxreg.h -+++ b/include/linux/platform_data/mlxreg.h -@@ -35,6 +35,8 @@ - #define __LINUX_PLATFORM_DATA_MLXREG_H - - #define MLXREG_CORE_LABEL_MAX_SIZE 32 -+#define MLXREG_CORE_WD_FEATURE_NOSTOP_AFTER_START BIT(0) -+#define MLXREG_CORE_WD_FEATURE_START_AT_BOOT BIT(1) - - /** - * struct mlxreg_hotplug_device - I2C device data: -@@ -112,11 +114,15 @@ struct mlxreg_core_item { - * @data: instance private data; - * @regmap: register map of parent device; - * @counter: number of instances; -+ * @features: supported features of device; -+ * @identity: device identity name; - */ - struct mlxreg_core_platform_data { - struct mlxreg_core_data *data; - void *regmap; - int counter; -+ u32 features; -+ char identity[MLXREG_CORE_LABEL_MAX_SIZE]; - }; - - /** --- -2.1.4 - diff --git a/patch/0029-mlxsw-qsfp_sysfs-Support-port-numbers-initialization.patch b/patch/0029-mlxsw-qsfp_sysfs-Support-port-numbers-initialization.patch deleted file mode 100644 index ae982fd44740..000000000000 --- a/patch/0029-mlxsw-qsfp_sysfs-Support-port-numbers-initialization.patch +++ /dev/null @@ -1,86 +0,0 @@ -From d83d9b8a4813c6a626db151f9b9269d8c69a032a Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Sun, 6 Jan 2019 12:25:46 +0000 -Subject: [PATCH v1] mlxsw: qsfp_sysfs: Support port numbers initialization - -Support port numbers initialization based on system type. - -Signed-off-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/core.c | 20 +++++++++++++++++++- - drivers/net/ethernet/mellanox/mlxsw/core.h | 10 +++------- - drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c | 1 + - 3 files changed, 23 insertions(+), 8 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c -index 10863d6..01987f0 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c -@@ -114,12 +114,30 @@ struct mlxsw_core { - struct mlxsw_resources resources; - struct mlxsw_hwmon *hwmon; - struct mlxsw_thermal *thermal; --struct mlxsw_qsfp *qsfp; -+ struct mlxsw_qsfp *qsfp; - struct mlxsw_core_port ports[MLXSW_PORT_MAX_PORTS]; -+ unsigned int max_ports; - unsigned long driver_priv[0]; - /* driver_priv has to be always the last item */ - }; - -+#define MLXSW_PORT_MAX_PORTS_DEFAULT 0x40 -+unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core) -+{ -+ if (mlxsw_core->max_ports) -+ return mlxsw_core->max_ports; -+ else -+ return MLXSW_PORT_MAX_PORTS_DEFAULT; -+} -+EXPORT_SYMBOL(mlxsw_core_max_ports); -+ -+void mlxsw_core_max_ports_set(struct mlxsw_core *mlxsw_core, -+ unsigned int max_ports) -+{ -+ mlxsw_core->max_ports = max_ports; -+} -+EXPORT_SYMBOL(mlxsw_core_max_ports_set); -+ - void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core) - { - return mlxsw_core->driver_priv; -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h -index 4fb104e..db27dd0 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h -@@ -63,13 +63,9 @@ struct mlxsw_driver; - struct mlxsw_bus; - struct mlxsw_bus_info; - --#define MLXSW_PORT_MAX_PORTS_DEFAULT 0x40 --static inline unsigned int --mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core) --{ -- return MLXSW_PORT_MAX_PORTS_DEFAULT; --} -- -+unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core); -+void mlxsw_core_max_ports_set(struct mlxsw_core *mlxsw_core, -+ unsigned int max_ports); - void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core); - - int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -index bee2a08..0781f16 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -@@ -298,6 +298,7 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, - mlxsw_qsfp->bus_info = mlxsw_bus_info; - mlxsw_bus_info->dev->platform_data = mlxsw_qsfp; - -+ mlxsw_core_max_ports_set(mlxsw_core, mlxsw_qsfp_num); - for (i = 1; i <= mlxsw_qsfp_num; i++) { - mlxsw_reg_pmlp_pack(pmlp_pl, i); - err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(pmlp), --- -2.1.4 - diff --git a/patch/0030-update-kernel-config.patch b/patch/0030-update-kernel-config.patch deleted file mode 100644 index d72fdbcc6a64..000000000000 --- a/patch/0030-update-kernel-config.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 90c84c4963764d537535d950ea3233db518a6287 Mon Sep 17 00:00:00 2001 -From: Mykola Kostenok -Date: Mon, 17 Dec 2018 20:54:49 +0200 -Subject: [PATCH] update kernel config add CONFIG_MLX_WDT - -Signed-off-by: Mykola Kostenok ---- - debian/build/build_amd64_none_amd64/.config | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index b7bcf15..21d0d6f 100644 ---- a/debian/build/build_amd64_none_amd64/.config -+++ b/debian/build/build_amd64_none_amd64/.config -@@ -4093,6 +4093,7 @@ CONFIG_SBC_EPX_C3_WATCHDOG=m - # CONFIG_NI903X_WDT is not set - # CONFIG_MEN_A21_WDT is not set - CONFIG_XEN_WDT=m -+CONFIG_MLX_WDT=y - - # - # PCI-based Watchdog Cards --- -1.9.1 - diff --git a/patch/0031-mlxsw-Align-code-with-kernel-v-5.0.patch b/patch/0031-mlxsw-Align-code-with-kernel-v-5.0.patch deleted file mode 100644 index 96ba7ac220e9..000000000000 --- a/patch/0031-mlxsw-Align-code-with-kernel-v-5.0.patch +++ /dev/null @@ -1,13374 +0,0 @@ -From bef153de6e232204874c3d2916ccb639f09d284e Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Tue, 15 Jan 2019 08:25:23 +0000 -Subject: [PATCH] mlxsw: Align code with kernel v 5.0 - -Signed-off-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/cmd.h | 108 +- - drivers/net/ethernet/mellanox/mlxsw/core.c | 732 +- - drivers/net/ethernet/mellanox/mlxsw/core.h | 219 +- - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 9 +- - drivers/net/ethernet/mellanox/mlxsw/i2c.c | 149 +- - drivers/net/ethernet/mellanox/mlxsw/item.h | 182 +- - drivers/net/ethernet/mellanox/mlxsw/minimal.c | 114 +- - drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c | 1 - - drivers/net/ethernet/mellanox/mlxsw/reg.h | 9380 ++++++++++++++------ - drivers/net/ethernet/mellanox/mlxsw/resources.h | 152 + - 10 files changed, 7657 insertions(+), 3389 deletions(-) - create mode 100644 drivers/net/ethernet/mellanox/mlxsw/resources.h - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/cmd.h b/drivers/net/ethernet/mellanox/mlxsw/cmd.h -index 28271be..0772e43 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/cmd.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/cmd.h -@@ -1,37 +1,5 @@ --/* -- * drivers/net/ethernet/mellanox/mlxsw/cmd.h -- * Copyright (c) 2015 Mellanox Technologies. All rights reserved. -- * Copyright (c) 2015 Jiri Pirko -- * Copyright (c) 2015 Ido Schimmel -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. 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. -- * 3. Neither the names of the copyright holders nor the names of its -- * contributors may be used to endorse or promote products derived from -- * this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * 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. -- */ -+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ -+/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ - - #ifndef _MLXSW_CMD_H - #define _MLXSW_CMD_H -@@ -58,7 +26,7 @@ static inline void mlxsw_cmd_mbox_zero(char *mbox) - struct mlxsw_core; - - int mlxsw_cmd_exec(struct mlxsw_core *mlxsw_core, u16 opcode, u8 opcode_mod, -- u32 in_mod, bool out_mbox_direct, -+ u32 in_mod, bool out_mbox_direct, bool reset_ok, - char *in_mbox, size_t in_mbox_size, - char *out_mbox, size_t out_mbox_size); - -@@ -67,7 +35,7 @@ static inline int mlxsw_cmd_exec_in(struct mlxsw_core *mlxsw_core, u16 opcode, - size_t in_mbox_size) - { - return mlxsw_cmd_exec(mlxsw_core, opcode, opcode_mod, in_mod, false, -- in_mbox, in_mbox_size, NULL, 0); -+ false, in_mbox, in_mbox_size, NULL, 0); - } - - static inline int mlxsw_cmd_exec_out(struct mlxsw_core *mlxsw_core, u16 opcode, -@@ -76,7 +44,7 @@ static inline int mlxsw_cmd_exec_out(struct mlxsw_core *mlxsw_core, u16 opcode, - char *out_mbox, size_t out_mbox_size) - { - return mlxsw_cmd_exec(mlxsw_core, opcode, opcode_mod, in_mod, -- out_mbox_direct, NULL, 0, -+ out_mbox_direct, false, NULL, 0, - out_mbox, out_mbox_size); - } - -@@ -84,7 +52,7 @@ static inline int mlxsw_cmd_exec_none(struct mlxsw_core *mlxsw_core, u16 opcode, - u8 opcode_mod, u32 in_mod) - { - return mlxsw_cmd_exec(mlxsw_core, opcode, opcode_mod, in_mod, false, -- NULL, 0, NULL, 0); -+ false, NULL, 0, NULL, 0); - } - - enum mlxsw_cmd_opcode { -@@ -179,6 +147,8 @@ enum mlxsw_cmd_status { - MLXSW_CMD_STATUS_BAD_INDEX = 0x0A, - /* NVMEM checksum/CRC failed. */ - MLXSW_CMD_STATUS_BAD_NVMEM = 0x0B, -+ /* Device is currently running reset */ -+ MLXSW_CMD_STATUS_RUNNING_RESET = 0x26, - /* Bad management packet (silently discarded). */ - MLXSW_CMD_STATUS_BAD_PKT = 0x30, - }; -@@ -208,6 +178,8 @@ static inline const char *mlxsw_cmd_status_str(u8 status) - return "BAD_INDEX"; - case MLXSW_CMD_STATUS_BAD_NVMEM: - return "BAD_NVMEM"; -+ case MLXSW_CMD_STATUS_RUNNING_RESET: -+ return "RUNNING_RESET"; - case MLXSW_CMD_STATUS_BAD_PKT: - return "BAD_PKT"; - default: -@@ -424,10 +396,15 @@ MLXSW_ITEM32(cmd_mbox, query_aq_cap, log_max_rdq_sz, 0x04, 24, 8); - MLXSW_ITEM32(cmd_mbox, query_aq_cap, max_num_rdqs, 0x04, 0, 8); - - /* cmd_mbox_query_aq_cap_log_max_cq_sz -- * Log (base 2) of max CQEs allowed on CQ. -+ * Log (base 2) of the Maximum CQEs allowed in a CQ for CQEv0 and CQEv1. - */ - MLXSW_ITEM32(cmd_mbox, query_aq_cap, log_max_cq_sz, 0x08, 24, 8); - -+/* cmd_mbox_query_aq_cap_log_max_cqv2_sz -+ * Log (base 2) of the Maximum CQEs allowed in a CQ for CQEv2. -+ */ -+MLXSW_ITEM32(cmd_mbox, query_aq_cap, log_max_cqv2_sz, 0x08, 16, 8); -+ - /* cmd_mbox_query_aq_cap_max_num_cqs - * Maximum number of CQs. - */ -@@ -513,6 +490,11 @@ static inline int mlxsw_cmd_unmap_fa(struct mlxsw_core *mlxsw_core) - * are no more sources in the table, will return resource id 0xFFF to indicate - * it. - */ -+ -+#define MLXSW_CMD_QUERY_RESOURCES_TABLE_END_ID 0xffff -+#define MLXSW_CMD_QUERY_RESOURCES_MAX_QUERIES 100 -+#define MLXSW_CMD_QUERY_RESOURCES_PER_QUERY 32 -+ - static inline int mlxsw_cmd_query_resources(struct mlxsw_core *mlxsw_core, - char *out_mbox, int index) - { -@@ -657,6 +639,12 @@ MLXSW_ITEM32(cmd_mbox, config_profile, set_kvd_hash_single_size, 0x0C, 25, 1); - */ - MLXSW_ITEM32(cmd_mbox, config_profile, set_kvd_hash_double_size, 0x0C, 26, 1); - -+/* cmd_mbox_config_set_cqe_version -+ * Capability bit. Setting a bit to 1 configures the profile -+ * according to the mailbox contents. -+ */ -+MLXSW_ITEM32(cmd_mbox, config_profile, set_cqe_version, 0x08, 0, 1); -+ - /* cmd_mbox_config_profile_max_vepa_channels - * Maximum number of VEPA channels per port (0 through 16) - * 0 - multi-channel VEPA is disabled -@@ -836,6 +824,14 @@ MLXSW_ITEM32_INDEXED(cmd_mbox, config_profile, swid_config_type, - MLXSW_ITEM32_INDEXED(cmd_mbox, config_profile, swid_config_properties, - 0x60, 0, 8, 0x08, 0x00, false); - -+/* cmd_mbox_config_profile_cqe_version -+ * CQE version: -+ * 0: CQE version is 0 -+ * 1: CQE version is either 1 or 2 -+ * CQE ver 1 or 2 is configured by Completion Queue Context field cqe_ver. -+ */ -+MLXSW_ITEM32(cmd_mbox, config_profile, cqe_version, 0xB0, 0, 8); -+ - /* ACCESS_REG - Access EMAD Supported Register - * ---------------------------------- - * OpMod == 0 (N/A), INMmod == 0 (N/A) -@@ -845,10 +841,12 @@ MLXSW_ITEM32_INDEXED(cmd_mbox, config_profile, swid_config_properties, - */ - - static inline int mlxsw_cmd_access_reg(struct mlxsw_core *mlxsw_core, -+ bool reset_ok, - char *in_mbox, char *out_mbox) - { - return mlxsw_cmd_exec(mlxsw_core, MLXSW_CMD_OPCODE_ACCESS_REG, -- 0, 0, false, in_mbox, MLXSW_CMD_MBOX_SIZE, -+ 0, 0, false, reset_ok, -+ in_mbox, MLXSW_CMD_MBOX_SIZE, - out_mbox, MLXSW_CMD_MBOX_SIZE); - } - -@@ -1027,24 +1025,21 @@ static inline int mlxsw_cmd_sw2hw_cq(struct mlxsw_core *mlxsw_core, - 0, cq_number, in_mbox, MLXSW_CMD_MBOX_SIZE); - } - --/* cmd_mbox_sw2hw_cq_cv -+enum mlxsw_cmd_mbox_sw2hw_cq_cqe_ver { -+ MLXSW_CMD_MBOX_SW2HW_CQ_CQE_VER_1, -+ MLXSW_CMD_MBOX_SW2HW_CQ_CQE_VER_2, -+}; -+ -+/* cmd_mbox_sw2hw_cq_cqe_ver - * CQE Version. -- * 0 - CQE Version 0, 1 - CQE Version 1 - */ --MLXSW_ITEM32(cmd_mbox, sw2hw_cq, cv, 0x00, 28, 4); -+MLXSW_ITEM32(cmd_mbox, sw2hw_cq, cqe_ver, 0x00, 28, 4); - - /* cmd_mbox_sw2hw_cq_c_eqn - * Event Queue this CQ reports completion events to. - */ - MLXSW_ITEM32(cmd_mbox, sw2hw_cq, c_eqn, 0x00, 24, 1); - --/* cmd_mbox_sw2hw_cq_oi -- * When set, overrun ignore is enabled. When set, updates of -- * CQ consumer counter (poll for completion) or Request completion -- * notifications (Arm CQ) DoorBells should not be rung on that CQ. -- */ --MLXSW_ITEM32(cmd_mbox, sw2hw_cq, oi, 0x00, 12, 1); -- - /* cmd_mbox_sw2hw_cq_st - * Event delivery state machine - * 0x0 - FIRED -@@ -1127,12 +1122,7 @@ static inline int mlxsw_cmd_sw2hw_eq(struct mlxsw_core *mlxsw_core, - */ - MLXSW_ITEM32(cmd_mbox, sw2hw_eq, int_msix, 0x00, 24, 1); - --/* cmd_mbox_sw2hw_eq_int_oi -- * When set, overrun ignore is enabled. -- */ --MLXSW_ITEM32(cmd_mbox, sw2hw_eq, oi, 0x00, 12, 1); -- --/* cmd_mbox_sw2hw_eq_int_st -+/* cmd_mbox_sw2hw_eq_st - * Event delivery state machine - * 0x0 - FIRED - * 0x1 - ARMED (Request for Notification) -@@ -1141,19 +1131,19 @@ MLXSW_ITEM32(cmd_mbox, sw2hw_eq, oi, 0x00, 12, 1); - */ - MLXSW_ITEM32(cmd_mbox, sw2hw_eq, st, 0x00, 8, 2); - --/* cmd_mbox_sw2hw_eq_int_log_eq_size -+/* cmd_mbox_sw2hw_eq_log_eq_size - * Log (base 2) of the EQ size (in entries). - */ - MLXSW_ITEM32(cmd_mbox, sw2hw_eq, log_eq_size, 0x00, 0, 4); - --/* cmd_mbox_sw2hw_eq_int_producer_counter -+/* cmd_mbox_sw2hw_eq_producer_counter - * Producer Counter. The counter is incremented for each EQE that is written - * by the HW to the EQ. - * Maintained by HW (valid for the QUERY_EQ command only) - */ - MLXSW_ITEM32(cmd_mbox, sw2hw_eq, producer_counter, 0x04, 0, 16); - --/* cmd_mbox_sw2hw_eq_int_pa -+/* cmd_mbox_sw2hw_eq_pa - * Physical Address. - */ - MLXSW_ITEM64_INDEXED(cmd_mbox, sw2hw_eq, pa, 0x10, 11, 53, 0x08, 0x00, true); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c -index 01987f0..e420451 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c -@@ -1,38 +1,5 @@ --/* -- * drivers/net/ethernet/mellanox/mlxsw/core.c -- * Copyright (c) 2015 Mellanox Technologies. All rights reserved. -- * Copyright (c) 2015 Jiri Pirko -- * Copyright (c) 2015 Ido Schimmel -- * Copyright (c) 2015 Elad Raz -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. 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. -- * 3. Neither the names of the copyright holders nor the names of its -- * contributors may be used to endorse or promote products derived from -- * this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * 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. -- */ -+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 -+/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ - - #include - #include -@@ -40,9 +7,6 @@ - #include - #include - #include --#include --#include --#include - #include - #include - #include -@@ -67,33 +31,39 @@ - #include "trap.h" - #include "emad.h" - #include "reg.h" -+#include "resources.h" - - static LIST_HEAD(mlxsw_core_driver_list); - static DEFINE_SPINLOCK(mlxsw_core_driver_list_lock); - - static const char mlxsw_core_driver_name[] = "mlxsw_core"; - --static struct dentry *mlxsw_core_dbg_root; -- - static struct workqueue_struct *mlxsw_wq; -+static struct workqueue_struct *mlxsw_owq; - --struct mlxsw_core_pcpu_stats { -- u64 trap_rx_packets[MLXSW_TRAP_ID_MAX]; -- u64 trap_rx_bytes[MLXSW_TRAP_ID_MAX]; -- u64 port_rx_packets[MLXSW_PORT_MAX_PORTS]; -- u64 port_rx_bytes[MLXSW_PORT_MAX_PORTS]; -- struct u64_stats_sync syncp; -- u32 trap_rx_dropped[MLXSW_TRAP_ID_MAX]; -- u32 port_rx_dropped[MLXSW_PORT_MAX_PORTS]; -- u32 trap_rx_invalid; -- u32 port_rx_invalid; -+struct mlxsw_core_port { -+ struct devlink_port devlink_port; -+ void *port_driver_priv; -+ u8 local_port; - }; - -+void *mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port) -+{ -+ return mlxsw_core_port->port_driver_priv; -+} -+EXPORT_SYMBOL(mlxsw_core_port_driver_priv); -+ -+static bool mlxsw_core_port_check(struct mlxsw_core_port *mlxsw_core_port) -+{ -+ return mlxsw_core_port->port_driver_priv != NULL; -+} -+ - struct mlxsw_core { - struct mlxsw_driver *driver; - const struct mlxsw_bus *bus; - void *bus_priv; - const struct mlxsw_bus_info *bus_info; -+ struct workqueue_struct *emad_wq; - struct list_head rx_listener_list; - struct list_head event_listener_list; - struct { -@@ -102,41 +72,49 @@ struct mlxsw_core { - spinlock_t trans_list_lock; /* protects trans_list writes */ - bool use_emad; - } emad; -- struct mlxsw_core_pcpu_stats __percpu *pcpu_stats; -- struct dentry *dbg_dir; -- struct { -- struct debugfs_blob_wrapper vsd_blob; -- struct debugfs_blob_wrapper psid_blob; -- } dbg; - struct { - u8 *mapping; /* lag_id+port_index to local_port mapping */ - } lag; -- struct mlxsw_resources resources; -+ struct mlxsw_res res; - struct mlxsw_hwmon *hwmon; - struct mlxsw_thermal *thermal; - struct mlxsw_qsfp *qsfp; -- struct mlxsw_core_port ports[MLXSW_PORT_MAX_PORTS]; -+ struct mlxsw_core_port *ports; - unsigned int max_ports; -+ bool reload_fail; - unsigned long driver_priv[0]; - /* driver_priv has to be always the last item */ - }; - - #define MLXSW_PORT_MAX_PORTS_DEFAULT 0x40 --unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core) -+ -+static int mlxsw_ports_init(struct mlxsw_core *mlxsw_core) - { -- if (mlxsw_core->max_ports) -- return mlxsw_core->max_ports; -+ /* Switch ports are numbered from 1 to queried value */ -+ if (MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SYSTEM_PORT)) -+ mlxsw_core->max_ports = MLXSW_CORE_RES_GET(mlxsw_core, -+ MAX_SYSTEM_PORT) + 1; - else -- return MLXSW_PORT_MAX_PORTS_DEFAULT; -+ mlxsw_core->max_ports = MLXSW_PORT_MAX_PORTS_DEFAULT + 1; -+ -+ mlxsw_core->ports = kcalloc(mlxsw_core->max_ports, -+ sizeof(struct mlxsw_core_port), GFP_KERNEL); -+ if (!mlxsw_core->ports) -+ return -ENOMEM; -+ -+ return 0; - } --EXPORT_SYMBOL(mlxsw_core_max_ports); - --void mlxsw_core_max_ports_set(struct mlxsw_core *mlxsw_core, -- unsigned int max_ports) -+static void mlxsw_ports_fini(struct mlxsw_core *mlxsw_core) - { -- mlxsw_core->max_ports = max_ports; -+ kfree(mlxsw_core->ports); - } --EXPORT_SYMBOL(mlxsw_core_max_ports_set); -+ -+unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core) -+{ -+ return mlxsw_core->max_ports; -+} -+EXPORT_SYMBOL(mlxsw_core_max_ports); - - void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core) - { -@@ -457,7 +435,7 @@ static void mlxsw_emad_trans_timeout_schedule(struct mlxsw_reg_trans *trans) - { - unsigned long timeout = msecs_to_jiffies(MLXSW_EMAD_TIMEOUT_MS); - -- mlxsw_core_schedule_dw(&trans->timeout_dw, timeout); -+ queue_delayed_work(trans->core->emad_wq, &trans->timeout_dw, timeout); - } - - static int mlxsw_emad_transmit(struct mlxsw_core *mlxsw_core, -@@ -573,36 +551,24 @@ static void mlxsw_emad_rx_listener_func(struct sk_buff *skb, u8 local_port, - dev_kfree_skb(skb); - } - --static const struct mlxsw_rx_listener mlxsw_emad_rx_listener = { -- .func = mlxsw_emad_rx_listener_func, -- .local_port = MLXSW_PORT_DONT_CARE, -- .trap_id = MLXSW_TRAP_ID_ETHEMAD, --}; -- --static int mlxsw_emad_traps_set(struct mlxsw_core *mlxsw_core) --{ -- char htgt_pl[MLXSW_REG_HTGT_LEN]; -- char hpkt_pl[MLXSW_REG_HPKT_LEN]; -- int err; -- -- mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_EMAD); -- err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); -- if (err) -- return err; -- -- mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_TRAP_TO_CPU, -- MLXSW_TRAP_ID_ETHEMAD); -- return mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl); --} -+static const struct mlxsw_listener mlxsw_emad_rx_listener = -+ MLXSW_RXL(mlxsw_emad_rx_listener_func, ETHEMAD, TRAP_TO_CPU, false, -+ EMAD, DISCARD); - - static int mlxsw_emad_init(struct mlxsw_core *mlxsw_core) - { -+ struct workqueue_struct *emad_wq; - u64 tid; - int err; - - if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX)) - return 0; - -+ emad_wq = alloc_workqueue("mlxsw_core_emad", WQ_MEM_RECLAIM, 0); -+ if (!emad_wq) -+ return -ENOMEM; -+ mlxsw_core->emad_wq = emad_wq; -+ - /* Set the upper 32 bits of the transaction ID field to a random - * number. This allows us to discard EMADs addressed to other - * devices. -@@ -614,42 +580,35 @@ static int mlxsw_emad_init(struct mlxsw_core *mlxsw_core) - INIT_LIST_HEAD(&mlxsw_core->emad.trans_list); - spin_lock_init(&mlxsw_core->emad.trans_list_lock); - -- err = mlxsw_core_rx_listener_register(mlxsw_core, -- &mlxsw_emad_rx_listener, -- mlxsw_core); -+ err = mlxsw_core_trap_register(mlxsw_core, &mlxsw_emad_rx_listener, -+ mlxsw_core); - if (err) - return err; - -- err = mlxsw_emad_traps_set(mlxsw_core); -+ err = mlxsw_core->driver->basic_trap_groups_set(mlxsw_core); - if (err) - goto err_emad_trap_set; -- - mlxsw_core->emad.use_emad = true; - - return 0; - - err_emad_trap_set: -- mlxsw_core_rx_listener_unregister(mlxsw_core, -- &mlxsw_emad_rx_listener, -- mlxsw_core); -+ mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_emad_rx_listener, -+ mlxsw_core); -+ destroy_workqueue(mlxsw_core->emad_wq); - return err; - } - - static void mlxsw_emad_fini(struct mlxsw_core *mlxsw_core) - { -- char hpkt_pl[MLXSW_REG_HPKT_LEN]; - - if (!(mlxsw_core->bus->features & MLXSW_BUS_F_TXRX)) - return; - - mlxsw_core->emad.use_emad = false; -- mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_DISCARD, -- MLXSW_TRAP_ID_ETHEMAD); -- mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl); -- -- mlxsw_core_rx_listener_unregister(mlxsw_core, -- &mlxsw_emad_rx_listener, -- mlxsw_core); -+ mlxsw_core_trap_unregister(mlxsw_core, &mlxsw_emad_rx_listener, -+ mlxsw_core); -+ destroy_workqueue(mlxsw_core->emad_wq); - } - - static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core, -@@ -686,7 +645,7 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core, - int err; - - dev_dbg(mlxsw_core->bus_info->dev, "EMAD reg access (tid=%llx,reg_id=%x(%s),type=%s)\n", -- trans->tid, reg->id, mlxsw_reg_id_str(reg->id), -+ tid, reg->id, mlxsw_reg_id_str(reg->id), - mlxsw_core_reg_access_type_str(type)); - - skb = mlxsw_emad_alloc(mlxsw_core, reg->len); -@@ -730,91 +689,6 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core, - * Core functions - *****************/ - --static int mlxsw_core_rx_stats_dbg_read(struct seq_file *file, void *data) --{ -- struct mlxsw_core *mlxsw_core = file->private; -- struct mlxsw_core_pcpu_stats *p; -- u64 rx_packets, rx_bytes; -- u64 tmp_rx_packets, tmp_rx_bytes; -- u32 rx_dropped, rx_invalid; -- unsigned int start; -- int i; -- int j; -- static const char hdr[] = -- " NUM RX_PACKETS RX_BYTES RX_DROPPED\n"; -- -- seq_printf(file, hdr); -- for (i = 0; i < MLXSW_TRAP_ID_MAX; i++) { -- rx_packets = 0; -- rx_bytes = 0; -- rx_dropped = 0; -- for_each_possible_cpu(j) { -- p = per_cpu_ptr(mlxsw_core->pcpu_stats, j); -- do { -- start = u64_stats_fetch_begin(&p->syncp); -- tmp_rx_packets = p->trap_rx_packets[i]; -- tmp_rx_bytes = p->trap_rx_bytes[i]; -- } while (u64_stats_fetch_retry(&p->syncp, start)); -- -- rx_packets += tmp_rx_packets; -- rx_bytes += tmp_rx_bytes; -- rx_dropped += p->trap_rx_dropped[i]; -- } -- seq_printf(file, "trap %3d %12llu %12llu %10u\n", -- i, rx_packets, rx_bytes, rx_dropped); -- } -- rx_invalid = 0; -- for_each_possible_cpu(j) { -- p = per_cpu_ptr(mlxsw_core->pcpu_stats, j); -- rx_invalid += p->trap_rx_invalid; -- } -- seq_printf(file, "trap INV %10u\n", -- rx_invalid); -- -- for (i = 0; i < MLXSW_PORT_MAX_PORTS; i++) { -- rx_packets = 0; -- rx_bytes = 0; -- rx_dropped = 0; -- for_each_possible_cpu(j) { -- p = per_cpu_ptr(mlxsw_core->pcpu_stats, j); -- do { -- start = u64_stats_fetch_begin(&p->syncp); -- tmp_rx_packets = p->port_rx_packets[i]; -- tmp_rx_bytes = p->port_rx_bytes[i]; -- } while (u64_stats_fetch_retry(&p->syncp, start)); -- -- rx_packets += tmp_rx_packets; -- rx_bytes += tmp_rx_bytes; -- rx_dropped += p->port_rx_dropped[i]; -- } -- seq_printf(file, "port %3d %12llu %12llu %10u\n", -- i, rx_packets, rx_bytes, rx_dropped); -- } -- rx_invalid = 0; -- for_each_possible_cpu(j) { -- p = per_cpu_ptr(mlxsw_core->pcpu_stats, j); -- rx_invalid += p->port_rx_invalid; -- } -- seq_printf(file, "port INV %10u\n", -- rx_invalid); -- return 0; --} -- --static int mlxsw_core_rx_stats_dbg_open(struct inode *inode, struct file *f) --{ -- struct mlxsw_core *mlxsw_core = inode->i_private; -- -- return single_open(f, mlxsw_core_rx_stats_dbg_read, mlxsw_core); --} -- --static const struct file_operations mlxsw_core_rx_stats_dbg_ops = { -- .owner = THIS_MODULE, -- .open = mlxsw_core_rx_stats_dbg_open, -- .release = single_release, -- .read = seq_read, -- .llseek = seq_lseek --}; -- - int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver) - { - spin_lock(&mlxsw_core_driver_list_lock); -@@ -849,84 +723,10 @@ static struct mlxsw_driver *mlxsw_core_driver_get(const char *kind) - - spin_lock(&mlxsw_core_driver_list_lock); - mlxsw_driver = __driver_find(kind); -- if (!mlxsw_driver) { -- spin_unlock(&mlxsw_core_driver_list_lock); -- request_module(MLXSW_MODULE_ALIAS_PREFIX "%s", kind); -- spin_lock(&mlxsw_core_driver_list_lock); -- mlxsw_driver = __driver_find(kind); -- } -- if (mlxsw_driver) { -- if (!try_module_get(mlxsw_driver->owner)) -- mlxsw_driver = NULL; -- } -- - spin_unlock(&mlxsw_core_driver_list_lock); - return mlxsw_driver; - } - --static void mlxsw_core_driver_put(const char *kind) --{ -- struct mlxsw_driver *mlxsw_driver; -- -- spin_lock(&mlxsw_core_driver_list_lock); -- mlxsw_driver = __driver_find(kind); -- spin_unlock(&mlxsw_core_driver_list_lock); -- if (!mlxsw_driver) -- return; -- module_put(mlxsw_driver->owner); --} -- --static int mlxsw_core_debugfs_init(struct mlxsw_core *mlxsw_core) --{ -- const struct mlxsw_bus_info *bus_info = mlxsw_core->bus_info; -- -- mlxsw_core->dbg_dir = debugfs_create_dir(bus_info->device_name, -- mlxsw_core_dbg_root); -- if (!mlxsw_core->dbg_dir) -- return -ENOMEM; -- debugfs_create_file("rx_stats", S_IRUGO, mlxsw_core->dbg_dir, -- mlxsw_core, &mlxsw_core_rx_stats_dbg_ops); -- mlxsw_core->dbg.vsd_blob.data = (void *) &bus_info->vsd; -- mlxsw_core->dbg.vsd_blob.size = sizeof(bus_info->vsd); -- debugfs_create_blob("vsd", S_IRUGO, mlxsw_core->dbg_dir, -- &mlxsw_core->dbg.vsd_blob); -- mlxsw_core->dbg.psid_blob.data = (void *) &bus_info->psid; -- mlxsw_core->dbg.psid_blob.size = sizeof(bus_info->psid); -- debugfs_create_blob("psid", S_IRUGO, mlxsw_core->dbg_dir, -- &mlxsw_core->dbg.psid_blob); -- return 0; --} -- --static void mlxsw_core_debugfs_fini(struct mlxsw_core *mlxsw_core) --{ -- debugfs_remove_recursive(mlxsw_core->dbg_dir); --} -- --static int mlxsw_devlink_port_split(struct devlink *devlink, -- unsigned int port_index, -- unsigned int count) --{ -- struct mlxsw_core *mlxsw_core = devlink_priv(devlink); -- -- if (port_index >= MLXSW_PORT_MAX_PORTS) -- return -EINVAL; -- if (!mlxsw_core->driver->port_split) -- return -EOPNOTSUPP; -- return mlxsw_core->driver->port_split(mlxsw_core, port_index, count); --} -- --static int mlxsw_devlink_port_unsplit(struct devlink *devlink, -- unsigned int port_index) --{ -- struct mlxsw_core *mlxsw_core = devlink_priv(devlink); -- -- if (port_index >= MLXSW_PORT_MAX_PORTS) -- return -EINVAL; -- if (!mlxsw_core->driver->port_unsplit) -- return -EOPNOTSUPP; -- return mlxsw_core->driver->port_unsplit(mlxsw_core, port_index); --} -- - static int - mlxsw_devlink_sb_pool_get(struct devlink *devlink, - unsigned int sb_index, u16 pool_index, -@@ -960,6 +760,21 @@ static void *__dl_port(struct devlink_port *devlink_port) - return container_of(devlink_port, struct mlxsw_core_port, devlink_port); - } - -+static int mlxsw_devlink_port_type_set(struct devlink_port *devlink_port, -+ enum devlink_port_type port_type) -+{ -+ struct mlxsw_core *mlxsw_core = devlink_priv(devlink_port->devlink); -+ struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; -+ struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); -+ -+ if (!mlxsw_driver->port_type_set) -+ return -EOPNOTSUPP; -+ -+ return mlxsw_driver->port_type_set(mlxsw_core, -+ mlxsw_core_port->local_port, -+ port_type); -+} -+ - static int mlxsw_devlink_sb_port_pool_get(struct devlink_port *devlink_port, - unsigned int sb_index, u16 pool_index, - u32 *p_threshold) -@@ -968,7 +783,8 @@ static int mlxsw_devlink_sb_port_pool_get(struct devlink_port *devlink_port, - struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; - struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); - -- if (!mlxsw_driver->sb_port_pool_get) -+ if (!mlxsw_driver->sb_port_pool_get || -+ !mlxsw_core_port_check(mlxsw_core_port)) - return -EOPNOTSUPP; - return mlxsw_driver->sb_port_pool_get(mlxsw_core_port, sb_index, - pool_index, p_threshold); -@@ -982,7 +798,8 @@ static int mlxsw_devlink_sb_port_pool_set(struct devlink_port *devlink_port, - struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; - struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); - -- if (!mlxsw_driver->sb_port_pool_set) -+ if (!mlxsw_driver->sb_port_pool_set || -+ !mlxsw_core_port_check(mlxsw_core_port)) - return -EOPNOTSUPP; - return mlxsw_driver->sb_port_pool_set(mlxsw_core_port, sb_index, - pool_index, threshold); -@@ -998,7 +815,8 @@ mlxsw_devlink_sb_tc_pool_bind_get(struct devlink_port *devlink_port, - struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; - struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); - -- if (!mlxsw_driver->sb_tc_pool_bind_get) -+ if (!mlxsw_driver->sb_tc_pool_bind_get || -+ !mlxsw_core_port_check(mlxsw_core_port)) - return -EOPNOTSUPP; - return mlxsw_driver->sb_tc_pool_bind_get(mlxsw_core_port, sb_index, - tc_index, pool_type, -@@ -1015,7 +833,8 @@ mlxsw_devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port, - struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; - struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); - -- if (!mlxsw_driver->sb_tc_pool_bind_set) -+ if (!mlxsw_driver->sb_tc_pool_bind_set || -+ !mlxsw_core_port_check(mlxsw_core_port)) - return -EOPNOTSUPP; - return mlxsw_driver->sb_tc_pool_bind_set(mlxsw_core_port, sb_index, - tc_index, pool_type, -@@ -1053,7 +872,8 @@ mlxsw_devlink_sb_occ_port_pool_get(struct devlink_port *devlink_port, - struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; - struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); - -- if (!mlxsw_driver->sb_occ_port_pool_get) -+ if (!mlxsw_driver->sb_occ_port_pool_get || -+ !mlxsw_core_port_check(mlxsw_core_port)) - return -EOPNOTSUPP; - return mlxsw_driver->sb_occ_port_pool_get(mlxsw_core_port, sb_index, - pool_index, p_cur, p_max); -@@ -1069,7 +889,8 @@ mlxsw_devlink_sb_occ_tc_port_bind_get(struct devlink_port *devlink_port, - struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; - struct mlxsw_core_port *mlxsw_core_port = __dl_port(devlink_port); - -- if (!mlxsw_driver->sb_occ_tc_port_bind_get) -+ if (!mlxsw_driver->sb_occ_tc_port_bind_get || -+ !mlxsw_core_port_check(mlxsw_core_port)) - return -EOPNOTSUPP; - return mlxsw_driver->sb_occ_tc_port_bind_get(mlxsw_core_port, - sb_index, tc_index, -@@ -1077,8 +898,7 @@ mlxsw_devlink_sb_occ_tc_port_bind_get(struct devlink_port *devlink_port, - } - - static const struct devlink_ops mlxsw_devlink_ops = { -- .port_split = mlxsw_devlink_port_split, -- .port_unsplit = mlxsw_devlink_port_unsplit, -+ .port_type_set = mlxsw_devlink_port_type_set, - .sb_pool_get = mlxsw_devlink_sb_pool_get, - .sb_pool_set = mlxsw_devlink_sb_pool_set, - .sb_port_pool_get = mlxsw_devlink_sb_port_pool_get, -@@ -1093,23 +913,27 @@ static const struct devlink_ops mlxsw_devlink_ops = { - - int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, - const struct mlxsw_bus *mlxsw_bus, -- void *bus_priv) -+ void *bus_priv, bool reload, -+ struct devlink *devlink) - { - const char *device_kind = mlxsw_bus_info->device_kind; - struct mlxsw_core *mlxsw_core; - struct mlxsw_driver *mlxsw_driver; -- struct devlink *devlink; -+ struct mlxsw_res *res; - size_t alloc_size; - int err; - - mlxsw_driver = mlxsw_core_driver_get(device_kind); - if (!mlxsw_driver) - return -EINVAL; -- alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size; -- devlink = devlink_alloc(&mlxsw_devlink_ops, alloc_size); -- if (!devlink) { -- err = -ENOMEM; -- goto err_devlink_alloc; -+ -+ if (!reload) { -+ alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size; -+ devlink = devlink_alloc(&mlxsw_devlink_ops, alloc_size); -+ if (!devlink) { -+ err = -ENOMEM; -+ goto err_devlink_alloc; -+ } - } - - mlxsw_core = devlink_priv(devlink); -@@ -1120,22 +944,26 @@ int 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; - -- mlxsw_core->pcpu_stats = -- netdev_alloc_pcpu_stats(struct mlxsw_core_pcpu_stats); -- if (!mlxsw_core->pcpu_stats) { -- err = -ENOMEM; -- goto err_alloc_stats; -+ res = mlxsw_driver->res_query_enabled ? &mlxsw_core->res : NULL; -+ err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile, res); -+ if (err) -+ goto err_bus_init; -+ -+ if (mlxsw_driver->resources_register && !reload) { -+ err = mlxsw_driver->resources_register(mlxsw_core); -+ if (err) -+ goto err_register_resources; - } - -- err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile, -- &mlxsw_core->resources); -+ err = mlxsw_ports_init(mlxsw_core); - if (err) -- goto err_bus_init; -+ goto err_ports_init; - -- if (mlxsw_core->resources.max_lag_valid && -- mlxsw_core->resources.max_ports_in_lag_valid) { -- alloc_size = sizeof(u8) * mlxsw_core->resources.max_lag * -- mlxsw_core->resources.max_ports_in_lag; -+ if (MLXSW_CORE_RES_VALID(mlxsw_core, MAX_LAG) && -+ MLXSW_CORE_RES_VALID(mlxsw_core, MAX_LAG_MEMBERS)) { -+ alloc_size = sizeof(u8) * -+ MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG) * -+ MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG_MEMBERS); - mlxsw_core->lag.mapping = kzalloc(alloc_size, GFP_KERNEL); - if (!mlxsw_core->lag.mapping) { - err = -ENOMEM; -@@ -1147,9 +975,11 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, - if (err) - goto err_emad_init; - -- err = devlink_register(devlink, mlxsw_bus_info->dev); -- if (err) -- goto err_devlink_register; -+ if (!reload) { -+ err = devlink_register(devlink, mlxsw_bus_info->dev); -+ if (err) -+ goto err_devlink_register; -+ } - - err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon); - if (err) -@@ -1171,54 +1001,66 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, - goto err_driver_init; - } - -- err = mlxsw_core_debugfs_init(mlxsw_core); -- if (err) -- goto err_debugfs_init; -- - return 0; - --err_debugfs_init: -- mlxsw_core->driver->fini(mlxsw_core); - err_driver_init: - mlxsw_qsfp_fini(mlxsw_core->qsfp); - err_qsfp_init: - mlxsw_thermal_fini(mlxsw_core->thermal); - err_thermal_init: -+ mlxsw_hwmon_fini(mlxsw_core->hwmon); - err_hwmon_init: -- devlink_unregister(devlink); -+ if (!reload) -+ devlink_unregister(devlink); - err_devlink_register: - mlxsw_emad_fini(mlxsw_core); - err_emad_init: - kfree(mlxsw_core->lag.mapping); - err_alloc_lag_mapping: -+ mlxsw_ports_fini(mlxsw_core); -+err_ports_init: -+err_register_resources: - mlxsw_bus->fini(bus_priv); - err_bus_init: -- free_percpu(mlxsw_core->pcpu_stats); --err_alloc_stats: -- devlink_free(devlink); -+ if (!reload) -+ devlink_free(devlink); - err_devlink_alloc: -- mlxsw_core_driver_put(device_kind); - return err; - } - EXPORT_SYMBOL(mlxsw_core_bus_device_register); - --void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core) -+void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, -+ bool reload) - { -- const char *device_kind = mlxsw_core->bus_info->device_kind; - struct devlink *devlink = priv_to_devlink(mlxsw_core); - -- mlxsw_core_debugfs_fini(mlxsw_core); -+ if (mlxsw_core->reload_fail) { -+ if (!reload) -+ /* Only the parts that were not de-initialized in the -+ * failed reload attempt need to be de-initialized. -+ */ -+ goto reload_fail_deinit; -+ else -+ return; -+ } -+ - if (mlxsw_core->driver->fini) - mlxsw_core->driver->fini(mlxsw_core); - mlxsw_qsfp_fini(mlxsw_core->qsfp); - mlxsw_thermal_fini(mlxsw_core->thermal); -- devlink_unregister(devlink); -+ mlxsw_hwmon_fini(mlxsw_core->hwmon); -+ if (!reload) -+ devlink_unregister(devlink); - mlxsw_emad_fini(mlxsw_core); -- mlxsw_core->bus->fini(mlxsw_core->bus_priv); - kfree(mlxsw_core->lag.mapping); -- free_percpu(mlxsw_core->pcpu_stats); -+ mlxsw_ports_fini(mlxsw_core); -+ mlxsw_core->bus->fini(mlxsw_core->bus_priv); -+ -+ return; -+ -+reload_fail_deinit: -+ devlink_unregister(devlink); - devlink_free(devlink); -- mlxsw_core_driver_put(device_kind); - } - EXPORT_SYMBOL(mlxsw_core_bus_device_unregister); - -@@ -1392,6 +1234,75 @@ void mlxsw_core_event_listener_unregister(struct mlxsw_core *mlxsw_core, - } - EXPORT_SYMBOL(mlxsw_core_event_listener_unregister); - -+static int mlxsw_core_listener_register(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_listener *listener, -+ void *priv) -+{ -+ if (listener->is_event) -+ return mlxsw_core_event_listener_register(mlxsw_core, -+ &listener->u.event_listener, -+ priv); -+ else -+ return mlxsw_core_rx_listener_register(mlxsw_core, -+ &listener->u.rx_listener, -+ priv); -+} -+ -+static void mlxsw_core_listener_unregister(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_listener *listener, -+ void *priv) -+{ -+ if (listener->is_event) -+ mlxsw_core_event_listener_unregister(mlxsw_core, -+ &listener->u.event_listener, -+ priv); -+ else -+ mlxsw_core_rx_listener_unregister(mlxsw_core, -+ &listener->u.rx_listener, -+ priv); -+} -+ -+int mlxsw_core_trap_register(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_listener *listener, void *priv) -+{ -+ char hpkt_pl[MLXSW_REG_HPKT_LEN]; -+ int err; -+ -+ err = mlxsw_core_listener_register(mlxsw_core, listener, priv); -+ if (err) -+ return err; -+ -+ mlxsw_reg_hpkt_pack(hpkt_pl, listener->action, listener->trap_id, -+ listener->trap_group, listener->is_ctrl); -+ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl); -+ if (err) -+ goto err_trap_set; -+ -+ return 0; -+ -+err_trap_set: -+ mlxsw_core_listener_unregister(mlxsw_core, listener, priv); -+ return err; -+} -+EXPORT_SYMBOL(mlxsw_core_trap_register); -+ -+void mlxsw_core_trap_unregister(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_listener *listener, -+ void *priv) -+{ -+ char hpkt_pl[MLXSW_REG_HPKT_LEN]; -+ -+ if (!listener->is_event) { -+ mlxsw_reg_hpkt_pack(hpkt_pl, listener->unreg_action, -+ listener->trap_id, listener->trap_group, -+ listener->is_ctrl); -+ mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl); -+ } -+ -+ mlxsw_core_listener_unregister(mlxsw_core, listener, priv); -+} -+EXPORT_SYMBOL(mlxsw_core_trap_unregister); -+ - static u64 mlxsw_core_tid_get(struct mlxsw_core *mlxsw_core) - { - return atomic64_inc_return(&mlxsw_core->emad.tid); -@@ -1492,6 +1403,7 @@ static int mlxsw_core_reg_access_cmd(struct mlxsw_core *mlxsw_core, - { - enum mlxsw_emad_op_tlv_status status; - int err, n_retry; -+ bool reset_ok; - char *in_mbox, *out_mbox, *tmp; - - dev_dbg(mlxsw_core->bus_info->dev, "Reg cmd access (reg_id=%x(%s),type=%s)\n", -@@ -1513,9 +1425,16 @@ static int mlxsw_core_reg_access_cmd(struct mlxsw_core *mlxsw_core, - tmp = in_mbox + MLXSW_EMAD_OP_TLV_LEN * sizeof(u32); - mlxsw_emad_pack_reg_tlv(tmp, reg, payload); - -+ /* There is a special treatment needed for MRSR (reset) register. -+ * The command interface will return error after the command -+ * is executed, so tell the lower layer to expect it -+ * and cope accordingly. -+ */ -+ reset_ok = reg->id == MLXSW_REG_MRSR_ID; -+ - n_retry = 0; - retry: -- err = mlxsw_cmd_access_reg(mlxsw_core, in_mbox, out_mbox); -+ err = mlxsw_cmd_access_reg(mlxsw_core, reset_ok, in_mbox, out_mbox); - if (!err) { - err = mlxsw_emad_process_status(out_mbox, &status); - if (err) { -@@ -1595,7 +1514,6 @@ void mlxsw_core_skb_receive(struct mlxsw_core *mlxsw_core, struct sk_buff *skb, - { - struct mlxsw_rx_listener_item *rxl_item; - const struct mlxsw_rx_listener *rxl; -- struct mlxsw_core_pcpu_stats *pcpu_stats; - u8 local_port; - bool found = false; - -@@ -1617,7 +1535,7 @@ void mlxsw_core_skb_receive(struct mlxsw_core *mlxsw_core, struct sk_buff *skb, - __func__, local_port, rx_info->trap_id); - - if ((rx_info->trap_id >= MLXSW_TRAP_ID_MAX) || -- (local_port >= MLXSW_PORT_MAX_PORTS)) -+ (local_port >= mlxsw_core->max_ports)) - goto drop; - - rcu_read_lock(); -@@ -1634,26 +1552,10 @@ void mlxsw_core_skb_receive(struct mlxsw_core *mlxsw_core, struct sk_buff *skb, - if (!found) - goto drop; - -- pcpu_stats = this_cpu_ptr(mlxsw_core->pcpu_stats); -- u64_stats_update_begin(&pcpu_stats->syncp); -- pcpu_stats->port_rx_packets[local_port]++; -- pcpu_stats->port_rx_bytes[local_port] += skb->len; -- pcpu_stats->trap_rx_packets[rx_info->trap_id]++; -- pcpu_stats->trap_rx_bytes[rx_info->trap_id] += skb->len; -- u64_stats_update_end(&pcpu_stats->syncp); -- - rxl->func(skb, local_port, rxl_item->priv); - return; - - drop: -- if (rx_info->trap_id >= MLXSW_TRAP_ID_MAX) -- this_cpu_inc(mlxsw_core->pcpu_stats->trap_rx_invalid); -- else -- this_cpu_inc(mlxsw_core->pcpu_stats->trap_rx_dropped[rx_info->trap_id]); -- if (local_port >= MLXSW_PORT_MAX_PORTS) -- this_cpu_inc(mlxsw_core->pcpu_stats->port_rx_invalid); -- else -- this_cpu_inc(mlxsw_core->pcpu_stats->port_rx_dropped[local_port]); - dev_kfree_skb(skb); - } - EXPORT_SYMBOL(mlxsw_core_skb_receive); -@@ -1661,7 +1563,7 @@ EXPORT_SYMBOL(mlxsw_core_skb_receive); - static int mlxsw_core_lag_mapping_index(struct mlxsw_core *mlxsw_core, - u16 lag_id, u8 port_index) - { -- return mlxsw_core->resources.max_ports_in_lag * lag_id + -+ return MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG_MEMBERS) * lag_id + - port_index; - } - -@@ -1690,7 +1592,7 @@ void mlxsw_core_lag_mapping_clear(struct mlxsw_core *mlxsw_core, - { - int i; - -- for (i = 0; i < mlxsw_core->resources.max_ports_in_lag; i++) { -+ for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_core, MAX_LAG_MEMBERS); i++) { - int index = mlxsw_core_lag_mapping_index(mlxsw_core, - lag_id, i); - -@@ -1700,34 +1602,82 @@ void mlxsw_core_lag_mapping_clear(struct mlxsw_core *mlxsw_core, - } - EXPORT_SYMBOL(mlxsw_core_lag_mapping_clear); - --struct mlxsw_resources *mlxsw_core_resources_get(struct mlxsw_core *mlxsw_core) -+bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core, -+ enum mlxsw_res_id res_id) -+{ -+ return mlxsw_res_valid(&mlxsw_core->res, res_id); -+} -+EXPORT_SYMBOL(mlxsw_core_res_valid); -+ -+u64 mlxsw_core_res_get(struct mlxsw_core *mlxsw_core, -+ enum mlxsw_res_id res_id) - { -- return &mlxsw_core->resources; -+ return mlxsw_res_get(&mlxsw_core->res, res_id); - } --EXPORT_SYMBOL(mlxsw_core_resources_get); -+EXPORT_SYMBOL(mlxsw_core_res_get); - --int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, -- struct mlxsw_core_port *mlxsw_core_port, u8 local_port, -- struct net_device *dev, bool split, u32 split_group) -+int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port) - { - struct devlink *devlink = priv_to_devlink(mlxsw_core); -+ struct mlxsw_core_port *mlxsw_core_port = -+ &mlxsw_core->ports[local_port]; - struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port; -+ int err; - -- if (split) -- devlink_port_split_set(devlink_port, split_group); -- devlink_port_type_eth_set(devlink_port, dev); -- return devlink_port_register(devlink, devlink_port, local_port); -+ mlxsw_core_port->local_port = local_port; -+ err = devlink_port_register(devlink, devlink_port, local_port); -+ if (err) -+ memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port)); -+ return err; - } - EXPORT_SYMBOL(mlxsw_core_port_init); - --void mlxsw_core_port_fini(struct mlxsw_core_port *mlxsw_core_port) -+void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port) - { -+ struct mlxsw_core_port *mlxsw_core_port = -+ &mlxsw_core->ports[local_port]; - struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port; - - devlink_port_unregister(devlink_port); -+ memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port)); - } - EXPORT_SYMBOL(mlxsw_core_port_fini); - -+void mlxsw_core_port_ib_set(struct mlxsw_core *mlxsw_core, u8 local_port, -+ void *port_driver_priv) -+{ -+ struct mlxsw_core_port *mlxsw_core_port = -+ &mlxsw_core->ports[local_port]; -+ struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port; -+ -+ mlxsw_core_port->port_driver_priv = port_driver_priv; -+ devlink_port_type_ib_set(devlink_port, NULL); -+} -+EXPORT_SYMBOL(mlxsw_core_port_ib_set); -+ -+void mlxsw_core_port_clear(struct mlxsw_core *mlxsw_core, u8 local_port, -+ void *port_driver_priv) -+{ -+ struct mlxsw_core_port *mlxsw_core_port = -+ &mlxsw_core->ports[local_port]; -+ struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port; -+ -+ mlxsw_core_port->port_driver_priv = port_driver_priv; -+ devlink_port_type_clear(devlink_port); -+} -+EXPORT_SYMBOL(mlxsw_core_port_clear); -+ -+enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core, -+ u8 local_port) -+{ -+ struct mlxsw_core_port *mlxsw_core_port = -+ &mlxsw_core->ports[local_port]; -+ struct devlink_port *devlink_port = &mlxsw_core_port->devlink_port; -+ -+ return devlink_port->type; -+} -+EXPORT_SYMBOL(mlxsw_core_port_type_get); -+ - static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core, - const char *buf, size_t size) - { -@@ -1747,7 +1697,7 @@ static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core, - } - - int mlxsw_cmd_exec(struct mlxsw_core *mlxsw_core, u16 opcode, u8 opcode_mod, -- u32 in_mod, bool out_mbox_direct, -+ u32 in_mod, bool out_mbox_direct, bool reset_ok, - char *in_mbox, size_t in_mbox_size, - char *out_mbox, size_t out_mbox_size) - { -@@ -1770,7 +1720,15 @@ int mlxsw_cmd_exec(struct mlxsw_core *mlxsw_core, u16 opcode, u8 opcode_mod, - in_mbox, in_mbox_size, - out_mbox, out_mbox_size, &status); - -- if (err == -EIO && status != MLXSW_CMD_STATUS_OK) { -+ if (!err && out_mbox) { -+ dev_dbg(mlxsw_core->bus_info->dev, "Output mailbox:\n"); -+ mlxsw_core_buf_dump_dbg(mlxsw_core, out_mbox, out_mbox_size); -+ } -+ -+ if (reset_ok && err == -EIO && -+ status == MLXSW_CMD_STATUS_RUNNING_RESET) { -+ err = 0; -+ } else if (err == -EIO && status != MLXSW_CMD_STATUS_OK) { - dev_err(mlxsw_core->bus_info->dev, "Cmd exec failed (opcode=%x(%s),opcode_mod=%x,in_mod=%x,status=%x(%s))\n", - opcode, mlxsw_cmd_opcode_str(opcode), opcode_mod, - in_mod, status, mlxsw_cmd_status_str(status)); -@@ -1780,10 +1738,6 @@ int mlxsw_cmd_exec(struct mlxsw_core *mlxsw_core, u16 opcode, u8 opcode_mod, - in_mod); - } - -- if (!err && out_mbox) { -- dev_dbg(mlxsw_core->bus_info->dev, "Output mailbox:\n"); -- mlxsw_core_buf_dump_dbg(mlxsw_core, out_mbox, out_mbox_size); -- } - return err; - } - EXPORT_SYMBOL(mlxsw_cmd_exec); -@@ -1794,6 +1748,71 @@ int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay) - } - EXPORT_SYMBOL(mlxsw_core_schedule_dw); - -+bool mlxsw_core_schedule_work(struct work_struct *work) -+{ -+ return queue_work(mlxsw_owq, work); -+} -+EXPORT_SYMBOL(mlxsw_core_schedule_work); -+ -+void mlxsw_core_flush_owq(void) -+{ -+ flush_workqueue(mlxsw_owq); -+} -+EXPORT_SYMBOL(mlxsw_core_flush_owq); -+ -+int mlxsw_core_kvd_sizes_get(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_config_profile *profile, -+ u64 *p_single_size, u64 *p_double_size, -+ u64 *p_linear_size) -+{ -+ struct mlxsw_driver *driver = mlxsw_core->driver; -+ -+ if (!driver->kvd_sizes_get) -+ return -EINVAL; -+ -+ return driver->kvd_sizes_get(mlxsw_core, profile, -+ p_single_size, p_double_size, -+ p_linear_size); -+} -+EXPORT_SYMBOL(mlxsw_core_kvd_sizes_get); -+ -+int mlxsw_core_resources_query(struct mlxsw_core *mlxsw_core, char *mbox, -+ struct mlxsw_res *res) -+{ -+ int index, i; -+ u64 data; -+ u16 id; -+ int err; -+ -+ if (!res) -+ return 0; -+ -+ mlxsw_cmd_mbox_zero(mbox); -+ -+ for (index = 0; index < MLXSW_CMD_QUERY_RESOURCES_MAX_QUERIES; -+ index++) { -+ err = mlxsw_cmd_query_resources(mlxsw_core, mbox, index); -+ if (err) -+ return err; -+ -+ for (i = 0; i < MLXSW_CMD_QUERY_RESOURCES_PER_QUERY; i++) { -+ id = mlxsw_cmd_mbox_query_resource_id_get(mbox, i); -+ data = mlxsw_cmd_mbox_query_resource_data_get(mbox, i); -+ -+ if (id == MLXSW_CMD_QUERY_RESOURCES_TABLE_END_ID) -+ return 0; -+ -+ mlxsw_res_parse(res, id, data); -+ } -+ } -+ -+ /* If after MLXSW_RESOURCES_QUERY_MAX_QUERIES we still didn't get -+ * MLXSW_RESOURCES_TABLE_END_ID, something went bad in the FW. -+ */ -+ return -EIO; -+} -+EXPORT_SYMBOL(mlxsw_core_resources_query); -+ - static int __init mlxsw_core_module_init(void) - { - int err; -@@ -1801,21 +1820,22 @@ static int __init mlxsw_core_module_init(void) - mlxsw_wq = alloc_workqueue(mlxsw_core_driver_name, WQ_MEM_RECLAIM, 0); - if (!mlxsw_wq) - return -ENOMEM; -- mlxsw_core_dbg_root = debugfs_create_dir(mlxsw_core_driver_name, NULL); -- if (!mlxsw_core_dbg_root) { -+ mlxsw_owq = alloc_ordered_workqueue("%s_ordered", WQ_MEM_RECLAIM, -+ mlxsw_core_driver_name); -+ if (!mlxsw_owq) { - err = -ENOMEM; -- goto err_debugfs_create_dir; -+ goto err_alloc_ordered_workqueue; - } - return 0; - --err_debugfs_create_dir: -+err_alloc_ordered_workqueue: - destroy_workqueue(mlxsw_wq); - return err; - } - - static void __exit mlxsw_core_module_exit(void) - { -- debugfs_remove_recursive(mlxsw_core_dbg_root); -+ destroy_workqueue(mlxsw_owq); - destroy_workqueue(mlxsw_wq); - } - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h -index db27dd0..76e8fd7 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h -@@ -1,38 +1,5 @@ --/* -- * drivers/net/ethernet/mellanox/mlxsw/core.h -- * Copyright (c) 2015 Mellanox Technologies. All rights reserved. -- * Copyright (c) 2015 Jiri Pirko -- * Copyright (c) 2015 Ido Schimmel -- * Copyright (c) 2015 Elad Raz -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. 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. -- * 3. Neither the names of the copyright holders nor the names of its -- * contributors may be used to endorse or promote products derived from -- * this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * 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. -- */ -+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ -+/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ - - #ifndef _MLXSW_CORE_H - #define _MLXSW_CORE_H -@@ -48,24 +15,17 @@ - - #include "trap.h" - #include "reg.h" -- - #include "cmd.h" -- --#define MLXSW_MODULE_ALIAS_PREFIX "mlxsw-driver-" --#define MODULE_MLXSW_DRIVER_ALIAS(kind) \ -- MODULE_ALIAS(MLXSW_MODULE_ALIAS_PREFIX kind) -- --#define MLXSW_DEVICE_KIND_SWITCHX2 "switchx2" --#define MLXSW_DEVICE_KIND_SPECTRUM "spectrum" -+#include "resources.h" - - struct mlxsw_core; -+struct mlxsw_core_port; - struct mlxsw_driver; - struct mlxsw_bus; - struct mlxsw_bus_info; - - unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core); --void mlxsw_core_max_ports_set(struct mlxsw_core *mlxsw_core, -- unsigned int max_ports); -+ - void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core); - - int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver); -@@ -73,8 +33,9 @@ void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver); - - int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, - const struct mlxsw_bus *mlxsw_bus, -- void *bus_priv); --void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core); -+ void *bus_priv, bool reload, -+ struct devlink *devlink); -+void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, bool reload); - - struct mlxsw_tx_info { - u8 local_port; -@@ -99,6 +60,50 @@ struct mlxsw_event_listener { - enum mlxsw_event_trap_id trap_id; - }; - -+struct mlxsw_listener { -+ u16 trap_id; -+ union { -+ struct mlxsw_rx_listener rx_listener; -+ struct mlxsw_event_listener event_listener; -+ } u; -+ enum mlxsw_reg_hpkt_action action; -+ enum mlxsw_reg_hpkt_action unreg_action; -+ u8 trap_group; -+ bool is_ctrl; /* should go via control buffer or not */ -+ bool is_event; -+}; -+ -+#define MLXSW_RXL(_func, _trap_id, _action, _is_ctrl, _trap_group, \ -+ _unreg_action) \ -+ { \ -+ .trap_id = MLXSW_TRAP_ID_##_trap_id, \ -+ .u.rx_listener = \ -+ { \ -+ .func = _func, \ -+ .local_port = MLXSW_PORT_DONT_CARE, \ -+ .trap_id = MLXSW_TRAP_ID_##_trap_id, \ -+ }, \ -+ .action = MLXSW_REG_HPKT_ACTION_##_action, \ -+ .unreg_action = MLXSW_REG_HPKT_ACTION_##_unreg_action, \ -+ .trap_group = MLXSW_REG_HTGT_TRAP_GROUP_##_trap_group, \ -+ .is_ctrl = _is_ctrl, \ -+ .is_event = false, \ -+ } -+ -+#define MLXSW_EVENTL(_func, _trap_id, _trap_group) \ -+ { \ -+ .trap_id = MLXSW_TRAP_ID_##_trap_id, \ -+ .u.event_listener = \ -+ { \ -+ .func = _func, \ -+ .trap_id = MLXSW_TRAP_ID_##_trap_id, \ -+ }, \ -+ .action = MLXSW_REG_HPKT_ACTION_TRAP_TO_CPU, \ -+ .trap_group = MLXSW_REG_HTGT_TRAP_GROUP_##_trap_group, \ -+ .is_ctrl = false, \ -+ .is_event = true, \ -+ } -+ - int mlxsw_core_rx_listener_register(struct mlxsw_core *mlxsw_core, - const struct mlxsw_rx_listener *rxl, - void *priv); -@@ -113,6 +118,13 @@ void mlxsw_core_event_listener_unregister(struct mlxsw_core *mlxsw_core, - const struct mlxsw_event_listener *el, - void *priv); - -+int mlxsw_core_trap_register(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_listener *listener, -+ void *priv); -+void mlxsw_core_trap_unregister(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_listener *listener, -+ void *priv); -+ - typedef void mlxsw_reg_trans_cb_t(struct mlxsw_core *mlxsw_core, char *payload, - size_t payload_len, unsigned long cb_priv); - -@@ -151,27 +163,27 @@ u8 mlxsw_core_lag_mapping_get(struct mlxsw_core *mlxsw_core, - void mlxsw_core_lag_mapping_clear(struct mlxsw_core *mlxsw_core, - u16 lag_id, u8 local_port); - --struct mlxsw_core_port { -- struct devlink_port devlink_port; --}; -- --static inline void * --mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port) --{ -- /* mlxsw_core_port is ensured to always be the first field in driver -- * port structure. -- */ -- return mlxsw_core_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); -+void mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port); -+void mlxsw_core_port_eth_set(struct mlxsw_core *mlxsw_core, u8 local_port, -+ void *port_driver_priv, struct net_device *dev, -+ u32 port_number, bool split, -+ u32 split_port_subnumber); -+void mlxsw_core_port_ib_set(struct mlxsw_core *mlxsw_core, u8 local_port, -+ void *port_driver_priv); -+void mlxsw_core_port_clear(struct mlxsw_core *mlxsw_core, u8 local_port, -+ void *port_driver_priv); -+enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core, -+ u8 local_port); - int mlxsw_core_port_get_phys_port_name(struct mlxsw_core *mlxsw_core, - u8 local_port, char *name, size_t len); --int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, -- struct mlxsw_core_port *mlxsw_core_port, u8 local_port, -- struct net_device *dev, bool split, u32 split_group); --void mlxsw_core_port_fini(struct mlxsw_core_port *mlxsw_core_port); - - int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay); -+bool mlxsw_core_schedule_work(struct work_struct *work); -+void mlxsw_core_flush_owq(void); -+int mlxsw_core_resources_query(struct mlxsw_core *mlxsw_core, char *mbox, -+ struct mlxsw_res *res); - - #define MLXSW_CONFIG_PROFILE_SWID_COUNT 8 - -@@ -195,8 +207,7 @@ struct mlxsw_config_profile { - used_max_pkey:1, - used_ar_sec:1, - used_adaptive_routing_group_cap:1, -- used_kvd_split_data:1; /* indicate for the kvd's values */ -- -+ used_kvd_sizes:1; - u8 max_vepa_channels; - u16 max_mid; - u16 max_pgt; -@@ -216,24 +227,21 @@ struct mlxsw_config_profile { - u16 adaptive_routing_group_cap; - u8 arn; - u32 kvd_linear_size; -- u16 kvd_hash_granularity; - u8 kvd_hash_single_parts; - u8 kvd_hash_double_parts; -- u8 resource_query_enable; - struct mlxsw_swid_config swid_config[MLXSW_CONFIG_PROFILE_SWID_COUNT]; - }; - - struct mlxsw_driver { - struct list_head list; - const char *kind; -- struct module *owner; - size_t priv_size; - int (*init)(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info); - void (*fini)(struct mlxsw_core *mlxsw_core); -- int (*port_split)(struct mlxsw_core *mlxsw_core, u8 local_port, -- unsigned int count); -- int (*port_unsplit)(struct mlxsw_core *mlxsw_core, u8 local_port); -+ int (*basic_trap_groups_set)(struct mlxsw_core *mlxsw_core); -+ int (*port_type_set)(struct mlxsw_core *mlxsw_core, u8 local_port, -+ enum devlink_port_type new_type); - int (*sb_pool_get)(struct mlxsw_core *mlxsw_core, - unsigned int sb_index, u16 pool_index, - struct devlink_sb_pool_info *pool_info); -@@ -267,51 +275,41 @@ struct mlxsw_driver { - u32 *p_cur, u32 *p_max); - void (*txhdr_construct)(struct sk_buff *skb, - const struct mlxsw_tx_info *tx_info); -+ int (*resources_register)(struct mlxsw_core *mlxsw_core); -+ int (*kvd_sizes_get)(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_config_profile *profile, -+ u64 *p_single_size, u64 *p_double_size, -+ u64 *p_linear_size); - u8 txhdr_len; - const struct mlxsw_config_profile *profile; -+ bool res_query_enabled; - }; - --struct mlxsw_resources { -- u32 max_span_valid:1, -- max_lag_valid:1, -- max_ports_in_lag_valid:1, -- kvd_size_valid:1, -- kvd_single_min_size_valid:1, -- kvd_double_min_size_valid:1, -- max_virtual_routers_valid:1, -- max_system_ports_valid:1, -- max_vlan_groups_valid:1, -- max_regions_valid:1, -- max_rif_valid:1; -- u8 max_span; -- u8 max_lag; -- u8 max_ports_in_lag; -- u32 kvd_size; -- u32 kvd_single_min_size; -- u32 kvd_double_min_size; -- u16 max_virtual_routers; -- u16 max_system_ports; -- u16 max_vlan_groups; -- u16 max_regions; -- u16 max_rif; -+int mlxsw_core_kvd_sizes_get(struct mlxsw_core *mlxsw_core, -+ const struct mlxsw_config_profile *profile, -+ u64 *p_single_size, u64 *p_double_size, -+ u64 *p_linear_size); - -- /* Internal resources. -- * Determined by the SW, not queried from the HW. -- */ -- u32 kvd_single_size; -- u32 kvd_double_size; -- u32 kvd_linear_size; --}; -+bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core, -+ enum mlxsw_res_id res_id); -+ -+#define MLXSW_CORE_RES_VALID(mlxsw_core, short_res_id) \ -+ mlxsw_core_res_valid(mlxsw_core, MLXSW_RES_ID_##short_res_id) - --struct mlxsw_resources *mlxsw_core_resources_get(struct mlxsw_core *mlxsw_core); -+u64 mlxsw_core_res_get(struct mlxsw_core *mlxsw_core, -+ enum mlxsw_res_id res_id); -+ -+#define MLXSW_CORE_RES_GET(mlxsw_core, short_res_id) \ -+ mlxsw_core_res_get(mlxsw_core, MLXSW_RES_ID_##short_res_id) - - #define MLXSW_BUS_F_TXRX BIT(0) -+#define MLXSW_BUS_F_RESET BIT(1) - - struct mlxsw_bus { - const char *kind; - int (*init)(void *bus_priv, struct mlxsw_core *mlxsw_core, - const struct mlxsw_config_profile *profile, -- struct mlxsw_resources *resources); -+ struct mlxsw_res *res); - void (*fini)(void *bus_priv); - bool (*skb_transmit_busy)(void *bus_priv, - const struct mlxsw_tx_info *tx_info); -@@ -325,15 +323,18 @@ struct mlxsw_bus { - u8 features; - }; - -+struct mlxsw_fw_rev { -+ u16 major; -+ u16 minor; -+ u16 subminor; -+ u16 can_reset_minor; -+}; -+ - struct mlxsw_bus_info { - const char *device_kind; - const char *device_name; - struct device *dev; -- struct { -- u16 major; -- u16 minor; -- u16 subminor; -- } fw_rev; -+ struct mlxsw_fw_rev fw_rev; - u8 vsd[MLXSW_CMD_BOARDINFO_VSD_LEN]; - u8 psid[MLXSW_CMD_BOARDINFO_PSID_LEN]; - u8 low_frequency; -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index c047b61..444455c 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -873,7 +873,7 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz) - &mlxsw_thermal_module_params, - 0, 0); - if (IS_ERR(module_tz->tzdev)) { -- err = PTR_ERR(module_tz); -+ err = PTR_ERR(module_tz->tzdev); - return err; - } - -@@ -942,7 +942,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, - if (!thermal->tz_module_arr) - return -ENOMEM; - -- for (i = 1; i <= module_count; i++) { -+ for (i = 1; i < module_count; i++) { - err = mlxsw_thermal_module_init(dev, core, thermal, i); - if (err) - goto err_unreg_tz_module_arr; -@@ -957,7 +957,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, - return 0; - - err_unreg_tz_module_arr: -- for (i = thermal->tz_module_num - 1; i >= 0; i--) -+ for (i = module_count - 1; i >= 0; i--) - mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); - kfree(thermal->tz_module_arr); - return err; -@@ -966,9 +966,10 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, - static void - mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal) - { -+ unsigned int module_count = mlxsw_core_max_ports(thermal->core); - int i; - -- for (i = thermal->tz_module_num - 1; i >= 0; i--) -+ for (i = module_count - 1; i >= 0; i--) - mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); - kfree(thermal->tz_module_arr); - } -diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c -index f1b95d5..b1471c2 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c -@@ -14,14 +14,17 @@ - #include "cmd.h" - #include "core.h" - #include "i2c.h" -+#include "resources.h" - - #define MLXSW_I2C_CIR2_BASE 0x72000 - #define MLXSW_I2C_CIR_STATUS_OFF 0x18 - #define MLXSW_I2C_CIR2_OFF_STATUS (MLXSW_I2C_CIR2_BASE + \ - MLXSW_I2C_CIR_STATUS_OFF) - #define MLXSW_I2C_OPMOD_SHIFT 12 -+#define MLXSW_I2C_EVENT_BIT_SHIFT 22 - #define MLXSW_I2C_GO_BIT_SHIFT 23 - #define MLXSW_I2C_CIR_CTRL_STATUS_SHIFT 24 -+#define MLXSW_I2C_EVENT_BIT BIT(MLXSW_I2C_EVENT_BIT_SHIFT) - #define MLXSW_I2C_GO_BIT BIT(MLXSW_I2C_GO_BIT_SHIFT) - #define MLXSW_I2C_GO_OPMODE BIT(MLXSW_I2C_OPMOD_SHIFT) - #define MLXSW_I2C_SET_IMM_CMD (MLXSW_I2C_GO_OPMODE | \ -@@ -33,6 +36,9 @@ - #define MLXSW_I2C_TLV_HDR_SIZE 0x10 - #define MLXSW_I2C_ADDR_WIDTH 4 - #define MLXSW_I2C_PUSH_CMD_SIZE (MLXSW_I2C_ADDR_WIDTH + 4) -+#define MLXSW_I2C_SET_EVENT_CMD (MLXSW_I2C_EVENT_BIT) -+#define MLXSW_I2C_PUSH_EVENT_CMD (MLXSW_I2C_GO_BIT | \ -+ MLXSW_I2C_SET_EVENT_CMD) - #define MLXSW_I2C_READ_SEMA_SIZE 4 - #define MLXSW_I2C_PREP_SIZE (MLXSW_I2C_ADDR_WIDTH + 28) - #define MLXSW_I2C_MBOX_SIZE 20 -@@ -44,6 +50,7 @@ - #define MLXSW_I2C_BLK_MAX 32 - #define MLXSW_I2C_RETRY 5 - #define MLXSW_I2C_TIMEOUT_MSECS 5000 -+#define MLXSW_I2C_MAX_DATA_SIZE 256 - - /** - * struct mlxsw_i2c - device private data: -@@ -167,7 +174,7 @@ static int mlxsw_i2c_wait_go_bit(struct i2c_client *client, - return err > 0 ? 0 : err; - } - --/* Routine posts a command to ASIC though mail box. */ -+/* Routine posts a command to ASIC through mail box. */ - static int mlxsw_i2c_write_cmd(struct i2c_client *client, - struct mlxsw_i2c *mlxsw_i2c, - int immediate) -@@ -213,6 +220,66 @@ static int mlxsw_i2c_write_cmd(struct i2c_client *client, - return 0; - } - -+/* Routine posts initialization command to ASIC through mail box. */ -+static int -+mlxsw_i2c_write_init_cmd(struct i2c_client *client, -+ struct mlxsw_i2c *mlxsw_i2c, u16 opcode, u32 in_mod) -+{ -+ __be32 push_cmd_buf[MLXSW_I2C_PUSH_CMD_SIZE / 4] = { -+ 0, cpu_to_be32(MLXSW_I2C_PUSH_EVENT_CMD) -+ }; -+ __be32 prep_cmd_buf[MLXSW_I2C_PREP_SIZE / 4] = { -+ 0, 0, 0, 0, 0, 0, -+ cpu_to_be32(client->adapter->nr & 0xffff), -+ cpu_to_be32(MLXSW_I2C_SET_EVENT_CMD) -+ }; -+ struct i2c_msg push_cmd = -+ MLXSW_I2C_WRITE_MSG(client, push_cmd_buf, -+ MLXSW_I2C_PUSH_CMD_SIZE); -+ struct i2c_msg prep_cmd = -+ MLXSW_I2C_WRITE_MSG(client, prep_cmd_buf, MLXSW_I2C_PREP_SIZE); -+ u8 status; -+ int err; -+ -+ push_cmd_buf[1] = cpu_to_be32(MLXSW_I2C_PUSH_EVENT_CMD | opcode); -+ prep_cmd_buf[3] = cpu_to_be32(in_mod); -+ prep_cmd_buf[7] = cpu_to_be32(MLXSW_I2C_GO_BIT | opcode); -+ mlxsw_i2c_set_slave_addr((u8 *)prep_cmd_buf, -+ MLXSW_I2C_CIR2_BASE); -+ mlxsw_i2c_set_slave_addr((u8 *)push_cmd_buf, -+ MLXSW_I2C_CIR2_OFF_STATUS); -+ -+ /* Prepare Command Interface Register for transaction */ -+ err = i2c_transfer(client->adapter, &prep_cmd, 1); -+ if (err < 0) -+ return err; -+ else if (err != 1) -+ return -EIO; -+ -+ /* Write out Command Interface Register GO bit to push transaction */ -+ err = i2c_transfer(client->adapter, &push_cmd, 1); -+ if (err < 0) -+ return err; -+ else if (err != 1) -+ return -EIO; -+ -+ /* 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"); -+ return err; -+ } -+ -+ /* Validate transaction completion status. */ -+ if (status) { -+ dev_err(&client->dev, "Bad transaction completion status %x\n", -+ status); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ - /* Routine obtains mail box offsets from ASIC register space. */ - static int mlxsw_i2c_get_mbox(struct i2c_client *client, - struct mlxsw_i2c *mlxsw_i2c) -@@ -310,8 +377,8 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num, - - /* Routine executes I2C command. */ - static int --mlxsw_i2c_cmd(struct device *dev, size_t in_mbox_size, u8 *in_mbox, -- size_t out_mbox_size, u8 *out_mbox, u8 *status) -+mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, -+ u8 *in_mbox, size_t out_mbox_size, u8 *out_mbox, u8 *status) - { - struct i2c_client *client = to_i2c_client(dev); - struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); -@@ -326,21 +393,34 @@ mlxsw_i2c_cmd(struct device *dev, size_t in_mbox_size, u8 *in_mbox, - - WARN_ON(in_mbox_size % sizeof(u32) || out_mbox_size % sizeof(u32)); - -- reg_size = mlxsw_i2c_get_reg_size(in_mbox); -- num = reg_size / MLXSW_I2C_BLK_MAX; -- if (reg_size % MLXSW_I2C_BLK_MAX) -- num++; -+ if (in_mbox) { -+ reg_size = mlxsw_i2c_get_reg_size(in_mbox); -+ num = reg_size / MLXSW_I2C_BLK_MAX; -+ if (reg_size % MLXSW_I2C_BLK_MAX) -+ num++; - -- mutex_lock(&mlxsw_i2c->cmd.lock); -+ mutex_lock(&mlxsw_i2c->cmd.lock); - -- err = mlxsw_i2c_write(dev, reg_size, in_mbox, num, status); -- if (err) -- goto cmd_fail; -+ err = mlxsw_i2c_write(dev, reg_size, in_mbox, num, status); -+ if (err) -+ goto cmd_fail; -+ -+ /* No out mailbox is case of write transaction. */ -+ if (!out_mbox) { -+ mutex_unlock(&mlxsw_i2c->cmd.lock); -+ return 0; -+ } -+ } else { -+ /* No input mailbox is case of initialization query command. */ -+ reg_size = MLXSW_I2C_MAX_DATA_SIZE; -+ num = reg_size / MLXSW_I2C_BLK_MAX; - -- /* No out mailbox is case of write transaction. */ -- if (!out_mbox) { -- mutex_unlock(&mlxsw_i2c->cmd.lock); -- return 0; -+ mutex_lock(&mlxsw_i2c->cmd.lock); -+ -+ err = mlxsw_i2c_write_init_cmd(client, mlxsw_i2c, opcode, -+ in_mod); -+ if (err) -+ goto cmd_fail; - } - - /* Send read transaction to get output mailbox content. */ -@@ -392,8 +472,8 @@ static int mlxsw_i2c_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod, - { - struct mlxsw_i2c *mlxsw_i2c = bus_priv; - -- return mlxsw_i2c_cmd(mlxsw_i2c->dev, in_mbox_size, in_mbox, -- out_mbox_size, out_mbox, status); -+ return mlxsw_i2c_cmd(mlxsw_i2c->dev, opcode, in_mod, in_mbox_size, -+ in_mbox, out_mbox_size, out_mbox, status); - } - - static bool mlxsw_i2c_skb_transmit_busy(void *bus_priv, -@@ -411,13 +491,34 @@ 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_resources *resources) -+ struct mlxsw_res *res) - { - struct mlxsw_i2c *mlxsw_i2c = bus_priv; -+ char *mbox; -+ int err; - - mlxsw_i2c->core = mlxsw_core; - -- return 0; -+ mbox = mlxsw_cmd_mbox_alloc(); -+ if (!mbox) -+ return -ENOMEM; -+ -+ err = mlxsw_cmd_query_fw(mlxsw_core, mbox); -+ if (err) -+ goto mbox_put; -+ -+ mlxsw_i2c->bus_info.fw_rev.major = -+ mlxsw_cmd_mbox_query_fw_fw_rev_major_get(mbox); -+ mlxsw_i2c->bus_info.fw_rev.minor = -+ mlxsw_cmd_mbox_query_fw_fw_rev_minor_get(mbox); -+ mlxsw_i2c->bus_info.fw_rev.subminor = -+ mlxsw_cmd_mbox_query_fw_fw_rev_subminor_get(mbox); -+ -+ err = mlxsw_core_resources_query(mlxsw_core, mbox, res); -+ -+mbox_put: -+ mlxsw_cmd_mbox_free(mbox); -+ return err; - } - - static void mlxsw_i2c_fini(void *bus_priv) -@@ -504,12 +605,18 @@ static int mlxsw_i2c_probe(struct i2c_client *client, - mlxsw_i2c->dev = &client->dev; - - err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info, -- &mlxsw_i2c_bus, mlxsw_i2c); -+ &mlxsw_i2c_bus, mlxsw_i2c, false, -+ NULL); - if (err) { - dev_err(&client->dev, "Fail to register core bus\n"); - return err; - } - -+ dev_info(&client->dev, "Firmware revision: %d.%d.%d\n", -+ mlxsw_i2c->bus_info.fw_rev.major, -+ mlxsw_i2c->bus_info.fw_rev.minor, -+ mlxsw_i2c->bus_info.fw_rev.subminor); -+ - return 0; - - errout: -@@ -522,7 +629,7 @@ static int mlxsw_i2c_remove(struct i2c_client *client) - { - struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); - -- mlxsw_core_bus_device_unregister(mlxsw_i2c->core); -+ mlxsw_core_bus_device_unregister(mlxsw_i2c->core, false); - mutex_destroy(&mlxsw_i2c->cmd.lock); - - return 0; -diff --git a/drivers/net/ethernet/mellanox/mlxsw/item.h b/drivers/net/ethernet/mellanox/mlxsw/item.h -index a94dbda6..e92cadc 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/item.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/item.h -@@ -1,37 +1,5 @@ --/* -- * drivers/net/ethernet/mellanox/mlxsw/item.h -- * Copyright (c) 2015 Mellanox Technologies. All rights reserved. -- * Copyright (c) 2015 Jiri Pirko -- * Copyright (c) 2015 Ido Schimmel -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. 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. -- * 3. Neither the names of the copyright holders nor the names of its -- * contributors may be used to endorse or promote products derived from -- * this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * 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. -- */ -+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ -+/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ - - #ifndef _MLXSW_ITEM_H - #define _MLXSW_ITEM_H -@@ -42,7 +10,7 @@ - - struct mlxsw_item { - unsigned short offset; /* bytes in container */ -- unsigned short step; /* step in bytes for indexed items */ -+ short step; /* step in bytes for indexed items */ - unsigned short in_step_offset; /* offset within one step */ - unsigned char shift; /* shift in bits */ - unsigned char element_size; /* size of element in bit array */ -@@ -55,7 +23,7 @@ struct mlxsw_item { - }; - - static inline unsigned int --__mlxsw_item_offset(struct mlxsw_item *item, unsigned short index, -+__mlxsw_item_offset(const struct mlxsw_item *item, unsigned short index, - size_t typesize) - { - BUG_ON(index && !item->step); -@@ -72,7 +40,42 @@ __mlxsw_item_offset(struct mlxsw_item *item, unsigned short index, - typesize); - } - --static inline u16 __mlxsw_item_get16(char *buf, struct mlxsw_item *item, -+static inline u8 __mlxsw_item_get8(const char *buf, -+ const struct mlxsw_item *item, -+ unsigned short index) -+{ -+ unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u8)); -+ u8 *b = (u8 *) buf; -+ u8 tmp; -+ -+ tmp = b[offset]; -+ tmp >>= item->shift; -+ tmp &= GENMASK(item->size.bits - 1, 0); -+ if (item->no_real_shift) -+ tmp <<= item->shift; -+ return tmp; -+} -+ -+static inline void __mlxsw_item_set8(char *buf, const struct mlxsw_item *item, -+ unsigned short index, u8 val) -+{ -+ unsigned int offset = __mlxsw_item_offset(item, index, -+ sizeof(u8)); -+ u8 *b = (u8 *) buf; -+ u8 mask = GENMASK(item->size.bits - 1, 0) << item->shift; -+ u8 tmp; -+ -+ if (!item->no_real_shift) -+ val <<= item->shift; -+ val &= mask; -+ tmp = b[offset]; -+ tmp &= ~mask; -+ tmp |= val; -+ b[offset] = tmp; -+} -+ -+static inline u16 __mlxsw_item_get16(const char *buf, -+ const struct mlxsw_item *item, - unsigned short index) - { - unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u16)); -@@ -87,7 +90,7 @@ static inline u16 __mlxsw_item_get16(char *buf, struct mlxsw_item *item, - return tmp; - } - --static inline void __mlxsw_item_set16(char *buf, struct mlxsw_item *item, -+static inline void __mlxsw_item_set16(char *buf, const struct mlxsw_item *item, - unsigned short index, u16 val) - { - unsigned int offset = __mlxsw_item_offset(item, index, -@@ -105,7 +108,8 @@ static inline void __mlxsw_item_set16(char *buf, struct mlxsw_item *item, - b[offset] = cpu_to_be16(tmp); - } - --static inline u32 __mlxsw_item_get32(char *buf, struct mlxsw_item *item, -+static inline u32 __mlxsw_item_get32(const char *buf, -+ const struct mlxsw_item *item, - unsigned short index) - { - unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u32)); -@@ -120,7 +124,7 @@ static inline u32 __mlxsw_item_get32(char *buf, struct mlxsw_item *item, - return tmp; - } - --static inline void __mlxsw_item_set32(char *buf, struct mlxsw_item *item, -+static inline void __mlxsw_item_set32(char *buf, const struct mlxsw_item *item, - unsigned short index, u32 val) - { - unsigned int offset = __mlxsw_item_offset(item, index, -@@ -138,7 +142,8 @@ static inline void __mlxsw_item_set32(char *buf, struct mlxsw_item *item, - b[offset] = cpu_to_be32(tmp); - } - --static inline u64 __mlxsw_item_get64(char *buf, struct mlxsw_item *item, -+static inline u64 __mlxsw_item_get64(const char *buf, -+ const struct mlxsw_item *item, - unsigned short index) - { - unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64)); -@@ -153,7 +158,7 @@ static inline u64 __mlxsw_item_get64(char *buf, struct mlxsw_item *item, - return tmp; - } - --static inline void __mlxsw_item_set64(char *buf, struct mlxsw_item *item, -+static inline void __mlxsw_item_set64(char *buf, const struct mlxsw_item *item, - unsigned short index, u64 val) - { - unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64)); -@@ -170,8 +175,8 @@ static inline void __mlxsw_item_set64(char *buf, struct mlxsw_item *item, - b[offset] = cpu_to_be64(tmp); - } - --static inline void __mlxsw_item_memcpy_from(char *buf, char *dst, -- struct mlxsw_item *item, -+static inline void __mlxsw_item_memcpy_from(const char *buf, char *dst, -+ const struct mlxsw_item *item, - unsigned short index) - { - unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char)); -@@ -180,7 +185,7 @@ static inline void __mlxsw_item_memcpy_from(char *buf, char *dst, - } - - static inline void __mlxsw_item_memcpy_to(char *buf, const char *src, -- struct mlxsw_item *item, -+ const struct mlxsw_item *item, - unsigned short index) - { - unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char)); -@@ -188,8 +193,17 @@ static inline void __mlxsw_item_memcpy_to(char *buf, const char *src, - memcpy(&buf[offset], src, item->size.bytes); - } - -+static inline char *__mlxsw_item_data(char *buf, const struct mlxsw_item *item, -+ unsigned short index) -+{ -+ unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char)); -+ -+ return &buf[offset]; -+} -+ - static inline u16 --__mlxsw_item_bit_array_offset(struct mlxsw_item *item, u16 index, u8 *shift) -+__mlxsw_item_bit_array_offset(const struct mlxsw_item *item, -+ u16 index, u8 *shift) - { - u16 max_index, be_index; - u16 offset; /* byte offset inside the array */ -@@ -212,7 +226,8 @@ __mlxsw_item_bit_array_offset(struct mlxsw_item *item, u16 index, u8 *shift) - return item->offset + offset; - } - --static inline u8 __mlxsw_item_bit_array_get(char *buf, struct mlxsw_item *item, -+static inline u8 __mlxsw_item_bit_array_get(const char *buf, -+ const struct mlxsw_item *item, - u16 index) - { - u8 shift, tmp; -@@ -224,7 +239,8 @@ static inline u8 __mlxsw_item_bit_array_get(char *buf, struct mlxsw_item *item, - return tmp; - } - --static inline void __mlxsw_item_bit_array_set(char *buf, struct mlxsw_item *item, -+static inline void __mlxsw_item_bit_array_set(char *buf, -+ const struct mlxsw_item *item, - u16 index, u8 val) - { - u8 shift, tmp; -@@ -247,6 +263,47 @@ static inline void __mlxsw_item_bit_array_set(char *buf, struct mlxsw_item *item - * _iname: item name within the container - */ - -+#define MLXSW_ITEM8(_type, _cname, _iname, _offset, _shift, _sizebits) \ -+static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ -+ .offset = _offset, \ -+ .shift = _shift, \ -+ .size = {.bits = _sizebits,}, \ -+ .name = #_type "_" #_cname "_" #_iname, \ -+}; \ -+static inline u8 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \ -+{ \ -+ return __mlxsw_item_get8(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \ -+} \ -+static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u8 val)\ -+{ \ -+ __mlxsw_item_set8(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \ -+} -+ -+#define MLXSW_ITEM8_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \ -+ _step, _instepoffset, _norealshift) \ -+static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ -+ .offset = _offset, \ -+ .step = _step, \ -+ .in_step_offset = _instepoffset, \ -+ .shift = _shift, \ -+ .no_real_shift = _norealshift, \ -+ .size = {.bits = _sizebits,}, \ -+ .name = #_type "_" #_cname "_" #_iname, \ -+}; \ -+static inline u8 \ -+mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\ -+{ \ -+ return __mlxsw_item_get8(buf, &__ITEM_NAME(_type, _cname, _iname), \ -+ index); \ -+} \ -+static inline void \ -+mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \ -+ u8 val) \ -+{ \ -+ __mlxsw_item_set8(buf, &__ITEM_NAME(_type, _cname, _iname), \ -+ index, val); \ -+} -+ - #define MLXSW_ITEM16(_type, _cname, _iname, _offset, _shift, _sizebits) \ - static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ - .offset = _offset, \ -@@ -254,7 +311,7 @@ static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ - .size = {.bits = _sizebits,}, \ - .name = #_type "_" #_cname "_" #_iname, \ - }; \ --static inline u16 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf) \ -+static inline u16 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \ - { \ - return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \ - } \ -@@ -275,7 +332,7 @@ static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ - .name = #_type "_" #_cname "_" #_iname, \ - }; \ - static inline u16 \ --mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, unsigned short index) \ -+mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\ - { \ - return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), \ - index); \ -@@ -295,7 +352,7 @@ static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ - .size = {.bits = _sizebits,}, \ - .name = #_type "_" #_cname "_" #_iname, \ - }; \ --static inline u32 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf) \ -+static inline u32 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \ - { \ - return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \ - } \ -@@ -316,7 +373,7 @@ static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ - .name = #_type "_" #_cname "_" #_iname, \ - }; \ - static inline u32 \ --mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, unsigned short index) \ -+mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\ - { \ - return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), \ - index); \ -@@ -336,7 +393,7 @@ static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ - .size = {.bits = _sizebits,}, \ - .name = #_type "_" #_cname "_" #_iname, \ - }; \ --static inline u64 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf) \ -+static inline u64 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \ - { \ - return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \ - } \ -@@ -357,7 +414,7 @@ static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ - .name = #_type "_" #_cname "_" #_iname, \ - }; \ - static inline u64 \ --mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, unsigned short index) \ -+mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\ - { \ - return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), \ - index); \ -@@ -377,7 +434,7 @@ static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ - .name = #_type "_" #_cname "_" #_iname, \ - }; \ - static inline void \ --mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(char *buf, char *dst) \ -+mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(const char *buf, char *dst) \ - { \ - __mlxsw_item_memcpy_from(buf, dst, \ - &__ITEM_NAME(_type, _cname, _iname), 0); \ -@@ -387,6 +444,11 @@ mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf, const char *src) \ - { \ - __mlxsw_item_memcpy_to(buf, src, \ - &__ITEM_NAME(_type, _cname, _iname), 0); \ -+} \ -+static inline char * \ -+mlxsw_##_type##_##_cname##_##_iname##_data(char *buf) \ -+{ \ -+ return __mlxsw_item_data(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \ - } - - #define MLXSW_ITEM_BUF_INDEXED(_type, _cname, _iname, _offset, _sizebytes, \ -@@ -399,7 +461,7 @@ static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ - .name = #_type "_" #_cname "_" #_iname, \ - }; \ - static inline void \ --mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(char *buf, \ -+mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(const char *buf, \ - unsigned short index, \ - char *dst) \ - { \ -@@ -413,6 +475,12 @@ mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf, \ - { \ - __mlxsw_item_memcpy_to(buf, src, \ - &__ITEM_NAME(_type, _cname, _iname), index); \ -+} \ -+static inline char * \ -+mlxsw_##_type##_##_cname##_##_iname##_data(char *buf, unsigned short index) \ -+{ \ -+ return __mlxsw_item_data(buf, \ -+ &__ITEM_NAME(_type, _cname, _iname), index); \ - } - - #define MLXSW_ITEM_BIT_ARRAY(_type, _cname, _iname, _offset, _sizebytes, \ -@@ -424,7 +492,7 @@ static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ - .name = #_type "_" #_cname "_" #_iname, \ - }; \ - static inline u8 \ --mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, u16 index) \ -+mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, u16 index) \ - { \ - return __mlxsw_item_bit_array_get(buf, \ - &__ITEM_NAME(_type, _cname, _iname), \ -diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -index c47949c..9312f42 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - - #include "core.h" -@@ -19,16 +20,15 @@ static const char mlxsw_m_driver_name[] = "mlxsw_minimal"; - struct mlxsw_m_port; - - struct mlxsw_m { -- struct mlxsw_m_port **modules; -+ 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_modules; -+ u8 max_ports; - }; - - struct mlxsw_m_port { -- struct mlxsw_core_port core_port; /* must be first */ - struct net_device *dev; - struct mlxsw_m *mlxsw_m; - u8 local_port; -@@ -114,6 +114,14 @@ mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port) - return 0; - } - -+static void mlxsw_m_port_switchdev_init(struct mlxsw_m_port *mlxsw_m_port) -+{ -+} -+ -+static void mlxsw_m_port_switchdev_fini(struct mlxsw_m_port *mlxsw_m_port) -+{ -+} -+ - static int - mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) - { -@@ -121,6 +129,13 @@ 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); -+ if (err) { -+ dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to init core port\n", -+ local_port); -+ return err; -+ } -+ - dev = alloc_etherdev(sizeof(struct mlxsw_m_port)); - if (!dev) { - err = -ENOMEM; -@@ -134,20 +149,9 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) - mlxsw_m_port->local_port = local_port; - mlxsw_m_port->module = module; - -- mlxsw_m->modules[local_port] = mlxsw_m_port; -- - dev->netdev_ops = &mlxsw_m_port_netdev_ops; - dev->ethtool_ops = &mlxsw_m_port_ethtool_ops; - -- err = mlxsw_core_port_init(mlxsw_m->core, -- &mlxsw_m_port->core_port, local_port, -- dev, false, module); -- if (err) { -- dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to init core port\n", -- local_port); -- goto err_alloc_etherdev; -- } -- - err = mlxsw_m_port_dev_addr_get(mlxsw_m_port); - if (err) { - dev_err(mlxsw_m->bus_info->dev, "Port %d: Unable to get port mac address\n", -@@ -156,7 +160,8 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) - } - - netif_carrier_off(dev); -- -+ mlxsw_m_port_switchdev_init(mlxsw_m_port); -+ mlxsw_m->ports[local_port] = mlxsw_m_port; - err = register_netdev(dev); - if (err) { - dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to register netdev\n", -@@ -167,38 +172,29 @@ 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; -+ mlxsw_m_port_switchdev_fini(mlxsw_m_port); - free_netdev(dev); - err_dev_addr_get: - err_alloc_etherdev: -- mlxsw_m->modules[local_port] = NULL; -+ mlxsw_core_port_fini(mlxsw_m->core, local_port); - return err; - } - - static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 local_port) - { -- struct mlxsw_m_port *mlxsw_m_port = mlxsw_m->modules[local_port]; -+ struct mlxsw_m_port *mlxsw_m_port = mlxsw_m->ports[local_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; -+ mlxsw_m_port_switchdev_fini(mlxsw_m_port); - free_netdev(mlxsw_m_port->dev); -- mlxsw_core_port_fini(&mlxsw_m_port->core_port); -+ mlxsw_core_port_fini(mlxsw_m->core, local_port); - } - --static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) --{ -- int i; -- -- for (i = 0; i < mlxsw_m->max_modules; i++) { -- if (mlxsw_m->module_to_port[i] > 0) -- mlxsw_m_port_remove(mlxsw_m, -- mlxsw_m->module_to_port[i]); -- } -- -- kfree(mlxsw_m->module_to_port); -- kfree(mlxsw_m->modules); --} -- --static int mlxsw_m_port_mapping_create(struct mlxsw_m *mlxsw_m, u8 local_port, -- u8 *last_module) -+static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port, -+ u8 *last_module) - { - u8 module, width; - int err; -@@ -215,11 +211,34 @@ static int mlxsw_m_port_mapping_create(struct mlxsw_m *mlxsw_m, u8 local_port, - if (module == *last_module) - return 0; - *last_module = module; -- mlxsw_m->module_to_port[module] = ++mlxsw_m->max_modules; -+ mlxsw_m->module_to_port[module] = ++mlxsw_m->max_ports; - - return 0; - } - -+static int mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 module) -+{ -+ mlxsw_m->module_to_port[module] = -1; -+ -+ return 0; -+} -+ -+static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) -+{ -+ int i; -+ -+ for (i = 0; i < mlxsw_m->max_ports; i++) { -+ if (mlxsw_m->module_to_port[i] > 0) { -+ mlxsw_m_port_remove(mlxsw_m, -+ mlxsw_m->module_to_port[i]); -+ mlxsw_m_port_module_unmap(mlxsw_m, i); -+ } -+ } -+ -+ kfree(mlxsw_m->module_to_port); -+ kfree(mlxsw_m->ports); -+} -+ - static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) - { - unsigned int max_port = mlxsw_core_max_ports(mlxsw_m->core); -@@ -227,9 +246,9 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) - int i; - int err; - -- mlxsw_m->modules = kcalloc(max_port, sizeof(*mlxsw_m->modules), -- GFP_KERNEL); -- if (!mlxsw_m->modules) -+ mlxsw_m->ports = kcalloc(max_port, sizeof(*mlxsw_m->ports), -+ GFP_KERNEL); -+ if (!mlxsw_m->ports) - return -ENOMEM; - - mlxsw_m->module_to_port = kmalloc_array(max_port, sizeof(int), -@@ -244,14 +263,14 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) - mlxsw_m->module_to_port[i] = -1; - - /* Fill out module to local port mapping array */ -- for (i = 1; i <= max_port; i++) { -- err = mlxsw_m_port_mapping_create(mlxsw_m, i, &last_module); -+ for (i = 1; i < max_port; i++) { -+ err = mlxsw_m_port_module_map(mlxsw_m, i, &last_module); - if (err) - goto err_port_create; - } - - /* Create port objects for each valid entry */ -- for (i = 0; i < mlxsw_m->max_modules; i++) { -+ for (i = 0; i < mlxsw_m->max_ports; i++) { - if (mlxsw_m->module_to_port[i] > 0) { - err = mlxsw_m_port_create(mlxsw_m, - mlxsw_m->module_to_port[i], -@@ -279,7 +298,7 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, - - err = mlxsw_m_ports_create(mlxsw_m); - if (err) { -- dev_err(mlxsw_m->bus_info->dev, "Failed to create modules\n"); -+ dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n"); - return err; - } - -@@ -296,11 +315,12 @@ static void mlxsw_m_fini(struct mlxsw_core *mlxsw_core) - static const struct mlxsw_config_profile mlxsw_m_config_profile; - - static struct mlxsw_driver mlxsw_m_driver = { -- .kind = mlxsw_m_driver_name, -- .priv_size = sizeof(struct mlxsw_m), -- .init = mlxsw_m_init, -- .fini = mlxsw_m_fini, -- .profile = &mlxsw_m_config_profile, -+ .kind = mlxsw_m_driver_name, -+ .priv_size = sizeof(struct mlxsw_m), -+ .init = mlxsw_m_init, -+ .fini = mlxsw_m_fini, -+ .profile = &mlxsw_m_config_profile, -+ .res_query_enabled = true, - }; - - static const struct i2c_device_id mlxsw_m_i2c_id[] = { -diff --git a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -index 0781f16..bee2a08 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -@@ -298,7 +298,6 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, - mlxsw_qsfp->bus_info = mlxsw_bus_info; - mlxsw_bus_info->dev->platform_data = mlxsw_qsfp; - -- mlxsw_core_max_ports_set(mlxsw_core, mlxsw_qsfp_num); - for (i = 1; i <= mlxsw_qsfp_num; i++) { - mlxsw_reg_pmlp_pack(pmlp_pl, i); - err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(pmlp), -diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h -index 20f01bb..4a12be2 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/reg.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h -@@ -1,43 +1,10 @@ --/* -- * drivers/net/ethernet/mellanox/mlxsw/reg.h -- * Copyright (c) 2015 Mellanox Technologies. All rights reserved. -- * Copyright (c) 2015-2016 Ido Schimmel -- * Copyright (c) 2015 Elad Raz -- * Copyright (c) 2015-2016 Jiri Pirko -- * Copyright (c) 2016 Yotam Gigi -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions are met: -- * -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. 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. -- * 3. Neither the names of the copyright holders nor the names of its -- * contributors may be used to endorse or promote products derived from -- * this software without specific prior written permission. -- * -- * Alternatively, this software may be distributed under the terms of the -- * GNU General Public License ("GPL") version 2 as published by the Free -- * Software Foundation. -- * -- * 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. -- */ -+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ -+/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ - - #ifndef _MLXSW_REG_H - #define _MLXSW_REG_H - -+#include - #include - #include - #include -@@ -48,12 +15,14 @@ - struct mlxsw_reg_info { - u16 id; - u16 len; /* In u8 */ -+ const char *name; - }; - - #define MLXSW_REG_DEFINE(_name, _id, _len) \ - static const struct mlxsw_reg_info mlxsw_reg_##_name = { \ - .id = _id, \ - .len = _len, \ -+ .name = #_name, \ - } - - #define MLXSW_REG(type) (&mlxsw_reg_##type) -@@ -67,10 +36,7 @@ static const struct mlxsw_reg_info mlxsw_reg_##_name = { \ - #define MLXSW_REG_SGCR_ID 0x2000 - #define MLXSW_REG_SGCR_LEN 0x10 - --static const struct mlxsw_reg_info mlxsw_reg_sgcr = { -- .id = MLXSW_REG_SGCR_ID, -- .len = MLXSW_REG_SGCR_LEN, --}; -+MLXSW_REG_DEFINE(sgcr, MLXSW_REG_SGCR_ID, MLXSW_REG_SGCR_LEN); - - /* reg_sgcr_llb - * Link Local Broadcast (Default=0) -@@ -93,10 +59,7 @@ static inline void mlxsw_reg_sgcr_pack(char *payload, bool llb) - #define MLXSW_REG_SPAD_ID 0x2002 - #define MLXSW_REG_SPAD_LEN 0x10 - --static const struct mlxsw_reg_info mlxsw_reg_spad = { -- .id = MLXSW_REG_SPAD_ID, -- .len = MLXSW_REG_SPAD_LEN, --}; -+MLXSW_REG_DEFINE(spad, MLXSW_REG_SPAD_ID, MLXSW_REG_SPAD_LEN); - - /* reg_spad_base_mac - * Base MAC address for the switch partitions. -@@ -115,10 +78,7 @@ MLXSW_ITEM_BUF(reg, spad, base_mac, 0x02, 6); - #define MLXSW_REG_SMID_ID 0x2007 - #define MLXSW_REG_SMID_LEN 0x240 - --static const struct mlxsw_reg_info mlxsw_reg_smid = { -- .id = MLXSW_REG_SMID_ID, -- .len = MLXSW_REG_SMID_LEN, --}; -+MLXSW_REG_DEFINE(smid, MLXSW_REG_SMID_ID, MLXSW_REG_SMID_LEN); - - /* reg_smid_swid - * Switch partition ID. -@@ -162,10 +122,7 @@ static inline void mlxsw_reg_smid_pack(char *payload, u16 mid, - #define MLXSW_REG_SSPR_ID 0x2008 - #define MLXSW_REG_SSPR_LEN 0x8 - --static const struct mlxsw_reg_info mlxsw_reg_sspr = { -- .id = MLXSW_REG_SSPR_ID, -- .len = MLXSW_REG_SSPR_LEN, --}; -+MLXSW_REG_DEFINE(sspr, MLXSW_REG_SSPR_ID, MLXSW_REG_SSPR_LEN); - - /* reg_sspr_m - * Master - if set, then the record describes the master system port. -@@ -221,10 +178,7 @@ static inline void mlxsw_reg_sspr_pack(char *payload, u8 local_port) - #define MLXSW_REG_SFDAT_ID 0x2009 - #define MLXSW_REG_SFDAT_LEN 0x8 - --static const struct mlxsw_reg_info mlxsw_reg_sfdat = { -- .id = MLXSW_REG_SFDAT_ID, -- .len = MLXSW_REG_SFDAT_LEN, --}; -+MLXSW_REG_DEFINE(sfdat, MLXSW_REG_SFDAT_ID, MLXSW_REG_SFDAT_LEN); - - /* reg_sfdat_swid - * Switch partition ID. -@@ -262,10 +216,7 @@ static inline void mlxsw_reg_sfdat_pack(char *payload, u32 age_time) - #define MLXSW_REG_SFD_LEN (MLXSW_REG_SFD_BASE_LEN + \ - MLXSW_REG_SFD_REC_LEN * MLXSW_REG_SFD_REC_MAX_COUNT) - --static const struct mlxsw_reg_info mlxsw_reg_sfd = { -- .id = MLXSW_REG_SFD_ID, -- .len = MLXSW_REG_SFD_LEN, --}; -+MLXSW_REG_DEFINE(sfd, MLXSW_REG_SFD_ID, MLXSW_REG_SFD_LEN); - - /* reg_sfd_swid - * Switch partition ID for queries. Reserved on Write. -@@ -344,6 +295,7 @@ enum mlxsw_reg_sfd_rec_type { - MLXSW_REG_SFD_REC_TYPE_UNICAST = 0x0, - MLXSW_REG_SFD_REC_TYPE_UNICAST_LAG = 0x1, - MLXSW_REG_SFD_REC_TYPE_MULTICAST = 0x2, -+ MLXSW_REG_SFD_REC_TYPE_UNICAST_TUNNEL = 0xC, - }; - - /* reg_sfd_rec_type -@@ -574,6 +526,61 @@ mlxsw_reg_sfd_mc_pack(char *payload, int rec_index, - mlxsw_reg_sfd_mc_mid_set(payload, rec_index, mid); - } - -+/* reg_sfd_uc_tunnel_uip_msb -+ * When protocol is IPv4, the most significant byte of the underlay IPv4 -+ * destination IP. -+ * When protocol is IPv6, reserved. -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_uip_msb, MLXSW_REG_SFD_BASE_LEN, 24, -+ 8, MLXSW_REG_SFD_REC_LEN, 0x08, false); -+ -+/* reg_sfd_uc_tunnel_fid -+ * Filtering ID. -+ * Access: Index -+ */ -+MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_fid, MLXSW_REG_SFD_BASE_LEN, 0, 16, -+ MLXSW_REG_SFD_REC_LEN, 0x08, false); -+ -+enum mlxsw_reg_sfd_uc_tunnel_protocol { -+ MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV4, -+ MLXSW_REG_SFD_UC_TUNNEL_PROTOCOL_IPV6, -+}; -+ -+/* reg_sfd_uc_tunnel_protocol -+ * IP protocol. -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_protocol, MLXSW_REG_SFD_BASE_LEN, 27, -+ 1, MLXSW_REG_SFD_REC_LEN, 0x0C, false); -+ -+/* reg_sfd_uc_tunnel_uip_lsb -+ * When protocol is IPv4, the least significant bytes of the underlay -+ * IPv4 destination IP. -+ * When protocol is IPv6, pointer to the underlay IPv6 destination IP -+ * which is configured by RIPS. -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, sfd, uc_tunnel_uip_lsb, MLXSW_REG_SFD_BASE_LEN, 0, -+ 24, MLXSW_REG_SFD_REC_LEN, 0x0C, false); -+ -+static inline void -+mlxsw_reg_sfd_uc_tunnel_pack(char *payload, int rec_index, -+ enum mlxsw_reg_sfd_rec_policy policy, -+ const char *mac, u16 fid, -+ enum mlxsw_reg_sfd_rec_action action, u32 uip, -+ enum mlxsw_reg_sfd_uc_tunnel_protocol proto) -+{ -+ mlxsw_reg_sfd_rec_pack(payload, rec_index, -+ MLXSW_REG_SFD_REC_TYPE_UNICAST_TUNNEL, mac, -+ action); -+ mlxsw_reg_sfd_rec_policy_set(payload, rec_index, policy); -+ mlxsw_reg_sfd_uc_tunnel_uip_msb_set(payload, rec_index, uip >> 24); -+ mlxsw_reg_sfd_uc_tunnel_uip_lsb_set(payload, rec_index, uip); -+ mlxsw_reg_sfd_uc_tunnel_fid_set(payload, rec_index, fid); -+ mlxsw_reg_sfd_uc_tunnel_protocol_set(payload, rec_index, proto); -+} -+ - /* SFN - Switch FDB Notification Register - * ------------------------------------------- - * The switch provides notifications on newly learned FDB entries and -@@ -586,10 +593,7 @@ mlxsw_reg_sfd_mc_pack(char *payload, int rec_index, - #define MLXSW_REG_SFN_LEN (MLXSW_REG_SFN_BASE_LEN + \ - MLXSW_REG_SFN_REC_LEN * MLXSW_REG_SFN_REC_MAX_COUNT) - --static const struct mlxsw_reg_info mlxsw_reg_sfn = { -- .id = MLXSW_REG_SFN_ID, -- .len = MLXSW_REG_SFN_LEN, --}; -+MLXSW_REG_DEFINE(sfn, MLXSW_REG_SFN_ID, MLXSW_REG_SFN_LEN); - - /* reg_sfn_swid - * Switch partition ID. -@@ -707,10 +711,7 @@ static inline void mlxsw_reg_sfn_mac_lag_unpack(char *payload, int rec_index, - #define MLXSW_REG_SPMS_ID 0x200D - #define MLXSW_REG_SPMS_LEN 0x404 - --static const struct mlxsw_reg_info mlxsw_reg_spms = { -- .id = MLXSW_REG_SPMS_ID, -- .len = MLXSW_REG_SPMS_LEN, --}; -+MLXSW_REG_DEFINE(spms, MLXSW_REG_SPMS_ID, MLXSW_REG_SPMS_LEN); - - /* reg_spms_local_port - * Local port number. -@@ -754,10 +755,7 @@ static inline void mlxsw_reg_spms_vid_pack(char *payload, u16 vid, - #define MLXSW_REG_SPVID_ID 0x200E - #define MLXSW_REG_SPVID_LEN 0x08 - --static const struct mlxsw_reg_info mlxsw_reg_spvid = { -- .id = MLXSW_REG_SPVID_ID, -- .len = MLXSW_REG_SPVID_LEN, --}; -+MLXSW_REG_DEFINE(spvid, MLXSW_REG_SPVID_ID, MLXSW_REG_SPVID_LEN); - - /* reg_spvid_local_port - * Local port number. -@@ -798,10 +796,7 @@ static inline void mlxsw_reg_spvid_pack(char *payload, u8 local_port, u16 pvid) - #define MLXSW_REG_SPVM_LEN (MLXSW_REG_SPVM_BASE_LEN + \ - MLXSW_REG_SPVM_REC_LEN * MLXSW_REG_SPVM_REC_MAX_COUNT) - --static const struct mlxsw_reg_info mlxsw_reg_spvm = { -- .id = MLXSW_REG_SPVM_ID, -- .len = MLXSW_REG_SPVM_LEN, --}; -+MLXSW_REG_DEFINE(spvm, MLXSW_REG_SPVM_ID, MLXSW_REG_SPVM_LEN); - - /* reg_spvm_pt - * Priority tagged. If this bit is set, packets forwarded to the port with -@@ -897,10 +892,7 @@ static inline void mlxsw_reg_spvm_pack(char *payload, u8 local_port, - #define MLXSW_REG_SPAFT_ID 0x2010 - #define MLXSW_REG_SPAFT_LEN 0x08 - --static const struct mlxsw_reg_info mlxsw_reg_spaft = { -- .id = MLXSW_REG_SPAFT_ID, -- .len = MLXSW_REG_SPAFT_LEN, --}; -+MLXSW_REG_DEFINE(spaft, MLXSW_REG_SPAFT_ID, MLXSW_REG_SPAFT_LEN); - - /* reg_spaft_local_port - * Local port number. -@@ -953,10 +945,7 @@ static inline void mlxsw_reg_spaft_pack(char *payload, u8 local_port, - #define MLXSW_REG_SFGC_ID 0x2011 - #define MLXSW_REG_SFGC_LEN 0x10 - --static const struct mlxsw_reg_info mlxsw_reg_sfgc = { -- .id = MLXSW_REG_SFGC_ID, -- .len = MLXSW_REG_SFGC_LEN, --}; -+MLXSW_REG_DEFINE(sfgc, MLXSW_REG_SFGC_ID, MLXSW_REG_SFGC_LEN); - - enum mlxsw_reg_sfgc_type { - MLXSW_REG_SFGC_TYPE_BROADCAST, -@@ -992,7 +981,7 @@ enum mlxsw_flood_table_type { - MLXSW_REG_SFGC_TABLE_TYPE_VID = 1, - MLXSW_REG_SFGC_TABLE_TYPE_SINGLE = 2, - MLXSW_REG_SFGC_TABLE_TYPE_ANY = 0, -- MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST = 3, -+ MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET = 3, - MLXSW_REG_SFGC_TABLE_TYPE_FID = 4, - }; - -@@ -1051,10 +1040,7 @@ mlxsw_reg_sfgc_pack(char *payload, enum mlxsw_reg_sfgc_type type, - #define MLXSW_REG_SFTR_ID 0x2012 - #define MLXSW_REG_SFTR_LEN 0x420 - --static const struct mlxsw_reg_info mlxsw_reg_sftr = { -- .id = MLXSW_REG_SFTR_ID, -- .len = MLXSW_REG_SFTR_LEN, --}; -+MLXSW_REG_DEFINE(sftr, MLXSW_REG_SFTR_ID, MLXSW_REG_SFTR_LEN); - - /* reg_sftr_swid - * Switch partition ID with which to associate the port. -@@ -1124,10 +1110,7 @@ static inline void mlxsw_reg_sftr_pack(char *payload, - #define MLXSW_REG_SFDF_ID 0x2013 - #define MLXSW_REG_SFDF_LEN 0x14 - --static const struct mlxsw_reg_info mlxsw_reg_sfdf = { -- .id = MLXSW_REG_SFDF_ID, -- .len = MLXSW_REG_SFDF_LEN, --}; -+MLXSW_REG_DEFINE(sfdf, MLXSW_REG_SFDF_ID, MLXSW_REG_SFDF_LEN); - - /* reg_sfdf_swid - * Switch partition ID. -@@ -1142,6 +1125,8 @@ enum mlxsw_reg_sfdf_flush_type { - MLXSW_REG_SFDF_FLUSH_PER_PORT_AND_FID, - MLXSW_REG_SFDF_FLUSH_PER_LAG, - MLXSW_REG_SFDF_FLUSH_PER_LAG_AND_FID, -+ MLXSW_REG_SFDF_FLUSH_PER_NVE, -+ MLXSW_REG_SFDF_FLUSH_PER_NVE_AND_FID, - }; - - /* reg_sfdf_flush_type -@@ -1152,6 +1137,10 @@ enum mlxsw_reg_sfdf_flush_type { - * 3 - All FID dynamic entries pointing to port are flushed. - * 4 - All dynamic entries pointing to LAG are flushed. - * 5 - All FID dynamic entries pointing to LAG are flushed. -+ * 6 - All entries of type "Unicast Tunnel" or "Multicast Tunnel" are -+ * flushed. -+ * 7 - All entries of type "Unicast Tunnel" or "Multicast Tunnel" are -+ * flushed, per FID. - * Access: RW - */ - MLXSW_ITEM32(reg, sfdf, flush_type, 0x04, 28, 4); -@@ -1211,10 +1200,7 @@ MLXSW_ITEM32(reg, sfdf, lag_fid_lag_id, 0x08, 0, 10); - #define MLXSW_REG_SLDR_ID 0x2014 - #define MLXSW_REG_SLDR_LEN 0x0C /* counting in only one port in list */ - --static const struct mlxsw_reg_info mlxsw_reg_sldr = { -- .id = MLXSW_REG_SLDR_ID, -- .len = MLXSW_REG_SLDR_LEN, --}; -+MLXSW_REG_DEFINE(sldr, MLXSW_REG_SLDR_ID, MLXSW_REG_SLDR_LEN); - - enum mlxsw_reg_sldr_op { - /* Indicates a creation of a new LAG-ID, lag_id must be valid */ -@@ -1294,10 +1280,7 @@ static inline void mlxsw_reg_sldr_lag_remove_port_pack(char *payload, u8 lag_id, - #define MLXSW_REG_SLCR_ID 0x2015 - #define MLXSW_REG_SLCR_LEN 0x10 - --static const struct mlxsw_reg_info mlxsw_reg_slcr = { -- .id = MLXSW_REG_SLCR_ID, -- .len = MLXSW_REG_SLCR_LEN, --}; -+MLXSW_REG_DEFINE(slcr, MLXSW_REG_SLCR_ID, MLXSW_REG_SLCR_LEN); - - enum mlxsw_reg_slcr_pp { - /* Global Configuration (for all ports) */ -@@ -1394,12 +1377,19 @@ MLXSW_ITEM32(reg, slcr, type, 0x00, 0, 4); - */ - MLXSW_ITEM32(reg, slcr, lag_hash, 0x04, 0, 20); - --static inline void mlxsw_reg_slcr_pack(char *payload, u16 lag_hash) -+/* reg_slcr_seed -+ * LAG seed value. The seed is the same for all ports. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, slcr, seed, 0x08, 0, 32); -+ -+static inline void mlxsw_reg_slcr_pack(char *payload, u16 lag_hash, u32 seed) - { - MLXSW_REG_ZERO(slcr, payload); - mlxsw_reg_slcr_pp_set(payload, MLXSW_REG_SLCR_PP_GLOBAL); - mlxsw_reg_slcr_type_set(payload, MLXSW_REG_SLCR_TYPE_CRC); - mlxsw_reg_slcr_lag_hash_set(payload, lag_hash); -+ mlxsw_reg_slcr_seed_set(payload, seed); - } - - /* SLCOR - Switch LAG Collector Register -@@ -1410,10 +1400,7 @@ static inline void mlxsw_reg_slcr_pack(char *payload, u16 lag_hash) - #define MLXSW_REG_SLCOR_ID 0x2016 - #define MLXSW_REG_SLCOR_LEN 0x10 - --static const struct mlxsw_reg_info mlxsw_reg_slcor = { -- .id = MLXSW_REG_SLCOR_ID, -- .len = MLXSW_REG_SLCOR_LEN, --}; -+MLXSW_REG_DEFINE(slcor, MLXSW_REG_SLCOR_ID, MLXSW_REG_SLCOR_LEN); - - enum mlxsw_reg_slcor_col { - /* Port is added with collector disabled */ -@@ -1496,10 +1483,7 @@ static inline void mlxsw_reg_slcor_col_disable_pack(char *payload, - #define MLXSW_REG_SPMLR_ID 0x2018 - #define MLXSW_REG_SPMLR_LEN 0x8 - --static const struct mlxsw_reg_info mlxsw_reg_spmlr = { -- .id = MLXSW_REG_SPMLR_ID, -- .len = MLXSW_REG_SPMLR_LEN, --}; -+MLXSW_REG_DEFINE(spmlr, MLXSW_REG_SPMLR_ID, MLXSW_REG_SPMLR_LEN); - - /* reg_spmlr_local_port - * Local port number. -@@ -1550,10 +1534,7 @@ static inline void mlxsw_reg_spmlr_pack(char *payload, u8 local_port, - #define MLXSW_REG_SVFA_ID 0x201C - #define MLXSW_REG_SVFA_LEN 0x10 - --static const struct mlxsw_reg_info mlxsw_reg_svfa = { -- .id = MLXSW_REG_SVFA_ID, -- .len = MLXSW_REG_SVFA_LEN, --}; -+MLXSW_REG_DEFINE(svfa, MLXSW_REG_SVFA_ID, MLXSW_REG_SVFA_LEN); - - /* reg_svfa_swid - * Switch partition ID. -@@ -1642,10 +1623,7 @@ static inline void mlxsw_reg_svfa_pack(char *payload, u8 local_port, - #define MLXSW_REG_SVPE_ID 0x201E - #define MLXSW_REG_SVPE_LEN 0x4 - --static const struct mlxsw_reg_info mlxsw_reg_svpe = { -- .id = MLXSW_REG_SVPE_ID, -- .len = MLXSW_REG_SVPE_LEN, --}; -+MLXSW_REG_DEFINE(svpe, MLXSW_REG_SVPE_ID, MLXSW_REG_SVPE_LEN); - - /* reg_svpe_local_port - * Local port number -@@ -1678,10 +1656,7 @@ static inline void mlxsw_reg_svpe_pack(char *payload, u8 local_port, - #define MLXSW_REG_SFMR_ID 0x201F - #define MLXSW_REG_SFMR_LEN 0x18 - --static const struct mlxsw_reg_info mlxsw_reg_sfmr = { -- .id = MLXSW_REG_SFMR_ID, -- .len = MLXSW_REG_SFMR_LEN, --}; -+MLXSW_REG_DEFINE(sfmr, MLXSW_REG_SFMR_ID, MLXSW_REG_SFMR_LEN); - - enum mlxsw_reg_sfmr_op { - MLXSW_REG_SFMR_OP_CREATE_FID, -@@ -1768,10 +1743,7 @@ static inline void mlxsw_reg_sfmr_pack(char *payload, - MLXSW_REG_SPVMLR_REC_LEN * \ - MLXSW_REG_SPVMLR_REC_MAX_COUNT) - --static const struct mlxsw_reg_info mlxsw_reg_spvmlr = { -- .id = MLXSW_REG_SPVMLR_ID, -- .len = MLXSW_REG_SPVMLR_LEN, --}; -+MLXSW_REG_DEFINE(spvmlr, MLXSW_REG_SPVMLR_ID, MLXSW_REG_SPVMLR_LEN); - - /* reg_spvmlr_local_port - * Local ingress port. -@@ -1821,3337 +1793,7279 @@ static inline void mlxsw_reg_spvmlr_pack(char *payload, u8 local_port, - } - } - --/* QTCT - QoS Switch Traffic Class Table -- * ------------------------------------- -- * Configures the mapping between the packet switch priority and the -- * traffic class on the transmit port. -+/* CWTP - Congetion WRED ECN TClass Profile -+ * ---------------------------------------- -+ * Configures the profiles for queues of egress port and traffic class - */ --#define MLXSW_REG_QTCT_ID 0x400A --#define MLXSW_REG_QTCT_LEN 0x08 -+#define MLXSW_REG_CWTP_ID 0x2802 -+#define MLXSW_REG_CWTP_BASE_LEN 0x28 -+#define MLXSW_REG_CWTP_PROFILE_DATA_REC_LEN 0x08 -+#define MLXSW_REG_CWTP_LEN 0x40 - --static const struct mlxsw_reg_info mlxsw_reg_qtct = { -- .id = MLXSW_REG_QTCT_ID, -- .len = MLXSW_REG_QTCT_LEN, --}; -+MLXSW_REG_DEFINE(cwtp, MLXSW_REG_CWTP_ID, MLXSW_REG_CWTP_LEN); - --/* reg_qtct_local_port -- * Local port number. -+/* reg_cwtp_local_port -+ * Local port number -+ * Not supported for CPU port - * Access: Index -- * -- * Note: CPU port is not supported. - */ --MLXSW_ITEM32(reg, qtct, local_port, 0x00, 16, 8); -+MLXSW_ITEM32(reg, cwtp, local_port, 0, 16, 8); - --/* reg_qtct_sub_port -- * Virtual port within the physical port. -- * Should be set to 0 when virtual ports are not enabled on the port. -+/* reg_cwtp_traffic_class -+ * Traffic Class to configure - * Access: Index - */ --MLXSW_ITEM32(reg, qtct, sub_port, 0x00, 8, 8); -+MLXSW_ITEM32(reg, cwtp, traffic_class, 32, 0, 8); - --/* reg_qtct_switch_prio -- * Switch priority. -- * Access: Index -+/* reg_cwtp_profile_min -+ * Minimum Average Queue Size of the profile in cells. -+ * Access: RW - */ --MLXSW_ITEM32(reg, qtct, switch_prio, 0x00, 0, 4); -+MLXSW_ITEM32_INDEXED(reg, cwtp, profile_min, MLXSW_REG_CWTP_BASE_LEN, -+ 0, 20, MLXSW_REG_CWTP_PROFILE_DATA_REC_LEN, 0, false); - --/* reg_qtct_tclass -- * Traffic class. -- * Default values: -- * switch_prio 0 : tclass 1 -- * switch_prio 1 : tclass 0 -- * switch_prio i : tclass i, for i > 1 -+/* reg_cwtp_profile_percent -+ * Percentage of WRED and ECN marking for maximum Average Queue size -+ * Range is 0 to 100, units of integer percentage - * Access: RW - */ --MLXSW_ITEM32(reg, qtct, tclass, 0x04, 0, 4); -+MLXSW_ITEM32_INDEXED(reg, cwtp, profile_percent, MLXSW_REG_CWTP_BASE_LEN, -+ 24, 7, MLXSW_REG_CWTP_PROFILE_DATA_REC_LEN, 4, false); - --static inline void mlxsw_reg_qtct_pack(char *payload, u8 local_port, -- u8 switch_prio, u8 tclass) -+/* reg_cwtp_profile_max -+ * Maximum Average Queue size of the profile in cells -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, cwtp, profile_max, MLXSW_REG_CWTP_BASE_LEN, -+ 0, 20, MLXSW_REG_CWTP_PROFILE_DATA_REC_LEN, 4, false); -+ -+#define MLXSW_REG_CWTP_MIN_VALUE 64 -+#define MLXSW_REG_CWTP_MAX_PROFILE 2 -+#define MLXSW_REG_CWTP_DEFAULT_PROFILE 1 -+ -+static inline void mlxsw_reg_cwtp_pack(char *payload, u8 local_port, -+ u8 traffic_class) - { -- MLXSW_REG_ZERO(qtct, payload); -- mlxsw_reg_qtct_local_port_set(payload, local_port); -- mlxsw_reg_qtct_switch_prio_set(payload, switch_prio); -- mlxsw_reg_qtct_tclass_set(payload, tclass); -+ int i; -+ -+ MLXSW_REG_ZERO(cwtp, payload); -+ mlxsw_reg_cwtp_local_port_set(payload, local_port); -+ mlxsw_reg_cwtp_traffic_class_set(payload, traffic_class); -+ -+ for (i = 0; i <= MLXSW_REG_CWTP_MAX_PROFILE; i++) { -+ mlxsw_reg_cwtp_profile_min_set(payload, i, -+ MLXSW_REG_CWTP_MIN_VALUE); -+ mlxsw_reg_cwtp_profile_max_set(payload, i, -+ MLXSW_REG_CWTP_MIN_VALUE); -+ } - } - --/* QEEC - QoS ETS Element Configuration Register -- * --------------------------------------------- -- * Configures the ETS elements. -- */ --#define MLXSW_REG_QEEC_ID 0x400D --#define MLXSW_REG_QEEC_LEN 0x1C -+#define MLXSW_REG_CWTP_PROFILE_TO_INDEX(profile) (profile - 1) - --static const struct mlxsw_reg_info mlxsw_reg_qeec = { -- .id = MLXSW_REG_QEEC_ID, -- .len = MLXSW_REG_QEEC_LEN, --}; -+static inline void -+mlxsw_reg_cwtp_profile_pack(char *payload, u8 profile, u32 min, u32 max, -+ u32 probability) -+{ -+ u8 index = MLXSW_REG_CWTP_PROFILE_TO_INDEX(profile); - --/* reg_qeec_local_port -- * Local port number. -- * Access: Index -- * -- * Note: CPU port is supported. -+ mlxsw_reg_cwtp_profile_min_set(payload, index, min); -+ mlxsw_reg_cwtp_profile_max_set(payload, index, max); -+ mlxsw_reg_cwtp_profile_percent_set(payload, index, probability); -+} -+ -+/* CWTPM - Congestion WRED ECN TClass and Pool Mapping -+ * --------------------------------------------------- -+ * The CWTPM register maps each egress port and traffic class to profile num. - */ --MLXSW_ITEM32(reg, qeec, local_port, 0x00, 16, 8); -+#define MLXSW_REG_CWTPM_ID 0x2803 -+#define MLXSW_REG_CWTPM_LEN 0x44 - --enum mlxsw_reg_qeec_hr { -- MLXSW_REG_QEEC_HIERARCY_PORT, -- MLXSW_REG_QEEC_HIERARCY_GROUP, -- MLXSW_REG_QEEC_HIERARCY_SUBGROUP, -- MLXSW_REG_QEEC_HIERARCY_TC, --}; -+MLXSW_REG_DEFINE(cwtpm, MLXSW_REG_CWTPM_ID, MLXSW_REG_CWTPM_LEN); - --/* reg_qeec_element_hierarchy -- * 0 - Port -- * 1 - Group -- * 2 - Subgroup -- * 3 - Traffic Class -+/* reg_cwtpm_local_port -+ * Local port number -+ * Not supported for CPU port - * Access: Index - */ --MLXSW_ITEM32(reg, qeec, element_hierarchy, 0x04, 16, 4); -+MLXSW_ITEM32(reg, cwtpm, local_port, 0, 16, 8); - --/* reg_qeec_element_index -- * The index of the element in the hierarchy. -+/* reg_cwtpm_traffic_class -+ * Traffic Class to configure - * Access: Index - */ --MLXSW_ITEM32(reg, qeec, element_index, 0x04, 0, 8); -+MLXSW_ITEM32(reg, cwtpm, traffic_class, 32, 0, 8); - --/* reg_qeec_next_element_index -- * The index of the next (lower) element in the hierarchy. -+/* reg_cwtpm_ew -+ * Control enablement of WRED for traffic class: -+ * 0 - Disable -+ * 1 - Enable - * Access: RW -- * -- * Note: Reserved for element_hierarchy 0. - */ --MLXSW_ITEM32(reg, qeec, next_element_index, 0x08, 0, 8); -- --enum { -- MLXSW_REG_QEEC_BYTES_MODE, -- MLXSW_REG_QEEC_PACKETS_MODE, --}; -+MLXSW_ITEM32(reg, cwtpm, ew, 36, 1, 1); - --/* reg_qeec_pb -- * Packets or bytes mode. -- * 0 - Bytes mode -- * 1 - Packets mode -+/* reg_cwtpm_ee -+ * Control enablement of ECN for traffic class: -+ * 0 - Disable -+ * 1 - Enable - * Access: RW -- * -- * Note: Used for max shaper configuration. For Spectrum, packets mode -- * is supported only for traffic classes of CPU port. - */ --MLXSW_ITEM32(reg, qeec, pb, 0x0C, 28, 1); -+MLXSW_ITEM32(reg, cwtpm, ee, 36, 0, 1); - --/* reg_qeec_mase -- * Max shaper configuration enable. Enables configuration of the max -- * shaper on this ETS element. -- * 0 - Disable -- * 1 - Enable -+/* reg_cwtpm_tcp_g -+ * TCP Green Profile. -+ * Index of the profile within {port, traffic class} to use. -+ * 0 for disabling both WRED and ECN for this type of traffic. - * Access: RW - */ --MLXSW_ITEM32(reg, qeec, mase, 0x10, 31, 1); -+MLXSW_ITEM32(reg, cwtpm, tcp_g, 52, 0, 2); - --/* A large max rate will disable the max shaper. */ --#define MLXSW_REG_QEEC_MAS_DIS 200000000 /* Kbps */ -+/* reg_cwtpm_tcp_y -+ * TCP Yellow Profile. -+ * Index of the profile within {port, traffic class} to use. -+ * 0 for disabling both WRED and ECN for this type of traffic. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, cwtpm, tcp_y, 56, 16, 2); - --/* reg_qeec_max_shaper_rate -- * Max shaper information rate. -- * For CPU port, can only be configured for port hierarchy. -- * When in bytes mode, value is specified in units of 1000bps. -+/* reg_cwtpm_tcp_r -+ * TCP Red Profile. -+ * Index of the profile within {port, traffic class} to use. -+ * 0 for disabling both WRED and ECN for this type of traffic. - * Access: RW - */ --MLXSW_ITEM32(reg, qeec, max_shaper_rate, 0x10, 0, 28); -+MLXSW_ITEM32(reg, cwtpm, tcp_r, 56, 0, 2); - --/* reg_qeec_de -- * DWRR configuration enable. Enables configuration of the dwrr and -- * dwrr_weight. -- * 0 - Disable -- * 1 - Enable -+/* reg_cwtpm_ntcp_g -+ * Non-TCP Green Profile. -+ * Index of the profile within {port, traffic class} to use. -+ * 0 for disabling both WRED and ECN for this type of traffic. - * Access: RW - */ --MLXSW_ITEM32(reg, qeec, de, 0x18, 31, 1); -+MLXSW_ITEM32(reg, cwtpm, ntcp_g, 60, 0, 2); - --/* reg_qeec_dwrr -- * Transmission selection algorithm to use on the link going down from -- * the ETS element. -- * 0 - Strict priority -- * 1 - DWRR -+/* reg_cwtpm_ntcp_y -+ * Non-TCP Yellow Profile. -+ * Index of the profile within {port, traffic class} to use. -+ * 0 for disabling both WRED and ECN for this type of traffic. - * Access: RW - */ --MLXSW_ITEM32(reg, qeec, dwrr, 0x18, 15, 1); -+MLXSW_ITEM32(reg, cwtpm, ntcp_y, 64, 16, 2); - --/* reg_qeec_dwrr_weight -- * DWRR weight on the link going down from the ETS element. The -- * percentage of bandwidth guaranteed to an ETS element within -- * its hierarchy. The sum of all weights across all ETS elements -- * within one hierarchy should be equal to 100. Reserved when -- * transmission selection algorithm is strict priority. -+/* reg_cwtpm_ntcp_r -+ * Non-TCP Red Profile. -+ * Index of the profile within {port, traffic class} to use. -+ * 0 for disabling both WRED and ECN for this type of traffic. - * Access: RW - */ --MLXSW_ITEM32(reg, qeec, dwrr_weight, 0x18, 0, 8); -+MLXSW_ITEM32(reg, cwtpm, ntcp_r, 64, 0, 2); - --static inline void mlxsw_reg_qeec_pack(char *payload, u8 local_port, -- enum mlxsw_reg_qeec_hr hr, u8 index, -- u8 next_index) -+#define MLXSW_REG_CWTPM_RESET_PROFILE 0 -+ -+static inline void mlxsw_reg_cwtpm_pack(char *payload, u8 local_port, -+ u8 traffic_class, u8 profile, -+ bool wred, bool ecn) - { -- MLXSW_REG_ZERO(qeec, payload); -- mlxsw_reg_qeec_local_port_set(payload, local_port); -- mlxsw_reg_qeec_element_hierarchy_set(payload, hr); -- mlxsw_reg_qeec_element_index_set(payload, index); -- mlxsw_reg_qeec_next_element_index_set(payload, next_index); -+ MLXSW_REG_ZERO(cwtpm, payload); -+ mlxsw_reg_cwtpm_local_port_set(payload, local_port); -+ mlxsw_reg_cwtpm_traffic_class_set(payload, traffic_class); -+ mlxsw_reg_cwtpm_ew_set(payload, wred); -+ mlxsw_reg_cwtpm_ee_set(payload, ecn); -+ mlxsw_reg_cwtpm_tcp_g_set(payload, profile); -+ mlxsw_reg_cwtpm_tcp_y_set(payload, profile); -+ mlxsw_reg_cwtpm_tcp_r_set(payload, profile); -+ mlxsw_reg_cwtpm_ntcp_g_set(payload, profile); -+ mlxsw_reg_cwtpm_ntcp_y_set(payload, profile); -+ mlxsw_reg_cwtpm_ntcp_r_set(payload, profile); - } - --/* PMLP - Ports Module to Local Port Register -- * ------------------------------------------ -- * Configures the assignment of modules to local ports. -+/* PGCR - Policy-Engine General Configuration Register -+ * --------------------------------------------------- -+ * This register configures general Policy-Engine settings. - */ --#define MLXSW_REG_PMLP_ID 0x5002 --#define MLXSW_REG_PMLP_LEN 0x40 -+#define MLXSW_REG_PGCR_ID 0x3001 -+#define MLXSW_REG_PGCR_LEN 0x20 - --static const struct mlxsw_reg_info mlxsw_reg_pmlp = { -- .id = MLXSW_REG_PMLP_ID, -- .len = MLXSW_REG_PMLP_LEN, --}; -+MLXSW_REG_DEFINE(pgcr, MLXSW_REG_PGCR_ID, MLXSW_REG_PGCR_LEN); - --/* reg_pmlp_rxtx -- * 0 - Tx value is used for both Tx and Rx. -- * 1 - Rx value is taken from a separte field. -+/* reg_pgcr_default_action_pointer_base -+ * Default action pointer base. Each region has a default action pointer -+ * which is equal to default_action_pointer_base + region_id. - * Access: RW - */ --MLXSW_ITEM32(reg, pmlp, rxtx, 0x00, 31, 1); -+MLXSW_ITEM32(reg, pgcr, default_action_pointer_base, 0x1C, 0, 24); - --/* reg_pmlp_local_port -- * Local port number. -+static inline void mlxsw_reg_pgcr_pack(char *payload, u32 pointer_base) -+{ -+ MLXSW_REG_ZERO(pgcr, payload); -+ mlxsw_reg_pgcr_default_action_pointer_base_set(payload, pointer_base); -+} -+ -+/* PPBT - Policy-Engine Port Binding Table -+ * --------------------------------------- -+ * This register is used for configuration of the Port Binding Table. -+ */ -+#define MLXSW_REG_PPBT_ID 0x3002 -+#define MLXSW_REG_PPBT_LEN 0x14 -+ -+MLXSW_REG_DEFINE(ppbt, MLXSW_REG_PPBT_ID, MLXSW_REG_PPBT_LEN); -+ -+enum mlxsw_reg_pxbt_e { -+ MLXSW_REG_PXBT_E_IACL, -+ MLXSW_REG_PXBT_E_EACL, -+}; -+ -+/* reg_ppbt_e - * Access: Index - */ --MLXSW_ITEM32(reg, pmlp, local_port, 0x00, 16, 8); -+MLXSW_ITEM32(reg, ppbt, e, 0x00, 31, 1); - --/* reg_pmlp_width -- * 0 - Unmap local port. -- * 1 - Lane 0 is used. -- * 2 - Lanes 0 and 1 are used. -- * 4 - Lanes 0, 1, 2 and 3 are used. -+enum mlxsw_reg_pxbt_op { -+ MLXSW_REG_PXBT_OP_BIND, -+ MLXSW_REG_PXBT_OP_UNBIND, -+}; -+ -+/* reg_ppbt_op - * Access: RW - */ --MLXSW_ITEM32(reg, pmlp, width, 0x00, 0, 8); -+MLXSW_ITEM32(reg, ppbt, op, 0x00, 28, 3); - --/* reg_pmlp_module -- * Module number. -- * Access: RW -+/* reg_ppbt_local_port -+ * Local port. Not including CPU port. -+ * Access: Index - */ --MLXSW_ITEM32_INDEXED(reg, pmlp, module, 0x04, 0, 8, 0x04, 0x00, false); -+MLXSW_ITEM32(reg, ppbt, local_port, 0x00, 16, 8); - --/* reg_pmlp_tx_lane -- * Tx Lane. When rxtx field is cleared, this field is used for Rx as well. -+/* reg_ppbt_g -+ * group - When set, the binding is of an ACL group. When cleared, -+ * the binding is of an ACL. -+ * Must be set to 1 for Spectrum. - * Access: RW - */ --MLXSW_ITEM32_INDEXED(reg, pmlp, tx_lane, 0x04, 16, 2, 0x04, 0x00, false); -+MLXSW_ITEM32(reg, ppbt, g, 0x10, 31, 1); - --/* reg_pmlp_rx_lane -- * Rx Lane. When rxtx field is cleared, this field is ignored and Rx lane is -- * equal to Tx lane. -+/* reg_ppbt_acl_info -+ * ACL/ACL group identifier. If the g bit is set, this field should hold -+ * the acl_group_id, else it should hold the acl_id. - * Access: RW - */ --MLXSW_ITEM32_INDEXED(reg, pmlp, rx_lane, 0x04, 24, 2, 0x04, 0x00, false); -+MLXSW_ITEM32(reg, ppbt, acl_info, 0x10, 0, 16); - --static inline void mlxsw_reg_pmlp_pack(char *payload, u8 local_port) -+static inline void mlxsw_reg_ppbt_pack(char *payload, enum mlxsw_reg_pxbt_e e, -+ enum mlxsw_reg_pxbt_op op, -+ u8 local_port, u16 acl_info) - { -- MLXSW_REG_ZERO(pmlp, payload); -- mlxsw_reg_pmlp_local_port_set(payload, local_port); -+ MLXSW_REG_ZERO(ppbt, payload); -+ mlxsw_reg_ppbt_e_set(payload, e); -+ mlxsw_reg_ppbt_op_set(payload, op); -+ mlxsw_reg_ppbt_local_port_set(payload, local_port); -+ mlxsw_reg_ppbt_g_set(payload, true); -+ mlxsw_reg_ppbt_acl_info_set(payload, acl_info); - } - --/* PMTU - Port MTU Register -- * ------------------------ -- * Configures and reports the port MTU. -+/* PACL - Policy-Engine ACL Register -+ * --------------------------------- -+ * This register is used for configuration of the ACL. - */ --#define MLXSW_REG_PMTU_ID 0x5003 --#define MLXSW_REG_PMTU_LEN 0x10 -+#define MLXSW_REG_PACL_ID 0x3004 -+#define MLXSW_REG_PACL_LEN 0x70 - --static const struct mlxsw_reg_info mlxsw_reg_pmtu = { -- .id = MLXSW_REG_PMTU_ID, -- .len = MLXSW_REG_PMTU_LEN, --}; -+MLXSW_REG_DEFINE(pacl, MLXSW_REG_PACL_ID, MLXSW_REG_PACL_LEN); - --/* reg_pmtu_local_port -- * Local port number. -+/* reg_pacl_v -+ * Valid. Setting the v bit makes the ACL valid. It should not be cleared -+ * while the ACL is bounded to either a port, VLAN or ACL rule. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pacl, v, 0x00, 24, 1); -+ -+/* reg_pacl_acl_id -+ * An identifier representing the ACL (managed by software) -+ * Range 0 .. cap_max_acl_regions - 1 - * Access: Index - */ --MLXSW_ITEM32(reg, pmtu, local_port, 0x00, 16, 8); -+MLXSW_ITEM32(reg, pacl, acl_id, 0x08, 0, 16); - --/* reg_pmtu_max_mtu -- * Maximum MTU. -- * When port type (e.g. Ethernet) is configured, the relevant MTU is -- * reported, otherwise the minimum between the max_mtu of the different -- * types is reported. -- * Access: RO -- */ --MLXSW_ITEM32(reg, pmtu, max_mtu, 0x04, 16, 16); -+#define MLXSW_REG_PXXX_TCAM_REGION_INFO_LEN 16 - --/* reg_pmtu_admin_mtu -- * MTU value to set port to. Must be smaller or equal to max_mtu. -- * Note: If port type is Infiniband, then port must be disabled, when its -- * MTU is set. -+/* reg_pacl_tcam_region_info -+ * Opaque object that represents a TCAM region. -+ * Obtained through PTAR register. - * Access: RW - */ --MLXSW_ITEM32(reg, pmtu, admin_mtu, 0x08, 16, 16); -+MLXSW_ITEM_BUF(reg, pacl, tcam_region_info, 0x30, -+ MLXSW_REG_PXXX_TCAM_REGION_INFO_LEN); - --/* reg_pmtu_oper_mtu -- * The actual MTU configured on the port. Packets exceeding this size -- * will be dropped. -- * Note: In Ethernet and FC oper_mtu == admin_mtu, however, in Infiniband -- * oper_mtu might be smaller than admin_mtu. -- * Access: RO -+static inline void mlxsw_reg_pacl_pack(char *payload, u16 acl_id, -+ bool valid, const char *tcam_region_info) -+{ -+ MLXSW_REG_ZERO(pacl, payload); -+ mlxsw_reg_pacl_acl_id_set(payload, acl_id); -+ mlxsw_reg_pacl_v_set(payload, valid); -+ mlxsw_reg_pacl_tcam_region_info_memcpy_to(payload, tcam_region_info); -+} -+ -+/* PAGT - Policy-Engine ACL Group Table -+ * ------------------------------------ -+ * This register is used for configuration of the ACL Group Table. -+ */ -+#define MLXSW_REG_PAGT_ID 0x3005 -+#define MLXSW_REG_PAGT_BASE_LEN 0x30 -+#define MLXSW_REG_PAGT_ACL_LEN 4 -+#define MLXSW_REG_PAGT_ACL_MAX_NUM 16 -+#define MLXSW_REG_PAGT_LEN (MLXSW_REG_PAGT_BASE_LEN + \ -+ MLXSW_REG_PAGT_ACL_MAX_NUM * MLXSW_REG_PAGT_ACL_LEN) -+ -+MLXSW_REG_DEFINE(pagt, MLXSW_REG_PAGT_ID, MLXSW_REG_PAGT_LEN); -+ -+/* reg_pagt_size -+ * Number of ACLs in the group. -+ * Size 0 invalidates a group. -+ * Range 0 .. cap_max_acl_group_size (hard coded to 16 for now) -+ * Total number of ACLs in all groups must be lower or equal -+ * to cap_max_acl_tot_groups -+ * Note: a group which is binded must not be invalidated -+ * Access: Index - */ --MLXSW_ITEM32(reg, pmtu, oper_mtu, 0x0C, 16, 16); -+MLXSW_ITEM32(reg, pagt, size, 0x00, 0, 8); - --static inline void mlxsw_reg_pmtu_pack(char *payload, u8 local_port, -- u16 new_mtu) -+/* reg_pagt_acl_group_id -+ * An identifier (numbered from 0..cap_max_acl_groups-1) representing -+ * the ACL Group identifier (managed by software). -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, pagt, acl_group_id, 0x08, 0, 16); -+ -+/* reg_pagt_acl_id -+ * ACL identifier -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, pagt, acl_id, 0x30, 0, 16, 0x04, 0x00, false); -+ -+static inline void mlxsw_reg_pagt_pack(char *payload, u16 acl_group_id) - { -- MLXSW_REG_ZERO(pmtu, payload); -- mlxsw_reg_pmtu_local_port_set(payload, local_port); -- mlxsw_reg_pmtu_max_mtu_set(payload, 0); -- mlxsw_reg_pmtu_admin_mtu_set(payload, new_mtu); -- mlxsw_reg_pmtu_oper_mtu_set(payload, 0); -+ MLXSW_REG_ZERO(pagt, payload); -+ mlxsw_reg_pagt_acl_group_id_set(payload, acl_group_id); - } - --/* PTYS - Port Type and Speed Register -- * ----------------------------------- -- * Configures and reports the port speed type. -- * -- * Note: When set while the link is up, the changes will not take effect -- * until the port transitions from down to up state. -- */ --#define MLXSW_REG_PTYS_ID 0x5004 --#define MLXSW_REG_PTYS_LEN 0x40 -+static inline void mlxsw_reg_pagt_acl_id_pack(char *payload, int index, -+ u16 acl_id) -+{ -+ u8 size = mlxsw_reg_pagt_size_get(payload); -+ -+ if (index >= size) -+ mlxsw_reg_pagt_size_set(payload, index + 1); -+ mlxsw_reg_pagt_acl_id_set(payload, index, acl_id); -+} - --static const struct mlxsw_reg_info mlxsw_reg_ptys = { -- .id = MLXSW_REG_PTYS_ID, -- .len = MLXSW_REG_PTYS_LEN, -+/* PTAR - Policy-Engine TCAM Allocation Register -+ * --------------------------------------------- -+ * This register is used for allocation of regions in the TCAM. -+ * Note: Query method is not supported on this register. -+ */ -+#define MLXSW_REG_PTAR_ID 0x3006 -+#define MLXSW_REG_PTAR_BASE_LEN 0x20 -+#define MLXSW_REG_PTAR_KEY_ID_LEN 1 -+#define MLXSW_REG_PTAR_KEY_ID_MAX_NUM 16 -+#define MLXSW_REG_PTAR_LEN (MLXSW_REG_PTAR_BASE_LEN + \ -+ MLXSW_REG_PTAR_KEY_ID_MAX_NUM * MLXSW_REG_PTAR_KEY_ID_LEN) -+ -+MLXSW_REG_DEFINE(ptar, MLXSW_REG_PTAR_ID, MLXSW_REG_PTAR_LEN); -+ -+enum mlxsw_reg_ptar_op { -+ /* allocate a TCAM region */ -+ MLXSW_REG_PTAR_OP_ALLOC, -+ /* resize a TCAM region */ -+ MLXSW_REG_PTAR_OP_RESIZE, -+ /* deallocate TCAM region */ -+ MLXSW_REG_PTAR_OP_FREE, -+ /* test allocation */ -+ MLXSW_REG_PTAR_OP_TEST, - }; - --/* reg_ptys_local_port -- * Local port number. -- * Access: Index -+/* reg_ptar_op -+ * Access: OP - */ --MLXSW_ITEM32(reg, ptys, local_port, 0x00, 16, 8); -- --#define MLXSW_REG_PTYS_PROTO_MASK_ETH BIT(2) -+MLXSW_ITEM32(reg, ptar, op, 0x00, 28, 4); - --/* reg_ptys_proto_mask -- * Protocol mask. Indicates which protocol is used. -- * 0 - Infiniband. -- * 1 - Fibre Channel. -- * 2 - Ethernet. -- * Access: Index -+/* reg_ptar_action_set_type -+ * Type of action set to be used on this region. -+ * For Spectrum and Spectrum-2, this is always type 2 - "flexible" -+ * Access: WO - */ --MLXSW_ITEM32(reg, ptys, proto_mask, 0x00, 0, 3); -+MLXSW_ITEM32(reg, ptar, action_set_type, 0x00, 16, 8); - --enum { -- MLXSW_REG_PTYS_AN_STATUS_NA, -- MLXSW_REG_PTYS_AN_STATUS_OK, -- MLXSW_REG_PTYS_AN_STATUS_FAIL, -+enum mlxsw_reg_ptar_key_type { -+ MLXSW_REG_PTAR_KEY_TYPE_FLEX = 0x50, /* Spetrum */ -+ MLXSW_REG_PTAR_KEY_TYPE_FLEX2 = 0x51, /* Spectrum-2 */ - }; - --/* reg_ptys_an_status -- * Autonegotiation status. -- * Access: RO -+/* reg_ptar_key_type -+ * TCAM key type for the region. -+ * Access: WO - */ --MLXSW_ITEM32(reg, ptys, an_status, 0x04, 28, 4); -+MLXSW_ITEM32(reg, ptar, key_type, 0x00, 0, 8); - --#define MLXSW_REG_PTYS_ETH_SPEED_SGMII BIT(0) --#define MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX BIT(1) --#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 BIT(2) --#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 BIT(3) --#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR BIT(4) --#define MLXSW_REG_PTYS_ETH_SPEED_20GBASE_KR2 BIT(5) --#define MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 BIT(6) --#define MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 BIT(7) --#define MLXSW_REG_PTYS_ETH_SPEED_56GBASE_R4 BIT(8) --#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR BIT(12) --#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR BIT(13) --#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_ER_LR BIT(14) --#define MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 BIT(15) --#define MLXSW_REG_PTYS_ETH_SPEED_40GBASE_LR4_ER4 BIT(16) --#define MLXSW_REG_PTYS_ETH_SPEED_50GBASE_SR2 BIT(18) --#define MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR4 BIT(19) --#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4 BIT(20) --#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 BIT(21) --#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 BIT(22) --#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4 BIT(23) --#define MLXSW_REG_PTYS_ETH_SPEED_100BASE_TX BIT(24) --#define MLXSW_REG_PTYS_ETH_SPEED_100BASE_T BIT(25) --#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_T BIT(26) --#define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR BIT(27) --#define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR BIT(28) --#define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR BIT(29) --#define MLXSW_REG_PTYS_ETH_SPEED_50GBASE_CR2 BIT(30) --#define MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR2 BIT(31) -+/* reg_ptar_region_size -+ * TCAM region size. When allocating/resizing this is the requested size, -+ * the response is the actual size. Note that actual size may be -+ * larger than requested. -+ * Allowed range 1 .. cap_max_rules-1 -+ * Reserved during op deallocate. -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, ptar, region_size, 0x04, 0, 16); - --/* reg_ptys_eth_proto_cap -- * Ethernet port supported speeds and protocols. -- * Access: RO -+/* reg_ptar_region_id -+ * Region identifier -+ * Range 0 .. cap_max_regions-1 -+ * Access: Index - */ --MLXSW_ITEM32(reg, ptys, eth_proto_cap, 0x0C, 0, 32); -+MLXSW_ITEM32(reg, ptar, region_id, 0x08, 0, 16); - --/* reg_ptys_eth_proto_admin -- * Speed and protocol to set port to. -+/* reg_ptar_tcam_region_info -+ * Opaque object that represents the TCAM region. -+ * Returned when allocating a region. -+ * Provided by software for ACL generation and region deallocation and resize. - * Access: RW - */ --MLXSW_ITEM32(reg, ptys, eth_proto_admin, 0x18, 0, 32); -+MLXSW_ITEM_BUF(reg, ptar, tcam_region_info, 0x10, -+ MLXSW_REG_PXXX_TCAM_REGION_INFO_LEN); - --/* reg_ptys_eth_proto_oper -- * The current speed and protocol configured for the port. -- * Access: RO -+/* reg_ptar_flexible_key_id -+ * Identifier of the Flexible Key. -+ * Only valid if key_type == "FLEX_KEY" -+ * The key size will be rounded up to one of the following values: -+ * 9B, 18B, 36B, 54B. -+ * This field is reserved for in resize operation. -+ * Access: WO - */ --MLXSW_ITEM32(reg, ptys, eth_proto_oper, 0x24, 0, 32); -+MLXSW_ITEM8_INDEXED(reg, ptar, flexible_key_id, 0x20, 0, 8, -+ MLXSW_REG_PTAR_KEY_ID_LEN, 0x00, false); - --/* reg_ptys_eth_proto_lp_advertise -- * The protocols that were advertised by the link partner during -- * autonegotiation. -- * Access: RO -- */ --MLXSW_ITEM32(reg, ptys, eth_proto_lp_advertise, 0x30, 0, 32); -+static inline void mlxsw_reg_ptar_pack(char *payload, enum mlxsw_reg_ptar_op op, -+ enum mlxsw_reg_ptar_key_type key_type, -+ u16 region_size, u16 region_id, -+ const char *tcam_region_info) -+{ -+ MLXSW_REG_ZERO(ptar, payload); -+ mlxsw_reg_ptar_op_set(payload, op); -+ mlxsw_reg_ptar_action_set_type_set(payload, 2); /* "flexible" */ -+ mlxsw_reg_ptar_key_type_set(payload, key_type); -+ mlxsw_reg_ptar_region_size_set(payload, region_size); -+ mlxsw_reg_ptar_region_id_set(payload, region_id); -+ mlxsw_reg_ptar_tcam_region_info_memcpy_to(payload, tcam_region_info); -+} - --static inline void mlxsw_reg_ptys_pack(char *payload, u8 local_port, -- u32 proto_admin) -+static inline void mlxsw_reg_ptar_key_id_pack(char *payload, int index, -+ u16 key_id) - { -- MLXSW_REG_ZERO(ptys, payload); -- mlxsw_reg_ptys_local_port_set(payload, local_port); -- mlxsw_reg_ptys_proto_mask_set(payload, MLXSW_REG_PTYS_PROTO_MASK_ETH); -- mlxsw_reg_ptys_eth_proto_admin_set(payload, proto_admin); -+ mlxsw_reg_ptar_flexible_key_id_set(payload, index, key_id); - } - --static inline void mlxsw_reg_ptys_unpack(char *payload, u32 *p_eth_proto_cap, -- u32 *p_eth_proto_adm, -- u32 *p_eth_proto_oper) -+static inline void mlxsw_reg_ptar_unpack(char *payload, char *tcam_region_info) - { -- if (p_eth_proto_cap) -- *p_eth_proto_cap = mlxsw_reg_ptys_eth_proto_cap_get(payload); -- if (p_eth_proto_adm) -- *p_eth_proto_adm = mlxsw_reg_ptys_eth_proto_admin_get(payload); -- if (p_eth_proto_oper) -- *p_eth_proto_oper = mlxsw_reg_ptys_eth_proto_oper_get(payload); -+ mlxsw_reg_ptar_tcam_region_info_memcpy_from(payload, tcam_region_info); - } - --/* PPAD - Port Physical Address Register -- * ------------------------------------- -- * The PPAD register configures the per port physical MAC address. -+/* PPBS - Policy-Engine Policy Based Switching Register -+ * ---------------------------------------------------- -+ * This register retrieves and sets Policy Based Switching Table entries. - */ --#define MLXSW_REG_PPAD_ID 0x5005 --#define MLXSW_REG_PPAD_LEN 0x10 -+#define MLXSW_REG_PPBS_ID 0x300C -+#define MLXSW_REG_PPBS_LEN 0x14 - --static const struct mlxsw_reg_info mlxsw_reg_ppad = { -- .id = MLXSW_REG_PPAD_ID, -- .len = MLXSW_REG_PPAD_LEN, --}; -- --/* reg_ppad_single_base_mac -- * 0: base_mac, local port should be 0 and mac[7:0] is -- * reserved. HW will set incremental -- * 1: single_mac - mac of the local_port -- * Access: RW -- */ --MLXSW_ITEM32(reg, ppad, single_base_mac, 0x00, 28, 1); -+MLXSW_REG_DEFINE(ppbs, MLXSW_REG_PPBS_ID, MLXSW_REG_PPBS_LEN); - --/* reg_ppad_local_port -- * port number, if single_base_mac = 0 then local_port is reserved -- * Access: RW -+/* reg_ppbs_pbs_ptr -+ * Index into the PBS table. -+ * For Spectrum, the index points to the KVD Linear. -+ * Access: Index - */ --MLXSW_ITEM32(reg, ppad, local_port, 0x00, 16, 8); -+MLXSW_ITEM32(reg, ppbs, pbs_ptr, 0x08, 0, 24); - --/* reg_ppad_mac -- * If single_base_mac = 0 - base MAC address, mac[7:0] is reserved. -- * If single_base_mac = 1 - the per port MAC address -+/* reg_ppbs_system_port -+ * Unique port identifier for the final destination of the packet. - * Access: RW - */ --MLXSW_ITEM_BUF(reg, ppad, mac, 0x02, 6); -+MLXSW_ITEM32(reg, ppbs, system_port, 0x10, 0, 16); - --static inline void mlxsw_reg_ppad_pack(char *payload, bool single_base_mac, -- u8 local_port) -+static inline void mlxsw_reg_ppbs_pack(char *payload, u32 pbs_ptr, -+ u16 system_port) - { -- MLXSW_REG_ZERO(ppad, payload); -- mlxsw_reg_ppad_single_base_mac_set(payload, !!single_base_mac); -- mlxsw_reg_ppad_local_port_set(payload, local_port); -+ MLXSW_REG_ZERO(ppbs, payload); -+ mlxsw_reg_ppbs_pbs_ptr_set(payload, pbs_ptr); -+ mlxsw_reg_ppbs_system_port_set(payload, system_port); - } - --/* PAOS - Ports Administrative and Operational Status Register -- * ----------------------------------------------------------- -- * Configures and retrieves per port administrative and operational status. -+/* PRCR - Policy-Engine Rules Copy Register -+ * ---------------------------------------- -+ * This register is used for accessing rules within a TCAM region. - */ --#define MLXSW_REG_PAOS_ID 0x5006 --#define MLXSW_REG_PAOS_LEN 0x10 -+#define MLXSW_REG_PRCR_ID 0x300D -+#define MLXSW_REG_PRCR_LEN 0x40 - --static const struct mlxsw_reg_info mlxsw_reg_paos = { -- .id = MLXSW_REG_PAOS_ID, -- .len = MLXSW_REG_PAOS_LEN, -+MLXSW_REG_DEFINE(prcr, MLXSW_REG_PRCR_ID, MLXSW_REG_PRCR_LEN); -+ -+enum mlxsw_reg_prcr_op { -+ /* Move rules. Moves the rules from "tcam_region_info" starting -+ * at offset "offset" to "dest_tcam_region_info" -+ * at offset "dest_offset." -+ */ -+ MLXSW_REG_PRCR_OP_MOVE, -+ /* Copy rules. Copies the rules from "tcam_region_info" starting -+ * at offset "offset" to "dest_tcam_region_info" -+ * at offset "dest_offset." -+ */ -+ MLXSW_REG_PRCR_OP_COPY, - }; - --/* reg_paos_swid -- * Switch partition ID with which to associate the port. -- * Note: while external ports uses unique local port numbers (and thus swid is -- * redundant), router ports use the same local port number where swid is the -- * only indication for the relevant port. -- * Access: Index -+/* reg_prcr_op -+ * Access: OP - */ --MLXSW_ITEM32(reg, paos, swid, 0x00, 24, 8); -+MLXSW_ITEM32(reg, prcr, op, 0x00, 28, 4); - --/* reg_paos_local_port -- * Local port number. -+/* reg_prcr_offset -+ * Offset within the source region to copy/move from. - * Access: Index - */ --MLXSW_ITEM32(reg, paos, local_port, 0x00, 16, 8); -- --/* reg_paos_admin_status -- * Port administrative state (the desired state of the port): -- * 1 - Up. -- * 2 - Down. -- * 3 - Up once. This means that in case of link failure, the port won't go -- * into polling mode, but will wait to be re-enabled by software. -- * 4 - Disabled by system. Can only be set by hardware. -- * Access: RW -- */ --MLXSW_ITEM32(reg, paos, admin_status, 0x00, 8, 4); -+MLXSW_ITEM32(reg, prcr, offset, 0x00, 0, 16); - --/* reg_paos_oper_status -- * Port operational state (the current state): -- * 1 - Up. -- * 2 - Down. -- * 3 - Down by port failure. This means that the device will not let the -- * port up again until explicitly specified by software. -- * Access: RO -+/* reg_prcr_size -+ * The number of rules to copy/move. -+ * Access: WO - */ --MLXSW_ITEM32(reg, paos, oper_status, 0x00, 0, 4); -+MLXSW_ITEM32(reg, prcr, size, 0x04, 0, 16); - --/* reg_paos_ase -- * Admin state update enabled. -- * Access: WO -+/* reg_prcr_tcam_region_info -+ * Opaque object that represents the source TCAM region. -+ * Access: Index - */ --MLXSW_ITEM32(reg, paos, ase, 0x04, 31, 1); -+MLXSW_ITEM_BUF(reg, prcr, tcam_region_info, 0x10, -+ MLXSW_REG_PXXX_TCAM_REGION_INFO_LEN); - --/* reg_paos_ee -- * Event update enable. If this bit is set, event generation will be -- * updated based on the e field. -- * Access: WO -+/* reg_prcr_dest_offset -+ * Offset within the source region to copy/move to. -+ * Access: Index - */ --MLXSW_ITEM32(reg, paos, ee, 0x04, 30, 1); -+MLXSW_ITEM32(reg, prcr, dest_offset, 0x20, 0, 16); - --/* reg_paos_e -- * Event generation on operational state change: -- * 0 - Do not generate event. -- * 1 - Generate Event. -- * 2 - Generate Single Event. -- * Access: RW -+/* reg_prcr_dest_tcam_region_info -+ * Opaque object that represents the destination TCAM region. -+ * Access: Index - */ --MLXSW_ITEM32(reg, paos, e, 0x04, 0, 2); -+MLXSW_ITEM_BUF(reg, prcr, dest_tcam_region_info, 0x30, -+ MLXSW_REG_PXXX_TCAM_REGION_INFO_LEN); - --static inline void mlxsw_reg_paos_pack(char *payload, u8 local_port, -- enum mlxsw_port_admin_status status) -+static inline void mlxsw_reg_prcr_pack(char *payload, enum mlxsw_reg_prcr_op op, -+ const char *src_tcam_region_info, -+ u16 src_offset, -+ const char *dest_tcam_region_info, -+ u16 dest_offset, u16 size) - { -- MLXSW_REG_ZERO(paos, payload); -- mlxsw_reg_paos_swid_set(payload, 0); -- mlxsw_reg_paos_local_port_set(payload, local_port); -- mlxsw_reg_paos_admin_status_set(payload, status); -- mlxsw_reg_paos_oper_status_set(payload, 0); -- mlxsw_reg_paos_ase_set(payload, 1); -- mlxsw_reg_paos_ee_set(payload, 1); -- mlxsw_reg_paos_e_set(payload, 1); -+ MLXSW_REG_ZERO(prcr, payload); -+ mlxsw_reg_prcr_op_set(payload, op); -+ mlxsw_reg_prcr_offset_set(payload, src_offset); -+ mlxsw_reg_prcr_size_set(payload, size); -+ mlxsw_reg_prcr_tcam_region_info_memcpy_to(payload, -+ src_tcam_region_info); -+ mlxsw_reg_prcr_dest_offset_set(payload, dest_offset); -+ mlxsw_reg_prcr_dest_tcam_region_info_memcpy_to(payload, -+ dest_tcam_region_info); - } - --/* PFCC - Ports Flow Control Configuration Register -- * ------------------------------------------------ -- * Configures and retrieves the per port flow control configuration. -+/* PEFA - Policy-Engine Extended Flexible Action Register -+ * ------------------------------------------------------ -+ * This register is used for accessing an extended flexible action entry -+ * in the central KVD Linear Database. - */ --#define MLXSW_REG_PFCC_ID 0x5007 --#define MLXSW_REG_PFCC_LEN 0x20 -- --static const struct mlxsw_reg_info mlxsw_reg_pfcc = { -- .id = MLXSW_REG_PFCC_ID, -- .len = MLXSW_REG_PFCC_LEN, --}; -+#define MLXSW_REG_PEFA_ID 0x300F -+#define MLXSW_REG_PEFA_LEN 0xB0 - --/* reg_pfcc_local_port -- * Local port number. -- * Access: Index -- */ --MLXSW_ITEM32(reg, pfcc, local_port, 0x00, 16, 8); -+MLXSW_REG_DEFINE(pefa, MLXSW_REG_PEFA_ID, MLXSW_REG_PEFA_LEN); - --/* reg_pfcc_pnat -- * Port number access type. Determines the way local_port is interpreted: -- * 0 - Local port number. -- * 1 - IB / label port number. -+/* reg_pefa_index -+ * Index in the KVD Linear Centralized Database. - * Access: Index - */ --MLXSW_ITEM32(reg, pfcc, pnat, 0x00, 14, 2); -+MLXSW_ITEM32(reg, pefa, index, 0x00, 0, 24); - --/* reg_pfcc_shl_cap -- * Send to higher layers capabilities: -- * 0 - No capability of sending Pause and PFC frames to higher layers. -- * 1 - Device has capability of sending Pause and PFC frames to higher -- * layers. -+/* reg_pefa_a -+ * Index in the KVD Linear Centralized Database. -+ * Activity -+ * For a new entry: set if ca=0, clear if ca=1 -+ * Set if a packet lookup has hit on the specific entry - * Access: RO - */ --MLXSW_ITEM32(reg, pfcc, shl_cap, 0x00, 1, 1); -+MLXSW_ITEM32(reg, pefa, a, 0x04, 29, 1); - --/* reg_pfcc_shl_opr -- * Send to higher layers operation: -- * 0 - Pause and PFC frames are handled by the port (default). -- * 1 - Pause and PFC frames are handled by the port and also sent to -- * higher layers. Only valid if shl_cap = 1. -- * Access: RW -+/* reg_pefa_ca -+ * Clear activity -+ * When write: activity is according to this field -+ * When read: after reading the activity is cleared according to ca -+ * Access: OP - */ --MLXSW_ITEM32(reg, pfcc, shl_opr, 0x00, 0, 1); -+MLXSW_ITEM32(reg, pefa, ca, 0x04, 24, 1); - --/* reg_pfcc_ppan -- * Pause policy auto negotiation. -- * 0 - Disabled. Generate / ignore Pause frames based on pptx / pprtx. -- * 1 - Enabled. When auto-negotiation is performed, set the Pause policy -- * based on the auto-negotiation resolution. -+#define MLXSW_REG_FLEX_ACTION_SET_LEN 0xA8 -+ -+/* reg_pefa_flex_action_set -+ * Action-set to perform when rule is matched. -+ * Must be zero padded if action set is shorter. - * Access: RW -- * -- * Note: The auto-negotiation advertisement is set according to pptx and -- * pprtx. When PFC is set on Tx / Rx, ppan must be set to 0. - */ --MLXSW_ITEM32(reg, pfcc, ppan, 0x04, 28, 4); -+MLXSW_ITEM_BUF(reg, pefa, flex_action_set, 0x08, MLXSW_REG_FLEX_ACTION_SET_LEN); - --/* reg_pfcc_prio_mask_tx -- * Bit per priority indicating if Tx flow control policy should be -- * updated based on bit pfctx. -- * Access: WO -- */ --MLXSW_ITEM32(reg, pfcc, prio_mask_tx, 0x04, 16, 8); -+static inline void mlxsw_reg_pefa_pack(char *payload, u32 index, bool ca, -+ const char *flex_action_set) -+{ -+ MLXSW_REG_ZERO(pefa, payload); -+ mlxsw_reg_pefa_index_set(payload, index); -+ mlxsw_reg_pefa_ca_set(payload, ca); -+ if (flex_action_set) -+ mlxsw_reg_pefa_flex_action_set_memcpy_to(payload, -+ flex_action_set); -+} - --/* reg_pfcc_prio_mask_rx -- * Bit per priority indicating if Rx flow control policy should be -- * updated based on bit pfcrx. -- * Access: WO -+static inline void mlxsw_reg_pefa_unpack(char *payload, bool *p_a) -+{ -+ *p_a = mlxsw_reg_pefa_a_get(payload); -+} -+ -+/* PTCE-V2 - Policy-Engine TCAM Entry Register Version 2 -+ * ----------------------------------------------------- -+ * This register is used for accessing rules within a TCAM region. -+ * It is a new version of PTCE in order to support wider key, -+ * mask and action within a TCAM region. This register is not supported -+ * by SwitchX and SwitchX-2. - */ --MLXSW_ITEM32(reg, pfcc, prio_mask_rx, 0x04, 0, 8); -+#define MLXSW_REG_PTCE2_ID 0x3017 -+#define MLXSW_REG_PTCE2_LEN 0x1D8 - --/* reg_pfcc_pptx -- * Admin Pause policy on Tx. -- * 0 - Never generate Pause frames (default). -- * 1 - Generate Pause frames according to Rx buffer threshold. -+MLXSW_REG_DEFINE(ptce2, MLXSW_REG_PTCE2_ID, MLXSW_REG_PTCE2_LEN); -+ -+/* reg_ptce2_v -+ * Valid. - * Access: RW - */ --MLXSW_ITEM32(reg, pfcc, pptx, 0x08, 31, 1); -+MLXSW_ITEM32(reg, ptce2, v, 0x00, 31, 1); - --/* reg_pfcc_aptx -- * Active (operational) Pause policy on Tx. -- * 0 - Never generate Pause frames. -- * 1 - Generate Pause frames according to Rx buffer threshold. -+/* reg_ptce2_a -+ * Activity. Set if a packet lookup has hit on the specific entry. -+ * To clear the "a" bit, use "clear activity" op or "clear on read" op. - * Access: RO - */ --MLXSW_ITEM32(reg, pfcc, aptx, 0x08, 30, 1); -+MLXSW_ITEM32(reg, ptce2, a, 0x00, 30, 1); - --/* reg_pfcc_pfctx -- * Priority based flow control policy on Tx[7:0]. Per-priority bit mask: -- * 0 - Never generate priority Pause frames on the specified priority -- * (default). -- * 1 - Generate priority Pause frames according to Rx buffer threshold on -- * the specified priority. -- * Access: RW -- * -- * Note: pfctx and pptx must be mutually exclusive. -+enum mlxsw_reg_ptce2_op { -+ /* Read operation. */ -+ MLXSW_REG_PTCE2_OP_QUERY_READ = 0, -+ /* clear on read operation. Used to read entry -+ * and clear Activity bit. -+ */ -+ MLXSW_REG_PTCE2_OP_QUERY_CLEAR_ON_READ = 1, -+ /* Write operation. Used to write a new entry to the table. -+ * All R/W fields are relevant for new entry. Activity bit is set -+ * for new entries - Note write with v = 0 will delete the entry. -+ */ -+ MLXSW_REG_PTCE2_OP_WRITE_WRITE = 0, -+ /* Update action. Only action set will be updated. */ -+ MLXSW_REG_PTCE2_OP_WRITE_UPDATE = 1, -+ /* Clear activity. A bit is cleared for the entry. */ -+ MLXSW_REG_PTCE2_OP_WRITE_CLEAR_ACTIVITY = 2, -+}; -+ -+/* reg_ptce2_op -+ * Access: OP - */ --MLXSW_ITEM32(reg, pfcc, pfctx, 0x08, 16, 8); -+MLXSW_ITEM32(reg, ptce2, op, 0x00, 20, 3); - --/* reg_pfcc_pprx -- * Admin Pause policy on Rx. -- * 0 - Ignore received Pause frames (default). -- * 1 - Respect received Pause frames. -+/* reg_ptce2_offset -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ptce2, offset, 0x00, 0, 16); -+ -+/* reg_ptce2_priority -+ * Priority of the rule, higher values win. The range is 1..cap_kvd_size-1. -+ * Note: priority does not have to be unique per rule. -+ * Within a region, higher priority should have lower offset (no limitation -+ * between regions in a multi-region). - * Access: RW - */ --MLXSW_ITEM32(reg, pfcc, pprx, 0x0C, 31, 1); -+MLXSW_ITEM32(reg, ptce2, priority, 0x04, 0, 24); - --/* reg_pfcc_aprx -- * Active (operational) Pause policy on Rx. -- * 0 - Ignore received Pause frames. -- * 1 - Respect received Pause frames. -- * Access: RO -+/* reg_ptce2_tcam_region_info -+ * Opaque object that represents the TCAM region. -+ * Access: Index - */ --MLXSW_ITEM32(reg, pfcc, aprx, 0x0C, 30, 1); -+MLXSW_ITEM_BUF(reg, ptce2, tcam_region_info, 0x10, -+ MLXSW_REG_PXXX_TCAM_REGION_INFO_LEN); - --/* reg_pfcc_pfcrx -- * Priority based flow control policy on Rx[7:0]. Per-priority bit mask: -- * 0 - Ignore incoming priority Pause frames on the specified priority -- * (default). -- * 1 - Respect incoming priority Pause frames on the specified priority. -+#define MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN 96 -+ -+/* reg_ptce2_flex_key_blocks -+ * ACL Key. - * Access: RW - */ --MLXSW_ITEM32(reg, pfcc, pfcrx, 0x0C, 16, 8); -+MLXSW_ITEM_BUF(reg, ptce2, flex_key_blocks, 0x20, -+ MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN); - --#define MLXSW_REG_PFCC_ALL_PRIO 0xFF -+/* reg_ptce2_mask -+ * mask- in the same size as key. A bit that is set directs the TCAM -+ * to compare the corresponding bit in key. A bit that is clear directs -+ * the TCAM to ignore the corresponding bit in key. -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, ptce2, mask, 0x80, -+ MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN); - --static inline void mlxsw_reg_pfcc_prio_pack(char *payload, u8 pfc_en) --{ -- mlxsw_reg_pfcc_prio_mask_tx_set(payload, MLXSW_REG_PFCC_ALL_PRIO); -- mlxsw_reg_pfcc_prio_mask_rx_set(payload, MLXSW_REG_PFCC_ALL_PRIO); -- mlxsw_reg_pfcc_pfctx_set(payload, pfc_en); -- mlxsw_reg_pfcc_pfcrx_set(payload, pfc_en); --} -+/* reg_ptce2_flex_action_set -+ * ACL action set. -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, ptce2, flex_action_set, 0xE0, -+ MLXSW_REG_FLEX_ACTION_SET_LEN); - --static inline void mlxsw_reg_pfcc_pack(char *payload, u8 local_port) -+static inline void mlxsw_reg_ptce2_pack(char *payload, bool valid, -+ enum mlxsw_reg_ptce2_op op, -+ const char *tcam_region_info, -+ u16 offset, u32 priority) - { -- MLXSW_REG_ZERO(pfcc, payload); -- mlxsw_reg_pfcc_local_port_set(payload, local_port); -+ MLXSW_REG_ZERO(ptce2, payload); -+ mlxsw_reg_ptce2_v_set(payload, valid); -+ mlxsw_reg_ptce2_op_set(payload, op); -+ mlxsw_reg_ptce2_offset_set(payload, offset); -+ mlxsw_reg_ptce2_priority_set(payload, priority); -+ mlxsw_reg_ptce2_tcam_region_info_memcpy_to(payload, tcam_region_info); - } - --/* PPCNT - Ports Performance Counters Register -- * ------------------------------------------- -- * The PPCNT register retrieves per port performance counters. -+/* PERPT - Policy-Engine ERP Table Register -+ * ---------------------------------------- -+ * This register adds and removes eRPs from the eRP table. - */ --#define MLXSW_REG_PPCNT_ID 0x5008 --#define MLXSW_REG_PPCNT_LEN 0x100 -+#define MLXSW_REG_PERPT_ID 0x3021 -+#define MLXSW_REG_PERPT_LEN 0x80 - --static const struct mlxsw_reg_info mlxsw_reg_ppcnt = { -- .id = MLXSW_REG_PPCNT_ID, -- .len = MLXSW_REG_PPCNT_LEN, --}; -+MLXSW_REG_DEFINE(perpt, MLXSW_REG_PERPT_ID, MLXSW_REG_PERPT_LEN); - --/* reg_ppcnt_swid -- * For HCA: must be always 0. -- * Switch partition ID to associate port with. -- * Switch partitions are numbered from 0 to 7 inclusively. -- * Switch partition 254 indicates stacking ports. -- * Switch partition 255 indicates all switch partitions. -- * Only valid on Set() operation with local_port=255. -+/* reg_perpt_erpt_bank -+ * eRP table bank. -+ * Range 0 .. cap_max_erp_table_banks - 1 - * Access: Index - */ --MLXSW_ITEM32(reg, ppcnt, swid, 0x00, 24, 8); -+MLXSW_ITEM32(reg, perpt, erpt_bank, 0x00, 16, 4); - --/* reg_ppcnt_local_port -- * Local port number. -- * 255 indicates all ports on the device, and is only allowed -- * for Set() operation. -+/* reg_perpt_erpt_index -+ * Index to eRP table within the eRP bank. -+ * Range is 0 .. cap_max_erp_table_bank_size - 1 - * Access: Index - */ --MLXSW_ITEM32(reg, ppcnt, local_port, 0x00, 16, 8); -+MLXSW_ITEM32(reg, perpt, erpt_index, 0x00, 0, 8); - --/* reg_ppcnt_pnat -- * Port number access type: -- * 0 - Local port number -- * 1 - IB port number -- * Access: Index -+enum mlxsw_reg_perpt_key_size { -+ MLXSW_REG_PERPT_KEY_SIZE_2KB, -+ MLXSW_REG_PERPT_KEY_SIZE_4KB, -+ MLXSW_REG_PERPT_KEY_SIZE_8KB, -+ MLXSW_REG_PERPT_KEY_SIZE_12KB, -+}; -+ -+/* reg_perpt_key_size -+ * Access: OP - */ --MLXSW_ITEM32(reg, ppcnt, pnat, 0x00, 14, 2); -+MLXSW_ITEM32(reg, perpt, key_size, 0x04, 0, 4); - --enum mlxsw_reg_ppcnt_grp { -- MLXSW_REG_PPCNT_IEEE_8023_CNT = 0x0, -- MLXSW_REG_PPCNT_PRIO_CNT = 0x10, -- MLXSW_REG_PPCNT_TC_CNT = 0x11, --}; -+/* reg_perpt_bf_bypass -+ * 0 - The eRP is used only if bloom filter state is set for the given -+ * rule. -+ * 1 - The eRP is used regardless of bloom filter state. -+ * The bypass is an OR condition of region_id or eRP. See PERCR.bf_bypass -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, perpt, bf_bypass, 0x08, 8, 1); - --/* reg_ppcnt_grp -- * Performance counter group. -- * Group 63 indicates all groups. Only valid on Set() operation with -- * clr bit set. -- * 0x0: IEEE 802.3 Counters -- * 0x1: RFC 2863 Counters -- * 0x2: RFC 2819 Counters -- * 0x3: RFC 3635 Counters -- * 0x5: Ethernet Extended Counters -- * 0x8: Link Level Retransmission Counters -- * 0x10: Per Priority Counters -- * 0x11: Per Traffic Class Counters -- * 0x12: Physical Layer Counters -- * Access: Index -+/* reg_perpt_erp_id -+ * eRP ID for use by the rules. -+ * Access: RW - */ --MLXSW_ITEM32(reg, ppcnt, grp, 0x00, 0, 6); -+MLXSW_ITEM32(reg, perpt, erp_id, 0x08, 0, 4); - --/* reg_ppcnt_clr -- * Clear counters. Setting the clr bit will reset the counter value -- * for all counters in the counter group. This bit can be set -- * for both Set() and Get() operation. -+/* reg_perpt_erpt_base_bank -+ * Base eRP table bank, points to head of erp_vector -+ * Range is 0 .. cap_max_erp_table_banks - 1 - * Access: OP - */ --MLXSW_ITEM32(reg, ppcnt, clr, 0x04, 31, 1); -+MLXSW_ITEM32(reg, perpt, erpt_base_bank, 0x0C, 16, 4); - --/* reg_ppcnt_prio_tc -- * Priority for counter set that support per priority, valid values: 0-7. -- * Traffic class for counter set that support per traffic class, -- * valid values: 0- cap_max_tclass-1 . -- * For HCA: cap_max_tclass is always 8. -- * Otherwise must be 0. -- * Access: Index -+/* reg_perpt_erpt_base_index -+ * Base index to eRP table within the eRP bank -+ * Range is 0 .. cap_max_erp_table_bank_size - 1 -+ * Access: OP - */ --MLXSW_ITEM32(reg, ppcnt, prio_tc, 0x04, 0, 5); -- --/* Ethernet IEEE 802.3 Counter Group */ -+MLXSW_ITEM32(reg, perpt, erpt_base_index, 0x0C, 0, 8); - --/* reg_ppcnt_a_frames_transmitted_ok -- * Access: RO -+/* reg_perpt_erp_index_in_vector -+ * eRP index in the vector. -+ * Access: OP - */ --MLXSW_ITEM64(reg, ppcnt, a_frames_transmitted_ok, -- 0x08 + 0x00, 0, 64); -+MLXSW_ITEM32(reg, perpt, erp_index_in_vector, 0x10, 0, 4); - --/* reg_ppcnt_a_frames_received_ok -- * Access: RO -+/* reg_perpt_erp_vector -+ * eRP vector. -+ * Access: OP - */ --MLXSW_ITEM64(reg, ppcnt, a_frames_received_ok, -- 0x08 + 0x08, 0, 64); -+MLXSW_ITEM_BIT_ARRAY(reg, perpt, erp_vector, 0x14, 4, 1); - --/* reg_ppcnt_a_frame_check_sequence_errors -- * Access: RO -+/* reg_perpt_mask -+ * Mask -+ * 0 - A-TCAM will ignore the bit in key -+ * 1 - A-TCAM will compare the bit in key -+ * Access: RW - */ --MLXSW_ITEM64(reg, ppcnt, a_frame_check_sequence_errors, -- 0x08 + 0x10, 0, 64); -+MLXSW_ITEM_BUF(reg, perpt, mask, 0x20, MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN); - --/* reg_ppcnt_a_alignment_errors -- * Access: RO -+static inline void mlxsw_reg_perpt_erp_vector_pack(char *payload, -+ unsigned long *erp_vector, -+ unsigned long size) -+{ -+ unsigned long bit; -+ -+ for_each_set_bit(bit, erp_vector, size) -+ mlxsw_reg_perpt_erp_vector_set(payload, bit, true); -+} -+ -+static inline void -+mlxsw_reg_perpt_pack(char *payload, u8 erpt_bank, u8 erpt_index, -+ enum mlxsw_reg_perpt_key_size key_size, u8 erp_id, -+ u8 erpt_base_bank, u8 erpt_base_index, u8 erp_index, -+ char *mask) -+{ -+ MLXSW_REG_ZERO(perpt, payload); -+ mlxsw_reg_perpt_erpt_bank_set(payload, erpt_bank); -+ mlxsw_reg_perpt_erpt_index_set(payload, erpt_index); -+ mlxsw_reg_perpt_key_size_set(payload, key_size); -+ mlxsw_reg_perpt_bf_bypass_set(payload, true); -+ mlxsw_reg_perpt_erp_id_set(payload, erp_id); -+ mlxsw_reg_perpt_erpt_base_bank_set(payload, erpt_base_bank); -+ mlxsw_reg_perpt_erpt_base_index_set(payload, erpt_base_index); -+ mlxsw_reg_perpt_erp_index_in_vector_set(payload, erp_index); -+ mlxsw_reg_perpt_mask_memcpy_to(payload, mask); -+} -+ -+/* PERAR - Policy-Engine Region Association Register -+ * ------------------------------------------------- -+ * This register associates a hw region for region_id's. Changing on the fly -+ * is supported by the device. - */ --MLXSW_ITEM64(reg, ppcnt, a_alignment_errors, -- 0x08 + 0x18, 0, 64); -+#define MLXSW_REG_PERAR_ID 0x3026 -+#define MLXSW_REG_PERAR_LEN 0x08 - --/* reg_ppcnt_a_octets_transmitted_ok -- * Access: RO -+MLXSW_REG_DEFINE(perar, MLXSW_REG_PERAR_ID, MLXSW_REG_PERAR_LEN); -+ -+/* reg_perar_region_id -+ * Region identifier -+ * Range 0 .. cap_max_regions-1 -+ * Access: Index - */ --MLXSW_ITEM64(reg, ppcnt, a_octets_transmitted_ok, -- 0x08 + 0x20, 0, 64); -+MLXSW_ITEM32(reg, perar, region_id, 0x00, 0, 16); - --/* reg_ppcnt_a_octets_received_ok -- * Access: RO -+static inline unsigned int -+mlxsw_reg_perar_hw_regions_needed(unsigned int block_num) -+{ -+ return DIV_ROUND_UP(block_num, 4); -+} -+ -+/* reg_perar_hw_region -+ * HW Region -+ * Range 0 .. cap_max_regions-1 -+ * Default: hw_region = region_id -+ * For a 8 key block region, 2 consecutive regions are used -+ * For a 12 key block region, 3 consecutive regions are used -+ * Access: RW - */ --MLXSW_ITEM64(reg, ppcnt, a_octets_received_ok, -- 0x08 + 0x28, 0, 64); -+MLXSW_ITEM32(reg, perar, hw_region, 0x04, 0, 16); - --/* reg_ppcnt_a_multicast_frames_xmitted_ok -- * Access: RO -+static inline void mlxsw_reg_perar_pack(char *payload, u16 region_id, -+ u16 hw_region) -+{ -+ MLXSW_REG_ZERO(perar, payload); -+ mlxsw_reg_perar_region_id_set(payload, region_id); -+ mlxsw_reg_perar_hw_region_set(payload, hw_region); -+} -+ -+/* PTCE-V3 - Policy-Engine TCAM Entry Register Version 3 -+ * ----------------------------------------------------- -+ * This register is a new version of PTCE-V2 in order to support the -+ * A-TCAM. This register is not supported by SwitchX/-2 and Spectrum. - */ --MLXSW_ITEM64(reg, ppcnt, a_multicast_frames_xmitted_ok, -- 0x08 + 0x30, 0, 64); -+#define MLXSW_REG_PTCE3_ID 0x3027 -+#define MLXSW_REG_PTCE3_LEN 0xF0 - --/* reg_ppcnt_a_broadcast_frames_xmitted_ok -- * Access: RO -+MLXSW_REG_DEFINE(ptce3, MLXSW_REG_PTCE3_ID, MLXSW_REG_PTCE3_LEN); -+ -+/* reg_ptce3_v -+ * Valid. -+ * Access: RW - */ --MLXSW_ITEM64(reg, ppcnt, a_broadcast_frames_xmitted_ok, -- 0x08 + 0x38, 0, 64); -+MLXSW_ITEM32(reg, ptce3, v, 0x00, 31, 1); - --/* reg_ppcnt_a_multicast_frames_received_ok -- * Access: RO -+enum mlxsw_reg_ptce3_op { -+ /* Write operation. Used to write a new entry to the table. -+ * All R/W fields are relevant for new entry. Activity bit is set -+ * for new entries. Write with v = 0 will delete the entry. Must -+ * not be used if an entry exists. -+ */ -+ MLXSW_REG_PTCE3_OP_WRITE_WRITE = 0, -+ /* Update operation */ -+ MLXSW_REG_PTCE3_OP_WRITE_UPDATE = 1, -+ /* Read operation */ -+ MLXSW_REG_PTCE3_OP_QUERY_READ = 0, -+}; -+ -+/* reg_ptce3_op -+ * Access: OP - */ --MLXSW_ITEM64(reg, ppcnt, a_multicast_frames_received_ok, -- 0x08 + 0x40, 0, 64); -+MLXSW_ITEM32(reg, ptce3, op, 0x00, 20, 3); - --/* reg_ppcnt_a_broadcast_frames_received_ok -- * Access: RO -+/* reg_ptce3_priority -+ * Priority of the rule. Higher values win. -+ * For Spectrum-2 range is 1..cap_kvd_size - 1 -+ * Note: Priority does not have to be unique per rule. -+ * Access: RW - */ --MLXSW_ITEM64(reg, ppcnt, a_broadcast_frames_received_ok, -- 0x08 + 0x48, 0, 64); -+MLXSW_ITEM32(reg, ptce3, priority, 0x04, 0, 24); - --/* reg_ppcnt_a_in_range_length_errors -- * Access: RO -+/* reg_ptce3_tcam_region_info -+ * Opaque object that represents the TCAM region. -+ * Access: Index - */ --MLXSW_ITEM64(reg, ppcnt, a_in_range_length_errors, -- 0x08 + 0x50, 0, 64); -+MLXSW_ITEM_BUF(reg, ptce3, tcam_region_info, 0x10, -+ MLXSW_REG_PXXX_TCAM_REGION_INFO_LEN); - --/* reg_ppcnt_a_out_of_range_length_field -- * Access: RO -+/* reg_ptce3_flex2_key_blocks -+ * ACL key. The key must be masked according to eRP (if exists) or -+ * according to master mask. -+ * Access: Index - */ --MLXSW_ITEM64(reg, ppcnt, a_out_of_range_length_field, -- 0x08 + 0x58, 0, 64); -+MLXSW_ITEM_BUF(reg, ptce3, flex2_key_blocks, 0x20, -+ MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN); - --/* reg_ppcnt_a_frame_too_long_errors -- * Access: RO -+/* reg_ptce3_erp_id -+ * eRP ID. -+ * Access: Index - */ --MLXSW_ITEM64(reg, ppcnt, a_frame_too_long_errors, -- 0x08 + 0x60, 0, 64); -+MLXSW_ITEM32(reg, ptce3, erp_id, 0x80, 0, 4); - --/* reg_ppcnt_a_symbol_error_during_carrier -- * Access: RO -+/* reg_ptce3_delta_start -+ * Start point of delta_value and delta_mask, in bits. Must not exceed -+ * num_key_blocks * 36 - 8. Reserved when delta_mask = 0. -+ * Access: Index - */ --MLXSW_ITEM64(reg, ppcnt, a_symbol_error_during_carrier, -- 0x08 + 0x68, 0, 64); -+MLXSW_ITEM32(reg, ptce3, delta_start, 0x84, 0, 10); - --/* reg_ppcnt_a_mac_control_frames_transmitted -- * Access: RO -+/* reg_ptce3_delta_mask -+ * Delta mask. -+ * 0 - Ignore relevant bit in delta_value -+ * 1 - Compare relevant bit in delta_value -+ * Delta mask must not be set for reserved fields in the key blocks. -+ * Note: No delta when no eRPs. Thus, for regions with -+ * PERERP.erpt_pointer_valid = 0 the delta mask must be 0. -+ * Access: Index - */ --MLXSW_ITEM64(reg, ppcnt, a_mac_control_frames_transmitted, -- 0x08 + 0x70, 0, 64); -+MLXSW_ITEM32(reg, ptce3, delta_mask, 0x88, 16, 8); - --/* reg_ppcnt_a_mac_control_frames_received -- * Access: RO -+/* reg_ptce3_delta_value -+ * Delta value. -+ * Bits which are masked by delta_mask must be 0. -+ * Access: Index - */ --MLXSW_ITEM64(reg, ppcnt, a_mac_control_frames_received, -- 0x08 + 0x78, 0, 64); -+MLXSW_ITEM32(reg, ptce3, delta_value, 0x88, 0, 8); - --/* reg_ppcnt_a_unsupported_opcodes_received -- * Access: RO -+/* reg_ptce3_prune_vector -+ * Pruning vector relative to the PERPT.erp_id. -+ * Used for reducing lookups. -+ * 0 - NEED: Do a lookup using the eRP. -+ * 1 - PRUNE: Do not perform a lookup using the eRP. -+ * Maybe be modified by PEAPBL and PEAPBM. -+ * Note: In Spectrum-2, a region of 8 key blocks must be set to either -+ * all 1's or all 0's. -+ * Access: RW - */ --MLXSW_ITEM64(reg, ppcnt, a_unsupported_opcodes_received, -- 0x08 + 0x80, 0, 64); -+MLXSW_ITEM_BIT_ARRAY(reg, ptce3, prune_vector, 0x90, 4, 1); - --/* reg_ppcnt_a_pause_mac_ctrl_frames_received -- * Access: RO -- */ --MLXSW_ITEM64(reg, ppcnt, a_pause_mac_ctrl_frames_received, -- 0x08 + 0x88, 0, 64); -- --/* reg_ppcnt_a_pause_mac_ctrl_frames_transmitted -- * Access: RO -+/* reg_ptce3_prune_ctcam -+ * Pruning on C-TCAM. Used for reducing lookups. -+ * 0 - NEED: Do a lookup in the C-TCAM. -+ * 1 - PRUNE: Do not perform a lookup in the C-TCAM. -+ * Access: RW - */ --MLXSW_ITEM64(reg, ppcnt, a_pause_mac_ctrl_frames_transmitted, -- 0x08 + 0x90, 0, 64); -- --/* Ethernet Per Priority Group Counters */ -+MLXSW_ITEM32(reg, ptce3, prune_ctcam, 0x94, 31, 1); - --/* reg_ppcnt_rx_octets -- * Access: RO -+/* reg_ptce3_large_exists -+ * Large entry key ID exists. -+ * Within the region: -+ * 0 - SINGLE: The large_entry_key_id is not currently in use. -+ * For rule insert: The MSB of the key (blocks 6..11) will be added. -+ * For rule delete: The MSB of the key will be removed. -+ * 1 - NON_SINGLE: The large_entry_key_id is currently in use. -+ * For rule insert: The MSB of the key (blocks 6..11) will not be added. -+ * For rule delete: The MSB of the key will not be removed. -+ * Access: WO - */ --MLXSW_ITEM64(reg, ppcnt, rx_octets, 0x08 + 0x00, 0, 64); -+MLXSW_ITEM32(reg, ptce3, large_exists, 0x98, 31, 1); - --/* reg_ppcnt_rx_frames -- * Access: RO -+/* reg_ptce3_large_entry_key_id -+ * Large entry key ID. -+ * A key for 12 key blocks rules. Reserved when region has less than 12 key -+ * blocks. Must be different for different keys which have the same common -+ * 6 key blocks (MSB, blocks 6..11) key within a region. -+ * Range is 0..cap_max_pe_large_key_id - 1 -+ * Access: RW - */ --MLXSW_ITEM64(reg, ppcnt, rx_frames, 0x08 + 0x20, 0, 64); -+MLXSW_ITEM32(reg, ptce3, large_entry_key_id, 0x98, 0, 24); - --/* reg_ppcnt_tx_octets -- * Access: RO -+/* reg_ptce3_action_pointer -+ * Pointer to action. -+ * Range is 0..cap_max_kvd_action_sets - 1 -+ * Access: RW - */ --MLXSW_ITEM64(reg, ppcnt, tx_octets, 0x08 + 0x28, 0, 64); -+MLXSW_ITEM32(reg, ptce3, action_pointer, 0xA0, 0, 24); - --/* reg_ppcnt_tx_frames -- * Access: RO -- */ --MLXSW_ITEM64(reg, ppcnt, tx_frames, 0x08 + 0x48, 0, 64); -+static inline void mlxsw_reg_ptce3_pack(char *payload, bool valid, -+ enum mlxsw_reg_ptce3_op op, -+ u32 priority, -+ const char *tcam_region_info, -+ const char *key, u8 erp_id, -+ bool large_exists, u32 lkey_id, -+ u32 action_pointer) -+{ -+ MLXSW_REG_ZERO(ptce3, payload); -+ mlxsw_reg_ptce3_v_set(payload, valid); -+ mlxsw_reg_ptce3_op_set(payload, op); -+ mlxsw_reg_ptce3_priority_set(payload, priority); -+ mlxsw_reg_ptce3_tcam_region_info_memcpy_to(payload, tcam_region_info); -+ mlxsw_reg_ptce3_flex2_key_blocks_memcpy_to(payload, key); -+ mlxsw_reg_ptce3_erp_id_set(payload, erp_id); -+ mlxsw_reg_ptce3_large_exists_set(payload, large_exists); -+ mlxsw_reg_ptce3_large_entry_key_id_set(payload, lkey_id); -+ mlxsw_reg_ptce3_action_pointer_set(payload, action_pointer); -+} - --/* reg_ppcnt_rx_pause -- * Access: RO -+/* PERCR - Policy-Engine Region Configuration Register -+ * --------------------------------------------------- -+ * This register configures the region parameters. The region_id must be -+ * allocated. - */ --MLXSW_ITEM64(reg, ppcnt, rx_pause, 0x08 + 0x50, 0, 64); -+#define MLXSW_REG_PERCR_ID 0x302A -+#define MLXSW_REG_PERCR_LEN 0x80 - --/* reg_ppcnt_rx_pause_duration -- * Access: RO -- */ --MLXSW_ITEM64(reg, ppcnt, rx_pause_duration, 0x08 + 0x58, 0, 64); -+MLXSW_REG_DEFINE(percr, MLXSW_REG_PERCR_ID, MLXSW_REG_PERCR_LEN); - --/* reg_ppcnt_tx_pause -- * Access: RO -+/* reg_percr_region_id -+ * Region identifier. -+ * Range 0..cap_max_regions-1 -+ * Access: Index - */ --MLXSW_ITEM64(reg, ppcnt, tx_pause, 0x08 + 0x60, 0, 64); -+MLXSW_ITEM32(reg, percr, region_id, 0x00, 0, 16); - --/* reg_ppcnt_tx_pause_duration -- * Access: RO -+/* reg_percr_atcam_ignore_prune -+ * Ignore prune_vector by other A-TCAM rules. Used e.g., for a new rule. -+ * Access: RW - */ --MLXSW_ITEM64(reg, ppcnt, tx_pause_duration, 0x08 + 0x68, 0, 64); -+MLXSW_ITEM32(reg, percr, atcam_ignore_prune, 0x04, 25, 1); - --/* reg_ppcnt_rx_pause_transition -- * Access: RO -+/* reg_percr_ctcam_ignore_prune -+ * Ignore prune_ctcam by other A-TCAM rules. Used e.g., for a new rule. -+ * Access: RW - */ --MLXSW_ITEM64(reg, ppcnt, tx_pause_transition, 0x08 + 0x70, 0, 64); -+MLXSW_ITEM32(reg, percr, ctcam_ignore_prune, 0x04, 24, 1); - --/* Ethernet Per Traffic Group Counters */ -- --/* reg_ppcnt_tc_transmit_queue -- * Contains the transmit queue depth in cells of traffic class -- * selected by prio_tc and the port selected by local_port. -- * The field cannot be cleared. -- * Access: RO -+/* reg_percr_bf_bypass -+ * Bloom filter bypass. -+ * 0 - Bloom filter is used (default) -+ * 1 - Bloom filter is bypassed. The bypass is an OR condition of -+ * region_id or eRP. See PERPT.bf_bypass -+ * Access: RW - */ --MLXSW_ITEM64(reg, ppcnt, tc_transmit_queue, 0x08 + 0x00, 0, 64); -+MLXSW_ITEM32(reg, percr, bf_bypass, 0x04, 16, 1); - --/* reg_ppcnt_tc_no_buffer_discard_uc -- * The number of unicast packets dropped due to lack of shared -- * buffer resources. -- * Access: RO -+/* reg_percr_master_mask -+ * Master mask. Logical OR mask of all masks of all rules of a region -+ * (both A-TCAM and C-TCAM). When there are no eRPs -+ * (erpt_pointer_valid = 0), then this provides the mask. -+ * Access: RW - */ --MLXSW_ITEM64(reg, ppcnt, tc_no_buffer_discard_uc, 0x08 + 0x08, 0, 64); -+MLXSW_ITEM_BUF(reg, percr, master_mask, 0x20, 96); - --static inline void mlxsw_reg_ppcnt_pack(char *payload, u8 local_port, -- enum mlxsw_reg_ppcnt_grp grp, -- u8 prio_tc) -+static inline void mlxsw_reg_percr_pack(char *payload, u16 region_id) - { -- MLXSW_REG_ZERO(ppcnt, payload); -- mlxsw_reg_ppcnt_swid_set(payload, 0); -- mlxsw_reg_ppcnt_local_port_set(payload, local_port); -- mlxsw_reg_ppcnt_pnat_set(payload, 0); -- mlxsw_reg_ppcnt_grp_set(payload, grp); -- mlxsw_reg_ppcnt_clr_set(payload, 0); -- mlxsw_reg_ppcnt_prio_tc_set(payload, prio_tc); -+ MLXSW_REG_ZERO(percr, payload); -+ mlxsw_reg_percr_region_id_set(payload, region_id); -+ mlxsw_reg_percr_atcam_ignore_prune_set(payload, false); -+ mlxsw_reg_percr_ctcam_ignore_prune_set(payload, false); -+ mlxsw_reg_percr_bf_bypass_set(payload, true); - } - --/* PPTB - Port Prio To Buffer Register -- * ----------------------------------- -- * Configures the switch priority to buffer table. -+/* PERERP - Policy-Engine Region eRP Register -+ * ------------------------------------------ -+ * This register configures the region eRP. The region_id must be -+ * allocated. - */ --#define MLXSW_REG_PPTB_ID 0x500B --#define MLXSW_REG_PPTB_LEN 0x10 -- --static const struct mlxsw_reg_info mlxsw_reg_pptb = { -- .id = MLXSW_REG_PPTB_ID, -- .len = MLXSW_REG_PPTB_LEN, --}; -- --enum { -- MLXSW_REG_PPTB_MM_UM, -- MLXSW_REG_PPTB_MM_UNICAST, -- MLXSW_REG_PPTB_MM_MULTICAST, --}; -+#define MLXSW_REG_PERERP_ID 0x302B -+#define MLXSW_REG_PERERP_LEN 0x1C - --/* reg_pptb_mm -- * Mapping mode. -- * 0 - Map both unicast and multicast packets to the same buffer. -- * 1 - Map only unicast packets. -- * 2 - Map only multicast packets. -- * Access: Index -- * -- * Note: SwitchX-2 only supports the first option. -- */ --MLXSW_ITEM32(reg, pptb, mm, 0x00, 28, 2); -+MLXSW_REG_DEFINE(pererp, MLXSW_REG_PERERP_ID, MLXSW_REG_PERERP_LEN); - --/* reg_pptb_local_port -- * Local port number. -+/* reg_pererp_region_id -+ * Region identifier. -+ * Range 0..cap_max_regions-1 - * Access: Index - */ --MLXSW_ITEM32(reg, pptb, local_port, 0x00, 16, 8); -+MLXSW_ITEM32(reg, pererp, region_id, 0x00, 0, 16); - --/* reg_pptb_um -- * Enables the update of the untagged_buf field. -+/* reg_pererp_ctcam_le -+ * C-TCAM lookup enable. Reserved when erpt_pointer_valid = 0. - * Access: RW - */ --MLXSW_ITEM32(reg, pptb, um, 0x00, 8, 1); -+MLXSW_ITEM32(reg, pererp, ctcam_le, 0x04, 28, 1); - --/* reg_pptb_pm -- * Enables the update of the prio_to_buff field. -- * Bit is a flag for updating the mapping for switch priority . -+/* reg_pererp_erpt_pointer_valid -+ * erpt_pointer is valid. - * Access: RW - */ --MLXSW_ITEM32(reg, pptb, pm, 0x00, 0, 8); -+MLXSW_ITEM32(reg, pererp, erpt_pointer_valid, 0x10, 31, 1); - --/* reg_pptb_prio_to_buff -- * Mapping of switch priority to one of the allocated receive port -- * buffers. -- * Access: RW -+/* reg_pererp_erpt_bank_pointer -+ * Pointer to eRP table bank. May be modified at any time. -+ * Range 0..cap_max_erp_table_banks-1 -+ * Reserved when erpt_pointer_valid = 0 - */ --MLXSW_ITEM_BIT_ARRAY(reg, pptb, prio_to_buff, 0x04, 0x04, 4); -+MLXSW_ITEM32(reg, pererp, erpt_bank_pointer, 0x10, 16, 4); - --/* reg_pptb_pm_msb -- * Enables the update of the prio_to_buff field. -- * Bit is a flag for updating the mapping for switch priority . -+/* reg_pererp_erpt_pointer -+ * Pointer to eRP table within the eRP bank. Can be changed for an -+ * existing region. -+ * Range 0..cap_max_erp_table_size-1 -+ * Reserved when erpt_pointer_valid = 0 - * Access: RW - */ --MLXSW_ITEM32(reg, pptb, pm_msb, 0x08, 24, 8); -+MLXSW_ITEM32(reg, pererp, erpt_pointer, 0x10, 0, 8); - --/* reg_pptb_untagged_buff -- * Mapping of untagged frames to one of the allocated receive port buffers. -+/* reg_pererp_erpt_vector -+ * Vector of allowed eRP indexes starting from erpt_pointer within the -+ * erpt_bank_pointer. Next entries will be in next bank. -+ * Note that eRP index is used and not eRP ID. -+ * Reserved when erpt_pointer_valid = 0 - * Access: RW -- * -- * Note: In SwitchX-2 this field must be mapped to buffer 8. Reserved for -- * Spectrum, as it maps untagged packets based on the default switch priority. - */ --MLXSW_ITEM32(reg, pptb, untagged_buff, 0x08, 0, 4); -+MLXSW_ITEM_BIT_ARRAY(reg, pererp, erpt_vector, 0x14, 4, 1); - --/* reg_pptb_prio_to_buff_msb -- * Mapping of switch priority to one of the allocated receive port -- * buffers. -+/* reg_pererp_master_rp_id -+ * Master RP ID. When there are no eRPs, then this provides the eRP ID -+ * for the lookup. Can be changed for an existing region. -+ * Reserved when erpt_pointer_valid = 1 - * Access: RW - */ --MLXSW_ITEM_BIT_ARRAY(reg, pptb, prio_to_buff_msb, 0x0C, 0x04, 4); -+MLXSW_ITEM32(reg, pererp, master_rp_id, 0x18, 0, 4); - --#define MLXSW_REG_PPTB_ALL_PRIO 0xFF -- --static inline void mlxsw_reg_pptb_pack(char *payload, u8 local_port) -+static inline void mlxsw_reg_pererp_erp_vector_pack(char *payload, -+ unsigned long *erp_vector, -+ unsigned long size) - { -- MLXSW_REG_ZERO(pptb, payload); -- mlxsw_reg_pptb_mm_set(payload, MLXSW_REG_PPTB_MM_UM); -- mlxsw_reg_pptb_local_port_set(payload, local_port); -- mlxsw_reg_pptb_pm_set(payload, MLXSW_REG_PPTB_ALL_PRIO); -- mlxsw_reg_pptb_pm_msb_set(payload, MLXSW_REG_PPTB_ALL_PRIO); -+ unsigned long bit; -+ -+ for_each_set_bit(bit, erp_vector, size) -+ mlxsw_reg_pererp_erpt_vector_set(payload, bit, true); - } - --static inline void mlxsw_reg_pptb_prio_to_buff_pack(char *payload, u8 prio, -- u8 buff) -+static inline void mlxsw_reg_pererp_pack(char *payload, u16 region_id, -+ bool ctcam_le, bool erpt_pointer_valid, -+ u8 erpt_bank_pointer, u8 erpt_pointer, -+ u8 master_rp_id) - { -- mlxsw_reg_pptb_prio_to_buff_set(payload, prio, buff); -- mlxsw_reg_pptb_prio_to_buff_msb_set(payload, prio, buff); -+ MLXSW_REG_ZERO(pererp, payload); -+ mlxsw_reg_pererp_region_id_set(payload, region_id); -+ mlxsw_reg_pererp_ctcam_le_set(payload, ctcam_le); -+ mlxsw_reg_pererp_erpt_pointer_valid_set(payload, erpt_pointer_valid); -+ mlxsw_reg_pererp_erpt_bank_pointer_set(payload, erpt_bank_pointer); -+ mlxsw_reg_pererp_erpt_pointer_set(payload, erpt_pointer); -+ mlxsw_reg_pererp_master_rp_id_set(payload, master_rp_id); - } - --/* PBMC - Port Buffer Management Control Register -- * ---------------------------------------------- -- * The PBMC register configures and retrieves the port packet buffer -- * allocation for different Prios, and the Pause threshold management. -+/* IEDR - Infrastructure Entry Delete Register -+ * ---------------------------------------------------- -+ * This register is used for deleting entries from the entry tables. -+ * It is legitimate to attempt to delete a nonexisting entry (the device will -+ * respond as a good flow). -+ */ -+#define MLXSW_REG_IEDR_ID 0x3804 -+#define MLXSW_REG_IEDR_BASE_LEN 0x10 /* base length, without records */ -+#define MLXSW_REG_IEDR_REC_LEN 0x8 /* record length */ -+#define MLXSW_REG_IEDR_REC_MAX_COUNT 64 -+#define MLXSW_REG_IEDR_LEN (MLXSW_REG_IEDR_BASE_LEN + \ -+ MLXSW_REG_IEDR_REC_LEN * \ -+ MLXSW_REG_IEDR_REC_MAX_COUNT) -+ -+MLXSW_REG_DEFINE(iedr, MLXSW_REG_IEDR_ID, MLXSW_REG_IEDR_LEN); -+ -+/* reg_iedr_num_rec -+ * Number of records. -+ * Access: OP - */ --#define MLXSW_REG_PBMC_ID 0x500C --#define MLXSW_REG_PBMC_LEN 0x6C -- --static const struct mlxsw_reg_info mlxsw_reg_pbmc = { -- .id = MLXSW_REG_PBMC_ID, -- .len = MLXSW_REG_PBMC_LEN, --}; -+MLXSW_ITEM32(reg, iedr, num_rec, 0x00, 0, 8); - --/* reg_pbmc_local_port -- * Local port number. -- * Access: Index -+/* reg_iedr_rec_type -+ * Resource type. -+ * Access: OP - */ --MLXSW_ITEM32(reg, pbmc, local_port, 0x00, 16, 8); -+MLXSW_ITEM32_INDEXED(reg, iedr, rec_type, MLXSW_REG_IEDR_BASE_LEN, 24, 8, -+ MLXSW_REG_IEDR_REC_LEN, 0x00, false); - --/* reg_pbmc_xoff_timer_value -- * When device generates a pause frame, it uses this value as the pause -- * timer (time for the peer port to pause in quota-512 bit time). -- * Access: RW -+/* reg_iedr_rec_size -+ * Size of entries do be deleted. The unit is 1 entry, regardless of entry type. -+ * Access: OP - */ --MLXSW_ITEM32(reg, pbmc, xoff_timer_value, 0x04, 16, 16); -+MLXSW_ITEM32_INDEXED(reg, iedr, rec_size, MLXSW_REG_IEDR_BASE_LEN, 0, 11, -+ MLXSW_REG_IEDR_REC_LEN, 0x00, false); - --/* reg_pbmc_xoff_refresh -- * The time before a new pause frame should be sent to refresh the pause RW -- * state. Using the same units as xoff_timer_value above (in quota-512 bit -- * time). -- * Access: RW -+/* reg_iedr_rec_index_start -+ * Resource index start. -+ * Access: OP - */ --MLXSW_ITEM32(reg, pbmc, xoff_refresh, 0x04, 0, 16); -+MLXSW_ITEM32_INDEXED(reg, iedr, rec_index_start, MLXSW_REG_IEDR_BASE_LEN, 0, 24, -+ MLXSW_REG_IEDR_REC_LEN, 0x04, false); - --#define MLXSW_REG_PBMC_PORT_SHARED_BUF_IDX 11 -+static inline void mlxsw_reg_iedr_pack(char *payload) -+{ -+ MLXSW_REG_ZERO(iedr, payload); -+} - --/* reg_pbmc_buf_lossy -- * The field indicates if the buffer is lossy. -- * 0 - Lossless -- * 1 - Lossy -- * Access: RW -- */ --MLXSW_ITEM32_INDEXED(reg, pbmc, buf_lossy, 0x0C, 25, 1, 0x08, 0x00, false); -+static inline void mlxsw_reg_iedr_rec_pack(char *payload, int rec_index, -+ u8 rec_type, u16 rec_size, -+ u32 rec_index_start) -+{ -+ u8 num_rec = mlxsw_reg_iedr_num_rec_get(payload); - --/* reg_pbmc_buf_epsb -- * Eligible for Port Shared buffer. -- * If epsb is set, packets assigned to buffer are allowed to insert the port -- * shared buffer. -- * When buf_lossy is MLXSW_REG_PBMC_LOSSY_LOSSY this field is reserved. -- * Access: RW -- */ --MLXSW_ITEM32_INDEXED(reg, pbmc, buf_epsb, 0x0C, 24, 1, 0x08, 0x00, false); -+ if (rec_index >= num_rec) -+ mlxsw_reg_iedr_num_rec_set(payload, rec_index + 1); -+ mlxsw_reg_iedr_rec_type_set(payload, rec_index, rec_type); -+ mlxsw_reg_iedr_rec_size_set(payload, rec_index, rec_size); -+ mlxsw_reg_iedr_rec_index_start_set(payload, rec_index, rec_index_start); -+} - --/* reg_pbmc_buf_size -- * The part of the packet buffer array is allocated for the specific buffer. -- * Units are represented in cells. -- * Access: RW -+/* QPTS - QoS Priority Trust State Register -+ * ---------------------------------------- -+ * This register controls the port policy to calculate the switch priority and -+ * packet color based on incoming packet fields. - */ --MLXSW_ITEM32_INDEXED(reg, pbmc, buf_size, 0x0C, 0, 16, 0x08, 0x00, false); -+#define MLXSW_REG_QPTS_ID 0x4002 -+#define MLXSW_REG_QPTS_LEN 0x8 - --/* reg_pbmc_buf_xoff_threshold -- * Once the amount of data in the buffer goes above this value, device -- * starts sending PFC frames for all priorities associated with the -- * buffer. Units are represented in cells. Reserved in case of lossy -- * buffer. -- * Access: RW -+MLXSW_REG_DEFINE(qpts, MLXSW_REG_QPTS_ID, MLXSW_REG_QPTS_LEN); -+ -+/* reg_qpts_local_port -+ * Local port number. -+ * Access: Index - * -- * Note: In Spectrum, reserved for buffer[9]. -+ * Note: CPU port is supported. - */ --MLXSW_ITEM32_INDEXED(reg, pbmc, buf_xoff_threshold, 0x0C, 16, 16, -- 0x08, 0x04, false); -+MLXSW_ITEM32(reg, qpts, local_port, 0x00, 16, 8); - --/* reg_pbmc_buf_xon_threshold -- * When the amount of data in the buffer goes below this value, device -- * stops sending PFC frames for the priorities associated with the -- * buffer. Units are represented in cells. Reserved in case of lossy -- * buffer. -+enum mlxsw_reg_qpts_trust_state { -+ MLXSW_REG_QPTS_TRUST_STATE_PCP = 1, -+ MLXSW_REG_QPTS_TRUST_STATE_DSCP = 2, /* For MPLS, trust EXP. */ -+}; -+ -+/* reg_qpts_trust_state -+ * Trust state for a given port. - * Access: RW -- * -- * Note: In Spectrum, reserved for buffer[9]. - */ --MLXSW_ITEM32_INDEXED(reg, pbmc, buf_xon_threshold, 0x0C, 0, 16, -- 0x08, 0x04, false); -+MLXSW_ITEM32(reg, qpts, trust_state, 0x04, 0, 3); - --static inline void mlxsw_reg_pbmc_pack(char *payload, u8 local_port, -- u16 xoff_timer_value, u16 xoff_refresh) --{ -- MLXSW_REG_ZERO(pbmc, payload); -- mlxsw_reg_pbmc_local_port_set(payload, local_port); -- mlxsw_reg_pbmc_xoff_timer_value_set(payload, xoff_timer_value); -- mlxsw_reg_pbmc_xoff_refresh_set(payload, xoff_refresh); --} -- --static inline void mlxsw_reg_pbmc_lossy_buffer_pack(char *payload, -- int buf_index, -- u16 size) -+static inline void mlxsw_reg_qpts_pack(char *payload, u8 local_port, -+ enum mlxsw_reg_qpts_trust_state ts) - { -- mlxsw_reg_pbmc_buf_lossy_set(payload, buf_index, 1); -- mlxsw_reg_pbmc_buf_epsb_set(payload, buf_index, 0); -- mlxsw_reg_pbmc_buf_size_set(payload, buf_index, size); --} -+ MLXSW_REG_ZERO(qpts, payload); - --static inline void mlxsw_reg_pbmc_lossless_buffer_pack(char *payload, -- int buf_index, u16 size, -- u16 threshold) --{ -- mlxsw_reg_pbmc_buf_lossy_set(payload, buf_index, 0); -- mlxsw_reg_pbmc_buf_epsb_set(payload, buf_index, 0); -- mlxsw_reg_pbmc_buf_size_set(payload, buf_index, size); -- mlxsw_reg_pbmc_buf_xoff_threshold_set(payload, buf_index, threshold); -- mlxsw_reg_pbmc_buf_xon_threshold_set(payload, buf_index, threshold); -+ mlxsw_reg_qpts_local_port_set(payload, local_port); -+ mlxsw_reg_qpts_trust_state_set(payload, ts); - } - --/* PSPA - Port Switch Partition Allocation -- * --------------------------------------- -- * Controls the association of a port with a switch partition and enables -- * configuring ports as stacking ports. -+/* QPCR - QoS Policer Configuration Register -+ * ----------------------------------------- -+ * The QPCR register is used to create policers - that limit -+ * the rate of bytes or packets via some trap group. - */ --#define MLXSW_REG_PSPA_ID 0x500D --#define MLXSW_REG_PSPA_LEN 0x8 -+#define MLXSW_REG_QPCR_ID 0x4004 -+#define MLXSW_REG_QPCR_LEN 0x28 - --static const struct mlxsw_reg_info mlxsw_reg_pspa = { -- .id = MLXSW_REG_PSPA_ID, -- .len = MLXSW_REG_PSPA_LEN, -+MLXSW_REG_DEFINE(qpcr, MLXSW_REG_QPCR_ID, MLXSW_REG_QPCR_LEN); -+ -+enum mlxsw_reg_qpcr_g { -+ MLXSW_REG_QPCR_G_GLOBAL = 2, -+ MLXSW_REG_QPCR_G_STORM_CONTROL = 3, - }; - --/* reg_pspa_swid -- * Switch partition ID. -- * Access: RW -+/* reg_qpcr_g -+ * The policer type. -+ * Access: Index - */ --MLXSW_ITEM32(reg, pspa, swid, 0x00, 24, 8); -+MLXSW_ITEM32(reg, qpcr, g, 0x00, 14, 2); - --/* reg_pspa_local_port -- * Local port number. -+/* reg_qpcr_pid -+ * Policer ID. - * Access: Index - */ --MLXSW_ITEM32(reg, pspa, local_port, 0x00, 16, 8); -+MLXSW_ITEM32(reg, qpcr, pid, 0x00, 0, 14); - --/* reg_pspa_sub_port -- * Virtual port within the local port. Set to 0 when virtual ports are -- * disabled on the local port. -- * Access: Index -+/* reg_qpcr_color_aware -+ * Is the policer aware of colors. -+ * Must be 0 (unaware) for cpu port. -+ * Access: RW for unbounded policer. RO for bounded policer. - */ --MLXSW_ITEM32(reg, pspa, sub_port, 0x00, 8, 8); -+MLXSW_ITEM32(reg, qpcr, color_aware, 0x04, 15, 1); - --static inline void mlxsw_reg_pspa_pack(char *payload, u8 swid, u8 local_port) --{ -- MLXSW_REG_ZERO(pspa, payload); -- mlxsw_reg_pspa_swid_set(payload, swid); -- mlxsw_reg_pspa_local_port_set(payload, local_port); -- mlxsw_reg_pspa_sub_port_set(payload, 0); --} -- --/* HTGT - Host Trap Group Table -- * ---------------------------- -- * Configures the properties for forwarding to CPU. -+/* reg_qpcr_bytes -+ * Is policer limit is for bytes per sec or packets per sec. -+ * 0 - packets -+ * 1 - bytes -+ * Access: RW for unbounded policer. RO for bounded policer. - */ --#define MLXSW_REG_HTGT_ID 0x7002 --#define MLXSW_REG_HTGT_LEN 0x100 -+MLXSW_ITEM32(reg, qpcr, bytes, 0x04, 14, 1); - --static const struct mlxsw_reg_info mlxsw_reg_htgt = { -- .id = MLXSW_REG_HTGT_ID, -- .len = MLXSW_REG_HTGT_LEN, -+enum mlxsw_reg_qpcr_ir_units { -+ MLXSW_REG_QPCR_IR_UNITS_M, -+ MLXSW_REG_QPCR_IR_UNITS_K, - }; - --/* reg_htgt_swid -- * Switch partition ID. -- * Access: Index -- */ --MLXSW_ITEM32(reg, htgt, swid, 0x00, 24, 8); -- --#define MLXSW_REG_HTGT_PATH_TYPE_LOCAL 0x0 /* For locally attached CPU */ -- --/* reg_htgt_type -- * CPU path type. -- * Access: RW -+/* reg_qpcr_ir_units -+ * Policer's units for cir and eir fields (for bytes limits only) -+ * 1 - 10^3 -+ * 0 - 10^6 -+ * Access: OP - */ --MLXSW_ITEM32(reg, htgt, type, 0x00, 8, 4); -+MLXSW_ITEM32(reg, qpcr, ir_units, 0x04, 12, 1); - --enum mlxsw_reg_htgt_trap_group { -- MLXSW_REG_HTGT_TRAP_GROUP_EMAD, -- MLXSW_REG_HTGT_TRAP_GROUP_RX, -- MLXSW_REG_HTGT_TRAP_GROUP_CTRL, -+enum mlxsw_reg_qpcr_rate_type { -+ MLXSW_REG_QPCR_RATE_TYPE_SINGLE = 1, -+ MLXSW_REG_QPCR_RATE_TYPE_DOUBLE = 2, - }; - --/* reg_htgt_trap_group -- * Trap group number. User defined number specifying which trap groups -- * should be forwarded to the CPU. The mapping between trap IDs and trap -- * groups is configured using HPKT register. -- * Access: Index -+/* reg_qpcr_rate_type -+ * Policer can have one limit (single rate) or 2 limits with specific operation -+ * for packets that exceed the lower rate but not the upper one. -+ * (For cpu port must be single rate) -+ * Access: RW for unbounded policer. RO for bounded policer. - */ --MLXSW_ITEM32(reg, htgt, trap_group, 0x00, 0, 8); -+MLXSW_ITEM32(reg, qpcr, rate_type, 0x04, 8, 2); - --enum { -- MLXSW_REG_HTGT_POLICER_DISABLE, -- MLXSW_REG_HTGT_POLICER_ENABLE, --}; -+/* reg_qpc_cbs -+ * Policer's committed burst size. -+ * The policer is working with time slices of 50 nano sec. By default every -+ * slice is granted the proportionate share of the committed rate. If we want to -+ * allow a slice to exceed that share (while still keeping the rate per sec) we -+ * can allow burst. The burst size is between the default proportionate share -+ * (and no lower than 8) to 32Gb. (Even though giving a number higher than the -+ * committed rate will result in exceeding the rate). The burst size must be a -+ * log of 2 and will be determined by 2^cbs. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, qpcr, cbs, 0x08, 24, 6); - --/* reg_htgt_pide -- * Enable policer ID specified using 'pid' field. -+/* reg_qpcr_cir -+ * Policer's committed rate. -+ * The rate used for sungle rate, the lower rate for double rate. -+ * For bytes limits, the rate will be this value * the unit from ir_units. -+ * (Resolution error is up to 1%). - * Access: RW - */ --MLXSW_ITEM32(reg, htgt, pide, 0x04, 15, 1); -+MLXSW_ITEM32(reg, qpcr, cir, 0x0C, 0, 32); - --/* reg_htgt_pid -- * Policer ID for the trap group. -+/* reg_qpcr_eir -+ * Policer's exceed rate. -+ * The higher rate for double rate, reserved for single rate. -+ * Lower rate for double rate policer. -+ * For bytes limits, the rate will be this value * the unit from ir_units. -+ * (Resolution error is up to 1%). - * Access: RW - */ --MLXSW_ITEM32(reg, htgt, pid, 0x04, 0, 8); -+MLXSW_ITEM32(reg, qpcr, eir, 0x10, 0, 32); - --#define MLXSW_REG_HTGT_TRAP_TO_CPU 0x0 -+#define MLXSW_REG_QPCR_DOUBLE_RATE_ACTION 2 - --/* reg_htgt_mirror_action -- * Mirror action to use. -- * 0 - Trap to CPU. -- * 1 - Trap to CPU and mirror to a mirroring agent. -- * 2 - Mirror to a mirroring agent and do not trap to CPU. -- * Access: RW -- * -- * Note: Mirroring to a mirroring agent is only supported in Spectrum. -+/* reg_qpcr_exceed_action. -+ * What to do with packets between the 2 limits for double rate. -+ * Access: RW for unbounded policer. RO for bounded policer. - */ --MLXSW_ITEM32(reg, htgt, mirror_action, 0x08, 8, 2); -+MLXSW_ITEM32(reg, qpcr, exceed_action, 0x14, 0, 4); - --/* reg_htgt_mirroring_agent -- * Mirroring agent. -- * Access: RW -+enum mlxsw_reg_qpcr_action { -+ /* Discard */ -+ MLXSW_REG_QPCR_ACTION_DISCARD = 1, -+ /* Forward and set color to red. -+ * If the packet is intended to cpu port, it will be dropped. -+ */ -+ MLXSW_REG_QPCR_ACTION_FORWARD = 2, -+}; -+ -+/* reg_qpcr_violate_action -+ * What to do with packets that cross the cir limit (for single rate) or the eir -+ * limit (for double rate). -+ * Access: RW for unbounded policer. RO for bounded policer. - */ --MLXSW_ITEM32(reg, htgt, mirroring_agent, 0x08, 0, 3); -+MLXSW_ITEM32(reg, qpcr, violate_action, 0x18, 0, 4); - --/* reg_htgt_priority -- * Trap group priority. -- * In case a packet matches multiple classification rules, the packet will -- * only be trapped once, based on the trap ID associated with the group (via -- * register HPKT) with the highest priority. -- * Supported values are 0-7, with 7 represnting the highest priority. -- * Access: RW -+static inline void mlxsw_reg_qpcr_pack(char *payload, u16 pid, -+ enum mlxsw_reg_qpcr_ir_units ir_units, -+ bool bytes, u32 cir, u16 cbs) -+{ -+ MLXSW_REG_ZERO(qpcr, payload); -+ mlxsw_reg_qpcr_pid_set(payload, pid); -+ mlxsw_reg_qpcr_g_set(payload, MLXSW_REG_QPCR_G_GLOBAL); -+ mlxsw_reg_qpcr_rate_type_set(payload, MLXSW_REG_QPCR_RATE_TYPE_SINGLE); -+ mlxsw_reg_qpcr_violate_action_set(payload, -+ MLXSW_REG_QPCR_ACTION_DISCARD); -+ mlxsw_reg_qpcr_cir_set(payload, cir); -+ mlxsw_reg_qpcr_ir_units_set(payload, ir_units); -+ mlxsw_reg_qpcr_bytes_set(payload, bytes); -+ mlxsw_reg_qpcr_cbs_set(payload, cbs); -+} -+ -+/* QTCT - QoS Switch Traffic Class Table -+ * ------------------------------------- -+ * Configures the mapping between the packet switch priority and the -+ * traffic class on the transmit port. -+ */ -+#define MLXSW_REG_QTCT_ID 0x400A -+#define MLXSW_REG_QTCT_LEN 0x08 -+ -+MLXSW_REG_DEFINE(qtct, MLXSW_REG_QTCT_ID, MLXSW_REG_QTCT_LEN); -+ -+/* reg_qtct_local_port -+ * Local port number. -+ * Access: Index - * -- * Note: In SwitchX-2 this field is ignored and the priority value is replaced -- * by the 'trap_group' field. -+ * Note: CPU port is not supported. - */ --MLXSW_ITEM32(reg, htgt, priority, 0x0C, 0, 4); -+MLXSW_ITEM32(reg, qtct, local_port, 0x00, 16, 8); - --/* reg_htgt_local_path_cpu_tclass -- * CPU ingress traffic class for the trap group. -- * Access: RW -+/* reg_qtct_sub_port -+ * Virtual port within the physical port. -+ * Should be set to 0 when virtual ports are not enabled on the port. -+ * Access: Index - */ --MLXSW_ITEM32(reg, htgt, local_path_cpu_tclass, 0x10, 16, 6); -+MLXSW_ITEM32(reg, qtct, sub_port, 0x00, 8, 8); - --#define MLXSW_REG_HTGT_LOCAL_PATH_RDQ_EMAD 0x15 --#define MLXSW_REG_HTGT_LOCAL_PATH_RDQ_RX 0x14 --#define MLXSW_REG_HTGT_LOCAL_PATH_RDQ_CTRL 0x13 -+/* reg_qtct_switch_prio -+ * Switch priority. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, qtct, switch_prio, 0x00, 0, 4); - --/* reg_htgt_local_path_rdq -- * Receive descriptor queue (RDQ) to use for the trap group. -+/* reg_qtct_tclass -+ * Traffic class. -+ * Default values: -+ * switch_prio 0 : tclass 1 -+ * switch_prio 1 : tclass 0 -+ * switch_prio i : tclass i, for i > 1 - * Access: RW - */ --MLXSW_ITEM32(reg, htgt, local_path_rdq, 0x10, 0, 6); -+MLXSW_ITEM32(reg, qtct, tclass, 0x04, 0, 4); - --static inline void mlxsw_reg_htgt_pack(char *payload, -- enum mlxsw_reg_htgt_trap_group group) -+static inline void mlxsw_reg_qtct_pack(char *payload, u8 local_port, -+ u8 switch_prio, u8 tclass) - { -- u8 swid, rdq; -- -- MLXSW_REG_ZERO(htgt, payload); -- switch (group) { -- case MLXSW_REG_HTGT_TRAP_GROUP_EMAD: -- swid = MLXSW_PORT_SWID_ALL_SWIDS; -- rdq = MLXSW_REG_HTGT_LOCAL_PATH_RDQ_EMAD; -- break; -- case MLXSW_REG_HTGT_TRAP_GROUP_RX: -- swid = 0; -- rdq = MLXSW_REG_HTGT_LOCAL_PATH_RDQ_RX; -- break; -- case MLXSW_REG_HTGT_TRAP_GROUP_CTRL: -- swid = 0; -- rdq = MLXSW_REG_HTGT_LOCAL_PATH_RDQ_CTRL; -- break; -- } -- mlxsw_reg_htgt_swid_set(payload, swid); -- mlxsw_reg_htgt_type_set(payload, MLXSW_REG_HTGT_PATH_TYPE_LOCAL); -- mlxsw_reg_htgt_trap_group_set(payload, group); -- mlxsw_reg_htgt_pide_set(payload, MLXSW_REG_HTGT_POLICER_DISABLE); -- mlxsw_reg_htgt_pid_set(payload, 0); -- mlxsw_reg_htgt_mirror_action_set(payload, MLXSW_REG_HTGT_TRAP_TO_CPU); -- mlxsw_reg_htgt_mirroring_agent_set(payload, 0); -- mlxsw_reg_htgt_priority_set(payload, 0); -- mlxsw_reg_htgt_local_path_cpu_tclass_set(payload, 7); -- mlxsw_reg_htgt_local_path_rdq_set(payload, rdq); -+ MLXSW_REG_ZERO(qtct, payload); -+ mlxsw_reg_qtct_local_port_set(payload, local_port); -+ mlxsw_reg_qtct_switch_prio_set(payload, switch_prio); -+ mlxsw_reg_qtct_tclass_set(payload, tclass); - } - --/* HPKT - Host Packet Trap -- * ----------------------- -- * Configures trap IDs inside trap groups. -+/* QEEC - QoS ETS Element Configuration Register -+ * --------------------------------------------- -+ * Configures the ETS elements. - */ --#define MLXSW_REG_HPKT_ID 0x7003 --#define MLXSW_REG_HPKT_LEN 0x10 -- --static const struct mlxsw_reg_info mlxsw_reg_hpkt = { -- .id = MLXSW_REG_HPKT_ID, -- .len = MLXSW_REG_HPKT_LEN, --}; -+#define MLXSW_REG_QEEC_ID 0x400D -+#define MLXSW_REG_QEEC_LEN 0x20 - --enum { -- MLXSW_REG_HPKT_ACK_NOT_REQUIRED, -- MLXSW_REG_HPKT_ACK_REQUIRED, --}; -+MLXSW_REG_DEFINE(qeec, MLXSW_REG_QEEC_ID, MLXSW_REG_QEEC_LEN); - --/* reg_hpkt_ack -- * Require acknowledgements from the host for events. -- * If set, then the device will wait for the event it sent to be acknowledged -- * by the host. This option is only relevant for event trap IDs. -- * Access: RW -+/* reg_qeec_local_port -+ * Local port number. -+ * Access: Index - * -- * Note: Currently not supported by firmware. -+ * Note: CPU port is supported. - */ --MLXSW_ITEM32(reg, hpkt, ack, 0x00, 24, 1); -+MLXSW_ITEM32(reg, qeec, local_port, 0x00, 16, 8); - --enum mlxsw_reg_hpkt_action { -- MLXSW_REG_HPKT_ACTION_FORWARD, -- MLXSW_REG_HPKT_ACTION_TRAP_TO_CPU, -- MLXSW_REG_HPKT_ACTION_MIRROR_TO_CPU, -- MLXSW_REG_HPKT_ACTION_DISCARD, -- MLXSW_REG_HPKT_ACTION_SOFT_DISCARD, -- MLXSW_REG_HPKT_ACTION_TRAP_AND_SOFT_DISCARD, -+enum mlxsw_reg_qeec_hr { -+ MLXSW_REG_QEEC_HIERARCY_PORT, -+ MLXSW_REG_QEEC_HIERARCY_GROUP, -+ MLXSW_REG_QEEC_HIERARCY_SUBGROUP, -+ MLXSW_REG_QEEC_HIERARCY_TC, - }; - --/* reg_hpkt_action -- * Action to perform on packet when trapped. -- * 0 - No action. Forward to CPU based on switching rules. -- * 1 - Trap to CPU (CPU receives sole copy). -- * 2 - Mirror to CPU (CPU receives a replica of the packet). -- * 3 - Discard. -- * 4 - Soft discard (allow other traps to act on the packet). -- * 5 - Trap and soft discard (allow other traps to overwrite this trap). -- * Access: RW -- * -- * Note: Must be set to 0 (forward) for event trap IDs, as they are already -- * addressed to the CPU. -+/* reg_qeec_element_hierarchy -+ * 0 - Port -+ * 1 - Group -+ * 2 - Subgroup -+ * 3 - Traffic Class -+ * Access: Index - */ --MLXSW_ITEM32(reg, hpkt, action, 0x00, 20, 3); -+MLXSW_ITEM32(reg, qeec, element_hierarchy, 0x04, 16, 4); - --/* reg_hpkt_trap_group -- * Trap group to associate the trap with. -- * Access: RW -+/* reg_qeec_element_index -+ * The index of the element in the hierarchy. -+ * Access: Index - */ --MLXSW_ITEM32(reg, hpkt, trap_group, 0x00, 12, 6); -+MLXSW_ITEM32(reg, qeec, element_index, 0x04, 0, 8); - --/* reg_hpkt_trap_id -- * Trap ID. -- * Access: Index -+/* reg_qeec_next_element_index -+ * The index of the next (lower) element in the hierarchy. -+ * Access: RW - * -- * Note: A trap ID can only be associated with a single trap group. The device -- * will associate the trap ID with the last trap group configured. -+ * Note: Reserved for element_hierarchy 0. - */ --MLXSW_ITEM32(reg, hpkt, trap_id, 0x00, 0, 9); -- --enum { -- MLXSW_REG_HPKT_CTRL_PACKET_DEFAULT, -- MLXSW_REG_HPKT_CTRL_PACKET_NO_BUFFER, -- MLXSW_REG_HPKT_CTRL_PACKET_USE_BUFFER, --}; -+MLXSW_ITEM32(reg, qeec, next_element_index, 0x08, 0, 8); - --/* reg_hpkt_ctrl -- * Configure dedicated buffer resources for control packets. -- * 0 - Keep factory defaults. -- * 1 - Do not use control buffer for this trap ID. -- * 2 - Use control buffer for this trap ID. -+/* reg_qeec_mise -+ * Min shaper configuration enable. Enables configuration of the min -+ * shaper on this ETS element -+ * 0 - Disable -+ * 1 - Enable - * Access: RW - */ --MLXSW_ITEM32(reg, hpkt, ctrl, 0x04, 16, 2); -+MLXSW_ITEM32(reg, qeec, mise, 0x0C, 31, 1); - --static inline void mlxsw_reg_hpkt_pack(char *payload, u8 action, u16 trap_id) --{ -- enum mlxsw_reg_htgt_trap_group trap_group; -- -- MLXSW_REG_ZERO(hpkt, payload); -- mlxsw_reg_hpkt_ack_set(payload, MLXSW_REG_HPKT_ACK_NOT_REQUIRED); -- mlxsw_reg_hpkt_action_set(payload, action); -- switch (trap_id) { -- case MLXSW_TRAP_ID_ETHEMAD: -- case MLXSW_TRAP_ID_PUDE: -- trap_group = MLXSW_REG_HTGT_TRAP_GROUP_EMAD; -- break; -- default: -- trap_group = MLXSW_REG_HTGT_TRAP_GROUP_RX; -- break; -- } -- mlxsw_reg_hpkt_trap_group_set(payload, trap_group); -- mlxsw_reg_hpkt_trap_id_set(payload, trap_id); -- mlxsw_reg_hpkt_ctrl_set(payload, MLXSW_REG_HPKT_CTRL_PACKET_DEFAULT); --} -+enum { -+ MLXSW_REG_QEEC_BYTES_MODE, -+ MLXSW_REG_QEEC_PACKETS_MODE, -+}; - --/* RGCR - Router General Configuration Register -- * -------------------------------------------- -- * The register is used for setting up the router configuration. -+/* reg_qeec_pb -+ * Packets or bytes mode. -+ * 0 - Bytes mode -+ * 1 - Packets mode -+ * Access: RW -+ * -+ * Note: Used for max shaper configuration. For Spectrum, packets mode -+ * is supported only for traffic classes of CPU port. - */ --#define MLXSW_REG_RGCR_ID 0x8001 --#define MLXSW_REG_RGCR_LEN 0x28 -+MLXSW_ITEM32(reg, qeec, pb, 0x0C, 28, 1); - --static const struct mlxsw_reg_info mlxsw_reg_rgcr = { -- .id = MLXSW_REG_RGCR_ID, -- .len = MLXSW_REG_RGCR_LEN, --}; -+/* The smallest permitted min shaper rate. */ -+#define MLXSW_REG_QEEC_MIS_MIN 200000 /* Kbps */ - --/* reg_rgcr_ipv4_en -- * IPv4 router enable. -+/* reg_qeec_min_shaper_rate -+ * Min shaper information rate. -+ * For CPU port, can only be configured for port hierarchy. -+ * When in bytes mode, value is specified in units of 1000bps. - * Access: RW - */ --MLXSW_ITEM32(reg, rgcr, ipv4_en, 0x00, 31, 1); -+MLXSW_ITEM32(reg, qeec, min_shaper_rate, 0x0C, 0, 28); - --/* reg_rgcr_ipv6_en -- * IPv6 router enable. -+/* reg_qeec_mase -+ * Max shaper configuration enable. Enables configuration of the max -+ * shaper on this ETS element. -+ * 0 - Disable -+ * 1 - Enable - * Access: RW - */ --MLXSW_ITEM32(reg, rgcr, ipv6_en, 0x00, 30, 1); -+MLXSW_ITEM32(reg, qeec, mase, 0x10, 31, 1); - --/* reg_rgcr_max_router_interfaces -- * Defines the maximum number of active router interfaces for all virtual -- * routers. -+/* A large max rate will disable the max shaper. */ -+#define MLXSW_REG_QEEC_MAS_DIS 200000000 /* Kbps */ -+ -+/* reg_qeec_max_shaper_rate -+ * Max shaper information rate. -+ * For CPU port, can only be configured for port hierarchy. -+ * When in bytes mode, value is specified in units of 1000bps. - * Access: RW - */ --MLXSW_ITEM32(reg, rgcr, max_router_interfaces, 0x10, 0, 16); -+MLXSW_ITEM32(reg, qeec, max_shaper_rate, 0x10, 0, 28); - --/* reg_rgcr_usp -- * Update switch priority and packet color. -- * 0 - Preserve the value of Switch Priority and packet color. -- * 1 - Recalculate the value of Switch Priority and packet color. -+/* reg_qeec_de -+ * DWRR configuration enable. Enables configuration of the dwrr and -+ * dwrr_weight. -+ * 0 - Disable -+ * 1 - Enable - * Access: RW -- * -- * Note: Not supported by SwitchX and SwitchX-2. - */ --MLXSW_ITEM32(reg, rgcr, usp, 0x18, 20, 1); -+MLXSW_ITEM32(reg, qeec, de, 0x18, 31, 1); - --/* reg_rgcr_pcp_rw -- * Indicates how to handle the pcp_rewrite_en value: -- * 0 - Preserve the value of pcp_rewrite_en. -- * 2 - Disable PCP rewrite. -- * 3 - Enable PCP rewrite. -+/* reg_qeec_dwrr -+ * Transmission selection algorithm to use on the link going down from -+ * the ETS element. -+ * 0 - Strict priority -+ * 1 - DWRR - * Access: RW -- * -- * Note: Not supported by SwitchX and SwitchX-2. - */ --MLXSW_ITEM32(reg, rgcr, pcp_rw, 0x18, 16, 2); -+MLXSW_ITEM32(reg, qeec, dwrr, 0x18, 15, 1); - --/* reg_rgcr_activity_dis -- * Activity disable: -- * 0 - Activity will be set when an entry is hit (default). -- * 1 - Activity will not be set when an entry is hit. -- * -- * Bit 0 - Disable activity bit in Router Algorithmic LPM Unicast Entry -- * (RALUE). -- * Bit 1 - Disable activity bit in Router Algorithmic LPM Unicast Host -- * Entry (RAUHT). -- * Bits 2:7 are reserved. -+/* reg_qeec_dwrr_weight -+ * DWRR weight on the link going down from the ETS element. The -+ * percentage of bandwidth guaranteed to an ETS element within -+ * its hierarchy. The sum of all weights across all ETS elements -+ * within one hierarchy should be equal to 100. Reserved when -+ * transmission selection algorithm is strict priority. - * Access: RW -- * -- * Note: Not supported by SwitchX, SwitchX-2 and Switch-IB. - */ --MLXSW_ITEM32(reg, rgcr, activity_dis, 0x20, 0, 8); -+MLXSW_ITEM32(reg, qeec, dwrr_weight, 0x18, 0, 8); - --static inline void mlxsw_reg_rgcr_pack(char *payload, bool ipv4_en) -+static inline void mlxsw_reg_qeec_pack(char *payload, u8 local_port, -+ enum mlxsw_reg_qeec_hr hr, u8 index, -+ u8 next_index) - { -- MLXSW_REG_ZERO(rgcr, payload); -- mlxsw_reg_rgcr_ipv4_en_set(payload, ipv4_en); -+ MLXSW_REG_ZERO(qeec, payload); -+ mlxsw_reg_qeec_local_port_set(payload, local_port); -+ mlxsw_reg_qeec_element_hierarchy_set(payload, hr); -+ mlxsw_reg_qeec_element_index_set(payload, index); -+ mlxsw_reg_qeec_next_element_index_set(payload, next_index); - } - --/* RITR - Router Interface Table Register -- * -------------------------------------- -- * The register is used to configure the router interface table. -+/* QRWE - QoS ReWrite Enable -+ * ------------------------- -+ * This register configures the rewrite enable per receive port. - */ --#define MLXSW_REG_RITR_ID 0x8002 --#define MLXSW_REG_RITR_LEN 0x40 -+#define MLXSW_REG_QRWE_ID 0x400F -+#define MLXSW_REG_QRWE_LEN 0x08 - --static const struct mlxsw_reg_info mlxsw_reg_ritr = { -- .id = MLXSW_REG_RITR_ID, -- .len = MLXSW_REG_RITR_LEN, --}; -+MLXSW_REG_DEFINE(qrwe, MLXSW_REG_QRWE_ID, MLXSW_REG_QRWE_LEN); - --/* reg_ritr_enable -- * Enables routing on the router interface. -- * Access: RW -+/* reg_qrwe_local_port -+ * Local port number. -+ * Access: Index -+ * -+ * Note: CPU port is supported. No support for router port. - */ --MLXSW_ITEM32(reg, ritr, enable, 0x00, 31, 1); -+MLXSW_ITEM32(reg, qrwe, local_port, 0x00, 16, 8); - --/* reg_ritr_ipv4 -- * IPv4 routing enable. Enables routing of IPv4 traffic on the router -- * interface. -+/* reg_qrwe_dscp -+ * Whether to enable DSCP rewrite (default is 0, don't rewrite). - * Access: RW - */ --MLXSW_ITEM32(reg, ritr, ipv4, 0x00, 29, 1); -+MLXSW_ITEM32(reg, qrwe, dscp, 0x04, 1, 1); - --/* reg_ritr_ipv6 -- * IPv6 routing enable. Enables routing of IPv6 traffic on the router -- * interface. -+/* reg_qrwe_pcp -+ * Whether to enable PCP and DEI rewrite (default is 0, don't rewrite). - * Access: RW - */ --MLXSW_ITEM32(reg, ritr, ipv6, 0x00, 28, 1); -+MLXSW_ITEM32(reg, qrwe, pcp, 0x04, 0, 1); - --enum mlxsw_reg_ritr_if_type { -- MLXSW_REG_RITR_VLAN_IF, -- MLXSW_REG_RITR_FID_IF, -- MLXSW_REG_RITR_SP_IF, --}; -+static inline void mlxsw_reg_qrwe_pack(char *payload, u8 local_port, -+ bool rewrite_pcp, bool rewrite_dscp) -+{ -+ MLXSW_REG_ZERO(qrwe, payload); -+ mlxsw_reg_qrwe_local_port_set(payload, local_port); -+ mlxsw_reg_qrwe_pcp_set(payload, rewrite_pcp); -+ mlxsw_reg_qrwe_dscp_set(payload, rewrite_dscp); -+} - --/* reg_ritr_type -- * Router interface type. -- * 0 - VLAN interface. -- * 1 - FID interface. -- * 2 - Sub-port interface. -- * Access: RW -+/* QPDSM - QoS Priority to DSCP Mapping -+ * ------------------------------------ -+ * QoS Priority to DSCP Mapping Register - */ --MLXSW_ITEM32(reg, ritr, type, 0x00, 23, 3); -- --enum { -- MLXSW_REG_RITR_RIF_CREATE, -- MLXSW_REG_RITR_RIF_DEL, --}; -+#define MLXSW_REG_QPDSM_ID 0x4011 -+#define MLXSW_REG_QPDSM_BASE_LEN 0x04 /* base length, without records */ -+#define MLXSW_REG_QPDSM_PRIO_ENTRY_REC_LEN 0x4 /* record length */ -+#define MLXSW_REG_QPDSM_PRIO_ENTRY_REC_MAX_COUNT 16 -+#define MLXSW_REG_QPDSM_LEN (MLXSW_REG_QPDSM_BASE_LEN + \ -+ MLXSW_REG_QPDSM_PRIO_ENTRY_REC_LEN * \ -+ MLXSW_REG_QPDSM_PRIO_ENTRY_REC_MAX_COUNT) - --/* reg_ritr_op -- * Opcode: -- * 0 - Create or edit RIF. -- * 1 - Delete RIF. -- * Reserved for SwitchX-2. For Spectrum, editing of interface properties -- * is not supported. An interface must be deleted and re-created in order -- * to update properties. -- * Access: WO -- */ --MLXSW_ITEM32(reg, ritr, op, 0x00, 20, 2); -+MLXSW_REG_DEFINE(qpdsm, MLXSW_REG_QPDSM_ID, MLXSW_REG_QPDSM_LEN); - --/* reg_ritr_rif -- * Router interface index. A pointer to the Router Interface Table. -+/* reg_qpdsm_local_port -+ * Local Port. Supported for data packets from CPU port. - * Access: Index - */ --MLXSW_ITEM32(reg, ritr, rif, 0x00, 0, 16); -+MLXSW_ITEM32(reg, qpdsm, local_port, 0x00, 16, 8); - --/* reg_ritr_ipv4_fe -- * IPv4 Forwarding Enable. -- * Enables routing of IPv4 traffic on the router interface. When disabled, -- * forwarding is blocked but local traffic (traps and IP2ME) will be enabled. -- * Not supported in SwitchX-2. -- * Access: RW -+/* reg_qpdsm_prio_entry_color0_e -+ * Enable update of the entry for color 0 and a given port. -+ * Access: WO - */ --MLXSW_ITEM32(reg, ritr, ipv4_fe, 0x04, 29, 1); -+MLXSW_ITEM32_INDEXED(reg, qpdsm, prio_entry_color0_e, -+ MLXSW_REG_QPDSM_BASE_LEN, 31, 1, -+ MLXSW_REG_QPDSM_PRIO_ENTRY_REC_LEN, 0x00, false); - --/* reg_ritr_ipv6_fe -- * IPv6 Forwarding Enable. -- * Enables routing of IPv6 traffic on the router interface. When disabled, -- * forwarding is blocked but local traffic (traps and IP2ME) will be enabled. -- * Not supported in SwitchX-2. -+/* reg_qpdsm_prio_entry_color0_dscp -+ * DSCP field in the outer label of the packet for color 0 and a given port. -+ * Reserved when e=0. - * Access: RW - */ --MLXSW_ITEM32(reg, ritr, ipv6_fe, 0x04, 28, 1); -+MLXSW_ITEM32_INDEXED(reg, qpdsm, prio_entry_color0_dscp, -+ MLXSW_REG_QPDSM_BASE_LEN, 24, 6, -+ MLXSW_REG_QPDSM_PRIO_ENTRY_REC_LEN, 0x00, false); - --/* reg_ritr_lb_en -- * Loop-back filter enable for unicast packets. -- * If the flag is set then loop-back filter for unicast packets is -- * implemented on the RIF. Multicast packets are always subject to -- * loop-back filtering. -- * Access: RW -+/* reg_qpdsm_prio_entry_color1_e -+ * Enable update of the entry for color 1 and a given port. -+ * Access: WO - */ --MLXSW_ITEM32(reg, ritr, lb_en, 0x04, 24, 1); -+MLXSW_ITEM32_INDEXED(reg, qpdsm, prio_entry_color1_e, -+ MLXSW_REG_QPDSM_BASE_LEN, 23, 1, -+ MLXSW_REG_QPDSM_PRIO_ENTRY_REC_LEN, 0x00, false); - --/* reg_ritr_virtual_router -- * Virtual router ID associated with the router interface. -+/* reg_qpdsm_prio_entry_color1_dscp -+ * DSCP field in the outer label of the packet for color 1 and a given port. -+ * Reserved when e=0. - * Access: RW - */ --MLXSW_ITEM32(reg, ritr, virtual_router, 0x04, 0, 16); -+MLXSW_ITEM32_INDEXED(reg, qpdsm, prio_entry_color1_dscp, -+ MLXSW_REG_QPDSM_BASE_LEN, 16, 6, -+ MLXSW_REG_QPDSM_PRIO_ENTRY_REC_LEN, 0x00, false); - --/* reg_ritr_mtu -- * Router interface MTU. -- * Access: RW -+/* reg_qpdsm_prio_entry_color2_e -+ * Enable update of the entry for color 2 and a given port. -+ * Access: WO - */ --MLXSW_ITEM32(reg, ritr, mtu, 0x34, 0, 16); -+MLXSW_ITEM32_INDEXED(reg, qpdsm, prio_entry_color2_e, -+ MLXSW_REG_QPDSM_BASE_LEN, 15, 1, -+ MLXSW_REG_QPDSM_PRIO_ENTRY_REC_LEN, 0x00, false); - --/* reg_ritr_if_swid -- * Switch partition ID. -+/* reg_qpdsm_prio_entry_color2_dscp -+ * DSCP field in the outer label of the packet for color 2 and a given port. -+ * Reserved when e=0. - * Access: RW - */ --MLXSW_ITEM32(reg, ritr, if_swid, 0x08, 24, 8); -+MLXSW_ITEM32_INDEXED(reg, qpdsm, prio_entry_color2_dscp, -+ MLXSW_REG_QPDSM_BASE_LEN, 8, 6, -+ MLXSW_REG_QPDSM_PRIO_ENTRY_REC_LEN, 0x00, false); - --/* reg_ritr_if_mac -- * Router interface MAC address. -- * In Spectrum, all MAC addresses must have the same 38 MSBits. -- * Access: RW -+static inline void mlxsw_reg_qpdsm_pack(char *payload, u8 local_port) -+{ -+ MLXSW_REG_ZERO(qpdsm, payload); -+ mlxsw_reg_qpdsm_local_port_set(payload, local_port); -+} -+ -+static inline void -+mlxsw_reg_qpdsm_prio_pack(char *payload, unsigned short prio, u8 dscp) -+{ -+ mlxsw_reg_qpdsm_prio_entry_color0_e_set(payload, prio, 1); -+ mlxsw_reg_qpdsm_prio_entry_color0_dscp_set(payload, prio, dscp); -+ mlxsw_reg_qpdsm_prio_entry_color1_e_set(payload, prio, 1); -+ mlxsw_reg_qpdsm_prio_entry_color1_dscp_set(payload, prio, dscp); -+ mlxsw_reg_qpdsm_prio_entry_color2_e_set(payload, prio, 1); -+ mlxsw_reg_qpdsm_prio_entry_color2_dscp_set(payload, prio, dscp); -+} -+ -+/* QPDPM - QoS Port DSCP to Priority Mapping Register -+ * -------------------------------------------------- -+ * This register controls the mapping from DSCP field to -+ * Switch Priority for IP packets. - */ --MLXSW_ITEM_BUF(reg, ritr, if_mac, 0x12, 6); -+#define MLXSW_REG_QPDPM_ID 0x4013 -+#define MLXSW_REG_QPDPM_BASE_LEN 0x4 /* base length, without records */ -+#define MLXSW_REG_QPDPM_DSCP_ENTRY_REC_LEN 0x2 /* record length */ -+#define MLXSW_REG_QPDPM_DSCP_ENTRY_REC_MAX_COUNT 64 -+#define MLXSW_REG_QPDPM_LEN (MLXSW_REG_QPDPM_BASE_LEN + \ -+ MLXSW_REG_QPDPM_DSCP_ENTRY_REC_LEN * \ -+ MLXSW_REG_QPDPM_DSCP_ENTRY_REC_MAX_COUNT) - --/* VLAN Interface */ -+MLXSW_REG_DEFINE(qpdpm, MLXSW_REG_QPDPM_ID, MLXSW_REG_QPDPM_LEN); - --/* reg_ritr_vlan_if_vid -- * VLAN ID. -- * Access: RW -+/* reg_qpdpm_local_port -+ * Local Port. Supported for data packets from CPU port. -+ * Access: Index - */ --MLXSW_ITEM32(reg, ritr, vlan_if_vid, 0x08, 0, 12); -+MLXSW_ITEM32(reg, qpdpm, local_port, 0x00, 16, 8); - --/* FID Interface */ -+/* reg_qpdpm_dscp_e -+ * Enable update of the specific entry. When cleared, the switch_prio and color -+ * fields are ignored and the previous switch_prio and color values are -+ * preserved. -+ * Access: WO -+ */ -+MLXSW_ITEM16_INDEXED(reg, qpdpm, dscp_entry_e, MLXSW_REG_QPDPM_BASE_LEN, 15, 1, -+ MLXSW_REG_QPDPM_DSCP_ENTRY_REC_LEN, 0x00, false); - --/* reg_ritr_fid_if_fid -- * Filtering ID. Used to connect a bridge to the router. Only FIDs from -- * the vFID range are supported. -+/* reg_qpdpm_dscp_prio -+ * The new Switch Priority value for the relevant DSCP value. - * Access: RW - */ --MLXSW_ITEM32(reg, ritr, fid_if_fid, 0x08, 0, 16); -+MLXSW_ITEM16_INDEXED(reg, qpdpm, dscp_entry_prio, -+ MLXSW_REG_QPDPM_BASE_LEN, 0, 4, -+ MLXSW_REG_QPDPM_DSCP_ENTRY_REC_LEN, 0x00, false); - --static inline void mlxsw_reg_ritr_fid_set(char *payload, -- enum mlxsw_reg_ritr_if_type rif_type, -- u16 fid) -+static inline void mlxsw_reg_qpdpm_pack(char *payload, u8 local_port) - { -- if (rif_type == MLXSW_REG_RITR_FID_IF) -- mlxsw_reg_ritr_fid_if_fid_set(payload, fid); -- else -- mlxsw_reg_ritr_vlan_if_vid_set(payload, fid); -+ MLXSW_REG_ZERO(qpdpm, payload); -+ mlxsw_reg_qpdpm_local_port_set(payload, local_port); - } - --/* Sub-port Interface */ -+static inline void -+mlxsw_reg_qpdpm_dscp_pack(char *payload, unsigned short dscp, u8 prio) -+{ -+ mlxsw_reg_qpdpm_dscp_entry_e_set(payload, dscp, 1); -+ mlxsw_reg_qpdpm_dscp_entry_prio_set(payload, dscp, prio); -+} - --/* reg_ritr_sp_if_lag -- * LAG indication. When this bit is set the system_port field holds the -- * LAG identifier. -- * Access: RW -+/* QTCTM - QoS Switch Traffic Class Table is Multicast-Aware Register -+ * ------------------------------------------------------------------ -+ * This register configures if the Switch Priority to Traffic Class mapping is -+ * based on Multicast packet indication. If so, then multicast packets will get -+ * a Traffic Class that is plus (cap_max_tclass_data/2) the value configured by -+ * QTCT. -+ * By default, Switch Priority to Traffic Class mapping is not based on -+ * Multicast packet indication. - */ --MLXSW_ITEM32(reg, ritr, sp_if_lag, 0x08, 24, 1); -+#define MLXSW_REG_QTCTM_ID 0x401A -+#define MLXSW_REG_QTCTM_LEN 0x08 - --/* reg_ritr_sp_system_port -- * Port unique indentifier. When lag bit is set, this field holds the -- * lag_id in bits 0:9. -- * Access: RW -+MLXSW_REG_DEFINE(qtctm, MLXSW_REG_QTCTM_ID, MLXSW_REG_QTCTM_LEN); -+ -+/* reg_qtctm_local_port -+ * Local port number. -+ * No support for CPU port. -+ * Access: Index - */ --MLXSW_ITEM32(reg, ritr, sp_if_system_port, 0x08, 0, 16); -+MLXSW_ITEM32(reg, qtctm, local_port, 0x00, 16, 8); - --/* reg_ritr_sp_if_vid -- * VLAN ID. -- * Access: RW -+/* reg_qtctm_mc -+ * Multicast Mode -+ * Whether Switch Priority to Traffic Class mapping is based on Multicast packet -+ * indication (default is 0, not based on Multicast packet indication). - */ --MLXSW_ITEM32(reg, ritr, sp_if_vid, 0x18, 0, 12); -+MLXSW_ITEM32(reg, qtctm, mc, 0x04, 0, 1); - --static inline void mlxsw_reg_ritr_rif_pack(char *payload, u16 rif) -+static inline void -+mlxsw_reg_qtctm_pack(char *payload, u8 local_port, bool mc) - { -- MLXSW_REG_ZERO(ritr, payload); -- mlxsw_reg_ritr_rif_set(payload, rif); -+ MLXSW_REG_ZERO(qtctm, payload); -+ mlxsw_reg_qtctm_local_port_set(payload, local_port); -+ mlxsw_reg_qtctm_mc_set(payload, mc); - } - --static inline void mlxsw_reg_ritr_sp_if_pack(char *payload, bool lag, -- u16 system_port, u16 vid) --{ -- mlxsw_reg_ritr_sp_if_lag_set(payload, lag); -- mlxsw_reg_ritr_sp_if_system_port_set(payload, system_port); -- mlxsw_reg_ritr_sp_if_vid_set(payload, vid); --} -+/* PMLP - Ports Module to Local Port Register -+ * ------------------------------------------ -+ * Configures the assignment of modules to local ports. -+ */ -+#define MLXSW_REG_PMLP_ID 0x5002 -+#define MLXSW_REG_PMLP_LEN 0x40 - --static inline void mlxsw_reg_ritr_pack(char *payload, bool enable, -- enum mlxsw_reg_ritr_if_type type, -- u16 rif, u16 mtu, const char *mac) --{ -- bool op = enable ? MLXSW_REG_RITR_RIF_CREATE : MLXSW_REG_RITR_RIF_DEL; -+MLXSW_REG_DEFINE(pmlp, MLXSW_REG_PMLP_ID, MLXSW_REG_PMLP_LEN); - -- MLXSW_REG_ZERO(ritr, payload); -- mlxsw_reg_ritr_enable_set(payload, enable); -- mlxsw_reg_ritr_ipv4_set(payload, 1); -- mlxsw_reg_ritr_type_set(payload, type); -- mlxsw_reg_ritr_op_set(payload, op); -- mlxsw_reg_ritr_rif_set(payload, rif); -- mlxsw_reg_ritr_ipv4_fe_set(payload, 1); -- mlxsw_reg_ritr_lb_en_set(payload, 1); -- mlxsw_reg_ritr_mtu_set(payload, mtu); -- mlxsw_reg_ritr_if_mac_memcpy_to(payload, mac); --} -+/* reg_pmlp_rxtx -+ * 0 - Tx value is used for both Tx and Rx. -+ * 1 - Rx value is taken from a separte field. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pmlp, rxtx, 0x00, 31, 1); - --/* RATR - Router Adjacency Table Register -- * -------------------------------------- -- * The RATR register is used to configure the Router Adjacency (next-hop) -- * Table. -+/* reg_pmlp_local_port -+ * Local port number. -+ * Access: Index - */ --#define MLXSW_REG_RATR_ID 0x8008 --#define MLXSW_REG_RATR_LEN 0x2C -+MLXSW_ITEM32(reg, pmlp, local_port, 0x00, 16, 8); - --static const struct mlxsw_reg_info mlxsw_reg_ratr = { -- .id = MLXSW_REG_RATR_ID, -- .len = MLXSW_REG_RATR_LEN, --}; -+/* reg_pmlp_width -+ * 0 - Unmap local port. -+ * 1 - Lane 0 is used. -+ * 2 - Lanes 0 and 1 are used. -+ * 4 - Lanes 0, 1, 2 and 3 are used. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pmlp, width, 0x00, 0, 8); - --enum mlxsw_reg_ratr_op { -- /* Read */ -- MLXSW_REG_RATR_OP_QUERY_READ = 0, -- /* Read and clear activity */ -- MLXSW_REG_RATR_OP_QUERY_READ_CLEAR = 2, -- /* Write Adjacency entry */ -- MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY = 1, -- /* Write Adjacency entry only if the activity is cleared. -- * The write may not succeed if the activity is set. There is not -- * direct feedback if the write has succeeded or not, however -- * the get will reveal the actual entry (SW can compare the get -- * response to the set command). -- */ -- MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY = 3, -+/* reg_pmlp_module -+ * Module number. -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, pmlp, module, 0x04, 0, 8, 0x04, 0x00, false); -+ -+/* reg_pmlp_tx_lane -+ * Tx Lane. When rxtx field is cleared, this field is used for Rx as well. -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, pmlp, tx_lane, 0x04, 16, 2, 0x04, 0x00, false); -+ -+/* reg_pmlp_rx_lane -+ * Rx Lane. When rxtx field is cleared, this field is ignored and Rx lane is -+ * equal to Tx lane. -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, pmlp, rx_lane, 0x04, 24, 2, 0x04, 0x00, false); -+ -+static inline void mlxsw_reg_pmlp_pack(char *payload, u8 local_port) -+{ -+ MLXSW_REG_ZERO(pmlp, payload); -+ mlxsw_reg_pmlp_local_port_set(payload, local_port); -+} -+ -+/* PMTU - Port MTU Register -+ * ------------------------ -+ * Configures and reports the port MTU. -+ */ -+#define MLXSW_REG_PMTU_ID 0x5003 -+#define MLXSW_REG_PMTU_LEN 0x10 -+ -+MLXSW_REG_DEFINE(pmtu, MLXSW_REG_PMTU_ID, MLXSW_REG_PMTU_LEN); -+ -+/* reg_pmtu_local_port -+ * Local port number. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, pmtu, local_port, 0x00, 16, 8); -+ -+/* reg_pmtu_max_mtu -+ * Maximum MTU. -+ * When port type (e.g. Ethernet) is configured, the relevant MTU is -+ * reported, otherwise the minimum between the max_mtu of the different -+ * types is reported. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, pmtu, max_mtu, 0x04, 16, 16); -+ -+/* reg_pmtu_admin_mtu -+ * MTU value to set port to. Must be smaller or equal to max_mtu. -+ * Note: If port type is Infiniband, then port must be disabled, when its -+ * MTU is set. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pmtu, admin_mtu, 0x08, 16, 16); -+ -+/* reg_pmtu_oper_mtu -+ * The actual MTU configured on the port. Packets exceeding this size -+ * will be dropped. -+ * Note: In Ethernet and FC oper_mtu == admin_mtu, however, in Infiniband -+ * oper_mtu might be smaller than admin_mtu. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, pmtu, oper_mtu, 0x0C, 16, 16); -+ -+static inline void mlxsw_reg_pmtu_pack(char *payload, u8 local_port, -+ u16 new_mtu) -+{ -+ MLXSW_REG_ZERO(pmtu, payload); -+ mlxsw_reg_pmtu_local_port_set(payload, local_port); -+ mlxsw_reg_pmtu_max_mtu_set(payload, 0); -+ mlxsw_reg_pmtu_admin_mtu_set(payload, new_mtu); -+ mlxsw_reg_pmtu_oper_mtu_set(payload, 0); -+} -+ -+/* PTYS - Port Type and Speed Register -+ * ----------------------------------- -+ * Configures and reports the port speed type. -+ * -+ * Note: When set while the link is up, the changes will not take effect -+ * until the port transitions from down to up state. -+ */ -+#define MLXSW_REG_PTYS_ID 0x5004 -+#define MLXSW_REG_PTYS_LEN 0x40 -+ -+MLXSW_REG_DEFINE(ptys, MLXSW_REG_PTYS_ID, MLXSW_REG_PTYS_LEN); -+ -+/* an_disable_admin -+ * Auto negotiation disable administrative configuration -+ * 0 - Device doesn't support AN disable. -+ * 1 - Device supports AN disable. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ptys, an_disable_admin, 0x00, 30, 1); -+ -+/* reg_ptys_local_port -+ * Local port number. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ptys, local_port, 0x00, 16, 8); -+ -+#define MLXSW_REG_PTYS_PROTO_MASK_IB BIT(0) -+#define MLXSW_REG_PTYS_PROTO_MASK_ETH BIT(2) -+ -+/* reg_ptys_proto_mask -+ * Protocol mask. Indicates which protocol is used. -+ * 0 - Infiniband. -+ * 1 - Fibre Channel. -+ * 2 - Ethernet. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ptys, proto_mask, 0x00, 0, 3); -+ -+enum { -+ MLXSW_REG_PTYS_AN_STATUS_NA, -+ MLXSW_REG_PTYS_AN_STATUS_OK, -+ MLXSW_REG_PTYS_AN_STATUS_FAIL, - }; - --/* reg_ratr_op -- * Note that Write operation may also be used for updating -- * counter_set_type and counter_index. In this case all other -- * fields must not be updated. -- * Access: OP -+/* reg_ptys_an_status -+ * Autonegotiation status. -+ * Access: RO - */ --MLXSW_ITEM32(reg, ratr, op, 0x00, 28, 4); -+MLXSW_ITEM32(reg, ptys, an_status, 0x04, 28, 4); - --/* reg_ratr_v -- * Valid bit. Indicates if the adjacency entry is valid. -- * Note: the device may need some time before reusing an invalidated -- * entry. During this time the entry can not be reused. It is -- * recommended to use another entry before reusing an invalidated -- * entry (e.g. software can put it at the end of the list for -- * reusing). Trying to access an invalidated entry not yet cleared -- * by the device results with failure indicating "Try Again" status. -- * When valid is '0' then egress_router_interface,trap_action, -- * adjacency_parameters and counters are reserved -+#define MLXSW_REG_PTYS_ETH_SPEED_SGMII BIT(0) -+#define MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX BIT(1) -+#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 BIT(2) -+#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 BIT(3) -+#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR BIT(4) -+#define MLXSW_REG_PTYS_ETH_SPEED_20GBASE_KR2 BIT(5) -+#define MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 BIT(6) -+#define MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 BIT(7) -+#define MLXSW_REG_PTYS_ETH_SPEED_56GBASE_R4 BIT(8) -+#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR BIT(12) -+#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR BIT(13) -+#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_ER_LR BIT(14) -+#define MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 BIT(15) -+#define MLXSW_REG_PTYS_ETH_SPEED_40GBASE_LR4_ER4 BIT(16) -+#define MLXSW_REG_PTYS_ETH_SPEED_50GBASE_SR2 BIT(18) -+#define MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR4 BIT(19) -+#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4 BIT(20) -+#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 BIT(21) -+#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 BIT(22) -+#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4 BIT(23) -+#define MLXSW_REG_PTYS_ETH_SPEED_100BASE_TX BIT(24) -+#define MLXSW_REG_PTYS_ETH_SPEED_100BASE_T BIT(25) -+#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_T BIT(26) -+#define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR BIT(27) -+#define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR BIT(28) -+#define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR BIT(29) -+#define MLXSW_REG_PTYS_ETH_SPEED_50GBASE_CR2 BIT(30) -+#define MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR2 BIT(31) -+ -+/* reg_ptys_eth_proto_cap -+ * Ethernet port supported speeds and protocols. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, ptys, eth_proto_cap, 0x0C, 0, 32); -+ -+/* reg_ptys_ib_link_width_cap -+ * IB port supported widths. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, ptys, ib_link_width_cap, 0x10, 16, 16); -+ -+#define MLXSW_REG_PTYS_IB_SPEED_SDR BIT(0) -+#define MLXSW_REG_PTYS_IB_SPEED_DDR BIT(1) -+#define MLXSW_REG_PTYS_IB_SPEED_QDR BIT(2) -+#define MLXSW_REG_PTYS_IB_SPEED_FDR10 BIT(3) -+#define MLXSW_REG_PTYS_IB_SPEED_FDR BIT(4) -+#define MLXSW_REG_PTYS_IB_SPEED_EDR BIT(5) -+ -+/* reg_ptys_ib_proto_cap -+ * IB port supported speeds and protocols. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, ptys, ib_proto_cap, 0x10, 0, 16); -+ -+/* reg_ptys_eth_proto_admin -+ * Speed and protocol to set port to. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ptys, eth_proto_admin, 0x18, 0, 32); -+ -+/* reg_ptys_ib_link_width_admin -+ * IB width to set port to. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ptys, ib_link_width_admin, 0x1C, 16, 16); -+ -+/* reg_ptys_ib_proto_admin -+ * IB speeds and protocols to set port to. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ptys, ib_proto_admin, 0x1C, 0, 16); -+ -+/* reg_ptys_eth_proto_oper -+ * The current speed and protocol configured for the port. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, ptys, eth_proto_oper, 0x24, 0, 32); -+ -+/* reg_ptys_ib_link_width_oper -+ * The current IB width to set port to. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, ptys, ib_link_width_oper, 0x28, 16, 16); -+ -+/* reg_ptys_ib_proto_oper -+ * The current IB speed and protocol. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, ptys, ib_proto_oper, 0x28, 0, 16); -+ -+/* reg_ptys_eth_proto_lp_advertise -+ * The protocols that were advertised by the link partner during -+ * autonegotiation. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, ptys, eth_proto_lp_advertise, 0x30, 0, 32); -+ -+static inline void mlxsw_reg_ptys_eth_pack(char *payload, u8 local_port, -+ u32 proto_admin, bool autoneg) -+{ -+ MLXSW_REG_ZERO(ptys, payload); -+ mlxsw_reg_ptys_local_port_set(payload, local_port); -+ mlxsw_reg_ptys_proto_mask_set(payload, MLXSW_REG_PTYS_PROTO_MASK_ETH); -+ mlxsw_reg_ptys_eth_proto_admin_set(payload, proto_admin); -+ mlxsw_reg_ptys_an_disable_admin_set(payload, !autoneg); -+} -+ -+static inline void mlxsw_reg_ptys_eth_unpack(char *payload, -+ u32 *p_eth_proto_cap, -+ u32 *p_eth_proto_adm, -+ u32 *p_eth_proto_oper) -+{ -+ if (p_eth_proto_cap) -+ *p_eth_proto_cap = mlxsw_reg_ptys_eth_proto_cap_get(payload); -+ if (p_eth_proto_adm) -+ *p_eth_proto_adm = mlxsw_reg_ptys_eth_proto_admin_get(payload); -+ if (p_eth_proto_oper) -+ *p_eth_proto_oper = mlxsw_reg_ptys_eth_proto_oper_get(payload); -+} -+ -+static inline void mlxsw_reg_ptys_ib_pack(char *payload, u8 local_port, -+ u16 proto_admin, u16 link_width) -+{ -+ MLXSW_REG_ZERO(ptys, payload); -+ mlxsw_reg_ptys_local_port_set(payload, local_port); -+ mlxsw_reg_ptys_proto_mask_set(payload, MLXSW_REG_PTYS_PROTO_MASK_IB); -+ mlxsw_reg_ptys_ib_proto_admin_set(payload, proto_admin); -+ mlxsw_reg_ptys_ib_link_width_admin_set(payload, link_width); -+} -+ -+static inline void mlxsw_reg_ptys_ib_unpack(char *payload, u16 *p_ib_proto_cap, -+ u16 *p_ib_link_width_cap, -+ u16 *p_ib_proto_oper, -+ u16 *p_ib_link_width_oper) -+{ -+ if (p_ib_proto_cap) -+ *p_ib_proto_cap = mlxsw_reg_ptys_ib_proto_cap_get(payload); -+ if (p_ib_link_width_cap) -+ *p_ib_link_width_cap = -+ mlxsw_reg_ptys_ib_link_width_cap_get(payload); -+ if (p_ib_proto_oper) -+ *p_ib_proto_oper = mlxsw_reg_ptys_ib_proto_oper_get(payload); -+ if (p_ib_link_width_oper) -+ *p_ib_link_width_oper = -+ mlxsw_reg_ptys_ib_link_width_oper_get(payload); -+} -+ -+/* PPAD - Port Physical Address Register -+ * ------------------------------------- -+ * The PPAD register configures the per port physical MAC address. -+ */ -+#define MLXSW_REG_PPAD_ID 0x5005 -+#define MLXSW_REG_PPAD_LEN 0x10 -+ -+MLXSW_REG_DEFINE(ppad, MLXSW_REG_PPAD_ID, MLXSW_REG_PPAD_LEN); -+ -+/* reg_ppad_single_base_mac -+ * 0: base_mac, local port should be 0 and mac[7:0] is -+ * reserved. HW will set incremental -+ * 1: single_mac - mac of the local_port -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ppad, single_base_mac, 0x00, 28, 1); -+ -+/* reg_ppad_local_port -+ * port number, if single_base_mac = 0 then local_port is reserved -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ppad, local_port, 0x00, 16, 8); -+ -+/* reg_ppad_mac -+ * If single_base_mac = 0 - base MAC address, mac[7:0] is reserved. -+ * If single_base_mac = 1 - the per port MAC address -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, ppad, mac, 0x02, 6); -+ -+static inline void mlxsw_reg_ppad_pack(char *payload, bool single_base_mac, -+ u8 local_port) -+{ -+ MLXSW_REG_ZERO(ppad, payload); -+ mlxsw_reg_ppad_single_base_mac_set(payload, !!single_base_mac); -+ mlxsw_reg_ppad_local_port_set(payload, local_port); -+} -+ -+/* PAOS - Ports Administrative and Operational Status Register -+ * ----------------------------------------------------------- -+ * Configures and retrieves per port administrative and operational status. -+ */ -+#define MLXSW_REG_PAOS_ID 0x5006 -+#define MLXSW_REG_PAOS_LEN 0x10 -+ -+MLXSW_REG_DEFINE(paos, MLXSW_REG_PAOS_ID, MLXSW_REG_PAOS_LEN); -+ -+/* reg_paos_swid -+ * Switch partition ID with which to associate the port. -+ * Note: while external ports uses unique local port numbers (and thus swid is -+ * redundant), router ports use the same local port number where swid is the -+ * only indication for the relevant port. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, paos, swid, 0x00, 24, 8); -+ -+/* reg_paos_local_port -+ * Local port number. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, paos, local_port, 0x00, 16, 8); -+ -+/* reg_paos_admin_status -+ * Port administrative state (the desired state of the port): -+ * 1 - Up. -+ * 2 - Down. -+ * 3 - Up once. This means that in case of link failure, the port won't go -+ * into polling mode, but will wait to be re-enabled by software. -+ * 4 - Disabled by system. Can only be set by hardware. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, paos, admin_status, 0x00, 8, 4); -+ -+/* reg_paos_oper_status -+ * Port operational state (the current state): -+ * 1 - Up. -+ * 2 - Down. -+ * 3 - Down by port failure. This means that the device will not let the -+ * port up again until explicitly specified by software. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, paos, oper_status, 0x00, 0, 4); -+ -+/* reg_paos_ase -+ * Admin state update enabled. -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, paos, ase, 0x04, 31, 1); -+ -+/* reg_paos_ee -+ * Event update enable. If this bit is set, event generation will be -+ * updated based on the e field. -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, paos, ee, 0x04, 30, 1); -+ -+/* reg_paos_e -+ * Event generation on operational state change: -+ * 0 - Do not generate event. -+ * 1 - Generate Event. -+ * 2 - Generate Single Event. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, paos, e, 0x04, 0, 2); -+ -+static inline void mlxsw_reg_paos_pack(char *payload, u8 local_port, -+ enum mlxsw_port_admin_status status) -+{ -+ MLXSW_REG_ZERO(paos, payload); -+ mlxsw_reg_paos_swid_set(payload, 0); -+ mlxsw_reg_paos_local_port_set(payload, local_port); -+ mlxsw_reg_paos_admin_status_set(payload, status); -+ mlxsw_reg_paos_oper_status_set(payload, 0); -+ mlxsw_reg_paos_ase_set(payload, 1); -+ mlxsw_reg_paos_ee_set(payload, 1); -+ mlxsw_reg_paos_e_set(payload, 1); -+} -+ -+/* PFCC - Ports Flow Control Configuration Register -+ * ------------------------------------------------ -+ * Configures and retrieves the per port flow control configuration. -+ */ -+#define MLXSW_REG_PFCC_ID 0x5007 -+#define MLXSW_REG_PFCC_LEN 0x20 -+ -+MLXSW_REG_DEFINE(pfcc, MLXSW_REG_PFCC_ID, MLXSW_REG_PFCC_LEN); -+ -+/* reg_pfcc_local_port -+ * Local port number. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, pfcc, local_port, 0x00, 16, 8); -+ -+/* reg_pfcc_pnat -+ * Port number access type. Determines the way local_port is interpreted: -+ * 0 - Local port number. -+ * 1 - IB / label port number. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, pfcc, pnat, 0x00, 14, 2); -+ -+/* reg_pfcc_shl_cap -+ * Send to higher layers capabilities: -+ * 0 - No capability of sending Pause and PFC frames to higher layers. -+ * 1 - Device has capability of sending Pause and PFC frames to higher -+ * layers. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, pfcc, shl_cap, 0x00, 1, 1); -+ -+/* reg_pfcc_shl_opr -+ * Send to higher layers operation: -+ * 0 - Pause and PFC frames are handled by the port (default). -+ * 1 - Pause and PFC frames are handled by the port and also sent to -+ * higher layers. Only valid if shl_cap = 1. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pfcc, shl_opr, 0x00, 0, 1); -+ -+/* reg_pfcc_ppan -+ * Pause policy auto negotiation. -+ * 0 - Disabled. Generate / ignore Pause frames based on pptx / pprtx. -+ * 1 - Enabled. When auto-negotiation is performed, set the Pause policy -+ * based on the auto-negotiation resolution. -+ * Access: RW -+ * -+ * Note: The auto-negotiation advertisement is set according to pptx and -+ * pprtx. When PFC is set on Tx / Rx, ppan must be set to 0. -+ */ -+MLXSW_ITEM32(reg, pfcc, ppan, 0x04, 28, 4); -+ -+/* reg_pfcc_prio_mask_tx -+ * Bit per priority indicating if Tx flow control policy should be -+ * updated based on bit pfctx. -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, pfcc, prio_mask_tx, 0x04, 16, 8); -+ -+/* reg_pfcc_prio_mask_rx -+ * Bit per priority indicating if Rx flow control policy should be -+ * updated based on bit pfcrx. -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, pfcc, prio_mask_rx, 0x04, 0, 8); -+ -+/* reg_pfcc_pptx -+ * Admin Pause policy on Tx. -+ * 0 - Never generate Pause frames (default). -+ * 1 - Generate Pause frames according to Rx buffer threshold. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pfcc, pptx, 0x08, 31, 1); -+ -+/* reg_pfcc_aptx -+ * Active (operational) Pause policy on Tx. -+ * 0 - Never generate Pause frames. -+ * 1 - Generate Pause frames according to Rx buffer threshold. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, pfcc, aptx, 0x08, 30, 1); -+ -+/* reg_pfcc_pfctx -+ * Priority based flow control policy on Tx[7:0]. Per-priority bit mask: -+ * 0 - Never generate priority Pause frames on the specified priority -+ * (default). -+ * 1 - Generate priority Pause frames according to Rx buffer threshold on -+ * the specified priority. -+ * Access: RW -+ * -+ * Note: pfctx and pptx must be mutually exclusive. -+ */ -+MLXSW_ITEM32(reg, pfcc, pfctx, 0x08, 16, 8); -+ -+/* reg_pfcc_pprx -+ * Admin Pause policy on Rx. -+ * 0 - Ignore received Pause frames (default). -+ * 1 - Respect received Pause frames. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pfcc, pprx, 0x0C, 31, 1); -+ -+/* reg_pfcc_aprx -+ * Active (operational) Pause policy on Rx. -+ * 0 - Ignore received Pause frames. -+ * 1 - Respect received Pause frames. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, pfcc, aprx, 0x0C, 30, 1); -+ -+/* reg_pfcc_pfcrx -+ * Priority based flow control policy on Rx[7:0]. Per-priority bit mask: -+ * 0 - Ignore incoming priority Pause frames on the specified priority -+ * (default). -+ * 1 - Respect incoming priority Pause frames on the specified priority. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pfcc, pfcrx, 0x0C, 16, 8); -+ -+#define MLXSW_REG_PFCC_ALL_PRIO 0xFF -+ -+static inline void mlxsw_reg_pfcc_prio_pack(char *payload, u8 pfc_en) -+{ -+ mlxsw_reg_pfcc_prio_mask_tx_set(payload, MLXSW_REG_PFCC_ALL_PRIO); -+ mlxsw_reg_pfcc_prio_mask_rx_set(payload, MLXSW_REG_PFCC_ALL_PRIO); -+ mlxsw_reg_pfcc_pfctx_set(payload, pfc_en); -+ mlxsw_reg_pfcc_pfcrx_set(payload, pfc_en); -+} -+ -+static inline void mlxsw_reg_pfcc_pack(char *payload, u8 local_port) -+{ -+ MLXSW_REG_ZERO(pfcc, payload); -+ mlxsw_reg_pfcc_local_port_set(payload, local_port); -+} -+ -+/* PPCNT - Ports Performance Counters Register -+ * ------------------------------------------- -+ * The PPCNT register retrieves per port performance counters. -+ */ -+#define MLXSW_REG_PPCNT_ID 0x5008 -+#define MLXSW_REG_PPCNT_LEN 0x100 -+#define MLXSW_REG_PPCNT_COUNTERS_OFFSET 0x08 -+ -+MLXSW_REG_DEFINE(ppcnt, MLXSW_REG_PPCNT_ID, MLXSW_REG_PPCNT_LEN); -+ -+/* reg_ppcnt_swid -+ * For HCA: must be always 0. -+ * Switch partition ID to associate port with. -+ * Switch partitions are numbered from 0 to 7 inclusively. -+ * Switch partition 254 indicates stacking ports. -+ * Switch partition 255 indicates all switch partitions. -+ * Only valid on Set() operation with local_port=255. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ppcnt, swid, 0x00, 24, 8); -+ -+/* reg_ppcnt_local_port -+ * Local port number. -+ * 255 indicates all ports on the device, and is only allowed -+ * for Set() operation. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ppcnt, local_port, 0x00, 16, 8); -+ -+/* reg_ppcnt_pnat -+ * Port number access type: -+ * 0 - Local port number -+ * 1 - IB port number -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ppcnt, pnat, 0x00, 14, 2); -+ -+enum mlxsw_reg_ppcnt_grp { -+ MLXSW_REG_PPCNT_IEEE_8023_CNT = 0x0, -+ MLXSW_REG_PPCNT_RFC_2819_CNT = 0x2, -+ MLXSW_REG_PPCNT_EXT_CNT = 0x5, -+ MLXSW_REG_PPCNT_PRIO_CNT = 0x10, -+ MLXSW_REG_PPCNT_TC_CNT = 0x11, -+ MLXSW_REG_PPCNT_TC_CONG_TC = 0x13, -+}; -+ -+/* reg_ppcnt_grp -+ * Performance counter group. -+ * Group 63 indicates all groups. Only valid on Set() operation with -+ * clr bit set. -+ * 0x0: IEEE 802.3 Counters -+ * 0x1: RFC 2863 Counters -+ * 0x2: RFC 2819 Counters -+ * 0x3: RFC 3635 Counters -+ * 0x5: Ethernet Extended Counters -+ * 0x8: Link Level Retransmission Counters -+ * 0x10: Per Priority Counters -+ * 0x11: Per Traffic Class Counters -+ * 0x12: Physical Layer Counters -+ * 0x13: Per Traffic Class Congestion Counters -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ppcnt, grp, 0x00, 0, 6); -+ -+/* reg_ppcnt_clr -+ * Clear counters. Setting the clr bit will reset the counter value -+ * for all counters in the counter group. This bit can be set -+ * for both Set() and Get() operation. -+ * Access: OP -+ */ -+MLXSW_ITEM32(reg, ppcnt, clr, 0x04, 31, 1); -+ -+/* reg_ppcnt_prio_tc -+ * Priority for counter set that support per priority, valid values: 0-7. -+ * Traffic class for counter set that support per traffic class, -+ * valid values: 0- cap_max_tclass-1 . -+ * For HCA: cap_max_tclass is always 8. -+ * Otherwise must be 0. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ppcnt, prio_tc, 0x04, 0, 5); -+ -+/* Ethernet IEEE 802.3 Counter Group */ -+ -+/* reg_ppcnt_a_frames_transmitted_ok -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_frames_transmitted_ok, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x00, 0, 64); -+ -+/* reg_ppcnt_a_frames_received_ok -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_frames_received_ok, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x08, 0, 64); -+ -+/* reg_ppcnt_a_frame_check_sequence_errors -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_frame_check_sequence_errors, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x10, 0, 64); -+ -+/* reg_ppcnt_a_alignment_errors -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_alignment_errors, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x18, 0, 64); -+ -+/* reg_ppcnt_a_octets_transmitted_ok -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_octets_transmitted_ok, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x20, 0, 64); -+ -+/* reg_ppcnt_a_octets_received_ok -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_octets_received_ok, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x28, 0, 64); -+ -+/* reg_ppcnt_a_multicast_frames_xmitted_ok -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_multicast_frames_xmitted_ok, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x30, 0, 64); -+ -+/* reg_ppcnt_a_broadcast_frames_xmitted_ok -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_broadcast_frames_xmitted_ok, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x38, 0, 64); -+ -+/* reg_ppcnt_a_multicast_frames_received_ok -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_multicast_frames_received_ok, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x40, 0, 64); -+ -+/* reg_ppcnt_a_broadcast_frames_received_ok -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_broadcast_frames_received_ok, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x48, 0, 64); -+ -+/* reg_ppcnt_a_in_range_length_errors -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_in_range_length_errors, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x50, 0, 64); -+ -+/* reg_ppcnt_a_out_of_range_length_field -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_out_of_range_length_field, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x58, 0, 64); -+ -+/* reg_ppcnt_a_frame_too_long_errors -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_frame_too_long_errors, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x60, 0, 64); -+ -+/* reg_ppcnt_a_symbol_error_during_carrier -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_symbol_error_during_carrier, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x68, 0, 64); -+ -+/* reg_ppcnt_a_mac_control_frames_transmitted -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_mac_control_frames_transmitted, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x70, 0, 64); -+ -+/* reg_ppcnt_a_mac_control_frames_received -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_mac_control_frames_received, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x78, 0, 64); -+ -+/* reg_ppcnt_a_unsupported_opcodes_received -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_unsupported_opcodes_received, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x80, 0, 64); -+ -+/* reg_ppcnt_a_pause_mac_ctrl_frames_received -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_pause_mac_ctrl_frames_received, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x88, 0, 64); -+ -+/* reg_ppcnt_a_pause_mac_ctrl_frames_transmitted -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, a_pause_mac_ctrl_frames_transmitted, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x90, 0, 64); -+ -+/* Ethernet RFC 2819 Counter Group */ -+ -+/* reg_ppcnt_ether_stats_pkts64octets -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, ether_stats_pkts64octets, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x58, 0, 64); -+ -+/* reg_ppcnt_ether_stats_pkts65to127octets -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, ether_stats_pkts65to127octets, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x60, 0, 64); -+ -+/* reg_ppcnt_ether_stats_pkts128to255octets -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, ether_stats_pkts128to255octets, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x68, 0, 64); -+ -+/* reg_ppcnt_ether_stats_pkts256to511octets -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, ether_stats_pkts256to511octets, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x70, 0, 64); -+ -+/* reg_ppcnt_ether_stats_pkts512to1023octets -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, ether_stats_pkts512to1023octets, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x78, 0, 64); -+ -+/* reg_ppcnt_ether_stats_pkts1024to1518octets -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, ether_stats_pkts1024to1518octets, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x80, 0, 64); -+ -+/* reg_ppcnt_ether_stats_pkts1519to2047octets -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, ether_stats_pkts1519to2047octets, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x88, 0, 64); -+ -+/* reg_ppcnt_ether_stats_pkts2048to4095octets -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, ether_stats_pkts2048to4095octets, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x90, 0, 64); -+ -+/* reg_ppcnt_ether_stats_pkts4096to8191octets -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, ether_stats_pkts4096to8191octets, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x98, 0, 64); -+ -+/* reg_ppcnt_ether_stats_pkts8192to10239octets -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, ether_stats_pkts8192to10239octets, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0xA0, 0, 64); -+ -+/* Ethernet Extended Counter Group Counters */ -+ -+/* reg_ppcnt_ecn_marked -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, ecn_marked, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x08, 0, 64); -+ -+/* Ethernet Per Priority Group Counters */ -+ -+/* reg_ppcnt_rx_octets -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, rx_octets, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x00, 0, 64); -+ -+/* reg_ppcnt_rx_frames -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, rx_frames, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x20, 0, 64); -+ -+/* reg_ppcnt_tx_octets -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, tx_octets, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x28, 0, 64); -+ -+/* reg_ppcnt_tx_frames -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, tx_frames, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x48, 0, 64); -+ -+/* reg_ppcnt_rx_pause -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, rx_pause, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x50, 0, 64); -+ -+/* reg_ppcnt_rx_pause_duration -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, rx_pause_duration, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x58, 0, 64); -+ -+/* reg_ppcnt_tx_pause -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, tx_pause, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x60, 0, 64); -+ -+/* reg_ppcnt_tx_pause_duration -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, tx_pause_duration, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x68, 0, 64); -+ -+/* reg_ppcnt_rx_pause_transition -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, tx_pause_transition, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x70, 0, 64); -+ -+/* Ethernet Per Traffic Group Counters */ -+ -+/* reg_ppcnt_tc_transmit_queue -+ * Contains the transmit queue depth in cells of traffic class -+ * selected by prio_tc and the port selected by local_port. -+ * The field cannot be cleared. -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, tc_transmit_queue, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x00, 0, 64); -+ -+/* reg_ppcnt_tc_no_buffer_discard_uc -+ * The number of unicast packets dropped due to lack of shared -+ * buffer resources. -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, tc_no_buffer_discard_uc, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x08, 0, 64); -+ -+/* Ethernet Per Traffic Class Congestion Group Counters */ -+ -+/* reg_ppcnt_wred_discard -+ * Access: RO -+ */ -+MLXSW_ITEM64(reg, ppcnt, wred_discard, -+ MLXSW_REG_PPCNT_COUNTERS_OFFSET + 0x00, 0, 64); -+ -+static inline void mlxsw_reg_ppcnt_pack(char *payload, u8 local_port, -+ enum mlxsw_reg_ppcnt_grp grp, -+ u8 prio_tc) -+{ -+ MLXSW_REG_ZERO(ppcnt, payload); -+ mlxsw_reg_ppcnt_swid_set(payload, 0); -+ mlxsw_reg_ppcnt_local_port_set(payload, local_port); -+ mlxsw_reg_ppcnt_pnat_set(payload, 0); -+ mlxsw_reg_ppcnt_grp_set(payload, grp); -+ mlxsw_reg_ppcnt_clr_set(payload, 0); -+ mlxsw_reg_ppcnt_prio_tc_set(payload, prio_tc); -+} -+ -+/* PLIB - Port Local to InfiniBand Port -+ * ------------------------------------ -+ * The PLIB register performs mapping from Local Port into InfiniBand Port. -+ */ -+#define MLXSW_REG_PLIB_ID 0x500A -+#define MLXSW_REG_PLIB_LEN 0x10 -+ -+MLXSW_REG_DEFINE(plib, MLXSW_REG_PLIB_ID, MLXSW_REG_PLIB_LEN); -+ -+/* reg_plib_local_port -+ * Local port number. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, plib, local_port, 0x00, 16, 8); -+ -+/* reg_plib_ib_port -+ * InfiniBand port remapping for local_port. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, plib, ib_port, 0x00, 0, 8); -+ -+/* PPTB - Port Prio To Buffer Register -+ * ----------------------------------- -+ * Configures the switch priority to buffer table. -+ */ -+#define MLXSW_REG_PPTB_ID 0x500B -+#define MLXSW_REG_PPTB_LEN 0x10 -+ -+MLXSW_REG_DEFINE(pptb, MLXSW_REG_PPTB_ID, MLXSW_REG_PPTB_LEN); -+ -+enum { -+ MLXSW_REG_PPTB_MM_UM, -+ MLXSW_REG_PPTB_MM_UNICAST, -+ MLXSW_REG_PPTB_MM_MULTICAST, -+}; -+ -+/* reg_pptb_mm -+ * Mapping mode. -+ * 0 - Map both unicast and multicast packets to the same buffer. -+ * 1 - Map only unicast packets. -+ * 2 - Map only multicast packets. -+ * Access: Index -+ * -+ * Note: SwitchX-2 only supports the first option. -+ */ -+MLXSW_ITEM32(reg, pptb, mm, 0x00, 28, 2); -+ -+/* reg_pptb_local_port -+ * Local port number. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, pptb, local_port, 0x00, 16, 8); -+ -+/* reg_pptb_um -+ * Enables the update of the untagged_buf field. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pptb, um, 0x00, 8, 1); -+ -+/* reg_pptb_pm -+ * Enables the update of the prio_to_buff field. -+ * Bit is a flag for updating the mapping for switch priority . -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pptb, pm, 0x00, 0, 8); -+ -+/* reg_pptb_prio_to_buff -+ * Mapping of switch priority to one of the allocated receive port -+ * buffers. -+ * Access: RW -+ */ -+MLXSW_ITEM_BIT_ARRAY(reg, pptb, prio_to_buff, 0x04, 0x04, 4); -+ -+/* reg_pptb_pm_msb -+ * Enables the update of the prio_to_buff field. -+ * Bit is a flag for updating the mapping for switch priority . -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pptb, pm_msb, 0x08, 24, 8); -+ -+/* reg_pptb_untagged_buff -+ * Mapping of untagged frames to one of the allocated receive port buffers. -+ * Access: RW -+ * -+ * Note: In SwitchX-2 this field must be mapped to buffer 8. Reserved for -+ * Spectrum, as it maps untagged packets based on the default switch priority. -+ */ -+MLXSW_ITEM32(reg, pptb, untagged_buff, 0x08, 0, 4); -+ -+/* reg_pptb_prio_to_buff_msb -+ * Mapping of switch priority to one of the allocated receive port -+ * buffers. -+ * Access: RW -+ */ -+MLXSW_ITEM_BIT_ARRAY(reg, pptb, prio_to_buff_msb, 0x0C, 0x04, 4); -+ -+#define MLXSW_REG_PPTB_ALL_PRIO 0xFF -+ -+static inline void mlxsw_reg_pptb_pack(char *payload, u8 local_port) -+{ -+ MLXSW_REG_ZERO(pptb, payload); -+ mlxsw_reg_pptb_mm_set(payload, MLXSW_REG_PPTB_MM_UM); -+ mlxsw_reg_pptb_local_port_set(payload, local_port); -+ mlxsw_reg_pptb_pm_set(payload, MLXSW_REG_PPTB_ALL_PRIO); -+ mlxsw_reg_pptb_pm_msb_set(payload, MLXSW_REG_PPTB_ALL_PRIO); -+} -+ -+static inline void mlxsw_reg_pptb_prio_to_buff_pack(char *payload, u8 prio, -+ u8 buff) -+{ -+ mlxsw_reg_pptb_prio_to_buff_set(payload, prio, buff); -+ mlxsw_reg_pptb_prio_to_buff_msb_set(payload, prio, buff); -+} -+ -+/* PBMC - Port Buffer Management Control Register -+ * ---------------------------------------------- -+ * The PBMC register configures and retrieves the port packet buffer -+ * allocation for different Prios, and the Pause threshold management. -+ */ -+#define MLXSW_REG_PBMC_ID 0x500C -+#define MLXSW_REG_PBMC_LEN 0x6C -+ -+MLXSW_REG_DEFINE(pbmc, MLXSW_REG_PBMC_ID, MLXSW_REG_PBMC_LEN); -+ -+/* reg_pbmc_local_port -+ * Local port number. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, pbmc, local_port, 0x00, 16, 8); -+ -+/* reg_pbmc_xoff_timer_value -+ * When device generates a pause frame, it uses this value as the pause -+ * timer (time for the peer port to pause in quota-512 bit time). -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pbmc, xoff_timer_value, 0x04, 16, 16); -+ -+/* reg_pbmc_xoff_refresh -+ * The time before a new pause frame should be sent to refresh the pause RW -+ * state. Using the same units as xoff_timer_value above (in quota-512 bit -+ * time). -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pbmc, xoff_refresh, 0x04, 0, 16); -+ -+#define MLXSW_REG_PBMC_PORT_SHARED_BUF_IDX 11 -+ -+/* reg_pbmc_buf_lossy -+ * The field indicates if the buffer is lossy. -+ * 0 - Lossless -+ * 1 - Lossy -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, pbmc, buf_lossy, 0x0C, 25, 1, 0x08, 0x00, false); -+ -+/* reg_pbmc_buf_epsb -+ * Eligible for Port Shared buffer. -+ * If epsb is set, packets assigned to buffer are allowed to insert the port -+ * shared buffer. -+ * When buf_lossy is MLXSW_REG_PBMC_LOSSY_LOSSY this field is reserved. -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, pbmc, buf_epsb, 0x0C, 24, 1, 0x08, 0x00, false); -+ -+/* reg_pbmc_buf_size -+ * The part of the packet buffer array is allocated for the specific buffer. -+ * Units are represented in cells. -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, pbmc, buf_size, 0x0C, 0, 16, 0x08, 0x00, false); -+ -+/* reg_pbmc_buf_xoff_threshold -+ * Once the amount of data in the buffer goes above this value, device -+ * starts sending PFC frames for all priorities associated with the -+ * buffer. Units are represented in cells. Reserved in case of lossy -+ * buffer. -+ * Access: RW -+ * -+ * Note: In Spectrum, reserved for buffer[9]. -+ */ -+MLXSW_ITEM32_INDEXED(reg, pbmc, buf_xoff_threshold, 0x0C, 16, 16, -+ 0x08, 0x04, false); -+ -+/* reg_pbmc_buf_xon_threshold -+ * When the amount of data in the buffer goes below this value, device -+ * stops sending PFC frames for the priorities associated with the -+ * buffer. Units are represented in cells. Reserved in case of lossy -+ * buffer. -+ * Access: RW -+ * -+ * Note: In Spectrum, reserved for buffer[9]. -+ */ -+MLXSW_ITEM32_INDEXED(reg, pbmc, buf_xon_threshold, 0x0C, 0, 16, -+ 0x08, 0x04, false); -+ -+static inline void mlxsw_reg_pbmc_pack(char *payload, u8 local_port, -+ u16 xoff_timer_value, u16 xoff_refresh) -+{ -+ MLXSW_REG_ZERO(pbmc, payload); -+ mlxsw_reg_pbmc_local_port_set(payload, local_port); -+ mlxsw_reg_pbmc_xoff_timer_value_set(payload, xoff_timer_value); -+ mlxsw_reg_pbmc_xoff_refresh_set(payload, xoff_refresh); -+} -+ -+static inline void mlxsw_reg_pbmc_lossy_buffer_pack(char *payload, -+ int buf_index, -+ u16 size) -+{ -+ mlxsw_reg_pbmc_buf_lossy_set(payload, buf_index, 1); -+ mlxsw_reg_pbmc_buf_epsb_set(payload, buf_index, 0); -+ mlxsw_reg_pbmc_buf_size_set(payload, buf_index, size); -+} -+ -+static inline void mlxsw_reg_pbmc_lossless_buffer_pack(char *payload, -+ int buf_index, u16 size, -+ u16 threshold) -+{ -+ mlxsw_reg_pbmc_buf_lossy_set(payload, buf_index, 0); -+ mlxsw_reg_pbmc_buf_epsb_set(payload, buf_index, 0); -+ mlxsw_reg_pbmc_buf_size_set(payload, buf_index, size); -+ mlxsw_reg_pbmc_buf_xoff_threshold_set(payload, buf_index, threshold); -+ mlxsw_reg_pbmc_buf_xon_threshold_set(payload, buf_index, threshold); -+} -+ -+/* PSPA - Port Switch Partition Allocation -+ * --------------------------------------- -+ * Controls the association of a port with a switch partition and enables -+ * configuring ports as stacking ports. -+ */ -+#define MLXSW_REG_PSPA_ID 0x500D -+#define MLXSW_REG_PSPA_LEN 0x8 -+ -+MLXSW_REG_DEFINE(pspa, MLXSW_REG_PSPA_ID, MLXSW_REG_PSPA_LEN); -+ -+/* reg_pspa_swid -+ * Switch partition ID. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, pspa, swid, 0x00, 24, 8); -+ -+/* reg_pspa_local_port -+ * Local port number. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, pspa, local_port, 0x00, 16, 8); -+ -+/* reg_pspa_sub_port -+ * Virtual port within the local port. Set to 0 when virtual ports are -+ * disabled on the local port. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, pspa, sub_port, 0x00, 8, 8); -+ -+static inline void mlxsw_reg_pspa_pack(char *payload, u8 swid, u8 local_port) -+{ -+ MLXSW_REG_ZERO(pspa, payload); -+ mlxsw_reg_pspa_swid_set(payload, swid); -+ mlxsw_reg_pspa_local_port_set(payload, local_port); -+ mlxsw_reg_pspa_sub_port_set(payload, 0); -+} -+ -+/* HTGT - Host Trap Group Table -+ * ---------------------------- -+ * Configures the properties for forwarding to CPU. -+ */ -+#define MLXSW_REG_HTGT_ID 0x7002 -+#define MLXSW_REG_HTGT_LEN 0x20 -+ -+MLXSW_REG_DEFINE(htgt, MLXSW_REG_HTGT_ID, MLXSW_REG_HTGT_LEN); -+ -+/* reg_htgt_swid -+ * Switch partition ID. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, htgt, swid, 0x00, 24, 8); -+ -+#define MLXSW_REG_HTGT_PATH_TYPE_LOCAL 0x0 /* For locally attached CPU */ -+ -+/* reg_htgt_type -+ * CPU path type. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, htgt, type, 0x00, 8, 4); -+ -+enum mlxsw_reg_htgt_trap_group { -+ MLXSW_REG_HTGT_TRAP_GROUP_EMAD, -+ MLXSW_REG_HTGT_TRAP_GROUP_SX2_RX, -+ MLXSW_REG_HTGT_TRAP_GROUP_SX2_CTRL, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_STP, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_LACP, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_LLDP, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_IGMP, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_BGP, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_OSPF, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_PIM, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_MULTICAST, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_ARP, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_HOST_MISS, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_ROUTER_EXP, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_REMOTE_ROUTE, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_IP2ME, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_DHCP, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_RPF, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_EVENT, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6_MLD, -+ MLXSW_REG_HTGT_TRAP_GROUP_SP_IPV6_ND, -+}; -+ -+/* reg_htgt_trap_group -+ * Trap group number. User defined number specifying which trap groups -+ * should be forwarded to the CPU. The mapping between trap IDs and trap -+ * groups is configured using HPKT register. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, htgt, trap_group, 0x00, 0, 8); -+ -+enum { -+ MLXSW_REG_HTGT_POLICER_DISABLE, -+ MLXSW_REG_HTGT_POLICER_ENABLE, -+}; -+ -+/* reg_htgt_pide -+ * Enable policer ID specified using 'pid' field. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, htgt, pide, 0x04, 15, 1); -+ -+#define MLXSW_REG_HTGT_INVALID_POLICER 0xff -+ -+/* reg_htgt_pid -+ * Policer ID for the trap group. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, htgt, pid, 0x04, 0, 8); -+ -+#define MLXSW_REG_HTGT_TRAP_TO_CPU 0x0 -+ -+/* reg_htgt_mirror_action -+ * Mirror action to use. -+ * 0 - Trap to CPU. -+ * 1 - Trap to CPU and mirror to a mirroring agent. -+ * 2 - Mirror to a mirroring agent and do not trap to CPU. -+ * Access: RW -+ * -+ * Note: Mirroring to a mirroring agent is only supported in Spectrum. -+ */ -+MLXSW_ITEM32(reg, htgt, mirror_action, 0x08, 8, 2); -+ -+/* reg_htgt_mirroring_agent -+ * Mirroring agent. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, htgt, mirroring_agent, 0x08, 0, 3); -+ -+#define MLXSW_REG_HTGT_DEFAULT_PRIORITY 0 -+ -+/* reg_htgt_priority -+ * Trap group priority. -+ * In case a packet matches multiple classification rules, the packet will -+ * only be trapped once, based on the trap ID associated with the group (via -+ * register HPKT) with the highest priority. -+ * Supported values are 0-7, with 7 represnting the highest priority. -+ * Access: RW -+ * -+ * Note: In SwitchX-2 this field is ignored and the priority value is replaced -+ * by the 'trap_group' field. -+ */ -+MLXSW_ITEM32(reg, htgt, priority, 0x0C, 0, 4); -+ -+#define MLXSW_REG_HTGT_DEFAULT_TC 7 -+ -+/* reg_htgt_local_path_cpu_tclass -+ * CPU ingress traffic class for the trap group. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, htgt, local_path_cpu_tclass, 0x10, 16, 6); -+ -+enum mlxsw_reg_htgt_local_path_rdq { -+ MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SX2_CTRL = 0x13, -+ MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SX2_RX = 0x14, -+ MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SX2_EMAD = 0x15, -+ MLXSW_REG_HTGT_LOCAL_PATH_RDQ_SIB_EMAD = 0x15, -+}; -+/* reg_htgt_local_path_rdq -+ * Receive descriptor queue (RDQ) to use for the trap group. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, htgt, local_path_rdq, 0x10, 0, 6); -+ -+static inline void mlxsw_reg_htgt_pack(char *payload, u8 group, u8 policer_id, -+ u8 priority, u8 tc) -+{ -+ MLXSW_REG_ZERO(htgt, payload); -+ -+ if (policer_id == MLXSW_REG_HTGT_INVALID_POLICER) { -+ mlxsw_reg_htgt_pide_set(payload, -+ MLXSW_REG_HTGT_POLICER_DISABLE); -+ } else { -+ mlxsw_reg_htgt_pide_set(payload, -+ MLXSW_REG_HTGT_POLICER_ENABLE); -+ mlxsw_reg_htgt_pid_set(payload, policer_id); -+ } -+ -+ mlxsw_reg_htgt_type_set(payload, MLXSW_REG_HTGT_PATH_TYPE_LOCAL); -+ mlxsw_reg_htgt_trap_group_set(payload, group); -+ mlxsw_reg_htgt_mirror_action_set(payload, MLXSW_REG_HTGT_TRAP_TO_CPU); -+ mlxsw_reg_htgt_mirroring_agent_set(payload, 0); -+ mlxsw_reg_htgt_priority_set(payload, priority); -+ mlxsw_reg_htgt_local_path_cpu_tclass_set(payload, tc); -+ mlxsw_reg_htgt_local_path_rdq_set(payload, group); -+} -+ -+/* HPKT - Host Packet Trap -+ * ----------------------- -+ * Configures trap IDs inside trap groups. -+ */ -+#define MLXSW_REG_HPKT_ID 0x7003 -+#define MLXSW_REG_HPKT_LEN 0x10 -+ -+MLXSW_REG_DEFINE(hpkt, MLXSW_REG_HPKT_ID, MLXSW_REG_HPKT_LEN); -+ -+enum { -+ MLXSW_REG_HPKT_ACK_NOT_REQUIRED, -+ MLXSW_REG_HPKT_ACK_REQUIRED, -+}; -+ -+/* reg_hpkt_ack -+ * Require acknowledgements from the host for events. -+ * If set, then the device will wait for the event it sent to be acknowledged -+ * by the host. This option is only relevant for event trap IDs. -+ * Access: RW -+ * -+ * Note: Currently not supported by firmware. -+ */ -+MLXSW_ITEM32(reg, hpkt, ack, 0x00, 24, 1); -+ -+enum mlxsw_reg_hpkt_action { -+ MLXSW_REG_HPKT_ACTION_FORWARD, -+ MLXSW_REG_HPKT_ACTION_TRAP_TO_CPU, -+ MLXSW_REG_HPKT_ACTION_MIRROR_TO_CPU, -+ MLXSW_REG_HPKT_ACTION_DISCARD, -+ MLXSW_REG_HPKT_ACTION_SOFT_DISCARD, -+ MLXSW_REG_HPKT_ACTION_TRAP_AND_SOFT_DISCARD, -+}; -+ -+/* reg_hpkt_action -+ * Action to perform on packet when trapped. -+ * 0 - No action. Forward to CPU based on switching rules. -+ * 1 - Trap to CPU (CPU receives sole copy). -+ * 2 - Mirror to CPU (CPU receives a replica of the packet). -+ * 3 - Discard. -+ * 4 - Soft discard (allow other traps to act on the packet). -+ * 5 - Trap and soft discard (allow other traps to overwrite this trap). -+ * Access: RW -+ * -+ * Note: Must be set to 0 (forward) for event trap IDs, as they are already -+ * addressed to the CPU. -+ */ -+MLXSW_ITEM32(reg, hpkt, action, 0x00, 20, 3); -+ -+/* reg_hpkt_trap_group -+ * Trap group to associate the trap with. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, hpkt, trap_group, 0x00, 12, 6); -+ -+/* reg_hpkt_trap_id -+ * Trap ID. -+ * Access: Index -+ * -+ * Note: A trap ID can only be associated with a single trap group. The device -+ * will associate the trap ID with the last trap group configured. -+ */ -+MLXSW_ITEM32(reg, hpkt, trap_id, 0x00, 0, 9); -+ -+enum { -+ MLXSW_REG_HPKT_CTRL_PACKET_DEFAULT, -+ MLXSW_REG_HPKT_CTRL_PACKET_NO_BUFFER, -+ MLXSW_REG_HPKT_CTRL_PACKET_USE_BUFFER, -+}; -+ -+/* reg_hpkt_ctrl -+ * Configure dedicated buffer resources for control packets. -+ * Ignored by SwitchX-2. -+ * 0 - Keep factory defaults. -+ * 1 - Do not use control buffer for this trap ID. -+ * 2 - Use control buffer for this trap ID. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, hpkt, ctrl, 0x04, 16, 2); -+ -+static inline void mlxsw_reg_hpkt_pack(char *payload, u8 action, u16 trap_id, -+ enum mlxsw_reg_htgt_trap_group trap_group, -+ bool is_ctrl) -+{ -+ MLXSW_REG_ZERO(hpkt, payload); -+ mlxsw_reg_hpkt_ack_set(payload, MLXSW_REG_HPKT_ACK_NOT_REQUIRED); -+ mlxsw_reg_hpkt_action_set(payload, action); -+ mlxsw_reg_hpkt_trap_group_set(payload, trap_group); -+ mlxsw_reg_hpkt_trap_id_set(payload, trap_id); -+ mlxsw_reg_hpkt_ctrl_set(payload, is_ctrl ? -+ MLXSW_REG_HPKT_CTRL_PACKET_USE_BUFFER : -+ MLXSW_REG_HPKT_CTRL_PACKET_NO_BUFFER); -+} -+ -+/* RGCR - Router General Configuration Register -+ * -------------------------------------------- -+ * The register is used for setting up the router configuration. -+ */ -+#define MLXSW_REG_RGCR_ID 0x8001 -+#define MLXSW_REG_RGCR_LEN 0x28 -+ -+MLXSW_REG_DEFINE(rgcr, MLXSW_REG_RGCR_ID, MLXSW_REG_RGCR_LEN); -+ -+/* reg_rgcr_ipv4_en -+ * IPv4 router enable. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rgcr, ipv4_en, 0x00, 31, 1); -+ -+/* reg_rgcr_ipv6_en -+ * IPv6 router enable. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rgcr, ipv6_en, 0x00, 30, 1); -+ -+/* reg_rgcr_max_router_interfaces -+ * Defines the maximum number of active router interfaces for all virtual -+ * routers. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rgcr, max_router_interfaces, 0x10, 0, 16); -+ -+/* reg_rgcr_usp -+ * Update switch priority and packet color. -+ * 0 - Preserve the value of Switch Priority and packet color. -+ * 1 - Recalculate the value of Switch Priority and packet color. -+ * Access: RW -+ * -+ * Note: Not supported by SwitchX and SwitchX-2. -+ */ -+MLXSW_ITEM32(reg, rgcr, usp, 0x18, 20, 1); -+ -+/* reg_rgcr_pcp_rw -+ * Indicates how to handle the pcp_rewrite_en value: -+ * 0 - Preserve the value of pcp_rewrite_en. -+ * 2 - Disable PCP rewrite. -+ * 3 - Enable PCP rewrite. -+ * Access: RW -+ * -+ * Note: Not supported by SwitchX and SwitchX-2. -+ */ -+MLXSW_ITEM32(reg, rgcr, pcp_rw, 0x18, 16, 2); -+ -+/* reg_rgcr_activity_dis -+ * Activity disable: -+ * 0 - Activity will be set when an entry is hit (default). -+ * 1 - Activity will not be set when an entry is hit. -+ * -+ * Bit 0 - Disable activity bit in Router Algorithmic LPM Unicast Entry -+ * (RALUE). -+ * Bit 1 - Disable activity bit in Router Algorithmic LPM Unicast Host -+ * Entry (RAUHT). -+ * Bits 2:7 are reserved. -+ * Access: RW -+ * -+ * Note: Not supported by SwitchX, SwitchX-2 and Switch-IB. -+ */ -+MLXSW_ITEM32(reg, rgcr, activity_dis, 0x20, 0, 8); -+ -+static inline void mlxsw_reg_rgcr_pack(char *payload, bool ipv4_en, -+ bool ipv6_en) -+{ -+ MLXSW_REG_ZERO(rgcr, payload); -+ mlxsw_reg_rgcr_ipv4_en_set(payload, ipv4_en); -+ mlxsw_reg_rgcr_ipv6_en_set(payload, ipv6_en); -+} -+ -+/* RITR - Router Interface Table Register -+ * -------------------------------------- -+ * The register is used to configure the router interface table. -+ */ -+#define MLXSW_REG_RITR_ID 0x8002 -+#define MLXSW_REG_RITR_LEN 0x40 -+ -+MLXSW_REG_DEFINE(ritr, MLXSW_REG_RITR_ID, MLXSW_REG_RITR_LEN); -+ -+/* reg_ritr_enable -+ * Enables routing on the router interface. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, enable, 0x00, 31, 1); -+ -+/* reg_ritr_ipv4 -+ * IPv4 routing enable. Enables routing of IPv4 traffic on the router -+ * interface. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, ipv4, 0x00, 29, 1); -+ -+/* reg_ritr_ipv6 -+ * IPv6 routing enable. Enables routing of IPv6 traffic on the router -+ * interface. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, ipv6, 0x00, 28, 1); -+ -+/* reg_ritr_ipv4_mc -+ * IPv4 multicast routing enable. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, ipv4_mc, 0x00, 27, 1); -+ -+/* reg_ritr_ipv6_mc -+ * IPv6 multicast routing enable. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, ipv6_mc, 0x00, 26, 1); -+ -+enum mlxsw_reg_ritr_if_type { -+ /* VLAN interface. */ -+ MLXSW_REG_RITR_VLAN_IF, -+ /* FID interface. */ -+ MLXSW_REG_RITR_FID_IF, -+ /* Sub-port interface. */ -+ MLXSW_REG_RITR_SP_IF, -+ /* Loopback Interface. */ -+ MLXSW_REG_RITR_LOOPBACK_IF, -+}; -+ -+/* reg_ritr_type -+ * Router interface type as per enum mlxsw_reg_ritr_if_type. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, type, 0x00, 23, 3); -+ -+enum { -+ MLXSW_REG_RITR_RIF_CREATE, -+ MLXSW_REG_RITR_RIF_DEL, -+}; -+ -+/* reg_ritr_op -+ * Opcode: -+ * 0 - Create or edit RIF. -+ * 1 - Delete RIF. -+ * Reserved for SwitchX-2. For Spectrum, editing of interface properties -+ * is not supported. An interface must be deleted and re-created in order -+ * to update properties. -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, ritr, op, 0x00, 20, 2); -+ -+/* reg_ritr_rif -+ * Router interface index. A pointer to the Router Interface Table. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ritr, rif, 0x00, 0, 16); -+ -+/* reg_ritr_ipv4_fe -+ * IPv4 Forwarding Enable. -+ * Enables routing of IPv4 traffic on the router interface. When disabled, -+ * forwarding is blocked but local traffic (traps and IP2ME) will be enabled. -+ * Not supported in SwitchX-2. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, ipv4_fe, 0x04, 29, 1); -+ -+/* reg_ritr_ipv6_fe -+ * IPv6 Forwarding Enable. -+ * Enables routing of IPv6 traffic on the router interface. When disabled, -+ * forwarding is blocked but local traffic (traps and IP2ME) will be enabled. -+ * Not supported in SwitchX-2. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, ipv6_fe, 0x04, 28, 1); -+ -+/* reg_ritr_ipv4_mc_fe -+ * IPv4 Multicast Forwarding Enable. -+ * When disabled, forwarding is blocked but local traffic (traps and IP to me) -+ * will be enabled. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, ipv4_mc_fe, 0x04, 27, 1); -+ -+/* reg_ritr_ipv6_mc_fe -+ * IPv6 Multicast Forwarding Enable. -+ * When disabled, forwarding is blocked but local traffic (traps and IP to me) -+ * will be enabled. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, ipv6_mc_fe, 0x04, 26, 1); -+ -+/* reg_ritr_lb_en -+ * Loop-back filter enable for unicast packets. -+ * If the flag is set then loop-back filter for unicast packets is -+ * implemented on the RIF. Multicast packets are always subject to -+ * loop-back filtering. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, lb_en, 0x04, 24, 1); -+ -+/* reg_ritr_virtual_router -+ * Virtual router ID associated with the router interface. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, virtual_router, 0x04, 0, 16); -+ -+/* reg_ritr_mtu -+ * Router interface MTU. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, mtu, 0x34, 0, 16); -+ -+/* reg_ritr_if_swid -+ * Switch partition ID. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, if_swid, 0x08, 24, 8); -+ -+/* reg_ritr_if_mac -+ * Router interface MAC address. -+ * In Spectrum, all MAC addresses must have the same 38 MSBits. -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, ritr, if_mac, 0x12, 6); -+ -+/* reg_ritr_if_vrrp_id_ipv6 -+ * VRRP ID for IPv6 -+ * Note: Reserved for RIF types other than VLAN, FID and Sub-port. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, if_vrrp_id_ipv6, 0x1C, 8, 8); -+ -+/* reg_ritr_if_vrrp_id_ipv4 -+ * VRRP ID for IPv4 -+ * Note: Reserved for RIF types other than VLAN, FID and Sub-port. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, if_vrrp_id_ipv4, 0x1C, 0, 8); -+ -+/* VLAN Interface */ -+ -+/* reg_ritr_vlan_if_vid -+ * VLAN ID. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, vlan_if_vid, 0x08, 0, 12); -+ -+/* FID Interface */ -+ -+/* reg_ritr_fid_if_fid -+ * Filtering ID. Used to connect a bridge to the router. Only FIDs from -+ * the vFID range are supported. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, fid_if_fid, 0x08, 0, 16); -+ -+static inline void mlxsw_reg_ritr_fid_set(char *payload, -+ enum mlxsw_reg_ritr_if_type rif_type, -+ u16 fid) -+{ -+ if (rif_type == MLXSW_REG_RITR_FID_IF) -+ mlxsw_reg_ritr_fid_if_fid_set(payload, fid); -+ else -+ mlxsw_reg_ritr_vlan_if_vid_set(payload, fid); -+} -+ -+/* Sub-port Interface */ -+ -+/* reg_ritr_sp_if_lag -+ * LAG indication. When this bit is set the system_port field holds the -+ * LAG identifier. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, sp_if_lag, 0x08, 24, 1); -+ -+/* reg_ritr_sp_system_port -+ * Port unique indentifier. When lag bit is set, this field holds the -+ * lag_id in bits 0:9. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, sp_if_system_port, 0x08, 0, 16); -+ -+/* reg_ritr_sp_if_vid -+ * VLAN ID. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, sp_if_vid, 0x18, 0, 12); -+ -+/* Loopback Interface */ -+ -+enum mlxsw_reg_ritr_loopback_protocol { -+ /* IPinIP IPv4 underlay Unicast */ -+ MLXSW_REG_RITR_LOOPBACK_PROTOCOL_IPIP_IPV4, -+ /* IPinIP IPv6 underlay Unicast */ -+ MLXSW_REG_RITR_LOOPBACK_PROTOCOL_IPIP_IPV6, -+}; -+ -+/* reg_ritr_loopback_protocol -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, loopback_protocol, 0x08, 28, 4); -+ -+enum mlxsw_reg_ritr_loopback_ipip_type { -+ /* Tunnel is IPinIP. */ -+ MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_IP, -+ /* Tunnel is GRE, no key. */ -+ MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP, -+ /* Tunnel is GRE, with a key. */ -+ MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP, -+}; -+ -+/* reg_ritr_loopback_ipip_type -+ * Encapsulation type. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, loopback_ipip_type, 0x10, 24, 4); -+ -+enum mlxsw_reg_ritr_loopback_ipip_options { -+ /* The key is defined by gre_key. */ -+ MLXSW_REG_RITR_LOOPBACK_IPIP_OPTIONS_GRE_KEY_PRESET, -+}; -+ -+/* reg_ritr_loopback_ipip_options -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, loopback_ipip_options, 0x10, 20, 4); -+ -+/* reg_ritr_loopback_ipip_uvr -+ * Underlay Virtual Router ID. -+ * Range is 0..cap_max_virtual_routers-1. -+ * Reserved for Spectrum-2. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, loopback_ipip_uvr, 0x10, 0, 16); -+ -+/* reg_ritr_loopback_ipip_usip* -+ * Encapsulation Underlay source IP. -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, ritr, loopback_ipip_usip6, 0x18, 16); -+MLXSW_ITEM32(reg, ritr, loopback_ipip_usip4, 0x24, 0, 32); -+ -+/* reg_ritr_loopback_ipip_gre_key -+ * GRE Key. -+ * Reserved when ipip_type is not IP_IN_GRE_KEY_IN_IP. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, loopback_ipip_gre_key, 0x28, 0, 32); -+ -+/* Shared between ingress/egress */ -+enum mlxsw_reg_ritr_counter_set_type { -+ /* No Count. */ -+ MLXSW_REG_RITR_COUNTER_SET_TYPE_NO_COUNT = 0x0, -+ /* Basic. Used for router interfaces, counting the following: -+ * - Error and Discard counters. -+ * - Unicast, Multicast and Broadcast counters. Sharing the -+ * same set of counters for the different type of traffic -+ * (IPv4, IPv6 and mpls). -+ */ -+ MLXSW_REG_RITR_COUNTER_SET_TYPE_BASIC = 0x9, -+}; -+ -+/* reg_ritr_ingress_counter_index -+ * Counter Index for flow counter. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, ingress_counter_index, 0x38, 0, 24); -+ -+/* reg_ritr_ingress_counter_set_type -+ * Igress Counter Set Type for router interface counter. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, ingress_counter_set_type, 0x38, 24, 8); -+ -+/* reg_ritr_egress_counter_index -+ * Counter Index for flow counter. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, egress_counter_index, 0x3C, 0, 24); -+ -+/* reg_ritr_egress_counter_set_type -+ * Egress Counter Set Type for router interface counter. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ritr, egress_counter_set_type, 0x3C, 24, 8); -+ -+static inline void mlxsw_reg_ritr_counter_pack(char *payload, u32 index, -+ bool enable, bool egress) -+{ -+ enum mlxsw_reg_ritr_counter_set_type set_type; -+ -+ if (enable) -+ set_type = MLXSW_REG_RITR_COUNTER_SET_TYPE_BASIC; -+ else -+ set_type = MLXSW_REG_RITR_COUNTER_SET_TYPE_NO_COUNT; -+ mlxsw_reg_ritr_egress_counter_set_type_set(payload, set_type); -+ -+ if (egress) -+ mlxsw_reg_ritr_egress_counter_index_set(payload, index); -+ else -+ mlxsw_reg_ritr_ingress_counter_index_set(payload, index); -+} -+ -+static inline void mlxsw_reg_ritr_rif_pack(char *payload, u16 rif) -+{ -+ MLXSW_REG_ZERO(ritr, payload); -+ mlxsw_reg_ritr_rif_set(payload, rif); -+} -+ -+static inline void mlxsw_reg_ritr_sp_if_pack(char *payload, bool lag, -+ u16 system_port, u16 vid) -+{ -+ mlxsw_reg_ritr_sp_if_lag_set(payload, lag); -+ mlxsw_reg_ritr_sp_if_system_port_set(payload, system_port); -+ mlxsw_reg_ritr_sp_if_vid_set(payload, vid); -+} -+ -+static inline void mlxsw_reg_ritr_pack(char *payload, bool enable, -+ enum mlxsw_reg_ritr_if_type type, -+ u16 rif, u16 vr_id, u16 mtu) -+{ -+ bool op = enable ? MLXSW_REG_RITR_RIF_CREATE : MLXSW_REG_RITR_RIF_DEL; -+ -+ MLXSW_REG_ZERO(ritr, payload); -+ mlxsw_reg_ritr_enable_set(payload, enable); -+ mlxsw_reg_ritr_ipv4_set(payload, 1); -+ mlxsw_reg_ritr_ipv6_set(payload, 1); -+ mlxsw_reg_ritr_ipv4_mc_set(payload, 1); -+ mlxsw_reg_ritr_ipv6_mc_set(payload, 1); -+ mlxsw_reg_ritr_type_set(payload, type); -+ mlxsw_reg_ritr_op_set(payload, op); -+ mlxsw_reg_ritr_rif_set(payload, rif); -+ mlxsw_reg_ritr_ipv4_fe_set(payload, 1); -+ mlxsw_reg_ritr_ipv6_fe_set(payload, 1); -+ mlxsw_reg_ritr_ipv4_mc_fe_set(payload, 1); -+ mlxsw_reg_ritr_ipv6_mc_fe_set(payload, 1); -+ mlxsw_reg_ritr_lb_en_set(payload, 1); -+ mlxsw_reg_ritr_virtual_router_set(payload, vr_id); -+ mlxsw_reg_ritr_mtu_set(payload, mtu); -+} -+ -+static inline void mlxsw_reg_ritr_mac_pack(char *payload, const char *mac) -+{ -+ mlxsw_reg_ritr_if_mac_memcpy_to(payload, mac); -+} -+ -+static inline void -+mlxsw_reg_ritr_loopback_ipip_common_pack(char *payload, -+ enum mlxsw_reg_ritr_loopback_ipip_type ipip_type, -+ enum mlxsw_reg_ritr_loopback_ipip_options options, -+ u16 uvr_id, u32 gre_key) -+{ -+ mlxsw_reg_ritr_loopback_ipip_type_set(payload, ipip_type); -+ mlxsw_reg_ritr_loopback_ipip_options_set(payload, options); -+ mlxsw_reg_ritr_loopback_ipip_uvr_set(payload, uvr_id); -+ mlxsw_reg_ritr_loopback_ipip_gre_key_set(payload, gre_key); -+} -+ -+static inline void -+mlxsw_reg_ritr_loopback_ipip4_pack(char *payload, -+ enum mlxsw_reg_ritr_loopback_ipip_type ipip_type, -+ enum mlxsw_reg_ritr_loopback_ipip_options options, -+ u16 uvr_id, u32 usip, u32 gre_key) -+{ -+ mlxsw_reg_ritr_loopback_protocol_set(payload, -+ MLXSW_REG_RITR_LOOPBACK_PROTOCOL_IPIP_IPV4); -+ mlxsw_reg_ritr_loopback_ipip_common_pack(payload, ipip_type, options, -+ uvr_id, gre_key); -+ mlxsw_reg_ritr_loopback_ipip_usip4_set(payload, usip); -+} -+ -+/* RTAR - Router TCAM Allocation Register -+ * -------------------------------------- -+ * This register is used for allocation of regions in the TCAM table. -+ */ -+#define MLXSW_REG_RTAR_ID 0x8004 -+#define MLXSW_REG_RTAR_LEN 0x20 -+ -+MLXSW_REG_DEFINE(rtar, MLXSW_REG_RTAR_ID, MLXSW_REG_RTAR_LEN); -+ -+enum mlxsw_reg_rtar_op { -+ MLXSW_REG_RTAR_OP_ALLOCATE, -+ MLXSW_REG_RTAR_OP_RESIZE, -+ MLXSW_REG_RTAR_OP_DEALLOCATE, -+}; -+ -+/* reg_rtar_op -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, rtar, op, 0x00, 28, 4); -+ -+enum mlxsw_reg_rtar_key_type { -+ MLXSW_REG_RTAR_KEY_TYPE_IPV4_MULTICAST = 1, -+ MLXSW_REG_RTAR_KEY_TYPE_IPV6_MULTICAST = 3 -+}; -+ -+/* reg_rtar_key_type -+ * TCAM key type for the region. -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, rtar, key_type, 0x00, 0, 8); -+ -+/* reg_rtar_region_size -+ * TCAM region size. When allocating/resizing this is the requested -+ * size, the response is the actual size. -+ * Note: Actual size may be larger than requested. -+ * Reserved for op = Deallocate -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, rtar, region_size, 0x04, 0, 16); -+ -+static inline void mlxsw_reg_rtar_pack(char *payload, -+ enum mlxsw_reg_rtar_op op, -+ enum mlxsw_reg_rtar_key_type key_type, -+ u16 region_size) -+{ -+ MLXSW_REG_ZERO(rtar, payload); -+ mlxsw_reg_rtar_op_set(payload, op); -+ mlxsw_reg_rtar_key_type_set(payload, key_type); -+ mlxsw_reg_rtar_region_size_set(payload, region_size); -+} -+ -+/* RATR - Router Adjacency Table Register -+ * -------------------------------------- -+ * The RATR register is used to configure the Router Adjacency (next-hop) -+ * Table. -+ */ -+#define MLXSW_REG_RATR_ID 0x8008 -+#define MLXSW_REG_RATR_LEN 0x2C -+ -+MLXSW_REG_DEFINE(ratr, MLXSW_REG_RATR_ID, MLXSW_REG_RATR_LEN); -+ -+enum mlxsw_reg_ratr_op { -+ /* Read */ -+ MLXSW_REG_RATR_OP_QUERY_READ = 0, -+ /* Read and clear activity */ -+ MLXSW_REG_RATR_OP_QUERY_READ_CLEAR = 2, -+ /* Write Adjacency entry */ -+ MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY = 1, -+ /* Write Adjacency entry only if the activity is cleared. -+ * The write may not succeed if the activity is set. There is not -+ * direct feedback if the write has succeeded or not, however -+ * the get will reveal the actual entry (SW can compare the get -+ * response to the set command). -+ */ -+ MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY = 3, -+}; -+ -+/* reg_ratr_op -+ * Note that Write operation may also be used for updating -+ * counter_set_type and counter_index. In this case all other -+ * fields must not be updated. -+ * Access: OP -+ */ -+MLXSW_ITEM32(reg, ratr, op, 0x00, 28, 4); -+ -+/* reg_ratr_v -+ * Valid bit. Indicates if the adjacency entry is valid. -+ * Note: the device may need some time before reusing an invalidated -+ * entry. During this time the entry can not be reused. It is -+ * recommended to use another entry before reusing an invalidated -+ * entry (e.g. software can put it at the end of the list for -+ * reusing). Trying to access an invalidated entry not yet cleared -+ * by the device results with failure indicating "Try Again" status. -+ * When valid is '0' then egress_router_interface,trap_action, -+ * adjacency_parameters and counters are reserved -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ratr, v, 0x00, 24, 1); -+ -+/* reg_ratr_a -+ * Activity. Set for new entries. Set if a packet lookup has hit on -+ * the specific entry. To clear the a bit, use "clear activity". -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, ratr, a, 0x00, 16, 1); -+ -+enum mlxsw_reg_ratr_type { -+ /* Ethernet */ -+ MLXSW_REG_RATR_TYPE_ETHERNET, -+ /* IPoIB Unicast without GRH. -+ * Reserved for Spectrum. -+ */ -+ MLXSW_REG_RATR_TYPE_IPOIB_UC, -+ /* IPoIB Unicast with GRH. Supported only in table 0 (Ethernet unicast -+ * adjacency). -+ * Reserved for Spectrum. -+ */ -+ MLXSW_REG_RATR_TYPE_IPOIB_UC_W_GRH, -+ /* IPoIB Multicast. -+ * Reserved for Spectrum. -+ */ -+ MLXSW_REG_RATR_TYPE_IPOIB_MC, -+ /* MPLS. -+ * Reserved for SwitchX/-2. -+ */ -+ MLXSW_REG_RATR_TYPE_MPLS, -+ /* IPinIP Encap. -+ * Reserved for SwitchX/-2. -+ */ -+ MLXSW_REG_RATR_TYPE_IPIP, -+}; -+ -+/* reg_ratr_type -+ * Adjacency entry type. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ratr, type, 0x04, 28, 4); -+ -+/* reg_ratr_adjacency_index_low -+ * Bits 15:0 of index into the adjacency table. -+ * For SwitchX and SwitchX-2, the adjacency table is linear and -+ * used for adjacency entries only. -+ * For Spectrum, the index is to the KVD linear. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ratr, adjacency_index_low, 0x04, 0, 16); -+ -+/* reg_ratr_egress_router_interface -+ * Range is 0 .. cap_max_router_interfaces - 1 -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ratr, egress_router_interface, 0x08, 0, 16); -+ -+enum mlxsw_reg_ratr_trap_action { -+ MLXSW_REG_RATR_TRAP_ACTION_NOP, -+ MLXSW_REG_RATR_TRAP_ACTION_TRAP, -+ MLXSW_REG_RATR_TRAP_ACTION_MIRROR_TO_CPU, -+ MLXSW_REG_RATR_TRAP_ACTION_MIRROR, -+ MLXSW_REG_RATR_TRAP_ACTION_DISCARD_ERRORS, -+}; -+ -+/* reg_ratr_trap_action -+ * see mlxsw_reg_ratr_trap_action -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ratr, trap_action, 0x0C, 28, 4); -+ -+/* reg_ratr_adjacency_index_high -+ * Bits 23:16 of the adjacency_index. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ratr, adjacency_index_high, 0x0C, 16, 8); -+ -+enum mlxsw_reg_ratr_trap_id { -+ MLXSW_REG_RATR_TRAP_ID_RTR_EGRESS0, -+ MLXSW_REG_RATR_TRAP_ID_RTR_EGRESS1, -+}; -+ -+/* reg_ratr_trap_id -+ * Trap ID to be reported to CPU. -+ * Trap-ID is RTR_EGRESS0 or RTR_EGRESS1. -+ * For trap_action of NOP, MIRROR and DISCARD_ERROR -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ratr, trap_id, 0x0C, 0, 8); -+ -+/* reg_ratr_eth_destination_mac -+ * MAC address of the destination next-hop. -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, ratr, eth_destination_mac, 0x12, 6); -+ -+enum mlxsw_reg_ratr_ipip_type { -+ /* IPv4, address set by mlxsw_reg_ratr_ipip_ipv4_udip. */ -+ MLXSW_REG_RATR_IPIP_TYPE_IPV4, -+ /* IPv6, address set by mlxsw_reg_ratr_ipip_ipv6_ptr. */ -+ MLXSW_REG_RATR_IPIP_TYPE_IPV6, -+}; -+ -+/* reg_ratr_ipip_type -+ * Underlay destination ip type. -+ * Note: the type field must match the protocol of the router interface. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ratr, ipip_type, 0x10, 16, 4); -+ -+/* reg_ratr_ipip_ipv4_udip -+ * Underlay ipv4 dip. -+ * Reserved when ipip_type is IPv6. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ratr, ipip_ipv4_udip, 0x18, 0, 32); -+ -+/* reg_ratr_ipip_ipv6_ptr -+ * Pointer to IPv6 underlay destination ip address. -+ * For Spectrum: Pointer to KVD linear space. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ratr, ipip_ipv6_ptr, 0x1C, 0, 24); -+ -+enum mlxsw_reg_flow_counter_set_type { -+ /* No count */ -+ MLXSW_REG_FLOW_COUNTER_SET_TYPE_NO_COUNT = 0x00, -+ /* Count packets and bytes */ -+ MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES = 0x03, -+ /* Count only packets */ -+ MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS = 0x05, -+}; -+ -+/* reg_ratr_counter_set_type -+ * Counter set type for flow counters -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ratr, counter_set_type, 0x28, 24, 8); -+ -+/* reg_ratr_counter_index -+ * Counter index for flow counters -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ratr, counter_index, 0x28, 0, 24); -+ -+static inline void -+mlxsw_reg_ratr_pack(char *payload, -+ enum mlxsw_reg_ratr_op op, bool valid, -+ enum mlxsw_reg_ratr_type type, -+ u32 adjacency_index, u16 egress_rif) -+{ -+ MLXSW_REG_ZERO(ratr, payload); -+ mlxsw_reg_ratr_op_set(payload, op); -+ mlxsw_reg_ratr_v_set(payload, valid); -+ mlxsw_reg_ratr_type_set(payload, type); -+ mlxsw_reg_ratr_adjacency_index_low_set(payload, adjacency_index); -+ mlxsw_reg_ratr_adjacency_index_high_set(payload, adjacency_index >> 16); -+ mlxsw_reg_ratr_egress_router_interface_set(payload, egress_rif); -+} -+ -+static inline void mlxsw_reg_ratr_eth_entry_pack(char *payload, -+ const char *dest_mac) -+{ -+ mlxsw_reg_ratr_eth_destination_mac_memcpy_to(payload, dest_mac); -+} -+ -+static inline void mlxsw_reg_ratr_ipip4_entry_pack(char *payload, u32 ipv4_udip) -+{ -+ mlxsw_reg_ratr_ipip_type_set(payload, MLXSW_REG_RATR_IPIP_TYPE_IPV4); -+ mlxsw_reg_ratr_ipip_ipv4_udip_set(payload, ipv4_udip); -+} -+ -+static inline void mlxsw_reg_ratr_counter_pack(char *payload, u64 counter_index, -+ bool counter_enable) -+{ -+ enum mlxsw_reg_flow_counter_set_type set_type; -+ -+ if (counter_enable) -+ set_type = MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES; -+ else -+ set_type = MLXSW_REG_FLOW_COUNTER_SET_TYPE_NO_COUNT; -+ -+ mlxsw_reg_ratr_counter_index_set(payload, counter_index); -+ mlxsw_reg_ratr_counter_set_type_set(payload, set_type); -+} -+ -+/* RDPM - Router DSCP to Priority Mapping -+ * -------------------------------------- -+ * Controls the mapping from DSCP field to switch priority on routed packets -+ */ -+#define MLXSW_REG_RDPM_ID 0x8009 -+#define MLXSW_REG_RDPM_BASE_LEN 0x00 -+#define MLXSW_REG_RDPM_DSCP_ENTRY_REC_LEN 0x01 -+#define MLXSW_REG_RDPM_DSCP_ENTRY_REC_MAX_COUNT 64 -+#define MLXSW_REG_RDPM_LEN 0x40 -+#define MLXSW_REG_RDPM_LAST_ENTRY (MLXSW_REG_RDPM_BASE_LEN + \ -+ MLXSW_REG_RDPM_LEN - \ -+ MLXSW_REG_RDPM_DSCP_ENTRY_REC_LEN) -+ -+MLXSW_REG_DEFINE(rdpm, MLXSW_REG_RDPM_ID, MLXSW_REG_RDPM_LEN); -+ -+/* reg_dscp_entry_e -+ * Enable update of the specific entry -+ * Access: Index -+ */ -+MLXSW_ITEM8_INDEXED(reg, rdpm, dscp_entry_e, MLXSW_REG_RDPM_LAST_ENTRY, 7, 1, -+ -MLXSW_REG_RDPM_DSCP_ENTRY_REC_LEN, 0x00, false); -+ -+/* reg_dscp_entry_prio -+ * Switch Priority -+ * Access: RW -+ */ -+MLXSW_ITEM8_INDEXED(reg, rdpm, dscp_entry_prio, MLXSW_REG_RDPM_LAST_ENTRY, 0, 4, -+ -MLXSW_REG_RDPM_DSCP_ENTRY_REC_LEN, 0x00, false); -+ -+static inline void mlxsw_reg_rdpm_pack(char *payload, unsigned short index, -+ u8 prio) -+{ -+ mlxsw_reg_rdpm_dscp_entry_e_set(payload, index, 1); -+ mlxsw_reg_rdpm_dscp_entry_prio_set(payload, index, prio); -+} -+ -+/* RICNT - Router Interface Counter Register -+ * ----------------------------------------- -+ * The RICNT register retrieves per port performance counters -+ */ -+#define MLXSW_REG_RICNT_ID 0x800B -+#define MLXSW_REG_RICNT_LEN 0x100 -+ -+MLXSW_REG_DEFINE(ricnt, MLXSW_REG_RICNT_ID, MLXSW_REG_RICNT_LEN); -+ -+/* reg_ricnt_counter_index -+ * Counter index -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ricnt, counter_index, 0x04, 0, 24); -+ -+enum mlxsw_reg_ricnt_counter_set_type { -+ /* No Count. */ -+ MLXSW_REG_RICNT_COUNTER_SET_TYPE_NO_COUNT = 0x00, -+ /* Basic. Used for router interfaces, counting the following: -+ * - Error and Discard counters. -+ * - Unicast, Multicast and Broadcast counters. Sharing the -+ * same set of counters for the different type of traffic -+ * (IPv4, IPv6 and mpls). -+ */ -+ MLXSW_REG_RICNT_COUNTER_SET_TYPE_BASIC = 0x09, -+}; -+ -+/* reg_ricnt_counter_set_type -+ * Counter Set Type for router interface counter -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ricnt, counter_set_type, 0x04, 24, 8); -+ -+enum mlxsw_reg_ricnt_opcode { -+ /* Nop. Supported only for read access*/ -+ MLXSW_REG_RICNT_OPCODE_NOP = 0x00, -+ /* Clear. Setting the clr bit will reset the counter value for -+ * all counters of the specified Router Interface. -+ */ -+ MLXSW_REG_RICNT_OPCODE_CLEAR = 0x08, -+}; -+ -+/* reg_ricnt_opcode -+ * Opcode -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ricnt, op, 0x00, 28, 4); -+ -+/* reg_ricnt_good_unicast_packets -+ * good unicast packets. -+ * Access: RW -+ */ -+MLXSW_ITEM64(reg, ricnt, good_unicast_packets, 0x08, 0, 64); -+ -+/* reg_ricnt_good_multicast_packets -+ * good multicast packets. -+ * Access: RW -+ */ -+MLXSW_ITEM64(reg, ricnt, good_multicast_packets, 0x10, 0, 64); -+ -+/* reg_ricnt_good_broadcast_packets -+ * good broadcast packets -+ * Access: RW -+ */ -+MLXSW_ITEM64(reg, ricnt, good_broadcast_packets, 0x18, 0, 64); -+ -+/* reg_ricnt_good_unicast_bytes -+ * A count of L3 data and padding octets not including L2 headers -+ * for good unicast frames. -+ * Access: RW -+ */ -+MLXSW_ITEM64(reg, ricnt, good_unicast_bytes, 0x20, 0, 64); -+ -+/* reg_ricnt_good_multicast_bytes -+ * A count of L3 data and padding octets not including L2 headers -+ * for good multicast frames. -+ * Access: RW -+ */ -+MLXSW_ITEM64(reg, ricnt, good_multicast_bytes, 0x28, 0, 64); -+ -+/* reg_ritr_good_broadcast_bytes -+ * A count of L3 data and padding octets not including L2 headers -+ * for good broadcast frames. -+ * Access: RW -+ */ -+MLXSW_ITEM64(reg, ricnt, good_broadcast_bytes, 0x30, 0, 64); -+ -+/* reg_ricnt_error_packets -+ * A count of errored frames that do not pass the router checks. -+ * Access: RW -+ */ -+MLXSW_ITEM64(reg, ricnt, error_packets, 0x38, 0, 64); -+ -+/* reg_ricnt_discrad_packets -+ * A count of non-errored frames that do not pass the router checks. -+ * Access: RW -+ */ -+MLXSW_ITEM64(reg, ricnt, discard_packets, 0x40, 0, 64); -+ -+/* reg_ricnt_error_bytes -+ * A count of L3 data and padding octets not including L2 headers -+ * for errored frames. -+ * Access: RW -+ */ -+MLXSW_ITEM64(reg, ricnt, error_bytes, 0x48, 0, 64); -+ -+/* reg_ricnt_discard_bytes -+ * A count of L3 data and padding octets not including L2 headers -+ * for non-errored frames that do not pass the router checks. -+ * Access: RW -+ */ -+MLXSW_ITEM64(reg, ricnt, discard_bytes, 0x50, 0, 64); -+ -+static inline void mlxsw_reg_ricnt_pack(char *payload, u32 index, -+ enum mlxsw_reg_ricnt_opcode op) -+{ -+ MLXSW_REG_ZERO(ricnt, payload); -+ mlxsw_reg_ricnt_op_set(payload, op); -+ mlxsw_reg_ricnt_counter_index_set(payload, index); -+ mlxsw_reg_ricnt_counter_set_type_set(payload, -+ MLXSW_REG_RICNT_COUNTER_SET_TYPE_BASIC); -+} -+ -+/* RRCR - Router Rules Copy Register Layout -+ * ---------------------------------------- -+ * This register is used for moving and copying route entry rules. -+ */ -+#define MLXSW_REG_RRCR_ID 0x800F -+#define MLXSW_REG_RRCR_LEN 0x24 -+ -+MLXSW_REG_DEFINE(rrcr, MLXSW_REG_RRCR_ID, MLXSW_REG_RRCR_LEN); -+ -+enum mlxsw_reg_rrcr_op { -+ /* Move rules */ -+ MLXSW_REG_RRCR_OP_MOVE, -+ /* Copy rules */ -+ MLXSW_REG_RRCR_OP_COPY, -+}; -+ -+/* reg_rrcr_op -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, rrcr, op, 0x00, 28, 4); -+ -+/* reg_rrcr_offset -+ * Offset within the region from which to copy/move. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rrcr, offset, 0x00, 0, 16); -+ -+/* reg_rrcr_size -+ * The number of rules to copy/move. -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, rrcr, size, 0x04, 0, 16); -+ -+/* reg_rrcr_table_id -+ * Identifier of the table on which to perform the operation. Encoding is the -+ * same as in RTAR.key_type -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rrcr, table_id, 0x10, 0, 4); -+ -+/* reg_rrcr_dest_offset -+ * Offset within the region to which to copy/move -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rrcr, dest_offset, 0x20, 0, 16); -+ -+static inline void mlxsw_reg_rrcr_pack(char *payload, enum mlxsw_reg_rrcr_op op, -+ u16 offset, u16 size, -+ enum mlxsw_reg_rtar_key_type table_id, -+ u16 dest_offset) -+{ -+ MLXSW_REG_ZERO(rrcr, payload); -+ mlxsw_reg_rrcr_op_set(payload, op); -+ mlxsw_reg_rrcr_offset_set(payload, offset); -+ mlxsw_reg_rrcr_size_set(payload, size); -+ mlxsw_reg_rrcr_table_id_set(payload, table_id); -+ mlxsw_reg_rrcr_dest_offset_set(payload, dest_offset); -+} -+ -+/* RALTA - Router Algorithmic LPM Tree Allocation Register -+ * ------------------------------------------------------- -+ * RALTA is used to allocate the LPM trees of the SHSPM method. -+ */ -+#define MLXSW_REG_RALTA_ID 0x8010 -+#define MLXSW_REG_RALTA_LEN 0x04 -+ -+MLXSW_REG_DEFINE(ralta, MLXSW_REG_RALTA_ID, MLXSW_REG_RALTA_LEN); -+ -+/* reg_ralta_op -+ * opcode (valid for Write, must be 0 on Read) -+ * 0 - allocate a tree -+ * 1 - deallocate a tree -+ * Access: OP -+ */ -+MLXSW_ITEM32(reg, ralta, op, 0x00, 28, 2); -+ -+enum mlxsw_reg_ralxx_protocol { -+ MLXSW_REG_RALXX_PROTOCOL_IPV4, -+ MLXSW_REG_RALXX_PROTOCOL_IPV6, -+}; -+ -+/* reg_ralta_protocol -+ * Protocol. -+ * Deallocation opcode: Reserved. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ralta, protocol, 0x00, 24, 4); -+ -+/* reg_ralta_tree_id -+ * An identifier (numbered from 1..cap_shspm_max_trees-1) representing -+ * the tree identifier (managed by software). -+ * Note that tree_id 0 is allocated for a default-route tree. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ralta, tree_id, 0x00, 0, 8); -+ -+static inline void mlxsw_reg_ralta_pack(char *payload, bool alloc, -+ enum mlxsw_reg_ralxx_protocol protocol, -+ u8 tree_id) -+{ -+ MLXSW_REG_ZERO(ralta, payload); -+ mlxsw_reg_ralta_op_set(payload, !alloc); -+ mlxsw_reg_ralta_protocol_set(payload, protocol); -+ mlxsw_reg_ralta_tree_id_set(payload, tree_id); -+} -+ -+/* RALST - Router Algorithmic LPM Structure Tree Register -+ * ------------------------------------------------------ -+ * RALST is used to set and query the structure of an LPM tree. -+ * The structure of the tree must be sorted as a sorted binary tree, while -+ * each node is a bin that is tagged as the length of the prefixes the lookup -+ * will refer to. Therefore, bin X refers to a set of entries with prefixes -+ * of X bits to match with the destination address. The bin 0 indicates -+ * the default action, when there is no match of any prefix. -+ */ -+#define MLXSW_REG_RALST_ID 0x8011 -+#define MLXSW_REG_RALST_LEN 0x104 -+ -+MLXSW_REG_DEFINE(ralst, MLXSW_REG_RALST_ID, MLXSW_REG_RALST_LEN); -+ -+/* reg_ralst_root_bin -+ * The bin number of the root bin. -+ * 064 the entry consumes -+ * two entries in the physical HW table. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ralue, prefix_len, 0x08, 0, 8); -+ -+/* reg_ralue_dip* -+ * The prefix of the route or of the marker that the object of the LPM -+ * is compared with. The most significant bits of the dip are the prefix. -+ * The least significant bits must be '0' if the prefix_len is smaller -+ * than 128 for IPv6 or smaller than 32 for IPv4. -+ * IPv4 address uses bits dip[31:0] and bits dip[127:32] are reserved. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, ralue, dip4, 0x18, 0, 32); -+MLXSW_ITEM_BUF(reg, ralue, dip6, 0x0C, 16); -+ -+enum mlxsw_reg_ralue_entry_type { -+ MLXSW_REG_RALUE_ENTRY_TYPE_MARKER_ENTRY = 1, -+ MLXSW_REG_RALUE_ENTRY_TYPE_ROUTE_ENTRY = 2, -+ MLXSW_REG_RALUE_ENTRY_TYPE_MARKER_AND_ROUTE_ENTRY = 3, -+}; -+ -+/* reg_ralue_entry_type -+ * Entry type. -+ * Note - for Marker entries, the action_type and action fields are reserved. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ralue, entry_type, 0x1C, 30, 2); -+ -+/* reg_ralue_bmp_len -+ * The best match prefix length in the case that there is no match for -+ * longer prefixes. -+ * If (entry_type != MARKER_ENTRY), bmp_len must be equal to prefix_len -+ * Note for any update operation with entry_type modification this -+ * field must be set. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ralue, bmp_len, 0x1C, 16, 8); -+ -+enum mlxsw_reg_ralue_action_type { -+ MLXSW_REG_RALUE_ACTION_TYPE_REMOTE, -+ MLXSW_REG_RALUE_ACTION_TYPE_LOCAL, -+ MLXSW_REG_RALUE_ACTION_TYPE_IP2ME, -+}; -+ -+/* reg_ralue_action_type -+ * Action Type -+ * Indicates how the IP address is connected. -+ * It can be connected to a local subnet through local_erif or can be -+ * on a remote subnet connected through a next-hop router, -+ * or transmitted to the CPU. -+ * Reserved when entry_type = MARKER_ENTRY -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ralue, action_type, 0x1C, 0, 2); -+ -+enum mlxsw_reg_ralue_trap_action { -+ MLXSW_REG_RALUE_TRAP_ACTION_NOP, -+ MLXSW_REG_RALUE_TRAP_ACTION_TRAP, -+ MLXSW_REG_RALUE_TRAP_ACTION_MIRROR_TO_CPU, -+ MLXSW_REG_RALUE_TRAP_ACTION_MIRROR, -+ MLXSW_REG_RALUE_TRAP_ACTION_DISCARD_ERROR, -+}; -+ -+/* reg_ralue_trap_action -+ * Trap action. -+ * For IP2ME action, only NOP and MIRROR are possible. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ralue, trap_action, 0x20, 28, 4); -+ -+/* reg_ralue_trap_id -+ * Trap ID to be reported to CPU. -+ * Trap ID is RTR_INGRESS0 or RTR_INGRESS1. -+ * For trap_action of NOP, MIRROR and DISCARD_ERROR, trap_id is reserved. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ralue, trap_id, 0x20, 0, 9); -+ -+/* reg_ralue_adjacency_index -+ * Points to the first entry of the group-based ECMP. -+ * Only relevant in case of REMOTE action. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ralue, adjacency_index, 0x24, 0, 24); -+ -+/* reg_ralue_ecmp_size -+ * Amount of sequential entries starting -+ * from the adjacency_index (the number of ECMPs). -+ * The valid range is 1-64, 512, 1024, 2048 and 4096. -+ * Reserved when trap_action is TRAP or DISCARD_ERROR. -+ * Only relevant in case of REMOTE action. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ralue, ecmp_size, 0x28, 0, 13); -+ -+/* reg_ralue_local_erif -+ * Egress Router Interface. -+ * Only relevant in case of LOCAL action. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ralue, local_erif, 0x24, 0, 16); -+ -+/* reg_ralue_ip2me_v -+ * Valid bit for the tunnel_ptr field. -+ * If valid = 0 then trap to CPU as IP2ME trap ID. -+ * If valid = 1 and the packet format allows NVE or IPinIP tunnel -+ * decapsulation then tunnel decapsulation is done. -+ * If valid = 1 and packet format does not allow NVE or IPinIP tunnel -+ * decapsulation then trap as IP2ME trap ID. -+ * Only relevant in case of IP2ME action. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ralue, ip2me_v, 0x24, 31, 1); -+ -+/* reg_ralue_ip2me_tunnel_ptr -+ * Tunnel Pointer for NVE or IPinIP tunnel decapsulation. -+ * For Spectrum, pointer to KVD Linear. -+ * Only relevant in case of IP2ME action. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, ralue, ip2me_tunnel_ptr, 0x24, 0, 24); -+ -+static inline void mlxsw_reg_ralue_pack(char *payload, -+ enum mlxsw_reg_ralxx_protocol protocol, -+ enum mlxsw_reg_ralue_op op, -+ u16 virtual_router, u8 prefix_len) -+{ -+ MLXSW_REG_ZERO(ralue, payload); -+ mlxsw_reg_ralue_protocol_set(payload, protocol); -+ mlxsw_reg_ralue_op_set(payload, op); -+ mlxsw_reg_ralue_virtual_router_set(payload, virtual_router); -+ mlxsw_reg_ralue_prefix_len_set(payload, prefix_len); -+ mlxsw_reg_ralue_entry_type_set(payload, -+ MLXSW_REG_RALUE_ENTRY_TYPE_ROUTE_ENTRY); -+ mlxsw_reg_ralue_bmp_len_set(payload, prefix_len); -+} -+ -+static inline void mlxsw_reg_ralue_pack4(char *payload, -+ enum mlxsw_reg_ralxx_protocol protocol, -+ enum mlxsw_reg_ralue_op op, -+ u16 virtual_router, u8 prefix_len, -+ u32 dip) -+{ -+ mlxsw_reg_ralue_pack(payload, protocol, op, virtual_router, prefix_len); -+ mlxsw_reg_ralue_dip4_set(payload, dip); -+} -+ -+static inline void mlxsw_reg_ralue_pack6(char *payload, -+ enum mlxsw_reg_ralxx_protocol protocol, -+ enum mlxsw_reg_ralue_op op, -+ u16 virtual_router, u8 prefix_len, -+ const void *dip) -+{ -+ mlxsw_reg_ralue_pack(payload, protocol, op, virtual_router, prefix_len); -+ mlxsw_reg_ralue_dip6_memcpy_to(payload, dip); -+} -+ -+static inline void -+mlxsw_reg_ralue_act_remote_pack(char *payload, -+ enum mlxsw_reg_ralue_trap_action trap_action, -+ u16 trap_id, u32 adjacency_index, u16 ecmp_size) -+{ -+ mlxsw_reg_ralue_action_type_set(payload, -+ MLXSW_REG_RALUE_ACTION_TYPE_REMOTE); -+ mlxsw_reg_ralue_trap_action_set(payload, trap_action); -+ mlxsw_reg_ralue_trap_id_set(payload, trap_id); -+ mlxsw_reg_ralue_adjacency_index_set(payload, adjacency_index); -+ mlxsw_reg_ralue_ecmp_size_set(payload, ecmp_size); -+} -+ -+static inline void -+mlxsw_reg_ralue_act_local_pack(char *payload, -+ enum mlxsw_reg_ralue_trap_action trap_action, -+ u16 trap_id, u16 local_erif) -+{ -+ mlxsw_reg_ralue_action_type_set(payload, -+ MLXSW_REG_RALUE_ACTION_TYPE_LOCAL); -+ mlxsw_reg_ralue_trap_action_set(payload, trap_action); -+ mlxsw_reg_ralue_trap_id_set(payload, trap_id); -+ mlxsw_reg_ralue_local_erif_set(payload, local_erif); -+} -+ -+static inline void -+mlxsw_reg_ralue_act_ip2me_pack(char *payload) -+{ -+ mlxsw_reg_ralue_action_type_set(payload, -+ MLXSW_REG_RALUE_ACTION_TYPE_IP2ME); -+} -+ -+static inline void -+mlxsw_reg_ralue_act_ip2me_tun_pack(char *payload, u32 tunnel_ptr) -+{ -+ mlxsw_reg_ralue_action_type_set(payload, -+ MLXSW_REG_RALUE_ACTION_TYPE_IP2ME); -+ mlxsw_reg_ralue_ip2me_v_set(payload, 1); -+ mlxsw_reg_ralue_ip2me_tunnel_ptr_set(payload, tunnel_ptr); -+} -+ -+/* RAUHT - Router Algorithmic LPM Unicast Host Table Register -+ * ---------------------------------------------------------- -+ * The RAUHT register is used to configure and query the Unicast Host table in -+ * devices that implement the Algorithmic LPM. -+ */ -+#define MLXSW_REG_RAUHT_ID 0x8014 -+#define MLXSW_REG_RAUHT_LEN 0x74 -+ -+MLXSW_REG_DEFINE(rauht, MLXSW_REG_RAUHT_ID, MLXSW_REG_RAUHT_LEN); -+ -+enum mlxsw_reg_rauht_type { -+ MLXSW_REG_RAUHT_TYPE_IPV4, -+ MLXSW_REG_RAUHT_TYPE_IPV6, -+}; -+ -+/* reg_rauht_type -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rauht, type, 0x00, 24, 2); -+ -+enum mlxsw_reg_rauht_op { -+ MLXSW_REG_RAUHT_OP_QUERY_READ = 0, -+ /* Read operation */ -+ MLXSW_REG_RAUHT_OP_QUERY_CLEAR_ON_READ = 1, -+ /* Clear on read operation. Used to read entry and clear -+ * activity bit. -+ */ -+ MLXSW_REG_RAUHT_OP_WRITE_ADD = 0, -+ /* Add. Used to write a new entry to the table. All R/W fields are -+ * relevant for new entry. Activity bit is set for new entries. -+ */ -+ MLXSW_REG_RAUHT_OP_WRITE_UPDATE = 1, -+ /* Update action. Used to update an existing route entry and -+ * only update the following fields: -+ * trap_action, trap_id, mac, counter_set_type, counter_index -+ */ -+ MLXSW_REG_RAUHT_OP_WRITE_CLEAR_ACTIVITY = 2, -+ /* Clear activity. A bit is cleared for the entry. */ -+ MLXSW_REG_RAUHT_OP_WRITE_DELETE = 3, -+ /* Delete entry */ -+ MLXSW_REG_RAUHT_OP_WRITE_DELETE_ALL = 4, -+ /* Delete all host entries on a RIF. In this command, dip -+ * field is reserved. -+ */ -+}; -+ -+/* reg_rauht_op -+ * Access: OP -+ */ -+MLXSW_ITEM32(reg, rauht, op, 0x00, 20, 3); -+ -+/* reg_rauht_a -+ * Activity. Set for new entries. Set if a packet lookup has hit on -+ * the specific entry. -+ * To clear the a bit, use "clear activity" op. -+ * Enabled by activity_dis in RGCR -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, rauht, a, 0x00, 16, 1); -+ -+/* reg_rauht_rif -+ * Router Interface -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rauht, rif, 0x00, 0, 16); -+ -+/* reg_rauht_dip* -+ * Destination address. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rauht, dip4, 0x1C, 0x0, 32); -+MLXSW_ITEM_BUF(reg, rauht, dip6, 0x10, 16); -+ -+enum mlxsw_reg_rauht_trap_action { -+ MLXSW_REG_RAUHT_TRAP_ACTION_NOP, -+ MLXSW_REG_RAUHT_TRAP_ACTION_TRAP, -+ MLXSW_REG_RAUHT_TRAP_ACTION_MIRROR_TO_CPU, -+ MLXSW_REG_RAUHT_TRAP_ACTION_MIRROR, -+ MLXSW_REG_RAUHT_TRAP_ACTION_DISCARD_ERRORS, -+}; -+ -+/* reg_rauht_trap_action -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rauht, trap_action, 0x60, 28, 4); -+ -+enum mlxsw_reg_rauht_trap_id { -+ MLXSW_REG_RAUHT_TRAP_ID_RTR_EGRESS0, -+ MLXSW_REG_RAUHT_TRAP_ID_RTR_EGRESS1, -+}; -+ -+/* reg_rauht_trap_id -+ * Trap ID to be reported to CPU. -+ * Trap-ID is RTR_EGRESS0 or RTR_EGRESS1. -+ * For trap_action of NOP, MIRROR and DISCARD_ERROR, -+ * trap_id is reserved. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rauht, trap_id, 0x60, 0, 9); -+ -+/* reg_rauht_counter_set_type -+ * Counter set type for flow counters -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rauht, counter_set_type, 0x68, 24, 8); -+ -+/* reg_rauht_counter_index -+ * Counter index for flow counters -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rauht, counter_index, 0x68, 0, 24); -+ -+/* reg_rauht_mac -+ * MAC address. -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, rauht, mac, 0x6E, 6); -+ -+static inline void mlxsw_reg_rauht_pack(char *payload, -+ enum mlxsw_reg_rauht_op op, u16 rif, -+ const char *mac) -+{ -+ MLXSW_REG_ZERO(rauht, payload); -+ mlxsw_reg_rauht_op_set(payload, op); -+ mlxsw_reg_rauht_rif_set(payload, rif); -+ mlxsw_reg_rauht_mac_memcpy_to(payload, mac); -+} -+ -+static inline void mlxsw_reg_rauht_pack4(char *payload, -+ enum mlxsw_reg_rauht_op op, u16 rif, -+ const char *mac, u32 dip) -+{ -+ mlxsw_reg_rauht_pack(payload, op, rif, mac); -+ mlxsw_reg_rauht_dip4_set(payload, dip); -+} -+ -+static inline void mlxsw_reg_rauht_pack6(char *payload, -+ enum mlxsw_reg_rauht_op op, u16 rif, -+ const char *mac, const char *dip) -+{ -+ mlxsw_reg_rauht_pack(payload, op, rif, mac); -+ mlxsw_reg_rauht_type_set(payload, MLXSW_REG_RAUHT_TYPE_IPV6); -+ mlxsw_reg_rauht_dip6_memcpy_to(payload, dip); -+} -+ -+static inline void mlxsw_reg_rauht_pack_counter(char *payload, -+ u64 counter_index) -+{ -+ mlxsw_reg_rauht_counter_index_set(payload, counter_index); -+ mlxsw_reg_rauht_counter_set_type_set(payload, -+ MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES); -+} -+ -+/* RALEU - Router Algorithmic LPM ECMP Update Register -+ * --------------------------------------------------- -+ * The register enables updating the ECMP section in the action for multiple -+ * LPM Unicast entries in a single operation. The update is executed to -+ * all entries of a {virtual router, protocol} tuple using the same ECMP group. -+ */ -+#define MLXSW_REG_RALEU_ID 0x8015 -+#define MLXSW_REG_RALEU_LEN 0x28 -+ -+MLXSW_REG_DEFINE(raleu, MLXSW_REG_RALEU_ID, MLXSW_REG_RALEU_LEN); -+ -+/* reg_raleu_protocol -+ * Protocol. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, raleu, protocol, 0x00, 24, 4); -+ -+/* reg_raleu_virtual_router -+ * Virtual Router ID -+ * Range is 0..cap_max_virtual_routers-1 -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, raleu, virtual_router, 0x00, 0, 16); -+ -+/* reg_raleu_adjacency_index -+ * Adjacency Index used for matching on the existing entries. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, raleu, adjacency_index, 0x10, 0, 24); -+ -+/* reg_raleu_ecmp_size -+ * ECMP Size used for matching on the existing entries. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, raleu, ecmp_size, 0x14, 0, 13); -+ -+/* reg_raleu_new_adjacency_index -+ * New Adjacency Index. -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, raleu, new_adjacency_index, 0x20, 0, 24); -+ -+/* reg_raleu_new_ecmp_size -+ * New ECMP Size. -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, raleu, new_ecmp_size, 0x24, 0, 13); -+ -+static inline void mlxsw_reg_raleu_pack(char *payload, -+ enum mlxsw_reg_ralxx_protocol protocol, -+ u16 virtual_router, -+ u32 adjacency_index, u16 ecmp_size, -+ u32 new_adjacency_index, -+ u16 new_ecmp_size) -+{ -+ MLXSW_REG_ZERO(raleu, payload); -+ mlxsw_reg_raleu_protocol_set(payload, protocol); -+ mlxsw_reg_raleu_virtual_router_set(payload, virtual_router); -+ mlxsw_reg_raleu_adjacency_index_set(payload, adjacency_index); -+ mlxsw_reg_raleu_ecmp_size_set(payload, ecmp_size); -+ mlxsw_reg_raleu_new_adjacency_index_set(payload, new_adjacency_index); -+ mlxsw_reg_raleu_new_ecmp_size_set(payload, new_ecmp_size); -+} -+ -+/* RAUHTD - Router Algorithmic LPM Unicast Host Table Dump Register -+ * ---------------------------------------------------------------- -+ * The RAUHTD register allows dumping entries from the Router Unicast Host -+ * Table. For a given session an entry is dumped no more than one time. The -+ * first RAUHTD access after reset is a new session. A session ends when the -+ * num_rec response is smaller than num_rec request or for IPv4 when the -+ * num_entries is smaller than 4. The clear activity affect the current session -+ * or the last session if a new session has not started. -+ */ -+#define MLXSW_REG_RAUHTD_ID 0x8018 -+#define MLXSW_REG_RAUHTD_BASE_LEN 0x20 -+#define MLXSW_REG_RAUHTD_REC_LEN 0x20 -+#define MLXSW_REG_RAUHTD_REC_MAX_NUM 32 -+#define MLXSW_REG_RAUHTD_LEN (MLXSW_REG_RAUHTD_BASE_LEN + \ -+ MLXSW_REG_RAUHTD_REC_MAX_NUM * MLXSW_REG_RAUHTD_REC_LEN) -+#define MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC 4 -+ -+MLXSW_REG_DEFINE(rauhtd, MLXSW_REG_RAUHTD_ID, MLXSW_REG_RAUHTD_LEN); -+ -+#define MLXSW_REG_RAUHTD_FILTER_A BIT(0) -+#define MLXSW_REG_RAUHTD_FILTER_RIF BIT(3) -+ -+/* reg_rauhtd_filter_fields -+ * if a bit is '0' then the relevant field is ignored and dump is done -+ * regardless of the field value -+ * Bit0 - filter by activity: entry_a -+ * Bit3 - filter by entry rip: entry_rif -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rauhtd, filter_fields, 0x00, 0, 8); -+ -+enum mlxsw_reg_rauhtd_op { -+ MLXSW_REG_RAUHTD_OP_DUMP, -+ MLXSW_REG_RAUHTD_OP_DUMP_AND_CLEAR, -+}; -+ -+/* reg_rauhtd_op -+ * Access: OP -+ */ -+MLXSW_ITEM32(reg, rauhtd, op, 0x04, 24, 2); -+ -+/* reg_rauhtd_num_rec -+ * At request: number of records requested -+ * At response: number of records dumped -+ * For IPv4, each record has 4 entries at request and up to 4 entries -+ * at response -+ * Range is 0..MLXSW_REG_RAUHTD_REC_MAX_NUM -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rauhtd, num_rec, 0x04, 0, 8); -+ -+/* reg_rauhtd_entry_a -+ * Dump only if activity has value of entry_a -+ * Reserved if filter_fields bit0 is '0' -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rauhtd, entry_a, 0x08, 16, 1); -+ -+enum mlxsw_reg_rauhtd_type { -+ MLXSW_REG_RAUHTD_TYPE_IPV4, -+ MLXSW_REG_RAUHTD_TYPE_IPV6, -+}; -+ -+/* reg_rauhtd_type -+ * Dump only if record type is: -+ * 0 - IPv4 -+ * 1 - IPv6 -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rauhtd, type, 0x08, 0, 4); -+ -+/* reg_rauhtd_entry_rif -+ * Dump only if RIF has value of entry_rif -+ * Reserved if filter_fields bit3 is '0' -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rauhtd, entry_rif, 0x0C, 0, 16); -+ -+static inline void mlxsw_reg_rauhtd_pack(char *payload, -+ enum mlxsw_reg_rauhtd_type type) -+{ -+ MLXSW_REG_ZERO(rauhtd, payload); -+ mlxsw_reg_rauhtd_filter_fields_set(payload, MLXSW_REG_RAUHTD_FILTER_A); -+ mlxsw_reg_rauhtd_op_set(payload, MLXSW_REG_RAUHTD_OP_DUMP_AND_CLEAR); -+ mlxsw_reg_rauhtd_num_rec_set(payload, MLXSW_REG_RAUHTD_REC_MAX_NUM); -+ mlxsw_reg_rauhtd_entry_a_set(payload, 1); -+ mlxsw_reg_rauhtd_type_set(payload, type); -+} -+ -+/* reg_rauhtd_ipv4_rec_num_entries -+ * Number of valid entries in this record: -+ * 0 - 1 valid entry -+ * 1 - 2 valid entries -+ * 2 - 3 valid entries -+ * 3 - 4 valid entries -+ * Access: RO -+ */ -+MLXSW_ITEM32_INDEXED(reg, rauhtd, ipv4_rec_num_entries, -+ MLXSW_REG_RAUHTD_BASE_LEN, 28, 2, -+ MLXSW_REG_RAUHTD_REC_LEN, 0x00, false); -+ -+/* reg_rauhtd_rec_type -+ * Record type. -+ * 0 - IPv4 -+ * 1 - IPv6 -+ * Access: RO -+ */ -+MLXSW_ITEM32_INDEXED(reg, rauhtd, rec_type, MLXSW_REG_RAUHTD_BASE_LEN, 24, 2, -+ MLXSW_REG_RAUHTD_REC_LEN, 0x00, false); -+ -+#define MLXSW_REG_RAUHTD_IPV4_ENT_LEN 0x8 -+ -+/* reg_rauhtd_ipv4_ent_a -+ * Activity. Set for new entries. Set if a packet lookup has hit on the -+ * specific entry. -+ * Access: RO -+ */ -+MLXSW_ITEM32_INDEXED(reg, rauhtd, ipv4_ent_a, MLXSW_REG_RAUHTD_BASE_LEN, 16, 1, -+ MLXSW_REG_RAUHTD_IPV4_ENT_LEN, 0x00, false); -+ -+/* reg_rauhtd_ipv4_ent_rif -+ * Router interface. -+ * Access: RO -+ */ -+MLXSW_ITEM32_INDEXED(reg, rauhtd, ipv4_ent_rif, MLXSW_REG_RAUHTD_BASE_LEN, 0, -+ 16, MLXSW_REG_RAUHTD_IPV4_ENT_LEN, 0x00, false); -+ -+/* reg_rauhtd_ipv4_ent_dip -+ * Destination IPv4 address. -+ * Access: RO -+ */ -+MLXSW_ITEM32_INDEXED(reg, rauhtd, ipv4_ent_dip, MLXSW_REG_RAUHTD_BASE_LEN, 0, -+ 32, MLXSW_REG_RAUHTD_IPV4_ENT_LEN, 0x04, false); -+ -+#define MLXSW_REG_RAUHTD_IPV6_ENT_LEN 0x20 -+ -+/* reg_rauhtd_ipv6_ent_a -+ * Activity. Set for new entries. Set if a packet lookup has hit on the -+ * specific entry. -+ * Access: RO -+ */ -+MLXSW_ITEM32_INDEXED(reg, rauhtd, ipv6_ent_a, MLXSW_REG_RAUHTD_BASE_LEN, 16, 1, -+ MLXSW_REG_RAUHTD_IPV6_ENT_LEN, 0x00, false); -+ -+/* reg_rauhtd_ipv6_ent_rif -+ * Router interface. -+ * Access: RO -+ */ -+MLXSW_ITEM32_INDEXED(reg, rauhtd, ipv6_ent_rif, MLXSW_REG_RAUHTD_BASE_LEN, 0, -+ 16, MLXSW_REG_RAUHTD_IPV6_ENT_LEN, 0x00, false); -+ -+/* reg_rauhtd_ipv6_ent_dip -+ * Destination IPv6 address. -+ * Access: RO -+ */ -+MLXSW_ITEM_BUF_INDEXED(reg, rauhtd, ipv6_ent_dip, MLXSW_REG_RAUHTD_BASE_LEN, -+ 16, MLXSW_REG_RAUHTD_IPV6_ENT_LEN, 0x10); -+ -+static inline void mlxsw_reg_rauhtd_ent_ipv4_unpack(char *payload, -+ int ent_index, u16 *p_rif, -+ u32 *p_dip) -+{ -+ *p_rif = mlxsw_reg_rauhtd_ipv4_ent_rif_get(payload, ent_index); -+ *p_dip = mlxsw_reg_rauhtd_ipv4_ent_dip_get(payload, ent_index); -+} -+ -+static inline void mlxsw_reg_rauhtd_ent_ipv6_unpack(char *payload, -+ int rec_index, u16 *p_rif, -+ char *p_dip) -+{ -+ *p_rif = mlxsw_reg_rauhtd_ipv6_ent_rif_get(payload, rec_index); -+ mlxsw_reg_rauhtd_ipv6_ent_dip_memcpy_from(payload, rec_index, p_dip); -+} -+ -+/* RTDP - Routing Tunnel Decap Properties Register -+ * ----------------------------------------------- -+ * The RTDP register is used for configuring the tunnel decap properties of NVE -+ * and IPinIP. -+ */ -+#define MLXSW_REG_RTDP_ID 0x8020 -+#define MLXSW_REG_RTDP_LEN 0x44 -+ -+MLXSW_REG_DEFINE(rtdp, MLXSW_REG_RTDP_ID, MLXSW_REG_RTDP_LEN); -+ -+enum mlxsw_reg_rtdp_type { -+ MLXSW_REG_RTDP_TYPE_NVE, -+ MLXSW_REG_RTDP_TYPE_IPIP, -+}; -+ -+/* reg_rtdp_type -+ * Type of the RTDP entry as per enum mlxsw_reg_rtdp_type. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rtdp, type, 0x00, 28, 4); -+ -+/* reg_rtdp_tunnel_index -+ * Index to the Decap entry. -+ * For Spectrum, Index to KVD Linear. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rtdp, tunnel_index, 0x00, 0, 24); -+ -+/* IPinIP */ -+ -+/* reg_rtdp_ipip_irif -+ * Ingress Router Interface for the overlay router -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rtdp, ipip_irif, 0x04, 16, 16); -+ -+enum mlxsw_reg_rtdp_ipip_sip_check { -+ /* No sip checks. */ -+ MLXSW_REG_RTDP_IPIP_SIP_CHECK_NO, -+ /* Filter packet if underlay is not IPv4 or if underlay SIP does not -+ * equal ipv4_usip. -+ */ -+ MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV4, -+ /* Filter packet if underlay is not IPv6 or if underlay SIP does not -+ * equal ipv6_usip. -+ */ -+ MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV6 = 3, -+}; -+ -+/* reg_rtdp_ipip_sip_check -+ * SIP check to perform. If decapsulation failed due to these configurations -+ * then trap_id is IPIP_DECAP_ERROR. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rtdp, ipip_sip_check, 0x04, 0, 3); -+ -+/* If set, allow decapsulation of IPinIP (without GRE). */ -+#define MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_IPIP BIT(0) -+/* If set, allow decapsulation of IPinGREinIP without a key. */ -+#define MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE BIT(1) -+/* If set, allow decapsulation of IPinGREinIP with a key. */ -+#define MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY BIT(2) -+ -+/* reg_rtdp_ipip_type_check -+ * Flags as per MLXSW_REG_RTDP_IPIP_TYPE_CHECK_*. If decapsulation failed due to -+ * these configurations then trap_id is IPIP_DECAP_ERROR. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rtdp, ipip_type_check, 0x08, 24, 3); -+ -+/* reg_rtdp_ipip_gre_key_check -+ * Whether GRE key should be checked. When check is enabled: -+ * - A packet received as IPinIP (without GRE) will always pass. -+ * - A packet received as IPinGREinIP without a key will not pass the check. -+ * - A packet received as IPinGREinIP with a key will pass the check only if the -+ * key in the packet is equal to expected_gre_key. -+ * If decapsulation failed due to GRE key then trap_id is IPIP_DECAP_ERROR. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rtdp, ipip_gre_key_check, 0x08, 23, 1); -+ -+/* reg_rtdp_ipip_ipv4_usip -+ * Underlay IPv4 address for ipv4 source address check. -+ * Reserved when sip_check is not '1'. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rtdp, ipip_ipv4_usip, 0x0C, 0, 32); -+ -+/* reg_rtdp_ipip_ipv6_usip_ptr -+ * This field is valid when sip_check is "sipv6 check explicitly". This is a -+ * pointer to the IPv6 DIP which is configured by RIPS. For Spectrum, the index -+ * is to the KVD linear. -+ * Reserved when sip_check is not MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV6. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rtdp, ipip_ipv6_usip_ptr, 0x10, 0, 24); -+ -+/* reg_rtdp_ipip_expected_gre_key -+ * GRE key for checking. -+ * Reserved when gre_key_check is '0'. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rtdp, ipip_expected_gre_key, 0x14, 0, 32); -+ -+static inline void mlxsw_reg_rtdp_pack(char *payload, -+ enum mlxsw_reg_rtdp_type type, -+ u32 tunnel_index) -+{ -+ MLXSW_REG_ZERO(rtdp, payload); -+ mlxsw_reg_rtdp_type_set(payload, type); -+ mlxsw_reg_rtdp_tunnel_index_set(payload, tunnel_index); -+} -+ -+static inline void -+mlxsw_reg_rtdp_ipip4_pack(char *payload, u16 irif, -+ enum mlxsw_reg_rtdp_ipip_sip_check sip_check, -+ unsigned int type_check, bool gre_key_check, -+ u32 ipv4_usip, u32 expected_gre_key) -+{ -+ mlxsw_reg_rtdp_ipip_irif_set(payload, irif); -+ mlxsw_reg_rtdp_ipip_sip_check_set(payload, sip_check); -+ mlxsw_reg_rtdp_ipip_type_check_set(payload, type_check); -+ mlxsw_reg_rtdp_ipip_gre_key_check_set(payload, gre_key_check); -+ mlxsw_reg_rtdp_ipip_ipv4_usip_set(payload, ipv4_usip); -+ mlxsw_reg_rtdp_ipip_expected_gre_key_set(payload, expected_gre_key); -+} -+ -+/* RIGR-V2 - Router Interface Group Register Version 2 -+ * --------------------------------------------------- -+ * The RIGR_V2 register is used to add, remove and query egress interface list -+ * of a multicast forwarding entry. -+ */ -+#define MLXSW_REG_RIGR2_ID 0x8023 -+#define MLXSW_REG_RIGR2_LEN 0xB0 -+ -+#define MLXSW_REG_RIGR2_MAX_ERIFS 32 -+ -+MLXSW_REG_DEFINE(rigr2, MLXSW_REG_RIGR2_ID, MLXSW_REG_RIGR2_LEN); -+ -+/* reg_rigr2_rigr_index -+ * KVD Linear index. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rigr2, rigr_index, 0x04, 0, 24); -+ -+/* reg_rigr2_vnext -+ * Next RIGR Index is valid. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rigr2, vnext, 0x08, 31, 1); -+ -+/* reg_rigr2_next_rigr_index -+ * Next RIGR Index. The index is to the KVD linear. -+ * Reserved when vnxet = '0'. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rigr2, next_rigr_index, 0x08, 0, 24); -+ -+/* reg_rigr2_vrmid -+ * RMID Index is valid. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rigr2, vrmid, 0x20, 31, 1); -+ -+/* reg_rigr2_rmid_index -+ * RMID Index. -+ * Range 0 .. max_mid - 1 -+ * Reserved when vrmid = '0'. -+ * The index is to the Port Group Table (PGT) -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rigr2, rmid_index, 0x20, 0, 16); -+ -+/* reg_rigr2_erif_entry_v -+ * Egress Router Interface is valid. -+ * Note that low-entries must be set if high-entries are set. For -+ * example: if erif_entry[2].v is set then erif_entry[1].v and -+ * erif_entry[0].v must be set. -+ * Index can be from 0 to cap_mc_erif_list_entries-1 -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, rigr2, erif_entry_v, 0x24, 31, 1, 4, 0, false); -+ -+/* reg_rigr2_erif_entry_erif -+ * Egress Router Interface. -+ * Valid range is from 0 to cap_max_router_interfaces - 1 -+ * Index can be from 0 to MLXSW_REG_RIGR2_MAX_ERIFS - 1 -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, rigr2, erif_entry_erif, 0x24, 0, 16, 4, 0, false); -+ -+static inline void mlxsw_reg_rigr2_pack(char *payload, u32 rigr_index, -+ bool vnext, u32 next_rigr_index) -+{ -+ MLXSW_REG_ZERO(rigr2, payload); -+ mlxsw_reg_rigr2_rigr_index_set(payload, rigr_index); -+ mlxsw_reg_rigr2_vnext_set(payload, vnext); -+ mlxsw_reg_rigr2_next_rigr_index_set(payload, next_rigr_index); -+ mlxsw_reg_rigr2_vrmid_set(payload, 0); -+ mlxsw_reg_rigr2_rmid_index_set(payload, 0); -+} -+ -+static inline void mlxsw_reg_rigr2_erif_entry_pack(char *payload, int index, -+ bool v, u16 erif) -+{ -+ mlxsw_reg_rigr2_erif_entry_v_set(payload, index, v); -+ mlxsw_reg_rigr2_erif_entry_erif_set(payload, index, erif); -+} -+ -+/* RECR-V2 - Router ECMP Configuration Version 2 Register -+ * ------------------------------------------------------ -+ */ -+#define MLXSW_REG_RECR2_ID 0x8025 -+#define MLXSW_REG_RECR2_LEN 0x38 -+ -+MLXSW_REG_DEFINE(recr2, MLXSW_REG_RECR2_ID, MLXSW_REG_RECR2_LEN); -+ -+/* reg_recr2_pp -+ * Per-port configuration -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, recr2, pp, 0x00, 24, 1); -+ -+/* reg_recr2_sh -+ * Symmetric hash -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, recr2, sh, 0x00, 8, 1); -+ -+/* reg_recr2_seed -+ * Seed -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, recr2, seed, 0x08, 0, 32); -+ -+enum { -+ /* Enable IPv4 fields if packet is not TCP and not UDP */ -+ MLXSW_REG_RECR2_IPV4_EN_NOT_TCP_NOT_UDP = 3, -+ /* Enable IPv4 fields if packet is TCP or UDP */ -+ MLXSW_REG_RECR2_IPV4_EN_TCP_UDP = 4, -+ /* Enable IPv6 fields if packet is not TCP and not UDP */ -+ MLXSW_REG_RECR2_IPV6_EN_NOT_TCP_NOT_UDP = 5, -+ /* Enable IPv6 fields if packet is TCP or UDP */ -+ MLXSW_REG_RECR2_IPV6_EN_TCP_UDP = 6, -+ /* Enable TCP/UDP header fields if packet is IPv4 */ -+ MLXSW_REG_RECR2_TCP_UDP_EN_IPV4 = 7, -+ /* Enable TCP/UDP header fields if packet is IPv6 */ -+ MLXSW_REG_RECR2_TCP_UDP_EN_IPV6 = 8, -+}; -+ -+/* reg_recr2_outer_header_enables -+ * Bit mask where each bit enables a specific layer to be included in -+ * the hash calculation. -+ * Access: RW -+ */ -+MLXSW_ITEM_BIT_ARRAY(reg, recr2, outer_header_enables, 0x10, 0x04, 1); -+ -+enum { -+ /* IPv4 Source IP */ -+ MLXSW_REG_RECR2_IPV4_SIP0 = 9, -+ MLXSW_REG_RECR2_IPV4_SIP3 = 12, -+ /* IPv4 Destination IP */ -+ MLXSW_REG_RECR2_IPV4_DIP0 = 13, -+ MLXSW_REG_RECR2_IPV4_DIP3 = 16, -+ /* IP Protocol */ -+ MLXSW_REG_RECR2_IPV4_PROTOCOL = 17, -+ /* IPv6 Source IP */ -+ MLXSW_REG_RECR2_IPV6_SIP0_7 = 21, -+ MLXSW_REG_RECR2_IPV6_SIP8 = 29, -+ MLXSW_REG_RECR2_IPV6_SIP15 = 36, -+ /* IPv6 Destination IP */ -+ MLXSW_REG_RECR2_IPV6_DIP0_7 = 37, -+ MLXSW_REG_RECR2_IPV6_DIP8 = 45, -+ MLXSW_REG_RECR2_IPV6_DIP15 = 52, -+ /* IPv6 Next Header */ -+ MLXSW_REG_RECR2_IPV6_NEXT_HEADER = 53, -+ /* IPv6 Flow Label */ -+ MLXSW_REG_RECR2_IPV6_FLOW_LABEL = 57, -+ /* TCP/UDP Source Port */ -+ MLXSW_REG_RECR2_TCP_UDP_SPORT = 74, -+ /* TCP/UDP Destination Port */ -+ MLXSW_REG_RECR2_TCP_UDP_DPORT = 75, -+}; -+ -+/* reg_recr2_outer_header_fields_enable -+ * Packet fields to enable for ECMP hash subject to outer_header_enable. -+ * Access: RW -+ */ -+MLXSW_ITEM_BIT_ARRAY(reg, recr2, outer_header_fields_enable, 0x14, 0x14, 1); -+ -+static inline void mlxsw_reg_recr2_ipv4_sip_enable(char *payload) -+{ -+ int i; -+ -+ for (i = MLXSW_REG_RECR2_IPV4_SIP0; i <= MLXSW_REG_RECR2_IPV4_SIP3; i++) -+ mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i, -+ true); -+} -+ -+static inline void mlxsw_reg_recr2_ipv4_dip_enable(char *payload) -+{ -+ int i; -+ -+ for (i = MLXSW_REG_RECR2_IPV4_DIP0; i <= MLXSW_REG_RECR2_IPV4_DIP3; i++) -+ mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i, -+ true); -+} -+ -+static inline void mlxsw_reg_recr2_ipv6_sip_enable(char *payload) -+{ -+ int i = MLXSW_REG_RECR2_IPV6_SIP0_7; -+ -+ mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i, true); -+ -+ i = MLXSW_REG_RECR2_IPV6_SIP8; -+ for (; i <= MLXSW_REG_RECR2_IPV6_SIP15; i++) -+ mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i, -+ true); -+} -+ -+static inline void mlxsw_reg_recr2_ipv6_dip_enable(char *payload) -+{ -+ int i = MLXSW_REG_RECR2_IPV6_DIP0_7; -+ -+ mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i, true); -+ -+ i = MLXSW_REG_RECR2_IPV6_DIP8; -+ for (; i <= MLXSW_REG_RECR2_IPV6_DIP15; i++) -+ mlxsw_reg_recr2_outer_header_fields_enable_set(payload, i, -+ true); -+} -+ -+static inline void mlxsw_reg_recr2_pack(char *payload, u32 seed) -+{ -+ MLXSW_REG_ZERO(recr2, payload); -+ mlxsw_reg_recr2_pp_set(payload, false); -+ mlxsw_reg_recr2_sh_set(payload, true); -+ mlxsw_reg_recr2_seed_set(payload, seed); -+} -+ -+/* RMFT-V2 - Router Multicast Forwarding Table Version 2 Register -+ * -------------------------------------------------------------- -+ * The RMFT_V2 register is used to configure and query the multicast table. -+ */ -+#define MLXSW_REG_RMFT2_ID 0x8027 -+#define MLXSW_REG_RMFT2_LEN 0x174 -+ -+MLXSW_REG_DEFINE(rmft2, MLXSW_REG_RMFT2_ID, MLXSW_REG_RMFT2_LEN); -+ -+/* reg_rmft2_v -+ * Valid -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rmft2, v, 0x00, 31, 1); -+ -+enum mlxsw_reg_rmft2_type { -+ MLXSW_REG_RMFT2_TYPE_IPV4, -+ MLXSW_REG_RMFT2_TYPE_IPV6 -+}; -+ -+/* reg_rmft2_type -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rmft2, type, 0x00, 28, 2); -+ -+enum mlxsw_sp_reg_rmft2_op { -+ /* For Write: -+ * Write operation. Used to write a new entry to the table. All RW -+ * fields are relevant for new entry. Activity bit is set for new -+ * entries - Note write with v (Valid) 0 will delete the entry. -+ * For Query: -+ * Read operation -+ */ -+ MLXSW_REG_RMFT2_OP_READ_WRITE, -+}; -+ -+/* reg_rmft2_op -+ * Operation. -+ * Access: OP -+ */ -+MLXSW_ITEM32(reg, rmft2, op, 0x00, 20, 2); -+ -+/* reg_rmft2_a -+ * Activity. Set for new entries. Set if a packet lookup has hit on the specific -+ * entry. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, rmft2, a, 0x00, 16, 1); -+ -+/* reg_rmft2_offset -+ * Offset within the multicast forwarding table to write to. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, rmft2, offset, 0x00, 0, 16); -+ -+/* reg_rmft2_virtual_router -+ * Virtual Router ID. Range from 0..cap_max_virtual_routers-1 -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rmft2, virtual_router, 0x04, 0, 16); -+ -+enum mlxsw_reg_rmft2_irif_mask { -+ MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, -+ MLXSW_REG_RMFT2_IRIF_MASK_COMPARE -+}; -+ -+/* reg_rmft2_irif_mask -+ * Ingress RIF mask. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rmft2, irif_mask, 0x08, 24, 1); -+ -+/* reg_rmft2_irif -+ * Ingress RIF index. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, rmft2, irif, 0x08, 0, 16); -+ -+/* reg_rmft2_dip{4,6} -+ * Destination IPv4/6 address -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, rmft2, dip6, 0x10, 16); -+MLXSW_ITEM32(reg, rmft2, dip4, 0x1C, 0, 32); -+ -+/* reg_rmft2_dip{4,6}_mask -+ * A bit that is set directs the TCAM to compare the corresponding bit in key. A -+ * bit that is clear directs the TCAM to ignore the corresponding bit in key. -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, rmft2, dip6_mask, 0x20, 16); -+MLXSW_ITEM32(reg, rmft2, dip4_mask, 0x2C, 0, 32); -+ -+/* reg_rmft2_sip{4,6} -+ * Source IPv4/6 address -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, rmft2, sip6, 0x30, 16); -+MLXSW_ITEM32(reg, rmft2, sip4, 0x3C, 0, 32); -+ -+/* reg_rmft2_sip{4,6}_mask -+ * A bit that is set directs the TCAM to compare the corresponding bit in key. A -+ * bit that is clear directs the TCAM to ignore the corresponding bit in key. -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, rmft2, sip6_mask, 0x40, 16); -+MLXSW_ITEM32(reg, rmft2, sip4_mask, 0x4C, 0, 32); -+ -+/* reg_rmft2_flexible_action_set -+ * ACL action set. The only supported action types in this field and in any -+ * action-set pointed from here are as follows: -+ * 00h: ACTION_NULL -+ * 01h: ACTION_MAC_TTL, only TTL configuration is supported. -+ * 03h: ACTION_TRAP -+ * 06h: ACTION_QOS -+ * 08h: ACTION_POLICING_MONITORING -+ * 10h: ACTION_ROUTER_MC -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, rmft2, flexible_action_set, 0x80, -+ MLXSW_REG_FLEX_ACTION_SET_LEN); -+ -+static inline void -+mlxsw_reg_rmft2_common_pack(char *payload, bool v, u16 offset, -+ u16 virtual_router, -+ enum mlxsw_reg_rmft2_irif_mask irif_mask, u16 irif, -+ const char *flex_action_set) -+{ -+ MLXSW_REG_ZERO(rmft2, payload); -+ mlxsw_reg_rmft2_v_set(payload, v); -+ mlxsw_reg_rmft2_op_set(payload, MLXSW_REG_RMFT2_OP_READ_WRITE); -+ mlxsw_reg_rmft2_offset_set(payload, offset); -+ mlxsw_reg_rmft2_virtual_router_set(payload, virtual_router); -+ mlxsw_reg_rmft2_irif_mask_set(payload, irif_mask); -+ mlxsw_reg_rmft2_irif_set(payload, irif); -+ if (flex_action_set) -+ mlxsw_reg_rmft2_flexible_action_set_memcpy_to(payload, -+ flex_action_set); -+} -+ -+static inline void -+mlxsw_reg_rmft2_ipv4_pack(char *payload, bool v, u16 offset, u16 virtual_router, -+ enum mlxsw_reg_rmft2_irif_mask irif_mask, u16 irif, -+ u32 dip4, u32 dip4_mask, u32 sip4, u32 sip4_mask, -+ const char *flexible_action_set) -+{ -+ mlxsw_reg_rmft2_common_pack(payload, v, offset, virtual_router, -+ irif_mask, irif, flexible_action_set); -+ mlxsw_reg_rmft2_type_set(payload, MLXSW_REG_RMFT2_TYPE_IPV4); -+ mlxsw_reg_rmft2_dip4_set(payload, dip4); -+ mlxsw_reg_rmft2_dip4_mask_set(payload, dip4_mask); -+ mlxsw_reg_rmft2_sip4_set(payload, sip4); -+ mlxsw_reg_rmft2_sip4_mask_set(payload, sip4_mask); -+} -+ -+static inline void -+mlxsw_reg_rmft2_ipv6_pack(char *payload, bool v, u16 offset, u16 virtual_router, -+ enum mlxsw_reg_rmft2_irif_mask irif_mask, u16 irif, -+ struct in6_addr dip6, struct in6_addr dip6_mask, -+ struct in6_addr sip6, struct in6_addr sip6_mask, -+ const char *flexible_action_set) -+{ -+ mlxsw_reg_rmft2_common_pack(payload, v, offset, virtual_router, -+ irif_mask, irif, flexible_action_set); -+ mlxsw_reg_rmft2_type_set(payload, MLXSW_REG_RMFT2_TYPE_IPV6); -+ mlxsw_reg_rmft2_dip6_memcpy_to(payload, (void *)&dip6); -+ mlxsw_reg_rmft2_dip6_mask_memcpy_to(payload, (void *)&dip6_mask); -+ mlxsw_reg_rmft2_sip6_memcpy_to(payload, (void *)&sip6); -+ mlxsw_reg_rmft2_sip6_mask_memcpy_to(payload, (void *)&sip6_mask); -+} -+ -+/* MFCR - Management Fan Control Register -+ * -------------------------------------- -+ * This register controls the settings of the Fan Speed PWM mechanism. -+ */ -+#define MLXSW_REG_MFCR_ID 0x9001 -+#define MLXSW_REG_MFCR_LEN 0x08 -+ -+MLXSW_REG_DEFINE(mfcr, MLXSW_REG_MFCR_ID, MLXSW_REG_MFCR_LEN); -+ -+enum mlxsw_reg_mfcr_pwm_frequency { -+ MLXSW_REG_MFCR_PWM_FEQ_11HZ = 0x00, -+ MLXSW_REG_MFCR_PWM_FEQ_14_7HZ = 0x01, -+ MLXSW_REG_MFCR_PWM_FEQ_22_1HZ = 0x02, -+ MLXSW_REG_MFCR_PWM_FEQ_1_4KHZ = 0x40, -+ MLXSW_REG_MFCR_PWM_FEQ_5KHZ = 0x41, -+ MLXSW_REG_MFCR_PWM_FEQ_20KHZ = 0x42, -+ MLXSW_REG_MFCR_PWM_FEQ_22_5KHZ = 0x43, -+ MLXSW_REG_MFCR_PWM_FEQ_25KHZ = 0x44, -+}; -+ -+/* reg_mfcr_pwm_frequency -+ * Controls the frequency of the PWM signal. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mfcr, pwm_frequency, 0x00, 0, 7); -+ -+#define MLXSW_MFCR_TACHOS_MAX 10 -+ -+/* reg_mfcr_tacho_active -+ * Indicates which of the tachometer is active (bit per tachometer). -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, mfcr, tacho_active, 0x04, 16, MLXSW_MFCR_TACHOS_MAX); -+ -+#define MLXSW_MFCR_PWMS_MAX 5 -+ -+/* reg_mfcr_pwm_active -+ * Indicates which of the PWM control is active (bit per PWM). -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, mfcr, pwm_active, 0x04, 0, MLXSW_MFCR_PWMS_MAX); -+ -+static inline void -+mlxsw_reg_mfcr_pack(char *payload, -+ enum mlxsw_reg_mfcr_pwm_frequency pwm_frequency) -+{ -+ MLXSW_REG_ZERO(mfcr, payload); -+ mlxsw_reg_mfcr_pwm_frequency_set(payload, pwm_frequency); -+} -+ -+static inline void -+mlxsw_reg_mfcr_unpack(char *payload, -+ enum mlxsw_reg_mfcr_pwm_frequency *p_pwm_frequency, -+ u16 *p_tacho_active, u8 *p_pwm_active) -+{ -+ *p_pwm_frequency = mlxsw_reg_mfcr_pwm_frequency_get(payload); -+ *p_tacho_active = mlxsw_reg_mfcr_tacho_active_get(payload); -+ *p_pwm_active = mlxsw_reg_mfcr_pwm_active_get(payload); -+} -+ -+/* MFSC - Management Fan Speed Control Register -+ * -------------------------------------------- -+ * This register controls the settings of the Fan Speed PWM mechanism. -+ */ -+#define MLXSW_REG_MFSC_ID 0x9002 -+#define MLXSW_REG_MFSC_LEN 0x08 -+ -+MLXSW_REG_DEFINE(mfsc, MLXSW_REG_MFSC_ID, MLXSW_REG_MFSC_LEN); -+ -+/* reg_mfsc_pwm -+ * Fan pwm to control / monitor. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, mfsc, pwm, 0x00, 24, 3); -+ -+/* reg_mfsc_pwm_duty_cycle -+ * Controls the duty cycle of the PWM. Value range from 0..255 to -+ * represent duty cycle of 0%...100%. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mfsc, pwm_duty_cycle, 0x04, 0, 8); -+ -+static inline void mlxsw_reg_mfsc_pack(char *payload, u8 pwm, -+ u8 pwm_duty_cycle) -+{ -+ MLXSW_REG_ZERO(mfsc, payload); -+ mlxsw_reg_mfsc_pwm_set(payload, pwm); -+ mlxsw_reg_mfsc_pwm_duty_cycle_set(payload, pwm_duty_cycle); -+} -+ -+/* MFSM - Management Fan Speed Measurement -+ * --------------------------------------- -+ * This register controls the settings of the Tacho measurements and -+ * enables reading the Tachometer measurements. -+ */ -+#define MLXSW_REG_MFSM_ID 0x9003 -+#define MLXSW_REG_MFSM_LEN 0x08 -+ -+MLXSW_REG_DEFINE(mfsm, MLXSW_REG_MFSM_ID, MLXSW_REG_MFSM_LEN); -+ -+/* reg_mfsm_tacho -+ * Fan tachometer index. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, mfsm, tacho, 0x00, 24, 4); -+ -+/* reg_mfsm_rpm -+ * Fan speed (round per minute). -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, mfsm, rpm, 0x04, 0, 16); -+ -+static inline void mlxsw_reg_mfsm_pack(char *payload, u8 tacho) -+{ -+ MLXSW_REG_ZERO(mfsm, payload); -+ mlxsw_reg_mfsm_tacho_set(payload, tacho); -+} -+ -+/* MFSL - Management Fan Speed Limit Register -+ * ------------------------------------------ -+ * The Fan Speed Limit register is used to configure the fan speed -+ * event / interrupt notification mechanism. Fan speed threshold are -+ * defined for both under-speed and over-speed. -+ */ -+#define MLXSW_REG_MFSL_ID 0x9004 -+#define MLXSW_REG_MFSL_LEN 0x0C -+ -+MLXSW_REG_DEFINE(mfsl, MLXSW_REG_MFSL_ID, MLXSW_REG_MFSL_LEN); -+ -+/* reg_mfsl_tacho -+ * Fan tachometer index. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, mfsl, tacho, 0x00, 24, 4); -+ -+/* reg_mfsl_tach_min -+ * Tachometer minimum value (minimum RPM). -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mfsl, tach_min, 0x04, 0, 16); -+ -+/* reg_mfsl_tach_max -+ * Tachometer maximum value (maximum RPM). -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mfsl, tach_max, 0x08, 0, 16); -+ -+static inline void mlxsw_reg_mfsl_pack(char *payload, u8 tacho, -+ u16 tach_min, u16 tach_max) -+{ -+ MLXSW_REG_ZERO(mfsl, payload); -+ mlxsw_reg_mfsl_tacho_set(payload, tacho); -+ mlxsw_reg_mfsl_tach_min_set(payload, tach_min); -+ mlxsw_reg_mfsl_tach_max_set(payload, tach_max); -+} -+ -+static inline void mlxsw_reg_mfsl_unpack(char *payload, u8 tacho, -+ u16 *p_tach_min, u16 *p_tach_max) -+{ -+ if (p_tach_min) -+ *p_tach_min = mlxsw_reg_mfsl_tach_min_get(payload); -+ -+ if (p_tach_max) -+ *p_tach_max = mlxsw_reg_mfsl_tach_max_get(payload); -+} -+ -+/* FORE - Fan Out of Range Event Register -+ * -------------------------------------- -+ * This register reports the status of the controlled fans compared to the -+ * range defined by the MFSL register. -+ */ -+#define MLXSW_REG_FORE_ID 0x9007 -+#define MLXSW_REG_FORE_LEN 0x0C -+ -+MLXSW_REG_DEFINE(fore, MLXSW_REG_FORE_ID, MLXSW_REG_FORE_LEN); -+ -+/* fan_under_limit -+ * Fan speed is below the low limit defined in MFSL register. Each bit relates -+ * to a single tachometer and indicates the specific tachometer reading is -+ * below the threshold. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, fore, fan_under_limit, 0x00, 16, 10); -+ -+static inline void mlxsw_reg_fore_unpack(char *payload, u8 tacho, -+ bool *fan_under_limit) -+{ -+ u16 limit; -+ -+ if (fan_under_limit) { -+ limit = mlxsw_reg_fore_fan_under_limit_get(payload); -+ *fan_under_limit = !!(limit & BIT(tacho)); -+ } -+} -+ -+/* MTCAP - Management Temperature Capabilities -+ * ------------------------------------------- -+ * This register exposes the capabilities of the device and -+ * system temperature sensing. -+ */ -+#define MLXSW_REG_MTCAP_ID 0x9009 -+#define MLXSW_REG_MTCAP_LEN 0x08 -+ -+MLXSW_REG_DEFINE(mtcap, MLXSW_REG_MTCAP_ID, MLXSW_REG_MTCAP_LEN); -+ -+/* reg_mtcap_sensor_count -+ * Number of sensors supported by the device. -+ * This includes the QSFP module sensors (if exists in the QSFP module). -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, mtcap, sensor_count, 0x00, 0, 7); -+ -+/* MTMP - Management Temperature -+ * ----------------------------- -+ * This register controls the settings of the temperature measurements -+ * and enables reading the temperature measurements. Note that temperature -+ * is in 0.125 degrees Celsius. -+ */ -+#define MLXSW_REG_MTMP_ID 0x900A -+#define MLXSW_REG_MTMP_LEN 0x20 -+ -+MLXSW_REG_DEFINE(mtmp, MLXSW_REG_MTMP_ID, MLXSW_REG_MTMP_LEN); -+ -+/* reg_mtmp_sensor_index -+ * Sensors index to access. -+ * 64-127 of sensor_index are mapped to the SFP+/QSFP modules sequentially -+ * (module 0 is mapped to sensor_index 64). -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 7); -+ -+/* Convert to milli degrees Celsius */ -+#define MLXSW_REG_MTMP_TEMP_TO_MC(val) (val * 125) -+ -+/* reg_mtmp_temperature -+ * Temperature reading from the sensor. Reading is in 0.125 Celsius -+ * degrees units. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, mtmp, temperature, 0x04, 0, 16); -+ -+/* reg_mtmp_mte -+ * Max Temperature Enable - enables measuring the max temperature on a sensor. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mtmp, mte, 0x08, 31, 1); -+ -+/* reg_mtmp_mtr -+ * Max Temperature Reset - clears the value of the max temperature register. -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, mtmp, mtr, 0x08, 30, 1); -+ -+/* reg_mtmp_max_temperature -+ * The highest measured temperature from the sensor. -+ * When the bit mte is cleared, the field max_temperature is reserved. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, mtmp, max_temperature, 0x08, 0, 16); -+ -+/* reg_mtmp_tee -+ * Temperature Event Enable. -+ * 0 - Do not generate event -+ * 1 - Generate event -+ * 2 - Generate single event -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mtmp, tee, 0x0C, 30, 2); -+ -+#define MLXSW_REG_MTMP_THRESH_HI 0x348 /* 105 Celsius */ -+ -+/* reg_mtmp_temperature_threshold_hi -+ * High threshold for Temperature Warning Event. In 0.125 Celsius. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, mtmp, temperature_threshold_hi, 0x0C, 0, 16); -+ -+/* reg_mtmp_temperature_threshold_lo -+ * Low threshold for Temperature Warning Event. In 0.125 Celsius. - * Access: RW - */ --MLXSW_ITEM32(reg, ratr, v, 0x00, 24, 1); -+MLXSW_ITEM32(reg, mtmp, temperature_threshold_lo, 0x10, 0, 16); - --/* reg_ratr_a -- * Activity. Set for new entries. Set if a packet lookup has hit on -- * the specific entry. To clear the a bit, use "clear activity". -+#define MLXSW_REG_MTMP_SENSOR_NAME_SIZE 8 -+ -+/* reg_mtmp_sensor_name -+ * Sensor Name - * Access: RO - */ --MLXSW_ITEM32(reg, ratr, a, 0x00, 16, 1); -+MLXSW_ITEM_BUF(reg, mtmp, sensor_name, 0x18, MLXSW_REG_MTMP_SENSOR_NAME_SIZE); - --/* reg_ratr_adjacency_index_low -- * Bits 15:0 of index into the adjacency table. -- * For SwitchX and SwitchX-2, the adjacency table is linear and -- * used for adjacency entries only. -- * For Spectrum, the index is to the KVD linear. -- * Access: Index -- */ --MLXSW_ITEM32(reg, ratr, adjacency_index_low, 0x04, 0, 16); -+static inline void mlxsw_reg_mtmp_pack(char *payload, u8 sensor_index, -+ bool max_temp_enable, -+ bool max_temp_reset) -+{ -+ MLXSW_REG_ZERO(mtmp, payload); -+ 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); -+ mlxsw_reg_mtmp_temperature_threshold_hi_set(payload, -+ MLXSW_REG_MTMP_THRESH_HI); -+} - --/* reg_ratr_egress_router_interface -- * Range is 0 .. cap_max_router_interfaces - 1 -- * Access: RW -- */ --MLXSW_ITEM32(reg, ratr, egress_router_interface, 0x08, 0, 16); -+static inline void mlxsw_reg_mtmp_unpack(char *payload, unsigned int *p_temp, -+ unsigned int *p_max_temp, -+ char *sensor_name) -+{ -+ u16 temp; - --enum mlxsw_reg_ratr_trap_action { -- MLXSW_REG_RATR_TRAP_ACTION_NOP, -- MLXSW_REG_RATR_TRAP_ACTION_TRAP, -- MLXSW_REG_RATR_TRAP_ACTION_MIRROR_TO_CPU, -- MLXSW_REG_RATR_TRAP_ACTION_MIRROR, -- MLXSW_REG_RATR_TRAP_ACTION_DISCARD_ERRORS, --}; -+ if (p_temp) { -+ temp = mlxsw_reg_mtmp_temperature_get(payload); -+ *p_temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp); -+ } -+ if (p_max_temp) { -+ temp = mlxsw_reg_mtmp_max_temperature_get(payload); -+ *p_max_temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp); -+ } -+ if (sensor_name) -+ mlxsw_reg_mtmp_sensor_name_memcpy_from(payload, sensor_name); -+} - --/* reg_ratr_trap_action -- * see mlxsw_reg_ratr_trap_action -- * Access: RW -+/* MTBR - Management Temperature Bulk Register -+ * ------------------------------------------- -+ * This register is used for bulk temperature reading. - */ --MLXSW_ITEM32(reg, ratr, trap_action, 0x0C, 28, 4); -+#define MLXSW_REG_MTBR_ID 0x900F -+#define MLXSW_REG_MTBR_BASE_LEN 0x10 /* base length, without records */ -+#define MLXSW_REG_MTBR_REC_LEN 0x04 /* record length */ -+#define MLXSW_REG_MTBR_REC_MAX_COUNT 47 /* firmware limitation */ -+#define MLXSW_REG_MTBR_LEN (MLXSW_REG_MTBR_BASE_LEN + \ -+ MLXSW_REG_MTBR_REC_LEN * \ -+ MLXSW_REG_MTBR_REC_MAX_COUNT) - --enum mlxsw_reg_ratr_trap_id { -- MLXSW_REG_RATR_TRAP_ID_RTR_EGRESS0 = 0, -- MLXSW_REG_RATR_TRAP_ID_RTR_EGRESS1 = 1, --}; -+MLXSW_REG_DEFINE(mtbr, MLXSW_REG_MTBR_ID, MLXSW_REG_MTBR_LEN); - --/* reg_ratr_adjacency_index_high -- * Bits 23:16 of the adjacency_index. -+/* 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). - * Access: Index - */ --MLXSW_ITEM32(reg, ratr, adjacency_index_high, 0x0C, 16, 8); -+MLXSW_ITEM32(reg, mtbr, base_sensor_index, 0x00, 0, 7); - --/* reg_ratr_trap_id -- * Trap ID to be reported to CPU. -- * Trap-ID is RTR_EGRESS0 or RTR_EGRESS1. -- * For trap_action of NOP, MIRROR and DISCARD_ERROR -+/* reg_mtbr_num_rec -+ * Request: Number of records to read -+ * Response: Number of records read -+ * See above description for more details. -+ * Range 1..255 - * Access: RW - */ --MLXSW_ITEM32(reg, ratr, trap_id, 0x0C, 0, 8); -+MLXSW_ITEM32(reg, mtbr, num_rec, 0x04, 0, 8); - --/* reg_ratr_eth_destination_mac -- * MAC address of the destination next-hop. -- * Access: RW -+/* reg_mtbr_rec_max_temp -+ * The highest measured temperature from the sensor. -+ * When the bit mte is cleared, the field max_temperature is reserved. -+ * Access: RO - */ --MLXSW_ITEM_BUF(reg, ratr, eth_destination_mac, 0x12, 6); -+MLXSW_ITEM32_INDEXED(reg, mtbr, rec_max_temp, MLXSW_REG_MTBR_BASE_LEN, 16, -+ 16, MLXSW_REG_MTBR_REC_LEN, 0x00, false); - --static inline void --mlxsw_reg_ratr_pack(char *payload, -- enum mlxsw_reg_ratr_op op, bool valid, -- u32 adjacency_index, u16 egress_rif) -+/* reg_mtbr_rec_temp -+ * Temperature reading from the sensor. Reading is in 0..125 Celsius -+ * degrees units. -+ * Access: RO -+ */ -+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, u8 base_sensor_index, -+ u8 num_rec) - { -- MLXSW_REG_ZERO(ratr, payload); -- mlxsw_reg_ratr_op_set(payload, op); -- mlxsw_reg_ratr_v_set(payload, valid); -- mlxsw_reg_ratr_adjacency_index_low_set(payload, adjacency_index); -- mlxsw_reg_ratr_adjacency_index_high_set(payload, adjacency_index >> 16); -- mlxsw_reg_ratr_egress_router_interface_set(payload, egress_rif); -+ MLXSW_REG_ZERO(mtbr, payload); -+ mlxsw_reg_mtbr_base_sensor_index_set(payload, base_sensor_index); -+ mlxsw_reg_mtbr_num_rec_set(payload, num_rec); - } - --static inline void mlxsw_reg_ratr_eth_entry_pack(char *payload, -- const char *dest_mac) -+/* Error codes from temperatute reading */ -+enum mlxsw_reg_mtbr_temp_status { -+ MLXSW_REG_MTBR_NO_CONN = 0x8000, -+ MLXSW_REG_MTBR_NO_TEMP_SENS = 0x8001, -+ MLXSW_REG_MTBR_INDEX_NA = 0x8002, -+ MLXSW_REG_MTBR_BAD_SENS_INFO = 0x8003, -+}; -+ -+/* Base index for reading modules temperature */ -+#define MLXSW_REG_MTBR_BASE_MODULE_INDEX 64 -+ -+static inline void mlxsw_reg_mtbr_temp_unpack(char *payload, int rec_ind, -+ u16 *p_temp, u16 *p_max_temp) - { -- mlxsw_reg_ratr_eth_destination_mac_memcpy_to(payload, dest_mac); -+ if (p_temp) -+ *p_temp = mlxsw_reg_mtbr_rec_temp_get(payload, rec_ind); -+ if (p_max_temp) -+ *p_max_temp = mlxsw_reg_mtbr_rec_max_temp_get(payload, rec_ind); - } - --/* RALTA - Router Algorithmic LPM Tree Allocation Register -- * ------------------------------------------------------- -- * RALTA is used to allocate the LPM trees of the SHSPM method. -+/* MCIA - Management Cable Info Access -+ * ----------------------------------- -+ * MCIA register is used to access the SFP+ and QSFP connector's EPROM. - */ --#define MLXSW_REG_RALTA_ID 0x8010 --#define MLXSW_REG_RALTA_LEN 0x04 - --static const struct mlxsw_reg_info mlxsw_reg_ralta = { -- .id = MLXSW_REG_RALTA_ID, -- .len = MLXSW_REG_RALTA_LEN, --}; -- --/* reg_ralta_op -- * opcode (valid for Write, must be 0 on Read) -- * 0 - allocate a tree -- * 1 - deallocate a tree -- * Access: OP -- */ --MLXSW_ITEM32(reg, ralta, op, 0x00, 28, 2); -+#define MLXSW_REG_MCIA_ID 0x9014 -+#define MLXSW_REG_MCIA_LEN 0x40 - --enum mlxsw_reg_ralxx_protocol { -- MLXSW_REG_RALXX_PROTOCOL_IPV4, -- MLXSW_REG_RALXX_PROTOCOL_IPV6, --}; -+MLXSW_REG_DEFINE(mcia, MLXSW_REG_MCIA_ID, MLXSW_REG_MCIA_LEN); - --/* reg_ralta_protocol -- * Protocol. -- * Deallocation opcode: Reserved. -+/* reg_mcia_l -+ * Lock bit. Setting this bit will lock the access to the specific -+ * cable. Used for updating a full page in a cable EPROM. Any access -+ * other then subsequence writes will fail while the port is locked. - * Access: RW - */ --MLXSW_ITEM32(reg, ralta, protocol, 0x00, 24, 4); -+MLXSW_ITEM32(reg, mcia, l, 0x00, 31, 1); - --/* reg_ralta_tree_id -- * An identifier (numbered from 1..cap_shspm_max_trees-1) representing -- * the tree identifier (managed by software). -- * Note that tree_id 0 is allocated for a default-route tree. -+/* reg_mcia_module -+ * Module number. - * Access: Index - */ --MLXSW_ITEM32(reg, ralta, tree_id, 0x00, 0, 8); -- --static inline void mlxsw_reg_ralta_pack(char *payload, bool alloc, -- enum mlxsw_reg_ralxx_protocol protocol, -- u8 tree_id) --{ -- MLXSW_REG_ZERO(ralta, payload); -- mlxsw_reg_ralta_op_set(payload, !alloc); -- mlxsw_reg_ralta_protocol_set(payload, protocol); -- mlxsw_reg_ralta_tree_id_set(payload, tree_id); --} -+MLXSW_ITEM32(reg, mcia, module, 0x00, 16, 8); - --/* RALST - Router Algorithmic LPM Structure Tree Register -- * ------------------------------------------------------ -- * RALST is used to set and query the structure of an LPM tree. -- * The structure of the tree must be sorted as a sorted binary tree, while -- * each node is a bin that is tagged as the length of the prefixes the lookup -- * will refer to. Therefore, bin X refers to a set of entries with prefixes -- * of X bits to match with the destination address. The bin 0 indicates -- * the default action, when there is no match of any prefix. -+/* reg_mcia_status -+ * Module status. -+ * Access: RO - */ --#define MLXSW_REG_RALST_ID 0x8011 --#define MLXSW_REG_RALST_LEN 0x104 -- --static const struct mlxsw_reg_info mlxsw_reg_ralst = { -- .id = MLXSW_REG_RALST_ID, -- .len = MLXSW_REG_RALST_LEN, --}; -+MLXSW_ITEM32(reg, mcia, status, 0x00, 0, 8); - --/* reg_ralst_root_bin -- * The bin number of the root bin. -- * 064 the entry consumes -- * two entries in the physical HW table. -- * Access: Index -+/* reg_mpat_eth_rspan_vid -+ * Encapsulation header VLAN ID. -+ * Access: RW - */ --MLXSW_ITEM32(reg, ralue, prefix_len, 0x08, 0, 8); -+MLXSW_ITEM32(reg, mpat, eth_rspan_vid, 0x18, 0, 12); - --/* reg_ralue_dip* -- * The prefix of the route or of the marker that the object of the LPM -- * is compared with. The most significant bits of the dip are the prefix. -- * The list significant bits must be '0' if the prefix_len is smaller -- * than 128 for IPv6 or smaller than 32 for IPv4. -- * IPv4 address uses bits dip[31:0] and bits dip[127:32] are reserved. -- * Access: Index -+/* Encapsulated Remote SPAN - Ethernet L2 -+ * - - - - - - - - - - - - - - - - - - - - */ --MLXSW_ITEM32(reg, ralue, dip4, 0x18, 0, 32); - --enum mlxsw_reg_ralue_entry_type { -- MLXSW_REG_RALUE_ENTRY_TYPE_MARKER_ENTRY = 1, -- MLXSW_REG_RALUE_ENTRY_TYPE_ROUTE_ENTRY = 2, -- MLXSW_REG_RALUE_ENTRY_TYPE_MARKER_AND_ROUTE_ENTRY = 3, -+enum mlxsw_reg_mpat_eth_rspan_version { -+ MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER = 15, - }; - --/* reg_ralue_entry_type -- * Entry type. -- * Note - for Marker entries, the action_type and action fields are reserved. -+/* reg_mpat_eth_rspan_version -+ * RSPAN mirror header version. - * Access: RW - */ --MLXSW_ITEM32(reg, ralue, entry_type, 0x1C, 30, 2); -+MLXSW_ITEM32(reg, mpat, eth_rspan_version, 0x10, 18, 4); - --/* reg_ralue_bmp_len -- * The best match prefix length in the case that there is no match for -- * longer prefixes. -- * If (entry_type != MARKER_ENTRY), bmp_len must be equal to prefix_len -- * Note for any update operation with entry_type modification this -- * field must be set. -+/* reg_mpat_eth_rspan_mac -+ * Destination MAC address. - * Access: RW - */ --MLXSW_ITEM32(reg, ralue, bmp_len, 0x1C, 16, 8); -- --enum mlxsw_reg_ralue_action_type { -- MLXSW_REG_RALUE_ACTION_TYPE_REMOTE, -- MLXSW_REG_RALUE_ACTION_TYPE_LOCAL, -- MLXSW_REG_RALUE_ACTION_TYPE_IP2ME, --}; -+MLXSW_ITEM_BUF(reg, mpat, eth_rspan_mac, 0x12, 6); - --/* reg_ralue_action_type -- * Action Type -- * Indicates how the IP address is connected. -- * It can be connected to a local subnet through local_erif or can be -- * on a remote subnet connected through a next-hop router, -- * or transmitted to the CPU. -- * Reserved when entry_type = MARKER_ENTRY -+/* reg_mpat_eth_rspan_tp -+ * Tag Packet. Indicates whether the mirroring header should be VLAN tagged. - * Access: RW - */ --MLXSW_ITEM32(reg, ralue, action_type, 0x1C, 0, 2); -- --enum mlxsw_reg_ralue_trap_action { -- MLXSW_REG_RALUE_TRAP_ACTION_NOP, -- MLXSW_REG_RALUE_TRAP_ACTION_TRAP, -- MLXSW_REG_RALUE_TRAP_ACTION_MIRROR_TO_CPU, -- MLXSW_REG_RALUE_TRAP_ACTION_MIRROR, -- MLXSW_REG_RALUE_TRAP_ACTION_DISCARD_ERROR, --}; -+MLXSW_ITEM32(reg, mpat, eth_rspan_tp, 0x18, 16, 1); - --/* reg_ralue_trap_action -- * Trap action. -- * For IP2ME action, only NOP and MIRROR are possible. -- * Access: RW -+/* Encapsulated Remote SPAN - Ethernet L3 -+ * - - - - - - - - - - - - - - - - - - - - */ --MLXSW_ITEM32(reg, ralue, trap_action, 0x20, 28, 4); - --/* reg_ralue_trap_id -- * Trap ID to be reported to CPU. -- * Trap ID is RTR_INGRESS0 or RTR_INGRESS1. -- * For trap_action of NOP, MIRROR and DISCARD_ERROR, trap_id is reserved. -- * Access: RW -- */ --MLXSW_ITEM32(reg, ralue, trap_id, 0x20, 0, 9); -+enum mlxsw_reg_mpat_eth_rspan_protocol { -+ MLXSW_REG_MPAT_ETH_RSPAN_PROTOCOL_IPV4, -+ MLXSW_REG_MPAT_ETH_RSPAN_PROTOCOL_IPV6, -+}; - --/* reg_ralue_adjacency_index -- * Points to the first entry of the group-based ECMP. -- * Only relevant in case of REMOTE action. -+/* reg_mpat_eth_rspan_protocol -+ * SPAN encapsulation protocol. - * Access: RW - */ --MLXSW_ITEM32(reg, ralue, adjacency_index, 0x24, 0, 24); -+MLXSW_ITEM32(reg, mpat, eth_rspan_protocol, 0x18, 24, 4); - --/* reg_ralue_ecmp_size -- * Amount of sequential entries starting -- * from the adjacency_index (the number of ECMPs). -- * The valid range is 1-64, 512, 1024, 2048 and 4096. -- * Reserved when trap_action is TRAP or DISCARD_ERROR. -- * Only relevant in case of REMOTE action. -+/* reg_mpat_eth_rspan_ttl -+ * Encapsulation header Time-to-Live/HopLimit. - * Access: RW - */ --MLXSW_ITEM32(reg, ralue, ecmp_size, 0x28, 0, 13); -+MLXSW_ITEM32(reg, mpat, eth_rspan_ttl, 0x1C, 4, 8); - --/* reg_ralue_local_erif -- * Egress Router Interface. -- * Only relevant in case of LOCAL action. -+/* reg_mpat_eth_rspan_smac -+ * Source MAC address - * Access: RW - */ --MLXSW_ITEM32(reg, ralue, local_erif, 0x24, 0, 16); -+MLXSW_ITEM_BUF(reg, mpat, eth_rspan_smac, 0x22, 6); - --/* reg_ralue_v -- * Valid bit for the tunnel_ptr field. -- * If valid = 0 then trap to CPU as IP2ME trap ID. -- * If valid = 1 and the packet format allows NVE or IPinIP tunnel -- * decapsulation then tunnel decapsulation is done. -- * If valid = 1 and packet format does not allow NVE or IPinIP tunnel -- * decapsulation then trap as IP2ME trap ID. -- * Only relevant in case of IP2ME action. -+/* reg_mpat_eth_rspan_dip* -+ * Destination IP address. The IP version is configured by protocol. - * Access: RW - */ --MLXSW_ITEM32(reg, ralue, v, 0x24, 31, 1); -+MLXSW_ITEM32(reg, mpat, eth_rspan_dip4, 0x4C, 0, 32); -+MLXSW_ITEM_BUF(reg, mpat, eth_rspan_dip6, 0x40, 16); - --/* reg_ralue_tunnel_ptr -- * Tunnel Pointer for NVE or IPinIP tunnel decapsulation. -- * For Spectrum, pointer to KVD Linear. -- * Only relevant in case of IP2ME action. -+/* reg_mpat_eth_rspan_sip* -+ * Source IP address. The IP version is configured by protocol. - * Access: RW - */ --MLXSW_ITEM32(reg, ralue, tunnel_ptr, 0x24, 0, 24); -+MLXSW_ITEM32(reg, mpat, eth_rspan_sip4, 0x5C, 0, 32); -+MLXSW_ITEM_BUF(reg, mpat, eth_rspan_sip6, 0x50, 16); - --static inline void mlxsw_reg_ralue_pack(char *payload, -- enum mlxsw_reg_ralxx_protocol protocol, -- enum mlxsw_reg_ralue_op op, -- u16 virtual_router, u8 prefix_len) -+static inline void mlxsw_reg_mpat_pack(char *payload, u8 pa_id, -+ u16 system_port, bool e, -+ enum mlxsw_reg_mpat_span_type span_type) - { -- MLXSW_REG_ZERO(ralue, payload); -- mlxsw_reg_ralue_protocol_set(payload, protocol); -- mlxsw_reg_ralue_op_set(payload, op); -- mlxsw_reg_ralue_virtual_router_set(payload, virtual_router); -- mlxsw_reg_ralue_prefix_len_set(payload, prefix_len); -- mlxsw_reg_ralue_entry_type_set(payload, -- MLXSW_REG_RALUE_ENTRY_TYPE_ROUTE_ENTRY); -- mlxsw_reg_ralue_bmp_len_set(payload, prefix_len); -+ MLXSW_REG_ZERO(mpat, payload); -+ mlxsw_reg_mpat_pa_id_set(payload, pa_id); -+ mlxsw_reg_mpat_system_port_set(payload, system_port); -+ mlxsw_reg_mpat_e_set(payload, e); -+ mlxsw_reg_mpat_qos_set(payload, 1); -+ mlxsw_reg_mpat_be_set(payload, 1); -+ mlxsw_reg_mpat_span_type_set(payload, span_type); - } - --static inline void mlxsw_reg_ralue_pack4(char *payload, -- enum mlxsw_reg_ralxx_protocol protocol, -- enum mlxsw_reg_ralue_op op, -- u16 virtual_router, u8 prefix_len, -- u32 dip) -+static inline void mlxsw_reg_mpat_eth_rspan_pack(char *payload, u16 vid) - { -- mlxsw_reg_ralue_pack(payload, protocol, op, virtual_router, prefix_len); -- mlxsw_reg_ralue_dip4_set(payload, dip); -+ mlxsw_reg_mpat_eth_rspan_vid_set(payload, vid); - } - - static inline void --mlxsw_reg_ralue_act_remote_pack(char *payload, -- enum mlxsw_reg_ralue_trap_action trap_action, -- u16 trap_id, u32 adjacency_index, u16 ecmp_size) -+mlxsw_reg_mpat_eth_rspan_l2_pack(char *payload, -+ enum mlxsw_reg_mpat_eth_rspan_version version, -+ const char *mac, -+ bool tp) - { -- mlxsw_reg_ralue_action_type_set(payload, -- MLXSW_REG_RALUE_ACTION_TYPE_REMOTE); -- mlxsw_reg_ralue_trap_action_set(payload, trap_action); -- mlxsw_reg_ralue_trap_id_set(payload, trap_id); -- mlxsw_reg_ralue_adjacency_index_set(payload, adjacency_index); -- mlxsw_reg_ralue_ecmp_size_set(payload, ecmp_size); -+ mlxsw_reg_mpat_eth_rspan_version_set(payload, version); -+ mlxsw_reg_mpat_eth_rspan_mac_memcpy_to(payload, mac); -+ mlxsw_reg_mpat_eth_rspan_tp_set(payload, tp); - } - - static inline void --mlxsw_reg_ralue_act_local_pack(char *payload, -- enum mlxsw_reg_ralue_trap_action trap_action, -- u16 trap_id, u16 local_erif) -+mlxsw_reg_mpat_eth_rspan_l3_ipv4_pack(char *payload, u8 ttl, -+ const char *smac, -+ u32 sip, u32 dip) - { -- mlxsw_reg_ralue_action_type_set(payload, -- MLXSW_REG_RALUE_ACTION_TYPE_LOCAL); -- mlxsw_reg_ralue_trap_action_set(payload, trap_action); -- mlxsw_reg_ralue_trap_id_set(payload, trap_id); -- mlxsw_reg_ralue_local_erif_set(payload, local_erif); -+ mlxsw_reg_mpat_eth_rspan_ttl_set(payload, ttl); -+ mlxsw_reg_mpat_eth_rspan_smac_memcpy_to(payload, smac); -+ mlxsw_reg_mpat_eth_rspan_protocol_set(payload, -+ MLXSW_REG_MPAT_ETH_RSPAN_PROTOCOL_IPV4); -+ mlxsw_reg_mpat_eth_rspan_sip4_set(payload, sip); -+ mlxsw_reg_mpat_eth_rspan_dip4_set(payload, dip); - } - - static inline void --mlxsw_reg_ralue_act_ip2me_pack(char *payload) -+mlxsw_reg_mpat_eth_rspan_l3_ipv6_pack(char *payload, u8 ttl, -+ const char *smac, -+ struct in6_addr sip, struct in6_addr dip) - { -- mlxsw_reg_ralue_action_type_set(payload, -- MLXSW_REG_RALUE_ACTION_TYPE_IP2ME); -+ mlxsw_reg_mpat_eth_rspan_ttl_set(payload, ttl); -+ mlxsw_reg_mpat_eth_rspan_smac_memcpy_to(payload, smac); -+ mlxsw_reg_mpat_eth_rspan_protocol_set(payload, -+ MLXSW_REG_MPAT_ETH_RSPAN_PROTOCOL_IPV6); -+ mlxsw_reg_mpat_eth_rspan_sip6_memcpy_to(payload, (void *)&sip); -+ mlxsw_reg_mpat_eth_rspan_dip6_memcpy_to(payload, (void *)&dip); - } - --/* RAUHT - Router Algorithmic LPM Unicast Host Table Register -- * ---------------------------------------------------------- -- * The RAUHT register is used to configure and query the Unicast Host table in -- * devices that implement the Algorithmic LPM. -+/* MPAR - Monitoring Port Analyzer Register -+ * ---------------------------------------- -+ * MPAR register is used to query and configure the port analyzer port mirroring -+ * properties. - */ --#define MLXSW_REG_RAUHT_ID 0x8014 --#define MLXSW_REG_RAUHT_LEN 0x74 -- --static const struct mlxsw_reg_info mlxsw_reg_rauht = { -- .id = MLXSW_REG_RAUHT_ID, -- .len = MLXSW_REG_RAUHT_LEN, --}; -+#define MLXSW_REG_MPAR_ID 0x901B -+#define MLXSW_REG_MPAR_LEN 0x08 - --enum mlxsw_reg_rauht_type { -- MLXSW_REG_RAUHT_TYPE_IPV4, -- MLXSW_REG_RAUHT_TYPE_IPV6, --}; -+MLXSW_REG_DEFINE(mpar, MLXSW_REG_MPAR_ID, MLXSW_REG_MPAR_LEN); - --/* reg_rauht_type -+/* reg_mpar_local_port -+ * The local port to mirror the packets from. - * Access: Index - */ --MLXSW_ITEM32(reg, rauht, type, 0x00, 24, 2); -+MLXSW_ITEM32(reg, mpar, local_port, 0x00, 16, 8); - --enum mlxsw_reg_rauht_op { -- MLXSW_REG_RAUHT_OP_QUERY_READ = 0, -- /* Read operation */ -- MLXSW_REG_RAUHT_OP_QUERY_CLEAR_ON_READ = 1, -- /* Clear on read operation. Used to read entry and clear -- * activity bit. -- */ -- MLXSW_REG_RAUHT_OP_WRITE_ADD = 0, -- /* Add. Used to write a new entry to the table. All R/W fields are -- * relevant for new entry. Activity bit is set for new entries. -- */ -- MLXSW_REG_RAUHT_OP_WRITE_UPDATE = 1, -- /* Update action. Used to update an existing route entry and -- * only update the following fields: -- * trap_action, trap_id, mac, counter_set_type, counter_index -- */ -- MLXSW_REG_RAUHT_OP_WRITE_CLEAR_ACTIVITY = 2, -- /* Clear activity. A bit is cleared for the entry. */ -- MLXSW_REG_RAUHT_OP_WRITE_DELETE = 3, -- /* Delete entry */ -- MLXSW_REG_RAUHT_OP_WRITE_DELETE_ALL = 4, -- /* Delete all host entries on a RIF. In this command, dip -- * field is reserved. -- */ -+enum mlxsw_reg_mpar_i_e { -+ MLXSW_REG_MPAR_TYPE_EGRESS, -+ MLXSW_REG_MPAR_TYPE_INGRESS, - }; - --/* reg_rauht_op -- * Access: OP -- */ --MLXSW_ITEM32(reg, rauht, op, 0x00, 20, 3); -- --/* reg_rauht_a -- * Activity. Set for new entries. Set if a packet lookup has hit on -- * the specific entry. -- * To clear the a bit, use "clear activity" op. -- * Enabled by activity_dis in RGCR -- * Access: RO -- */ --MLXSW_ITEM32(reg, rauht, a, 0x00, 16, 1); -- --/* reg_rauht_rif -- * Router Interface -- * Access: Index -- */ --MLXSW_ITEM32(reg, rauht, rif, 0x00, 0, 16); -- --/* reg_rauht_dip* -- * Destination address. -+/* reg_mpar_i_e -+ * Ingress/Egress - * Access: Index - */ --MLXSW_ITEM32(reg, rauht, dip4, 0x1C, 0x0, 32); -- --enum mlxsw_reg_rauht_trap_action { -- MLXSW_REG_RAUHT_TRAP_ACTION_NOP, -- MLXSW_REG_RAUHT_TRAP_ACTION_TRAP, -- MLXSW_REG_RAUHT_TRAP_ACTION_MIRROR_TO_CPU, -- MLXSW_REG_RAUHT_TRAP_ACTION_MIRROR, -- MLXSW_REG_RAUHT_TRAP_ACTION_DISCARD_ERRORS, --}; -+MLXSW_ITEM32(reg, mpar, i_e, 0x00, 0, 4); - --/* reg_rauht_trap_action -+/* reg_mpar_enable -+ * Enable mirroring -+ * By default, port mirroring is disabled for all ports. - * Access: RW - */ --MLXSW_ITEM32(reg, rauht, trap_action, 0x60, 28, 4); -- --enum mlxsw_reg_rauht_trap_id { -- MLXSW_REG_RAUHT_TRAP_ID_RTR_EGRESS0, -- MLXSW_REG_RAUHT_TRAP_ID_RTR_EGRESS1, --}; -+MLXSW_ITEM32(reg, mpar, enable, 0x04, 31, 1); - --/* reg_rauht_trap_id -- * Trap ID to be reported to CPU. -- * Trap-ID is RTR_EGRESS0 or RTR_EGRESS1. -- * For trap_action of NOP, MIRROR and DISCARD_ERROR, -- * trap_id is reserved. -+/* reg_mpar_pa_id -+ * Port Analyzer ID. - * Access: RW - */ --MLXSW_ITEM32(reg, rauht, trap_id, 0x60, 0, 9); -+MLXSW_ITEM32(reg, mpar, pa_id, 0x04, 0, 4); - --/* reg_rauht_counter_set_type -- * Counter set type for flow counters -- * Access: RW -- */ --MLXSW_ITEM32(reg, rauht, counter_set_type, 0x68, 24, 8); -+static inline void mlxsw_reg_mpar_pack(char *payload, u8 local_port, -+ enum mlxsw_reg_mpar_i_e i_e, -+ bool enable, u8 pa_id) -+{ -+ MLXSW_REG_ZERO(mpar, payload); -+ mlxsw_reg_mpar_local_port_set(payload, local_port); -+ mlxsw_reg_mpar_enable_set(payload, enable); -+ mlxsw_reg_mpar_i_e_set(payload, i_e); -+ mlxsw_reg_mpar_pa_id_set(payload, pa_id); -+} - --/* reg_rauht_counter_index -- * Counter index for flow counters -- * Access: RW -+/* MRSR - Management Reset and Shutdown Register -+ * --------------------------------------------- -+ * MRSR register is used to reset or shutdown the switch or -+ * the entire system (when applicable). - */ --MLXSW_ITEM32(reg, rauht, counter_index, 0x68, 0, 24); -+#define MLXSW_REG_MRSR_ID 0x9023 -+#define MLXSW_REG_MRSR_LEN 0x08 - --/* reg_rauht_mac -- * MAC address. -- * Access: RW -- */ --MLXSW_ITEM_BUF(reg, rauht, mac, 0x6E, 6); -+MLXSW_REG_DEFINE(mrsr, MLXSW_REG_MRSR_ID, MLXSW_REG_MRSR_LEN); - --static inline void mlxsw_reg_rauht_pack(char *payload, -- enum mlxsw_reg_rauht_op op, u16 rif, -- const char *mac) --{ -- MLXSW_REG_ZERO(rauht, payload); -- mlxsw_reg_rauht_op_set(payload, op); -- mlxsw_reg_rauht_rif_set(payload, rif); -- mlxsw_reg_rauht_mac_memcpy_to(payload, mac); --} -+/* reg_mrsr_command -+ * Reset/shutdown command -+ * 0 - do nothing -+ * 1 - software reset -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, mrsr, command, 0x00, 0, 4); - --static inline void mlxsw_reg_rauht_pack4(char *payload, -- enum mlxsw_reg_rauht_op op, u16 rif, -- const char *mac, u32 dip) -+static inline void mlxsw_reg_mrsr_pack(char *payload) - { -- mlxsw_reg_rauht_pack(payload, op, rif, mac); -- mlxsw_reg_rauht_dip4_set(payload, dip); -+ MLXSW_REG_ZERO(mrsr, payload); -+ mlxsw_reg_mrsr_command_set(payload, 1); - } - --/* RALEU - Router Algorithmic LPM ECMP Update Register -- * --------------------------------------------------- -- * The register enables updating the ECMP section in the action for multiple -- * LPM Unicast entries in a single operation. The update is executed to -- * all entries of a {virtual router, protocol} tuple using the same ECMP group. -- */ --#define MLXSW_REG_RALEU_ID 0x8015 --#define MLXSW_REG_RALEU_LEN 0x28 -- --static const struct mlxsw_reg_info mlxsw_reg_raleu = { -- .id = MLXSW_REG_RALEU_ID, -- .len = MLXSW_REG_RALEU_LEN, --}; -- --/* reg_raleu_protocol -- * Protocol. -- * Access: Index -+/* MLCR - Management LED Control Register -+ * -------------------------------------- -+ * Controls the system LEDs. - */ --MLXSW_ITEM32(reg, raleu, protocol, 0x00, 24, 4); -+#define MLXSW_REG_MLCR_ID 0x902B -+#define MLXSW_REG_MLCR_LEN 0x0C - --/* reg_raleu_virtual_router -- * Virtual Router ID -- * Range is 0..cap_max_virtual_routers-1 -- * Access: Index -- */ --MLXSW_ITEM32(reg, raleu, virtual_router, 0x00, 0, 16); -+MLXSW_REG_DEFINE(mlcr, MLXSW_REG_MLCR_ID, MLXSW_REG_MLCR_LEN); - --/* reg_raleu_adjacency_index -- * Adjacency Index used for matching on the existing entries. -- * Access: Index -+/* reg_mlcr_local_port -+ * Local port number. -+ * Access: RW - */ --MLXSW_ITEM32(reg, raleu, adjacency_index, 0x10, 0, 24); -+MLXSW_ITEM32(reg, mlcr, local_port, 0x00, 16, 8); - --/* reg_raleu_ecmp_size -- * ECMP Size used for matching on the existing entries. -- * Access: Index -- */ --MLXSW_ITEM32(reg, raleu, ecmp_size, 0x14, 0, 13); -+#define MLXSW_REG_MLCR_DURATION_MAX 0xFFFF - --/* reg_raleu_new_adjacency_index -- * New Adjacency Index. -- * Access: WO -+/* reg_mlcr_beacon_duration -+ * Duration of the beacon to be active, in seconds. -+ * 0x0 - Will turn off the beacon. -+ * 0xFFFF - Will turn on the beacon until explicitly turned off. -+ * Access: RW - */ --MLXSW_ITEM32(reg, raleu, new_adjacency_index, 0x20, 0, 24); -+MLXSW_ITEM32(reg, mlcr, beacon_duration, 0x04, 0, 16); - --/* reg_raleu_new_ecmp_size -- * New ECMP Size. -- * Access: WO -+/* reg_mlcr_beacon_remain -+ * Remaining duration of the beacon, in seconds. -+ * 0xFFFF indicates an infinite amount of time. -+ * Access: RO - */ --MLXSW_ITEM32(reg, raleu, new_ecmp_size, 0x24, 0, 13); -+MLXSW_ITEM32(reg, mlcr, beacon_remain, 0x08, 0, 16); - --static inline void mlxsw_reg_raleu_pack(char *payload, -- enum mlxsw_reg_ralxx_protocol protocol, -- u16 virtual_router, -- u32 adjacency_index, u16 ecmp_size, -- u32 new_adjacency_index, -- u16 new_ecmp_size) -+static inline void mlxsw_reg_mlcr_pack(char *payload, u8 local_port, -+ bool active) - { -- MLXSW_REG_ZERO(raleu, payload); -- mlxsw_reg_raleu_protocol_set(payload, protocol); -- mlxsw_reg_raleu_virtual_router_set(payload, virtual_router); -- mlxsw_reg_raleu_adjacency_index_set(payload, adjacency_index); -- mlxsw_reg_raleu_ecmp_size_set(payload, ecmp_size); -- mlxsw_reg_raleu_new_adjacency_index_set(payload, new_adjacency_index); -- mlxsw_reg_raleu_new_ecmp_size_set(payload, new_ecmp_size); -+ MLXSW_REG_ZERO(mlcr, payload); -+ mlxsw_reg_mlcr_local_port_set(payload, local_port); -+ mlxsw_reg_mlcr_beacon_duration_set(payload, active ? -+ MLXSW_REG_MLCR_DURATION_MAX : 0); - } - --/* RAUHTD - Router Algorithmic LPM Unicast Host Table Dump Register -- * ---------------------------------------------------------------- -- * The RAUHTD register allows dumping entries from the Router Unicast Host -- * Table. For a given session an entry is dumped no more than one time. The -- * first RAUHTD access after reset is a new session. A session ends when the -- * num_rec response is smaller than num_rec request or for IPv4 when the -- * num_entries is smaller than 4. The clear activity affect the current session -- * or the last session if a new session has not started. -+/* MSCI - Management System CPLD Information Register -+ * --------------------------------------------------- -+ * This register allows querying for the System CPLD(s) information. - */ --#define MLXSW_REG_RAUHTD_ID 0x8018 --#define MLXSW_REG_RAUHTD_BASE_LEN 0x20 --#define MLXSW_REG_RAUHTD_REC_LEN 0x20 --#define MLXSW_REG_RAUHTD_REC_MAX_NUM 32 --#define MLXSW_REG_RAUHTD_LEN (MLXSW_REG_RAUHTD_BASE_LEN + \ -- MLXSW_REG_RAUHTD_REC_MAX_NUM * MLXSW_REG_RAUHTD_REC_LEN) --#define MLXSW_REG_RAUHTD_IPV4_ENT_PER_REC 4 -+#define MLXSW_REG_MSCI_ID 0x902A -+#define MLXSW_REG_MSCI_LEN 0x10 - --static const struct mlxsw_reg_info mlxsw_reg_rauhtd = { -- .id = MLXSW_REG_RAUHTD_ID, -- .len = MLXSW_REG_RAUHTD_LEN, -+static const struct mlxsw_reg_info mlxsw_reg_msci = { -+ .id = MLXSW_REG_MSCI_ID, -+ .len = MLXSW_REG_MSCI_LEN, - }; - --#define MLXSW_REG_RAUHTD_FILTER_A BIT(0) --#define MLXSW_REG_RAUHTD_FILTER_RIF BIT(3) -- --/* reg_rauhtd_filter_fields -- * if a bit is '0' then the relevant field is ignored and dump is done -- * regardless of the field value -- * Bit0 - filter by activity: entry_a -- * Bit3 - filter by entry rip: entry_rif -+/* reg_msci_index -+ * Index to access. - * Access: Index - */ --MLXSW_ITEM32(reg, rauhtd, filter_fields, 0x00, 0, 8); -- --enum mlxsw_reg_rauhtd_op { -- MLXSW_REG_RAUHTD_OP_DUMP, -- MLXSW_REG_RAUHTD_OP_DUMP_AND_CLEAR, --}; -+MLXSW_ITEM32(reg, msci, index, 0x00, 0, 4); - --/* reg_rauhtd_op -- * Access: OP -+/* reg_msci_version -+ * CPLD version. -+ * Access: R0 - */ --MLXSW_ITEM32(reg, rauhtd, op, 0x04, 24, 2); -+MLXSW_ITEM32(reg, msci, version, 0x04, 0, 32); - --/* reg_rauhtd_num_rec -- * At request: number of records requested -- * At response: number of records dumped -- * For IPv4, each record has 4 entries at request and up to 4 entries -- * at response -- * Range is 0..MLXSW_REG_RAUHTD_REC_MAX_NUM -- * Access: Index -+static inline void -+mlxsw_reg_msci_pack(char *payload, u8 index) -+{ -+ MLXSW_REG_ZERO(msci, payload); -+ mlxsw_reg_msci_index_set(payload, index); -+} -+ -+static inline void -+mlxsw_reg_msci_unpack(char *payload, u16 *p_version) -+{ -+ *p_version = mlxsw_reg_msci_version_get(payload); -+} -+ -+/* MCQI - Management Component Query Information -+ * --------------------------------------------- -+ * This register allows querying information about firmware components. - */ --MLXSW_ITEM32(reg, rauhtd, num_rec, 0x04, 0, 8); -+#define MLXSW_REG_MCQI_ID 0x9061 -+#define MLXSW_REG_MCQI_BASE_LEN 0x18 -+#define MLXSW_REG_MCQI_CAP_LEN 0x14 -+#define MLXSW_REG_MCQI_LEN (MLXSW_REG_MCQI_BASE_LEN + MLXSW_REG_MCQI_CAP_LEN) - --/* reg_rauhtd_entry_a -- * Dump only if activity has value of entry_a -- * Reserved if filter_fields bit0 is '0' -+MLXSW_REG_DEFINE(mcqi, MLXSW_REG_MCQI_ID, MLXSW_REG_MCQI_LEN); -+ -+/* reg_mcqi_component_index -+ * Index of the accessed component. - * Access: Index - */ --MLXSW_ITEM32(reg, rauhtd, entry_a, 0x08, 16, 1); -+MLXSW_ITEM32(reg, mcqi, component_index, 0x00, 0, 16); - --enum mlxsw_reg_rauhtd_type { -- MLXSW_REG_RAUHTD_TYPE_IPV4, -- MLXSW_REG_RAUHTD_TYPE_IPV6, -+enum mlxfw_reg_mcqi_info_type { -+ MLXSW_REG_MCQI_INFO_TYPE_CAPABILITIES, - }; - --/* reg_rauhtd_type -- * Dump only if record type is: -- * 0 - IPv4 -- * 1 - IPv6 -- * Access: Index -+/* reg_mcqi_info_type -+ * Component properties set. -+ * Access: RW - */ --MLXSW_ITEM32(reg, rauhtd, type, 0x08, 0, 4); -+MLXSW_ITEM32(reg, mcqi, info_type, 0x08, 0, 5); - --/* reg_rauhtd_entry_rif -- * Dump only if RIF has value of entry_rif -- * Reserved if filter_fields bit3 is '0' -- * Access: Index -+/* reg_mcqi_offset -+ * The requested/returned data offset from the section start, given in bytes. -+ * Must be DWORD aligned. -+ * Access: RW - */ --MLXSW_ITEM32(reg, rauhtd, entry_rif, 0x0C, 0, 16); -- --static inline void mlxsw_reg_rauhtd_pack(char *payload, -- enum mlxsw_reg_rauhtd_type type) --{ -- MLXSW_REG_ZERO(rauhtd, payload); -- mlxsw_reg_rauhtd_filter_fields_set(payload, MLXSW_REG_RAUHTD_FILTER_A); -- mlxsw_reg_rauhtd_op_set(payload, MLXSW_REG_RAUHTD_OP_DUMP_AND_CLEAR); -- mlxsw_reg_rauhtd_num_rec_set(payload, MLXSW_REG_RAUHTD_REC_MAX_NUM); -- mlxsw_reg_rauhtd_entry_a_set(payload, 1); -- mlxsw_reg_rauhtd_type_set(payload, type); --} -+MLXSW_ITEM32(reg, mcqi, offset, 0x10, 0, 32); - --/* reg_rauhtd_ipv4_rec_num_entries -- * Number of valid entries in this record: -- * 0 - 1 valid entry -- * 1 - 2 valid entries -- * 2 - 3 valid entries -- * 3 - 4 valid entries -- * Access: RO -+/* reg_mcqi_data_size -+ * The requested/returned data size, given in bytes. If data_size is not DWORD -+ * aligned, the last bytes are zero padded. -+ * Access: RW - */ --MLXSW_ITEM32_INDEXED(reg, rauhtd, ipv4_rec_num_entries, -- MLXSW_REG_RAUHTD_BASE_LEN, 28, 2, -- MLXSW_REG_RAUHTD_REC_LEN, 0x00, false); -+MLXSW_ITEM32(reg, mcqi, data_size, 0x14, 0, 16); - --/* reg_rauhtd_rec_type -- * Record type. -- * 0 - IPv4 -- * 1 - IPv6 -+/* reg_mcqi_cap_max_component_size -+ * Maximum size for this component, given in bytes. - * Access: RO - */ --MLXSW_ITEM32_INDEXED(reg, rauhtd, rec_type, MLXSW_REG_RAUHTD_BASE_LEN, 24, 2, -- MLXSW_REG_RAUHTD_REC_LEN, 0x00, false); -+MLXSW_ITEM32(reg, mcqi, cap_max_component_size, 0x20, 0, 32); - --#define MLXSW_REG_RAUHTD_IPV4_ENT_LEN 0x8 -- --/* reg_rauhtd_ipv4_ent_a -- * Activity. Set for new entries. Set if a packet lookup has hit on the -- * specific entry. -+/* reg_mcqi_cap_log_mcda_word_size -+ * Log 2 of the access word size in bytes. Read and write access must be aligned -+ * to the word size. Write access must be done for an integer number of words. - * Access: RO - */ --MLXSW_ITEM32_INDEXED(reg, rauhtd, ipv4_ent_a, MLXSW_REG_RAUHTD_BASE_LEN, 16, 1, -- MLXSW_REG_RAUHTD_IPV4_ENT_LEN, 0x00, false); -+MLXSW_ITEM32(reg, mcqi, cap_log_mcda_word_size, 0x24, 28, 4); - --/* reg_rauhtd_ipv4_ent_rif -- * Router interface. -+/* reg_mcqi_cap_mcda_max_write_size -+ * Maximal write size for MCDA register - * Access: RO - */ --MLXSW_ITEM32_INDEXED(reg, rauhtd, ipv4_ent_rif, MLXSW_REG_RAUHTD_BASE_LEN, 0, -- 16, MLXSW_REG_RAUHTD_IPV4_ENT_LEN, 0x00, false); -+MLXSW_ITEM32(reg, mcqi, cap_mcda_max_write_size, 0x24, 0, 16); - --/* reg_rauhtd_ipv4_ent_dip -- * Destination IPv4 address. -- * Access: RO -- */ --MLXSW_ITEM32_INDEXED(reg, rauhtd, ipv4_ent_dip, MLXSW_REG_RAUHTD_BASE_LEN, 0, -- 32, MLXSW_REG_RAUHTD_IPV4_ENT_LEN, 0x04, false); -+static inline void mlxsw_reg_mcqi_pack(char *payload, u16 component_index) -+{ -+ MLXSW_REG_ZERO(mcqi, payload); -+ mlxsw_reg_mcqi_component_index_set(payload, component_index); -+ mlxsw_reg_mcqi_info_type_set(payload, -+ MLXSW_REG_MCQI_INFO_TYPE_CAPABILITIES); -+ mlxsw_reg_mcqi_offset_set(payload, 0); -+ mlxsw_reg_mcqi_data_size_set(payload, MLXSW_REG_MCQI_CAP_LEN); -+} - --static inline void mlxsw_reg_rauhtd_ent_ipv4_unpack(char *payload, -- int ent_index, u16 *p_rif, -- u32 *p_dip) -+static inline void mlxsw_reg_mcqi_unpack(char *payload, -+ u32 *p_cap_max_component_size, -+ u8 *p_cap_log_mcda_word_size, -+ u16 *p_cap_mcda_max_write_size) - { -- *p_rif = mlxsw_reg_rauhtd_ipv4_ent_rif_get(payload, ent_index); -- *p_dip = mlxsw_reg_rauhtd_ipv4_ent_dip_get(payload, ent_index); -+ *p_cap_max_component_size = -+ mlxsw_reg_mcqi_cap_max_component_size_get(payload); -+ *p_cap_log_mcda_word_size = -+ mlxsw_reg_mcqi_cap_log_mcda_word_size_get(payload); -+ *p_cap_mcda_max_write_size = -+ mlxsw_reg_mcqi_cap_mcda_max_write_size_get(payload); - } - --/* MFCR - Management Fan Control Register -- * -------------------------------------- -- * This register controls the settings of the Fan Speed PWM mechanism. -+/* MCC - Management Component Control -+ * ---------------------------------- -+ * Controls the firmware component and updates the FSM. - */ --#define MLXSW_REG_MFCR_ID 0x9001 --#define MLXSW_REG_MFCR_LEN 0x08 -+#define MLXSW_REG_MCC_ID 0x9062 -+#define MLXSW_REG_MCC_LEN 0x1C - --static const struct mlxsw_reg_info mlxsw_reg_mfcr = { -- .id = MLXSW_REG_MFCR_ID, -- .len = MLXSW_REG_MFCR_LEN, --}; -+MLXSW_REG_DEFINE(mcc, MLXSW_REG_MCC_ID, MLXSW_REG_MCC_LEN); - --enum mlxsw_reg_mfcr_pwm_frequency { -- MLXSW_REG_MFCR_PWM_FEQ_11HZ = 0x00, -- MLXSW_REG_MFCR_PWM_FEQ_14_7HZ = 0x01, -- MLXSW_REG_MFCR_PWM_FEQ_22_1HZ = 0x02, -- MLXSW_REG_MFCR_PWM_FEQ_1_4KHZ = 0x40, -- MLXSW_REG_MFCR_PWM_FEQ_5KHZ = 0x41, -- MLXSW_REG_MFCR_PWM_FEQ_20KHZ = 0x42, -- MLXSW_REG_MFCR_PWM_FEQ_22_5KHZ = 0x43, -- MLXSW_REG_MFCR_PWM_FEQ_25KHZ = 0x44, -+enum mlxsw_reg_mcc_instruction { -+ MLXSW_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE = 0x01, -+ MLXSW_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE = 0x02, -+ MLXSW_REG_MCC_INSTRUCTION_UPDATE_COMPONENT = 0x03, -+ MLXSW_REG_MCC_INSTRUCTION_VERIFY_COMPONENT = 0x04, -+ MLXSW_REG_MCC_INSTRUCTION_ACTIVATE = 0x06, -+ MLXSW_REG_MCC_INSTRUCTION_CANCEL = 0x08, - }; - --/* reg_mfcr_pwm_frequency -- * Controls the frequency of the PWM signal. -+/* reg_mcc_instruction -+ * Command to be executed by the FSM. -+ * Applicable for write operation only. - * Access: RW - */ --MLXSW_ITEM32(reg, mfcr, pwm_frequency, 0x00, 0, 6); -+MLXSW_ITEM32(reg, mcc, instruction, 0x00, 0, 8); - --#define MLXSW_MFCR_TACHOS_MAX 12 -+/* reg_mcc_component_index -+ * Index of the accessed component. Applicable only for commands that -+ * refer to components. Otherwise, this field is reserved. -+ * Access: Index -+ */ -+MLXSW_ITEM32(reg, mcc, component_index, 0x04, 0, 16); - --/* reg_mfcr_tacho_active -- * Indicates which of the tachometer is active (bit per tachometer). -- * Access: RO -+/* reg_mcc_update_handle -+ * Token representing the current flow executed by the FSM. -+ * Access: WO - */ --MLXSW_ITEM32(reg, mfcr, tacho_active, 0x04, 16, MLXSW_MFCR_TACHOS_MAX); -+MLXSW_ITEM32(reg, mcc, update_handle, 0x08, 0, 24); - --#define MLXSW_MFCR_PWMS_MAX 5 -+/* reg_mcc_error_code -+ * Indicates the successful completion of the instruction, or the reason it -+ * failed -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, mcc, error_code, 0x0C, 8, 8); - --/* reg_mfcr_pwm_active -- * Indicates which of the PWM control is active (bit per PWM). -+/* reg_mcc_control_state -+ * Current FSM state - * Access: RO - */ --MLXSW_ITEM32(reg, mfcr, pwm_active, 0x04, 0, MLXSW_MFCR_PWMS_MAX); -+MLXSW_ITEM32(reg, mcc, control_state, 0x0C, 0, 4); - --static inline void --mlxsw_reg_mfcr_pack(char *payload, -- enum mlxsw_reg_mfcr_pwm_frequency pwm_frequency) -+/* reg_mcc_component_size -+ * Component size in bytes. Valid for UPDATE_COMPONENT instruction. Specifying -+ * the size may shorten the update time. Value 0x0 means that size is -+ * unspecified. -+ * Access: WO -+ */ -+MLXSW_ITEM32(reg, mcc, component_size, 0x10, 0, 32); -+ -+static inline void mlxsw_reg_mcc_pack(char *payload, -+ enum mlxsw_reg_mcc_instruction instr, -+ u16 component_index, u32 update_handle, -+ u32 component_size) - { -- MLXSW_REG_ZERO(mfcr, payload); -- mlxsw_reg_mfcr_pwm_frequency_set(payload, pwm_frequency); -+ MLXSW_REG_ZERO(mcc, payload); -+ mlxsw_reg_mcc_instruction_set(payload, instr); -+ mlxsw_reg_mcc_component_index_set(payload, component_index); -+ mlxsw_reg_mcc_update_handle_set(payload, update_handle); -+ mlxsw_reg_mcc_component_size_set(payload, component_size); - } - --static inline void --mlxsw_reg_mfcr_unpack(char *payload, -- enum mlxsw_reg_mfcr_pwm_frequency *p_pwm_frequency, -- u16 *p_tacho_active, u8 *p_pwm_active) -+static inline void mlxsw_reg_mcc_unpack(char *payload, u32 *p_update_handle, -+ u8 *p_error_code, u8 *p_control_state) - { -- *p_pwm_frequency = mlxsw_reg_mfcr_pwm_frequency_get(payload); -- *p_tacho_active = mlxsw_reg_mfcr_tacho_active_get(payload); -- *p_pwm_active = mlxsw_reg_mfcr_pwm_active_get(payload); -+ if (p_update_handle) -+ *p_update_handle = mlxsw_reg_mcc_update_handle_get(payload); -+ if (p_error_code) -+ *p_error_code = mlxsw_reg_mcc_error_code_get(payload); -+ if (p_control_state) -+ *p_control_state = mlxsw_reg_mcc_control_state_get(payload); - } - --/* MFSC - Management Fan Speed Control Register -- * -------------------------------------------- -- * This register controls the settings of the Fan Speed PWM mechanism. -+/* MCDA - Management Component Data Access -+ * --------------------------------------- -+ * This register allows reading and writing a firmware component. - */ --#define MLXSW_REG_MFSC_ID 0x9002 --#define MLXSW_REG_MFSC_LEN 0x08 -+#define MLXSW_REG_MCDA_ID 0x9063 -+#define MLXSW_REG_MCDA_BASE_LEN 0x10 -+#define MLXSW_REG_MCDA_MAX_DATA_LEN 0x80 -+#define MLXSW_REG_MCDA_LEN \ -+ (MLXSW_REG_MCDA_BASE_LEN + MLXSW_REG_MCDA_MAX_DATA_LEN) - --static const struct mlxsw_reg_info mlxsw_reg_mfsc = { -- .id = MLXSW_REG_MFSC_ID, -- .len = MLXSW_REG_MFSC_LEN, --}; -- --/* reg_mfsc_pwm -- * Fan pwm to control / monitor. -- * Access: Index -- */ --MLXSW_ITEM32(reg, mfsc, pwm, 0x00, 24, 3); -+MLXSW_REG_DEFINE(mcda, MLXSW_REG_MCDA_ID, MLXSW_REG_MCDA_LEN); - --/* reg_mfsc_pwm_duty_cycle -- * Controls the duty cycle of the PWM. Value range from 0..255 to -- * represent duty cycle of 0%...100%. -+/* reg_mcda_update_handle -+ * Token representing the current flow executed by the FSM. - * Access: RW - */ --MLXSW_ITEM32(reg, mfsc, pwm_duty_cycle, 0x04, 0, 8); -- --static inline void mlxsw_reg_mfsc_pack(char *payload, u8 pwm, -- u8 pwm_duty_cycle) --{ -- MLXSW_REG_ZERO(mfsc, payload); -- mlxsw_reg_mfsc_pwm_set(payload, pwm); -- mlxsw_reg_mfsc_pwm_duty_cycle_set(payload, pwm_duty_cycle); --} -+MLXSW_ITEM32(reg, mcda, update_handle, 0x00, 0, 24); - --/* MFSM - Management Fan Speed Measurement -- * --------------------------------------- -- * This register controls the settings of the Tacho measurements and -- * enables reading the Tachometer measurements. -+/* reg_mcda_offset -+ * Offset of accessed address relative to component start. Accesses must be in -+ * accordance to log_mcda_word_size in MCQI reg. -+ * Access: RW - */ --#define MLXSW_REG_MFSM_ID 0x9003 --#define MLXSW_REG_MFSM_LEN 0x08 -- --static const struct mlxsw_reg_info mlxsw_reg_mfsm = { -- .id = MLXSW_REG_MFSM_ID, -- .len = MLXSW_REG_MFSM_LEN, --}; -+MLXSW_ITEM32(reg, mcda, offset, 0x04, 0, 32); - --/* reg_mfsm_tacho -- * Fan tachometer index. -- * Access: Index -+/* reg_mcda_size -+ * Size of the data accessed, given in bytes. -+ * Access: RW - */ --MLXSW_ITEM32(reg, mfsm, tacho, 0x00, 24, 4); -+MLXSW_ITEM32(reg, mcda, size, 0x08, 0, 16); - --/* reg_mfsm_rpm -- * Fan speed (round per minute). -- * Access: RO -+/* reg_mcda_data -+ * Data block accessed. -+ * Access: RW - */ --MLXSW_ITEM32(reg, mfsm, rpm, 0x04, 0, 16); -+MLXSW_ITEM32_INDEXED(reg, mcda, data, 0x10, 0, 32, 4, 0, false); - --static inline void mlxsw_reg_mfsm_pack(char *payload, u8 tacho) -+static inline void mlxsw_reg_mcda_pack(char *payload, u32 update_handle, -+ u32 offset, u16 size, u8 *data) - { -- MLXSW_REG_ZERO(mfsm, payload); -- mlxsw_reg_mfsm_tacho_set(payload, tacho); -+ int i; -+ -+ MLXSW_REG_ZERO(mcda, payload); -+ mlxsw_reg_mcda_update_handle_set(payload, update_handle); -+ mlxsw_reg_mcda_offset_set(payload, offset); -+ mlxsw_reg_mcda_size_set(payload, size); -+ -+ for (i = 0; i < size / 4; i++) -+ mlxsw_reg_mcda_data_set(payload, i, *(u32 *) &data[i * 4]); - } - --/* MFSL - Management Fan Speed Limit Register -- * ------------------------------------------ -- * The Fan Speed Limit register is used to configure the fan speed -- * event / interrupt notification mechanism. Fan speed threshold are -- * defined for both under-speed and over-speed. -+/* MPSC - Monitoring Packet Sampling Configuration Register -+ * -------------------------------------------------------- -+ * MPSC Register is used to configure the Packet Sampling mechanism. - */ --#define MLXSW_REG_MFSL_ID 0x9004 --#define MLXSW_REG_MFSL_LEN 0x0C -+#define MLXSW_REG_MPSC_ID 0x9080 -+#define MLXSW_REG_MPSC_LEN 0x1C - --MLXSW_REG_DEFINE(mfsl, MLXSW_REG_MFSL_ID, MLXSW_REG_MFSL_LEN); -+MLXSW_REG_DEFINE(mpsc, MLXSW_REG_MPSC_ID, MLXSW_REG_MPSC_LEN); - --/* reg_mfsl_tacho -- * Fan tachometer index. -+/* reg_mpsc_local_port -+ * Local port number -+ * Not supported for CPU port - * Access: Index - */ --MLXSW_ITEM32(reg, mfsl, tacho, 0x00, 24, 4); -+MLXSW_ITEM32(reg, mpsc, local_port, 0x00, 16, 8); - --/* reg_mfsl_tach_min -- * Tachometer minimum value (minimum RPM). -+/* reg_mpsc_e -+ * Enable sampling on port local_port - * Access: RW - */ --MLXSW_ITEM32(reg, mfsl, tach_min, 0x04, 0, 16); -+MLXSW_ITEM32(reg, mpsc, e, 0x04, 30, 1); - --/* reg_mfsl_tach_max -- * Tachometer maximum value (maximum RPM). -+#define MLXSW_REG_MPSC_RATE_MAX 3500000000UL -+ -+/* reg_mpsc_rate -+ * Sampling rate = 1 out of rate packets (with randomization around -+ * the point). Valid values are: 1 to MLXSW_REG_MPSC_RATE_MAX - * Access: RW - */ --MLXSW_ITEM32(reg, mfsl, tach_max, 0x08, 0, 16); -- --static inline void mlxsw_reg_mfsl_pack(char *payload, u8 tacho, -- u16 tach_min, u16 tach_max) --{ -- MLXSW_REG_ZERO(mfsl, payload); -- mlxsw_reg_mfsl_tacho_set(payload, tacho); -- mlxsw_reg_mfsl_tach_min_set(payload, tach_min); -- mlxsw_reg_mfsl_tach_max_set(payload, tach_max); --} -+MLXSW_ITEM32(reg, mpsc, rate, 0x08, 0, 32); - --static inline void mlxsw_reg_mfsl_unpack(char *payload, u8 tacho, -- u16 *p_tach_min, u16 *p_tach_max) -+static inline void mlxsw_reg_mpsc_pack(char *payload, u8 local_port, bool e, -+ u32 rate) - { -- if (p_tach_min) -- *p_tach_min = mlxsw_reg_mfsl_tach_min_get(payload); -- -- if (p_tach_max) -- *p_tach_max = mlxsw_reg_mfsl_tach_max_get(payload); -+ MLXSW_REG_ZERO(mpsc, payload); -+ mlxsw_reg_mpsc_local_port_set(payload, local_port); -+ mlxsw_reg_mpsc_e_set(payload, e); -+ mlxsw_reg_mpsc_rate_set(payload, rate); - } - --/* FORE - Fan Out of Range Event Register -- * -------------------------------------- -- * This register reports the status of the controlled fans compared to the -- * range defined by the MFSL register. -+/* MGPC - Monitoring General Purpose Counter Set Register -+ * The MGPC register retrieves and sets the General Purpose Counter Set. - */ --#define MLXSW_REG_FORE_ID 0x9007 --#define MLXSW_REG_FORE_LEN 0x0C -+#define MLXSW_REG_MGPC_ID 0x9081 -+#define MLXSW_REG_MGPC_LEN 0x18 - --MLXSW_REG_DEFINE(fore, MLXSW_REG_FORE_ID, MLXSW_REG_FORE_LEN); -+MLXSW_REG_DEFINE(mgpc, MLXSW_REG_MGPC_ID, MLXSW_REG_MGPC_LEN); - --/* fan_under_limit -- * Fan speed is below the low limit defined in MFSL register. Each bit relates -- * to a single tachometer and indicates the specific tachometer reading is -- * below the threshold. -- * Access: RO -+/* reg_mgpc_counter_set_type -+ * Counter set type. -+ * Access: OP - */ --MLXSW_ITEM32(reg, fore, fan_under_limit, 0x00, 16, 10); -- --static inline void mlxsw_reg_fore_unpack(char *payload, u8 tacho, -- bool *fan_under_limit) --{ -- u16 limit; -- -- if (fan_under_limit) { -- limit = mlxsw_reg_fore_fan_under_limit_get(payload); -- *fan_under_limit = !!(limit & BIT(tacho)); -- } --} -+MLXSW_ITEM32(reg, mgpc, counter_set_type, 0x00, 24, 8); - --/* MTCAP - Management Temperature Capabilities -- * ------------------------------------------- -- * This register exposes the capabilities of the device and -- * system temperature sensing. -+/* reg_mgpc_counter_index -+ * Counter index. -+ * Access: Index - */ --#define MLXSW_REG_MTCAP_ID 0x9009 --#define MLXSW_REG_MTCAP_LEN 0x08 -+MLXSW_ITEM32(reg, mgpc, counter_index, 0x00, 0, 24); - --static const struct mlxsw_reg_info mlxsw_reg_mtcap = { -- .id = MLXSW_REG_MTCAP_ID, -- .len = MLXSW_REG_MTCAP_LEN, -+enum mlxsw_reg_mgpc_opcode { -+ /* Nop */ -+ MLXSW_REG_MGPC_OPCODE_NOP = 0x00, -+ /* Clear counters */ -+ MLXSW_REG_MGPC_OPCODE_CLEAR = 0x08, - }; - --/* reg_mtcap_sensor_count -- * Number of sensors supported by the device. -- * This includes the QSFP module sensors (if exists in the QSFP module). -- * Access: RO -+/* reg_mgpc_opcode -+ * Opcode. -+ * Access: OP - */ --MLXSW_ITEM32(reg, mtcap, sensor_count, 0x00, 0, 7); -+MLXSW_ITEM32(reg, mgpc, opcode, 0x04, 28, 4); - --/* MTMP - Management Temperature -- * ----------------------------- -- * This register controls the settings of the temperature measurements -- * and enables reading the temperature measurements. Note that temperature -- * is in 0.125 degrees Celsius. -+/* reg_mgpc_byte_counter -+ * Byte counter value. -+ * Access: RW - */ --#define MLXSW_REG_MTMP_ID 0x900A --#define MLXSW_REG_MTMP_LEN 0x20 -+MLXSW_ITEM64(reg, mgpc, byte_counter, 0x08, 0, 64); - --static const struct mlxsw_reg_info mlxsw_reg_mtmp = { -- .id = MLXSW_REG_MTMP_ID, -- .len = MLXSW_REG_MTMP_LEN, --}; -+/* reg_mgpc_packet_counter -+ * Packet counter value. -+ * Access: RW -+ */ -+MLXSW_ITEM64(reg, mgpc, packet_counter, 0x10, 0, 64); - --/* reg_mtmp_sensor_index -- * Sensors index to access. -- * 64-127 of sensor_index are mapped to the SFP+/QSFP modules sequentially -- * (module 0 is mapped to sensor_index 64). -- * Access: Index -+static inline void mlxsw_reg_mgpc_pack(char *payload, u32 counter_index, -+ enum mlxsw_reg_mgpc_opcode opcode, -+ enum mlxsw_reg_flow_counter_set_type set_type) -+{ -+ MLXSW_REG_ZERO(mgpc, payload); -+ mlxsw_reg_mgpc_counter_index_set(payload, counter_index); -+ mlxsw_reg_mgpc_counter_set_type_set(payload, set_type); -+ mlxsw_reg_mgpc_opcode_set(payload, opcode); -+} -+ -+/* MPRS - Monitoring Parsing State Register -+ * ---------------------------------------- -+ * The MPRS register is used for setting up the parsing for hash, -+ * policy-engine and routing. - */ --MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 7); -+#define MLXSW_REG_MPRS_ID 0x9083 -+#define MLXSW_REG_MPRS_LEN 0x14 - --/* Convert to milli degrees Celsius */ --#define MLXSW_REG_MTMP_TEMP_TO_MC(val) (val * 125) -+MLXSW_REG_DEFINE(mprs, MLXSW_REG_MPRS_ID, MLXSW_REG_MPRS_LEN); - --/* reg_mtmp_temperature -- * Temperature reading from the sensor. Reading is in 0.125 Celsius -- * degrees units. -- * Access: RO -+/* reg_mprs_parsing_depth -+ * Minimum parsing depth. -+ * Need to enlarge parsing depth according to L3, MPLS, tunnels, ACL -+ * rules, traps, hash, etc. Default is 96 bytes. Reserved when SwitchX-2. -+ * Access: RW - */ --MLXSW_ITEM32(reg, mtmp, temperature, 0x04, 0, 16); -+MLXSW_ITEM32(reg, mprs, parsing_depth, 0x00, 0, 16); - --/* reg_mtmp_mte -- * Max Temperature Enable - enables measuring the max temperature on a sensor. -+/* reg_mprs_parsing_en -+ * Parsing enable. -+ * Bit 0 - Enable parsing of NVE of types VxLAN, VxLAN-GPE, GENEVE and -+ * NVGRE. Default is enabled. Reserved when SwitchX-2. - * Access: RW - */ --MLXSW_ITEM32(reg, mtmp, mte, 0x08, 31, 1); -+MLXSW_ITEM32(reg, mprs, parsing_en, 0x04, 0, 16); - --/* reg_mtmp_mtr -- * Max Temperature Reset - clears the value of the max temperature register. -- * Access: WO -+/* reg_mprs_vxlan_udp_dport -+ * VxLAN UDP destination port. -+ * Used for identifying VxLAN packets and for dport field in -+ * encapsulation. Default is 4789. -+ * Access: RW - */ --MLXSW_ITEM32(reg, mtmp, mtr, 0x08, 30, 1); -+MLXSW_ITEM32(reg, mprs, vxlan_udp_dport, 0x10, 0, 16); - --/* reg_mtmp_max_temperature -- * The highest measured temperature from the sensor. -- * When the bit mte is cleared, the field max_temperature is reserved. -- * Access: RO -+static inline void mlxsw_reg_mprs_pack(char *payload, u16 parsing_depth, -+ u16 vxlan_udp_dport) -+{ -+ MLXSW_REG_ZERO(mprs, payload); -+ mlxsw_reg_mprs_parsing_depth_set(payload, parsing_depth); -+ mlxsw_reg_mprs_parsing_en_set(payload, true); -+ mlxsw_reg_mprs_vxlan_udp_dport_set(payload, vxlan_udp_dport); -+} -+ -+/* TNGCR - Tunneling NVE General Configuration Register -+ * ---------------------------------------------------- -+ * The TNGCR register is used for setting up the NVE Tunneling configuration. - */ --MLXSW_ITEM32(reg, mtmp, max_temperature, 0x08, 0, 16); -+#define MLXSW_REG_TNGCR_ID 0xA001 -+#define MLXSW_REG_TNGCR_LEN 0x44 - --/* reg_mtmp_tee -- * Temperature Event Enable. -- * 0 - Do not generate event -- * 1 - Generate event -- * 2 - Generate single event -+MLXSW_REG_DEFINE(tngcr, MLXSW_REG_TNGCR_ID, MLXSW_REG_TNGCR_LEN); -+ -+enum mlxsw_reg_tngcr_type { -+ MLXSW_REG_TNGCR_TYPE_VXLAN, -+ MLXSW_REG_TNGCR_TYPE_VXLAN_GPE, -+ MLXSW_REG_TNGCR_TYPE_GENEVE, -+ MLXSW_REG_TNGCR_TYPE_NVGRE, -+}; -+ -+/* reg_tngcr_type -+ * Tunnel type for encapsulation and decapsulation. The types are mutually -+ * exclusive. -+ * Note: For Spectrum the NVE parsing must be enabled in MPRS. - * Access: RW - */ --MLXSW_ITEM32(reg, mtmp, tee, 0x0C, 30, 2); -+MLXSW_ITEM32(reg, tngcr, type, 0x00, 0, 4); - --#define MLXSW_REG_MTMP_THRESH_HI 0x348 /* 105 Celsius */ -+/* reg_tngcr_nve_valid -+ * The VTEP is valid. Allows adding FDB entries for tunnel encapsulation. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, tngcr, nve_valid, 0x04, 31, 1); - --/* reg_mtmp_temperature_threshold_hi -- * High threshold for Temperature Warning Event. In 0.125 Celsius. -+/* reg_tngcr_nve_ttl_uc -+ * The TTL for NVE tunnel encapsulation underlay unicast packets. - * Access: RW - */ --MLXSW_ITEM32(reg, mtmp, temperature_threshold_hi, 0x0C, 0, 16); -+MLXSW_ITEM32(reg, tngcr, nve_ttl_uc, 0x04, 0, 8); - --/* reg_mtmp_temperature_threshold_lo -- * Low threshold for Temperature Warning Event. In 0.125 Celsius. -+/* reg_tngcr_nve_ttl_mc -+ * The TTL for NVE tunnel encapsulation underlay multicast packets. - * Access: RW - */ --MLXSW_ITEM32(reg, mtmp, temperature_threshold_lo, 0x10, 0, 16); -+MLXSW_ITEM32(reg, tngcr, nve_ttl_mc, 0x08, 0, 8); - --#define MLXSW_REG_MTMP_SENSOR_NAME_SIZE 8 -+enum { -+ /* Do not copy flow label. Calculate flow label using nve_flh. */ -+ MLXSW_REG_TNGCR_FL_NO_COPY, -+ /* Copy flow label from inner packet if packet is IPv6 and -+ * encapsulation is by IPv6. Otherwise, calculate flow label using -+ * nve_flh. -+ */ -+ MLXSW_REG_TNGCR_FL_COPY, -+}; - --/* reg_mtmp_sensor_name -- * Sensor Name -- * Access: RO -+/* reg_tngcr_nve_flc -+ * For NVE tunnel encapsulation: Flow label copy from inner packet. -+ * Access: RW - */ --MLXSW_ITEM_BUF(reg, mtmp, sensor_name, 0x18, MLXSW_REG_MTMP_SENSOR_NAME_SIZE); -+MLXSW_ITEM32(reg, tngcr, nve_flc, 0x0C, 25, 1); - --static inline void mlxsw_reg_mtmp_pack(char *payload, u8 sensor_index, -- bool max_temp_enable, -- bool max_temp_reset) --{ -- MLXSW_REG_ZERO(mtmp, payload); -- 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); -- mlxsw_reg_mtmp_temperature_threshold_hi_set(payload, -- MLXSW_REG_MTMP_THRESH_HI); --} -+enum { -+ /* Flow label is static. In Spectrum this means '0'. Spectrum-2 -+ * uses {nve_fl_prefix, nve_fl_suffix}. -+ */ -+ MLXSW_REG_TNGCR_FL_NO_HASH, -+ /* 8 LSBs of the flow label are calculated from ECMP hash of the -+ * inner packet. 12 MSBs are configured by nve_fl_prefix. -+ */ -+ MLXSW_REG_TNGCR_FL_HASH, -+}; - --static inline void mlxsw_reg_mtmp_unpack(char *payload, unsigned int *p_temp, -- unsigned int *p_max_temp, -- char *sensor_name) --{ -- u16 temp; -+/* reg_tngcr_nve_flh -+ * NVE flow label hash. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, tngcr, nve_flh, 0x0C, 24, 1); - -- if (p_temp) { -- temp = mlxsw_reg_mtmp_temperature_get(payload); -- *p_temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp); -- } -- if (p_max_temp) { -- temp = mlxsw_reg_mtmp_max_temperature_get(payload); -- *p_max_temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp); -- } -- if (sensor_name) -- mlxsw_reg_mtmp_sensor_name_memcpy_from(payload, sensor_name); --} -+/* reg_tngcr_nve_fl_prefix -+ * NVE flow label prefix. Constant 12 MSBs of the flow label. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, tngcr, nve_fl_prefix, 0x0C, 8, 12); - --/* MTBR - Management Temperature Bulk Register -- * ------------------------------------------- -- * This register is used for bulk temperature reading. -+/* reg_tngcr_nve_fl_suffix -+ * NVE flow label suffix. Constant 8 LSBs of the flow label. -+ * Reserved when nve_flh=1 and for Spectrum. -+ * Access: RW - */ --#define MLXSW_REG_MTBR_ID 0x900F --#define MLXSW_REG_MTBR_BASE_LEN 0x10 /* base length, without records */ --#define MLXSW_REG_MTBR_REC_LEN 0x04 /* record length */ --#define MLXSW_REG_MTBR_REC_MAX_COUNT 47 /* firmware limitation */ --#define MLXSW_REG_MTBR_LEN (MLXSW_REG_MTBR_BASE_LEN + \ -- MLXSW_REG_MTBR_REC_LEN * \ -- MLXSW_REG_MTBR_REC_MAX_COUNT) -+MLXSW_ITEM32(reg, tngcr, nve_fl_suffix, 0x0C, 0, 8); - --MLXSW_REG_DEFINE(mtbr, MLXSW_REG_MTBR_ID, MLXSW_REG_MTBR_LEN); -+enum { -+ /* Source UDP port is fixed (default '0') */ -+ MLXSW_REG_TNGCR_UDP_SPORT_NO_HASH, -+ /* Source UDP port is calculated based on hash */ -+ MLXSW_REG_TNGCR_UDP_SPORT_HASH, -+}; - --/* 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). -- * Access: Index -+/* reg_tngcr_nve_udp_sport_type -+ * NVE UDP source port type. -+ * Spectrum uses LAG hash (SLCRv2). Spectrum-2 uses ECMP hash (RECRv2). -+ * When the source UDP port is calculated based on hash, then the 8 LSBs -+ * are calculated from hash the 8 MSBs are configured by -+ * nve_udp_sport_prefix. -+ * Access: RW - */ --MLXSW_ITEM32(reg, mtbr, base_sensor_index, 0x00, 0, 7); -+MLXSW_ITEM32(reg, tngcr, nve_udp_sport_type, 0x10, 24, 1); - --/* reg_mtbr_num_rec -- * Request: Number of records to read -- * Response: Number of records read -- * See above description for more details. -- * Range 1..255 -+/* reg_tngcr_nve_udp_sport_prefix -+ * NVE UDP source port prefix. Constant 8 MSBs of the UDP source port. -+ * Reserved when NVE type is NVGRE. - * Access: RW - */ --MLXSW_ITEM32(reg, mtbr, num_rec, 0x04, 0, 8); -+MLXSW_ITEM32(reg, tngcr, nve_udp_sport_prefix, 0x10, 8, 8); - --/* reg_mtbr_rec_max_temp -- * The highest measured temperature from the sensor. -- * When the bit mte is cleared, the field max_temperature is reserved. -- * Access: RO -+/* reg_tngcr_nve_group_size_mc -+ * The amount of sequential linked lists of MC entries. The first linked -+ * list is configured by SFD.underlay_mc_ptr. -+ * Valid values: 1, 2, 4, 8, 16, 32, 64 -+ * The linked list are configured by TNUMT. -+ * The hash is set by LAG hash. -+ * Access: RW - */ --MLXSW_ITEM32_INDEXED(reg, mtbr, rec_max_temp, MLXSW_REG_MTBR_BASE_LEN, 16, -- 16, MLXSW_REG_MTBR_REC_LEN, 0x00, false); -+MLXSW_ITEM32(reg, tngcr, nve_group_size_mc, 0x18, 0, 8); - --/* reg_mtbr_rec_temp -- * Temperature reading from the sensor. Reading is in 0..125 Celsius -- * degrees units. -- * Access: RO -+/* reg_tngcr_nve_group_size_flood -+ * The amount of sequential linked lists of flooding entries. The first -+ * linked list is configured by SFMR.nve_tunnel_flood_ptr -+ * Valid values: 1, 2, 4, 8, 16, 32, 64 -+ * The linked list are configured by TNUMT. -+ * The hash is set by LAG hash. -+ * Access: RW - */ --MLXSW_ITEM32_INDEXED(reg, mtbr, rec_temp, MLXSW_REG_MTBR_BASE_LEN, 0, 16, -- MLXSW_REG_MTBR_REC_LEN, 0x00, false); -+MLXSW_ITEM32(reg, tngcr, nve_group_size_flood, 0x1C, 0, 8); - --static inline void mlxsw_reg_mtbr_pack(char *payload, u8 base_sensor_index, -- u8 num_rec) --{ -- MLXSW_REG_ZERO(mtbr, payload); -- mlxsw_reg_mtbr_base_sensor_index_set(payload, base_sensor_index); -- mlxsw_reg_mtbr_num_rec_set(payload, num_rec); --} -+/* reg_tngcr_learn_enable -+ * During decapsulation, whether to learn from NVE port. -+ * Reserved when Spectrum-2. See TNPC. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, tngcr, learn_enable, 0x20, 31, 1); - --/* Error codes from temperatute reading */ --enum mlxsw_reg_mtbr_temp_status { -- MLXSW_REG_MTBR_NO_CONN = 0x8000, -- MLXSW_REG_MTBR_NO_TEMP_SENS = 0x8001, -- MLXSW_REG_MTBR_INDEX_NA = 0x8002, -- MLXSW_REG_MTBR_BAD_SENS_INFO = 0x8003, --}; -+/* reg_tngcr_underlay_virtual_router -+ * Underlay virtual router. -+ * Reserved when Spectrum-2. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, tngcr, underlay_virtual_router, 0x20, 0, 16); - --/* Base index for reading modules temperature */ --#define MLXSW_REG_MTBR_BASE_MODULE_INDEX 64 -+/* reg_tngcr_underlay_rif -+ * Underlay ingress router interface. RIF type should be loopback generic. -+ * Reserved when Spectrum. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, tngcr, underlay_rif, 0x24, 0, 16); - --static inline void mlxsw_reg_mtbr_temp_unpack(char *payload, int rec_ind, -- u16 *p_temp, u16 *p_max_temp) -+/* reg_tngcr_usipv4 -+ * Underlay source IPv4 address of the NVE. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, tngcr, usipv4, 0x28, 0, 32); -+ -+/* reg_tngcr_usipv6 -+ * Underlay source IPv6 address of the NVE. For Spectrum, must not be -+ * modified under traffic of NVE tunneling encapsulation. -+ * Access: RW -+ */ -+MLXSW_ITEM_BUF(reg, tngcr, usipv6, 0x30, 16); -+ -+static inline void mlxsw_reg_tngcr_pack(char *payload, -+ enum mlxsw_reg_tngcr_type type, -+ bool valid, u8 ttl) - { -- if (p_temp) -- *p_temp = mlxsw_reg_mtbr_rec_temp_get(payload, rec_ind); -- if (p_max_temp) -- *p_max_temp = mlxsw_reg_mtbr_rec_max_temp_get(payload, rec_ind); -+ MLXSW_REG_ZERO(tngcr, payload); -+ mlxsw_reg_tngcr_type_set(payload, type); -+ mlxsw_reg_tngcr_nve_valid_set(payload, valid); -+ mlxsw_reg_tngcr_nve_ttl_uc_set(payload, ttl); -+ mlxsw_reg_tngcr_nve_ttl_mc_set(payload, ttl); -+ mlxsw_reg_tngcr_nve_flc_set(payload, MLXSW_REG_TNGCR_FL_NO_COPY); -+ mlxsw_reg_tngcr_nve_flh_set(payload, 0); -+ mlxsw_reg_tngcr_nve_udp_sport_type_set(payload, -+ MLXSW_REG_TNGCR_UDP_SPORT_HASH); -+ mlxsw_reg_tngcr_nve_udp_sport_prefix_set(payload, 0); -+ mlxsw_reg_tngcr_nve_group_size_mc_set(payload, 1); -+ mlxsw_reg_tngcr_nve_group_size_flood_set(payload, 1); - } - --/* MCIA - Management Cable Info Access -- * ----------------------------------- -- * MCIA register is used to access the SFP+ and QSFP connector's EPROM. -+/* TNUMT - Tunneling NVE Underlay Multicast Table Register -+ * ------------------------------------------------------- -+ * The TNUMT register is for building the underlay MC table. It is used -+ * for MC, flooding and BC traffic into the NVE tunnel. - */ -+#define MLXSW_REG_TNUMT_ID 0xA003 -+#define MLXSW_REG_TNUMT_LEN 0x20 - --#define MLXSW_REG_MCIA_ID 0x9014 --#define MLXSW_REG_MCIA_LEN 0x40 -+MLXSW_REG_DEFINE(tnumt, MLXSW_REG_TNUMT_ID, MLXSW_REG_TNUMT_LEN); - --MLXSW_REG_DEFINE(mcia, MLXSW_REG_MCIA_ID, MLXSW_REG_MCIA_LEN); -+enum mlxsw_reg_tnumt_record_type { -+ MLXSW_REG_TNUMT_RECORD_TYPE_IPV4, -+ MLXSW_REG_TNUMT_RECORD_TYPE_IPV6, -+ MLXSW_REG_TNUMT_RECORD_TYPE_LABEL, -+}; - --/* reg_mcia_l -- * Lock bit. Setting this bit will lock the access to the specific -- * cable. Used for updating a full page in a cable EPROM. Any access -- * other then subsequence writes will fail while the port is locked. -+/* reg_tnumt_record_type -+ * Record type. - * Access: RW - */ --MLXSW_ITEM32(reg, mcia, l, 0x00, 31, 1); -+MLXSW_ITEM32(reg, tnumt, record_type, 0x00, 28, 4); - --/* reg_mcia_module -- * Module number. -- * Access: Index -+enum mlxsw_reg_tnumt_tunnel_port { -+ MLXSW_REG_TNUMT_TUNNEL_PORT_NVE, -+ MLXSW_REG_TNUMT_TUNNEL_PORT_VPLS, -+ MLXSW_REG_TNUMT_TUNNEL_FLEX_TUNNEL0, -+ MLXSW_REG_TNUMT_TUNNEL_FLEX_TUNNEL1, -+}; -+ -+/* reg_tnumt_tunnel_port -+ * Tunnel port. -+ * Access: RW - */ --MLXSW_ITEM32(reg, mcia, module, 0x00, 16, 8); -+MLXSW_ITEM32(reg, tnumt, tunnel_port, 0x00, 24, 4); - --/* reg_mcia_status -- * Module status. -- * Access: RO -+/* reg_tnumt_underlay_mc_ptr -+ * Index to the underlay multicast table. -+ * For Spectrum the index is to the KVD linear. -+ * Access: Index - */ --MLXSW_ITEM32(reg, mcia, status, 0x00, 0, 8); -+MLXSW_ITEM32(reg, tnumt, underlay_mc_ptr, 0x00, 0, 24); - --/* reg_mcia_i2c_device_address -- * I2C device address. -+/* reg_tnumt_vnext -+ * The next_underlay_mc_ptr is valid. - * Access: RW - */ --MLXSW_ITEM32(reg, mcia, i2c_device_address, 0x04, 24, 8); -+MLXSW_ITEM32(reg, tnumt, vnext, 0x04, 31, 1); - --/* reg_mcia_page_number -- * Page number. -+/* reg_tnumt_next_underlay_mc_ptr -+ * The next index to the underlay multicast table. - * Access: RW - */ --MLXSW_ITEM32(reg, mcia, page_number, 0x04, 16, 8); -+MLXSW_ITEM32(reg, tnumt, next_underlay_mc_ptr, 0x04, 0, 24); - --/* reg_mcia_device_address -- * Device address. -+/* reg_tnumt_record_size -+ * Number of IP addresses in the record. -+ * Range is 1..cap_max_nve_mc_entries_ipv{4,6} - * Access: RW - */ --MLXSW_ITEM32(reg, mcia, device_address, 0x04, 0, 16); -+MLXSW_ITEM32(reg, tnumt, record_size, 0x08, 0, 3); - --/* reg_mcia_size -- * Number of bytes to read/write (up to 48 bytes). -+/* reg_tnumt_udip -+ * The underlay IPv4 addresses. udip[i] is reserved if i >= size - * Access: RW - */ --MLXSW_ITEM32(reg, mcia, size, 0x08, 0, 16); -+MLXSW_ITEM32_INDEXED(reg, tnumt, udip, 0x0C, 0, 32, 0x04, 0x00, false); - --#define MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH 256 --#define MLXSW_REG_MCIA_EEPROM_SIZE 48 --#define MLXSW_REG_MCIA_I2C_ADDR_LOW 0x50 --#define MLXSW_REG_MCIA_I2C_ADDR_HIGH 0x51 --#define MLXSW_REG_MCIA_PAGE0_LO_OFF 0xa0 --#define MLXSW_REG_MCIA_TH_ITEM_SIZE 2 --#define MLXSW_REG_MCIA_TH_PAGE_NUM 3 --#define MLXSW_REG_MCIA_PAGE0_LO 0 --#define MLXSW_REG_MCIA_TH_PAGE_OFF 0x80 -+/* reg_tnumt_udip_ptr -+ * The pointer to the underlay IPv6 addresses. udip_ptr[i] is reserved if -+ * i >= size. The IPv6 addresses are configured by RIPS. -+ * Access: RW -+ */ -+MLXSW_ITEM32_INDEXED(reg, tnumt, udip_ptr, 0x0C, 0, 24, 0x04, 0x00, false); - --enum mlxsw_reg_mcia_eeprom_module_info_rev_id { -- MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_UNSPC = 0x00, -- MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8436 = 0x01, -- MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636 = 0x03, --}; -+static inline void mlxsw_reg_tnumt_pack(char *payload, -+ enum mlxsw_reg_tnumt_record_type type, -+ enum mlxsw_reg_tnumt_tunnel_port tport, -+ u32 underlay_mc_ptr, bool vnext, -+ u32 next_underlay_mc_ptr, -+ u8 record_size) -+{ -+ MLXSW_REG_ZERO(tnumt, payload); -+ mlxsw_reg_tnumt_record_type_set(payload, type); -+ mlxsw_reg_tnumt_tunnel_port_set(payload, tport); -+ mlxsw_reg_tnumt_underlay_mc_ptr_set(payload, underlay_mc_ptr); -+ mlxsw_reg_tnumt_vnext_set(payload, vnext); -+ mlxsw_reg_tnumt_next_underlay_mc_ptr_set(payload, next_underlay_mc_ptr); -+ mlxsw_reg_tnumt_record_size_set(payload, record_size); -+} - --enum mlxsw_reg_mcia_eeprom_module_info_id { -- MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP = 0x03, -- MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP = 0x0C, -- MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS = 0x0D, -- MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28 = 0x11, -- MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_DD = 0x18, --}; -+/* TNQCR - Tunneling NVE QoS Configuration Register -+ * ------------------------------------------------ -+ * The TNQCR register configures how QoS is set in encapsulation into the -+ * underlay network. -+ */ -+#define MLXSW_REG_TNQCR_ID 0xA010 -+#define MLXSW_REG_TNQCR_LEN 0x0C - --enum mlxsw_reg_mcia_eeprom_module_info { -- MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID, -- MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID, -- MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE, --}; -+MLXSW_REG_DEFINE(tnqcr, MLXSW_REG_TNQCR_ID, MLXSW_REG_TNQCR_LEN); - --/* reg_mcia_eeprom -- * Bytes to read/write. -+/* reg_tnqcr_enc_set_dscp -+ * For encapsulation: How to set DSCP field: -+ * 0 - Copy the DSCP from the overlay (inner) IP header to the underlay -+ * (outer) IP header. If there is no IP header, use TNQDR.dscp -+ * 1 - Set the DSCP field as TNQDR.dscp - * Access: RW - */ --MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE); -+MLXSW_ITEM32(reg, tnqcr, enc_set_dscp, 0x04, 28, 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_tnqcr_pack(char *payload) - { -- MLXSW_REG_ZERO(mcia, payload); -- mlxsw_reg_mcia_module_set(payload, module); -- mlxsw_reg_mcia_l_set(payload, lock); -- mlxsw_reg_mcia_page_number_set(payload, page_number); -- mlxsw_reg_mcia_device_address_set(payload, device_addr); -- mlxsw_reg_mcia_size_set(payload, size); -- mlxsw_reg_mcia_i2c_device_address_set(payload, i2c_device_addr); -+ MLXSW_REG_ZERO(tnqcr, payload); -+ mlxsw_reg_tnqcr_enc_set_dscp_set(payload, 0); - } - --/* MPAT - Monitoring Port Analyzer Table -- * ------------------------------------- -- * MPAT Register is used to query and configure the Switch PortAnalyzer Table. -- * For an enabled analyzer, all fields except e (enable) cannot be modified. -+/* TNQDR - Tunneling NVE QoS Default Register -+ * ------------------------------------------ -+ * The TNQDR register configures the default QoS settings for NVE -+ * encapsulation. - */ --#define MLXSW_REG_MPAT_ID 0x901A --#define MLXSW_REG_MPAT_LEN 0x78 -+#define MLXSW_REG_TNQDR_ID 0xA011 -+#define MLXSW_REG_TNQDR_LEN 0x08 - --static const struct mlxsw_reg_info mlxsw_reg_mpat = { -- .id = MLXSW_REG_MPAT_ID, -- .len = MLXSW_REG_MPAT_LEN, --}; -+MLXSW_REG_DEFINE(tnqdr, MLXSW_REG_TNQDR_ID, MLXSW_REG_TNQDR_LEN); - --/* reg_mpat_pa_id -- * Port Analyzer ID. -+/* reg_tnqdr_local_port -+ * Local port number (receive port). CPU port is supported. - * Access: Index - */ --MLXSW_ITEM32(reg, mpat, pa_id, 0x00, 28, 4); -+MLXSW_ITEM32(reg, tnqdr, local_port, 0x00, 16, 8); - --/* reg_mpat_system_port -- * A unique port identifier for the final destination of the packet. -+/* reg_tnqdr_dscp -+ * For encapsulation, the default DSCP. - * Access: RW - */ --MLXSW_ITEM32(reg, mpat, system_port, 0x00, 0, 16); -+MLXSW_ITEM32(reg, tnqdr, dscp, 0x04, 0, 6); - --/* reg_mpat_e -- * Enable. Indicating the Port Analyzer is enabled. -- * Access: RW -+static inline void mlxsw_reg_tnqdr_pack(char *payload, u8 local_port) -+{ -+ MLXSW_REG_ZERO(tnqdr, payload); -+ mlxsw_reg_tnqdr_local_port_set(payload, local_port); -+ mlxsw_reg_tnqdr_dscp_set(payload, 0); -+} -+ -+/* TNEEM - Tunneling NVE Encapsulation ECN Mapping Register -+ * -------------------------------------------------------- -+ * The TNEEM register maps ECN of the IP header at the ingress to the -+ * encapsulation to the ECN of the underlay network. - */ --MLXSW_ITEM32(reg, mpat, e, 0x04, 31, 1); -+#define MLXSW_REG_TNEEM_ID 0xA012 -+#define MLXSW_REG_TNEEM_LEN 0x0C - --/* reg_mpat_qos -- * Quality Of Service Mode. -- * 0: CONFIGURED - QoS parameters (Switch Priority, and encapsulation -- * PCP, DEI, DSCP or VL) are configured. -- * 1: MAINTAIN - QoS parameters (Switch Priority, Color) are the -- * same as in the original packet that has triggered the mirroring. For -- * SPAN also the pcp,dei are maintained. -- * Access: RW -+MLXSW_REG_DEFINE(tneem, MLXSW_REG_TNEEM_ID, MLXSW_REG_TNEEM_LEN); -+ -+/* reg_tneem_overlay_ecn -+ * ECN of the IP header in the overlay network. -+ * Access: Index - */ --MLXSW_ITEM32(reg, mpat, qos, 0x04, 26, 1); -+MLXSW_ITEM32(reg, tneem, overlay_ecn, 0x04, 24, 2); - --/* reg_mpat_be -- * Best effort mode. Indicates mirroring traffic should not cause packet -- * drop or back pressure, but will discard the mirrored packets. Mirrored -- * packets will be forwarded on a best effort manner. -- * 0: Do not discard mirrored packets -- * 1: Discard mirrored packets if causing congestion -+/* reg_tneem_underlay_ecn -+ * ECN of the IP header in the underlay network. - * Access: RW - */ --MLXSW_ITEM32(reg, mpat, be, 0x04, 25, 1); -+MLXSW_ITEM32(reg, tneem, underlay_ecn, 0x04, 16, 2); - --static inline void mlxsw_reg_mpat_pack(char *payload, u8 pa_id, -- u16 system_port, bool e) -+static inline void mlxsw_reg_tneem_pack(char *payload, u8 overlay_ecn, -+ u8 underlay_ecn) - { -- MLXSW_REG_ZERO(mpat, payload); -- mlxsw_reg_mpat_pa_id_set(payload, pa_id); -- mlxsw_reg_mpat_system_port_set(payload, system_port); -- mlxsw_reg_mpat_e_set(payload, e); -- mlxsw_reg_mpat_qos_set(payload, 1); -- mlxsw_reg_mpat_be_set(payload, 1); -+ MLXSW_REG_ZERO(tneem, payload); -+ mlxsw_reg_tneem_overlay_ecn_set(payload, overlay_ecn); -+ mlxsw_reg_tneem_underlay_ecn_set(payload, underlay_ecn); - } - --/* MPAR - Monitoring Port Analyzer Register -- * ---------------------------------------- -- * MPAR register is used to query and configure the port analyzer port mirroring -- * properties. -+/* TNDEM - Tunneling NVE Decapsulation ECN Mapping Register -+ * -------------------------------------------------------- -+ * The TNDEM register configures the actions that are done in the -+ * decapsulation. - */ --#define MLXSW_REG_MPAR_ID 0x901B --#define MLXSW_REG_MPAR_LEN 0x08 -+#define MLXSW_REG_TNDEM_ID 0xA013 -+#define MLXSW_REG_TNDEM_LEN 0x0C - --static const struct mlxsw_reg_info mlxsw_reg_mpar = { -- .id = MLXSW_REG_MPAR_ID, -- .len = MLXSW_REG_MPAR_LEN, --}; -+MLXSW_REG_DEFINE(tndem, MLXSW_REG_TNDEM_ID, MLXSW_REG_TNDEM_LEN); - --/* reg_mpar_local_port -- * The local port to mirror the packets from. -+/* reg_tndem_underlay_ecn -+ * ECN field of the IP header in the underlay network. - * Access: Index - */ --MLXSW_ITEM32(reg, mpar, local_port, 0x00, 16, 8); -- --enum mlxsw_reg_mpar_i_e { -- MLXSW_REG_MPAR_TYPE_EGRESS, -- MLXSW_REG_MPAR_TYPE_INGRESS, --}; -+MLXSW_ITEM32(reg, tndem, underlay_ecn, 0x04, 24, 2); - --/* reg_mpar_i_e -- * Ingress/Egress -+/* reg_tndem_overlay_ecn -+ * ECN field of the IP header in the overlay network. - * Access: Index - */ --MLXSW_ITEM32(reg, mpar, i_e, 0x00, 0, 4); -+MLXSW_ITEM32(reg, tndem, overlay_ecn, 0x04, 16, 2); - --/* reg_mpar_enable -- * Enable mirroring -- * By default, port mirroring is disabled for all ports. -+/* reg_tndem_eip_ecn -+ * Egress IP ECN. ECN field of the IP header of the packet which goes out -+ * from the decapsulation. - * Access: RW - */ --MLXSW_ITEM32(reg, mpar, enable, 0x04, 31, 1); -+MLXSW_ITEM32(reg, tndem, eip_ecn, 0x04, 8, 2); - --/* reg_mpar_pa_id -- * Port Analyzer ID. -+/* reg_tndem_trap_en -+ * Trap enable: -+ * 0 - No trap due to decap ECN -+ * 1 - Trap enable with trap_id - * Access: RW - */ --MLXSW_ITEM32(reg, mpar, pa_id, 0x04, 0, 4); -+MLXSW_ITEM32(reg, tndem, trap_en, 0x08, 28, 4); - --static inline void mlxsw_reg_mpar_pack(char *payload, u8 local_port, -- enum mlxsw_reg_mpar_i_e i_e, -- bool enable, u8 pa_id) -+/* reg_tndem_trap_id -+ * Trap ID. Either DECAP_ECN0 or DECAP_ECN1. -+ * Reserved when trap_en is '0'. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, tndem, trap_id, 0x08, 0, 9); -+ -+static inline void mlxsw_reg_tndem_pack(char *payload, u8 underlay_ecn, -+ u8 overlay_ecn, u8 ecn, bool trap_en, -+ u16 trap_id) - { -- MLXSW_REG_ZERO(mpar, payload); -- mlxsw_reg_mpar_local_port_set(payload, local_port); -- mlxsw_reg_mpar_enable_set(payload, enable); -- mlxsw_reg_mpar_i_e_set(payload, i_e); -- mlxsw_reg_mpar_pa_id_set(payload, pa_id); -+ MLXSW_REG_ZERO(tndem, payload); -+ mlxsw_reg_tndem_underlay_ecn_set(payload, underlay_ecn); -+ mlxsw_reg_tndem_overlay_ecn_set(payload, overlay_ecn); -+ mlxsw_reg_tndem_eip_ecn_set(payload, ecn); -+ mlxsw_reg_tndem_trap_en_set(payload, trap_en); -+ mlxsw_reg_tndem_trap_id_set(payload, trap_id); - } - --/* MSCI - Management System CPLD Information Register -- * --------------------------------------------------- -- * This register allows querying for the System CPLD(s) information. -+/* TNPC - Tunnel Port Configuration Register -+ * ----------------------------------------- -+ * The TNPC register is used for tunnel port configuration. -+ * Reserved when Spectrum. - */ --#define MLXSW_REG_MSCI_ID 0x902A --#define MLXSW_REG_MSCI_LEN 0x10 -+#define MLXSW_REG_TNPC_ID 0xA020 -+#define MLXSW_REG_TNPC_LEN 0x18 - --static const struct mlxsw_reg_info mlxsw_reg_msci = { -- .id = MLXSW_REG_MSCI_ID, -- .len = MLXSW_REG_MSCI_LEN, -+MLXSW_REG_DEFINE(tnpc, MLXSW_REG_TNPC_ID, MLXSW_REG_TNPC_LEN); -+ -+enum mlxsw_reg_tnpc_tunnel_port { -+ MLXSW_REG_TNPC_TUNNEL_PORT_NVE, -+ MLXSW_REG_TNPC_TUNNEL_PORT_VPLS, -+ MLXSW_REG_TNPC_TUNNEL_FLEX_TUNNEL0, -+ MLXSW_REG_TNPC_TUNNEL_FLEX_TUNNEL1, - }; - --/* reg_msci_index -- * Index to access. -+/* reg_tnpc_tunnel_port -+ * Tunnel port. - * Access: Index - */ --MLXSW_ITEM32(reg, msci, index, 0x00, 0, 4); -+MLXSW_ITEM32(reg, tnpc, tunnel_port, 0x00, 0, 4); - --/* reg_msci_version -- * CPLD version. -- * Access: R0 -+/* reg_tnpc_learn_enable_v6 -+ * During IPv6 underlay decapsulation, whether to learn from tunnel port. -+ * Access: RW - */ --MLXSW_ITEM32(reg, msci, version, 0x04, 0, 32); -+MLXSW_ITEM32(reg, tnpc, learn_enable_v6, 0x04, 1, 1); - --static inline void --mlxsw_reg_msci_pack(char *payload, u8 index) --{ -- MLXSW_REG_ZERO(msci, payload); -- mlxsw_reg_msci_index_set(payload, index); --} -+/* reg_tnpc_learn_enable_v4 -+ * During IPv4 underlay decapsulation, whether to learn from tunnel port. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, tnpc, learn_enable_v4, 0x04, 0, 1); - --static inline void --mlxsw_reg_msci_unpack(char *payload, u16 *p_version) -+static inline void mlxsw_reg_tnpc_pack(char *payload, -+ enum mlxsw_reg_tnpc_tunnel_port tport, -+ bool learn_enable) - { -- *p_version = mlxsw_reg_msci_version_get(payload); -+ MLXSW_REG_ZERO(tnpc, payload); -+ mlxsw_reg_tnpc_tunnel_port_set(payload, tport); -+ mlxsw_reg_tnpc_learn_enable_v4_set(payload, learn_enable); -+ mlxsw_reg_tnpc_learn_enable_v6_set(payload, learn_enable); - } - --/* MLCR - Management LED Control Register -- * -------------------------------------- -- * Controls the system LEDs. -+/* TIGCR - Tunneling IPinIP General Configuration Register -+ * ------------------------------------------------------- -+ * The TIGCR register is used for setting up the IPinIP Tunnel configuration. - */ --#define MLXSW_REG_MLCR_ID 0x902B --#define MLXSW_REG_MLCR_LEN 0x0C -+#define MLXSW_REG_TIGCR_ID 0xA801 -+#define MLXSW_REG_TIGCR_LEN 0x10 - --static const struct mlxsw_reg_info mlxsw_reg_mlcr = { -- .id = MLXSW_REG_MLCR_ID, -- .len = MLXSW_REG_MLCR_LEN, --}; -+MLXSW_REG_DEFINE(tigcr, MLXSW_REG_TIGCR_ID, MLXSW_REG_TIGCR_LEN); - --/* reg_mlcr_local_port -- * Local port number. -+/* reg_tigcr_ipip_ttlc -+ * For IPinIP Tunnel encapsulation: whether to copy the ttl from the packet -+ * header. - * Access: RW - */ --MLXSW_ITEM32(reg, mlcr, local_port, 0x00, 16, 8); -+MLXSW_ITEM32(reg, tigcr, ttlc, 0x04, 8, 1); - --#define MLXSW_REG_MLCR_DURATION_MAX 0xFFFF -- --/* reg_mlcr_beacon_duration -- * Duration of the beacon to be active, in seconds. -- * 0x0 - Will turn off the beacon. -- * 0xFFFF - Will turn on the beacon until explicitly turned off. -+/* reg_tigcr_ipip_ttl_uc -+ * The TTL for IPinIP Tunnel encapsulation of unicast packets if -+ * reg_tigcr_ipip_ttlc is unset. - * Access: RW - */ --MLXSW_ITEM32(reg, mlcr, beacon_duration, 0x04, 0, 16); -- --/* reg_mlcr_beacon_remain -- * Remaining duration of the beacon, in seconds. -- * 0xFFFF indicates an infinite amount of time. -- * Access: RO -- */ --MLXSW_ITEM32(reg, mlcr, beacon_remain, 0x08, 0, 16); -+MLXSW_ITEM32(reg, tigcr, ttl_uc, 0x04, 0, 8); - --static inline void mlxsw_reg_mlcr_pack(char *payload, u8 local_port, -- bool active) -+static inline void mlxsw_reg_tigcr_pack(char *payload, bool ttlc, u8 ttl_uc) - { -- MLXSW_REG_ZERO(mlcr, payload); -- mlxsw_reg_mlcr_local_port_set(payload, local_port); -- mlxsw_reg_mlcr_beacon_duration_set(payload, active ? -- MLXSW_REG_MLCR_DURATION_MAX : 0); -+ MLXSW_REG_ZERO(tigcr, payload); -+ mlxsw_reg_tigcr_ttlc_set(payload, ttlc); -+ mlxsw_reg_tigcr_ttl_uc_set(payload, ttl_uc); - } - - /* SBPR - Shared Buffer Pools Register -@@ -5161,10 +9075,7 @@ static inline void mlxsw_reg_mlcr_pack(char *payload, u8 local_port, - #define MLXSW_REG_SBPR_ID 0xB001 - #define MLXSW_REG_SBPR_LEN 0x14 - --static const struct mlxsw_reg_info mlxsw_reg_sbpr = { -- .id = MLXSW_REG_SBPR_ID, -- .len = MLXSW_REG_SBPR_LEN, --}; -+MLXSW_REG_DEFINE(sbpr, MLXSW_REG_SBPR_ID, MLXSW_REG_SBPR_LEN); - - /* shared direstion enum for SBPR, SBCM, SBPM */ - enum mlxsw_reg_sbxx_dir { -@@ -5184,8 +9095,15 @@ MLXSW_ITEM32(reg, sbpr, dir, 0x00, 24, 2); - */ - MLXSW_ITEM32(reg, sbpr, pool, 0x00, 0, 4); - -+/* reg_sbpr_infi_size -+ * Size is infinite. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, sbpr, infi_size, 0x04, 31, 1); -+ - /* reg_sbpr_size - * Pool size in buffer cells. -+ * Reserved when infi_size = 1. - * Access: RW - */ - MLXSW_ITEM32(reg, sbpr, size, 0x04, 0, 24); -@@ -5203,13 +9121,15 @@ MLXSW_ITEM32(reg, sbpr, mode, 0x08, 0, 4); - - static inline void mlxsw_reg_sbpr_pack(char *payload, u8 pool, - enum mlxsw_reg_sbxx_dir dir, -- enum mlxsw_reg_sbpr_mode mode, u32 size) -+ enum mlxsw_reg_sbpr_mode mode, u32 size, -+ bool infi_size) - { - MLXSW_REG_ZERO(sbpr, payload); - mlxsw_reg_sbpr_pool_set(payload, pool); - mlxsw_reg_sbpr_dir_set(payload, dir); - mlxsw_reg_sbpr_mode_set(payload, mode); - mlxsw_reg_sbpr_size_set(payload, size); -+ mlxsw_reg_sbpr_infi_size_set(payload, infi_size); - } - - /* SBCM - Shared Buffer Class Management Register -@@ -5221,10 +9141,7 @@ static inline void mlxsw_reg_sbpr_pack(char *payload, u8 pool, - #define MLXSW_REG_SBCM_ID 0xB002 - #define MLXSW_REG_SBCM_LEN 0x28 - --static const struct mlxsw_reg_info mlxsw_reg_sbcm = { -- .id = MLXSW_REG_SBCM_ID, -- .len = MLXSW_REG_SBCM_LEN, --}; -+MLXSW_REG_DEFINE(sbcm, MLXSW_REG_SBCM_ID, MLXSW_REG_SBCM_LEN); - - /* reg_sbcm_local_port - * Local port number. -@@ -5260,6 +9177,12 @@ MLXSW_ITEM32(reg, sbcm, min_buff, 0x18, 0, 24); - #define MLXSW_REG_SBXX_DYN_MAX_BUFF_MIN 1 - #define MLXSW_REG_SBXX_DYN_MAX_BUFF_MAX 14 - -+/* reg_sbcm_infi_max -+ * Max buffer is infinite. -+ * Access: RW -+ */ -+MLXSW_ITEM32(reg, sbcm, infi_max, 0x1C, 31, 1); -+ - /* reg_sbcm_max_buff - * When the pool associated to the port-pg/tclass is configured to - * static, Maximum buffer size for the limiter configured in cells. -@@ -5269,6 +9192,7 @@ MLXSW_ITEM32(reg, sbcm, min_buff, 0x18, 0, 24); - * 0: 0 - * i: (1/128)*2^(i-1), for i=1..14 - * 0xFF: Infinity -+ * Reserved when infi_max = 1. - * Access: RW - */ - MLXSW_ITEM32(reg, sbcm, max_buff, 0x1C, 0, 24); -@@ -5281,7 +9205,8 @@ MLXSW_ITEM32(reg, sbcm, pool, 0x24, 0, 4); - - static inline void mlxsw_reg_sbcm_pack(char *payload, u8 local_port, u8 pg_buff, - enum mlxsw_reg_sbxx_dir dir, -- u32 min_buff, u32 max_buff, u8 pool) -+ u32 min_buff, u32 max_buff, -+ bool infi_max, u8 pool) - { - MLXSW_REG_ZERO(sbcm, payload); - mlxsw_reg_sbcm_local_port_set(payload, local_port); -@@ -5289,6 +9214,7 @@ static inline void mlxsw_reg_sbcm_pack(char *payload, u8 local_port, u8 pg_buff, - mlxsw_reg_sbcm_dir_set(payload, dir); - mlxsw_reg_sbcm_min_buff_set(payload, min_buff); - mlxsw_reg_sbcm_max_buff_set(payload, max_buff); -+ mlxsw_reg_sbcm_infi_max_set(payload, infi_max); - mlxsw_reg_sbcm_pool_set(payload, pool); - } - -@@ -5301,10 +9227,7 @@ static inline void mlxsw_reg_sbcm_pack(char *payload, u8 local_port, u8 pg_buff, - #define MLXSW_REG_SBPM_ID 0xB003 - #define MLXSW_REG_SBPM_LEN 0x28 - --static const struct mlxsw_reg_info mlxsw_reg_sbpm = { -- .id = MLXSW_REG_SBPM_ID, -- .len = MLXSW_REG_SBPM_LEN, --}; -+MLXSW_REG_DEFINE(sbpm, MLXSW_REG_SBPM_ID, MLXSW_REG_SBPM_LEN); - - /* reg_sbpm_local_port - * Local port number. -@@ -5395,10 +9318,7 @@ static inline void mlxsw_reg_sbpm_unpack(char *payload, u32 *p_buff_occupancy, - #define MLXSW_REG_SBMM_ID 0xB004 - #define MLXSW_REG_SBMM_LEN 0x28 - --static const struct mlxsw_reg_info mlxsw_reg_sbmm = { -- .id = MLXSW_REG_SBMM_ID, -- .len = MLXSW_REG_SBMM_LEN, --}; -+MLXSW_REG_DEFINE(sbmm, MLXSW_REG_SBMM_ID, MLXSW_REG_SBMM_LEN); - - /* reg_sbmm_prio - * Switch Priority. -@@ -5457,10 +9377,7 @@ static inline void mlxsw_reg_sbmm_pack(char *payload, u8 prio, u32 min_buff, - MLXSW_REG_SBSR_REC_LEN * \ - MLXSW_REG_SBSR_REC_MAX_COUNT) - --static const struct mlxsw_reg_info mlxsw_reg_sbsr = { -- .id = MLXSW_REG_SBSR_ID, -- .len = MLXSW_REG_SBSR_LEN, --}; -+MLXSW_REG_DEFINE(sbsr, MLXSW_REG_SBSR_ID, MLXSW_REG_SBSR_LEN); - - /* reg_sbsr_clr - * Clear Max Buffer Occupancy. When this bit is set, the max_buff_occupancy -@@ -5550,10 +9467,7 @@ static inline void mlxsw_reg_sbsr_rec_unpack(char *payload, int rec_index, - #define MLXSW_REG_SBIB_ID 0xB006 - #define MLXSW_REG_SBIB_LEN 0x10 - --static const struct mlxsw_reg_info mlxsw_reg_sbib = { -- .id = MLXSW_REG_SBIB_ID, -- .len = MLXSW_REG_SBIB_LEN, --}; -+MLXSW_REG_DEFINE(sbib, MLXSW_REG_SBIB_ID, MLXSW_REG_SBIB_LEN); - - /* reg_sbib_local_port - * Local port number -@@ -5578,136 +9492,132 @@ static inline void mlxsw_reg_sbib_pack(char *payload, u8 local_port, - mlxsw_reg_sbib_buff_size_set(payload, buff_size); - } - -+static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { -+ MLXSW_REG(sgcr), -+ MLXSW_REG(spad), -+ MLXSW_REG(smid), -+ MLXSW_REG(sspr), -+ MLXSW_REG(sfdat), -+ MLXSW_REG(sfd), -+ MLXSW_REG(sfn), -+ MLXSW_REG(spms), -+ MLXSW_REG(spvid), -+ MLXSW_REG(spvm), -+ MLXSW_REG(spaft), -+ MLXSW_REG(sfgc), -+ MLXSW_REG(sftr), -+ MLXSW_REG(sfdf), -+ MLXSW_REG(sldr), -+ MLXSW_REG(slcr), -+ MLXSW_REG(slcor), -+ MLXSW_REG(spmlr), -+ MLXSW_REG(svfa), -+ MLXSW_REG(svpe), -+ MLXSW_REG(sfmr), -+ MLXSW_REG(spvmlr), -+ MLXSW_REG(cwtp), -+ MLXSW_REG(cwtpm), -+ MLXSW_REG(pgcr), -+ MLXSW_REG(ppbt), -+ MLXSW_REG(pacl), -+ MLXSW_REG(pagt), -+ MLXSW_REG(ptar), -+ MLXSW_REG(ppbs), -+ MLXSW_REG(prcr), -+ MLXSW_REG(pefa), -+ MLXSW_REG(ptce2), -+ MLXSW_REG(perpt), -+ MLXSW_REG(perar), -+ MLXSW_REG(ptce3), -+ MLXSW_REG(percr), -+ MLXSW_REG(pererp), -+ MLXSW_REG(iedr), -+ MLXSW_REG(qpts), -+ MLXSW_REG(qpcr), -+ MLXSW_REG(qtct), -+ MLXSW_REG(qeec), -+ MLXSW_REG(qrwe), -+ MLXSW_REG(qpdsm), -+ MLXSW_REG(qpdpm), -+ MLXSW_REG(qtctm), -+ MLXSW_REG(pmlp), -+ MLXSW_REG(pmtu), -+ MLXSW_REG(ptys), -+ MLXSW_REG(ppad), -+ MLXSW_REG(paos), -+ MLXSW_REG(pfcc), -+ MLXSW_REG(ppcnt), -+ MLXSW_REG(plib), -+ MLXSW_REG(pptb), -+ MLXSW_REG(pbmc), -+ MLXSW_REG(pspa), -+ MLXSW_REG(htgt), -+ MLXSW_REG(hpkt), -+ MLXSW_REG(rgcr), -+ MLXSW_REG(ritr), -+ MLXSW_REG(rtar), -+ MLXSW_REG(ratr), -+ MLXSW_REG(rtdp), -+ MLXSW_REG(rdpm), -+ MLXSW_REG(ricnt), -+ MLXSW_REG(rrcr), -+ MLXSW_REG(ralta), -+ MLXSW_REG(ralst), -+ MLXSW_REG(raltb), -+ MLXSW_REG(ralue), -+ MLXSW_REG(rauht), -+ MLXSW_REG(raleu), -+ MLXSW_REG(rauhtd), -+ MLXSW_REG(rigr2), -+ MLXSW_REG(recr2), -+ MLXSW_REG(rmft2), -+ MLXSW_REG(mfcr), -+ MLXSW_REG(mfsc), -+ MLXSW_REG(mfsm), -+ MLXSW_REG(mfsl), -+ MLXSW_REG(fore), -+ MLXSW_REG(mtcap), -+ MLXSW_REG(mtmp), -+ MLXSW_REG(mtbr), -+ MLXSW_REG(mcia), -+ MLXSW_REG(mpat), -+ MLXSW_REG(mpar), -+ MLXSW_REG(mrsr), -+ MLXSW_REG(mlcr), -+ MLXSW_REG(msci), -+ MLXSW_REG(mpsc), -+ MLXSW_REG(mcqi), -+ MLXSW_REG(mcc), -+ MLXSW_REG(mcda), -+ MLXSW_REG(mgpc), -+ MLXSW_REG(mprs), -+ MLXSW_REG(tngcr), -+ MLXSW_REG(tnumt), -+ MLXSW_REG(tnqcr), -+ MLXSW_REG(tnqdr), -+ MLXSW_REG(tneem), -+ MLXSW_REG(tndem), -+ MLXSW_REG(tnpc), -+ MLXSW_REG(tigcr), -+ MLXSW_REG(sbpr), -+ MLXSW_REG(sbcm), -+ MLXSW_REG(sbpm), -+ MLXSW_REG(sbmm), -+ MLXSW_REG(sbsr), -+ MLXSW_REG(sbib), -+}; -+ - static inline const char *mlxsw_reg_id_str(u16 reg_id) - { -- switch (reg_id) { -- case MLXSW_REG_SGCR_ID: -- return "SGCR"; -- case MLXSW_REG_SPAD_ID: -- return "SPAD"; -- case MLXSW_REG_SMID_ID: -- return "SMID"; -- case MLXSW_REG_SSPR_ID: -- return "SSPR"; -- case MLXSW_REG_SFDAT_ID: -- return "SFDAT"; -- case MLXSW_REG_SFD_ID: -- return "SFD"; -- case MLXSW_REG_SFN_ID: -- return "SFN"; -- case MLXSW_REG_SPMS_ID: -- return "SPMS"; -- case MLXSW_REG_SPVID_ID: -- return "SPVID"; -- case MLXSW_REG_SPVM_ID: -- return "SPVM"; -- case MLXSW_REG_SPAFT_ID: -- return "SPAFT"; -- case MLXSW_REG_SFGC_ID: -- return "SFGC"; -- case MLXSW_REG_SFTR_ID: -- return "SFTR"; -- case MLXSW_REG_SFDF_ID: -- return "SFDF"; -- case MLXSW_REG_SLDR_ID: -- return "SLDR"; -- case MLXSW_REG_SLCR_ID: -- return "SLCR"; -- case MLXSW_REG_SLCOR_ID: -- return "SLCOR"; -- case MLXSW_REG_SPMLR_ID: -- return "SPMLR"; -- case MLXSW_REG_SVFA_ID: -- return "SVFA"; -- case MLXSW_REG_SVPE_ID: -- return "SVPE"; -- case MLXSW_REG_SFMR_ID: -- return "SFMR"; -- case MLXSW_REG_SPVMLR_ID: -- return "SPVMLR"; -- case MLXSW_REG_QTCT_ID: -- return "QTCT"; -- case MLXSW_REG_QEEC_ID: -- return "QEEC"; -- case MLXSW_REG_PMLP_ID: -- return "PMLP"; -- case MLXSW_REG_PMTU_ID: -- return "PMTU"; -- case MLXSW_REG_PTYS_ID: -- return "PTYS"; -- case MLXSW_REG_PPAD_ID: -- return "PPAD"; -- case MLXSW_REG_PAOS_ID: -- return "PAOS"; -- case MLXSW_REG_PFCC_ID: -- return "PFCC"; -- case MLXSW_REG_PPCNT_ID: -- return "PPCNT"; -- case MLXSW_REG_PPTB_ID: -- return "PPTB"; -- case MLXSW_REG_PBMC_ID: -- return "PBMC"; -- case MLXSW_REG_PSPA_ID: -- return "PSPA"; -- case MLXSW_REG_HTGT_ID: -- return "HTGT"; -- case MLXSW_REG_HPKT_ID: -- return "HPKT"; -- case MLXSW_REG_RGCR_ID: -- return "RGCR"; -- case MLXSW_REG_RITR_ID: -- return "RITR"; -- case MLXSW_REG_RATR_ID: -- return "RATR"; -- case MLXSW_REG_RALTA_ID: -- return "RALTA"; -- case MLXSW_REG_RALST_ID: -- return "RALST"; -- case MLXSW_REG_RALTB_ID: -- return "RALTB"; -- case MLXSW_REG_RALUE_ID: -- return "RALUE"; -- case MLXSW_REG_RAUHT_ID: -- return "RAUHT"; -- case MLXSW_REG_RALEU_ID: -- return "RALEU"; -- case MLXSW_REG_RAUHTD_ID: -- return "RAUHTD"; -- case MLXSW_REG_MFCR_ID: -- return "MFCR"; -- case MLXSW_REG_MFSC_ID: -- return "MFSC"; -- case MLXSW_REG_MFSM_ID: -- return "MFSM"; -- case MLXSW_REG_FORE_ID: -- return "FORE"; -- case MLXSW_REG_MTCAP_ID: -- return "MTCAP"; -- case MLXSW_REG_MPAT_ID: -- return "MPAT"; -- case MLXSW_REG_MPAR_ID: -- return "MPAR"; -- case MLXSW_REG_MTMP_ID: -- return "MTMP"; -- case MLXSW_REG_MTBR_ID: -- return "MTBR"; -- case MLXSW_REG_MLCR_ID: -- return "MLCR"; -- case MLXSW_REG_SBPR_ID: -- return "SBPR"; -- case MLXSW_REG_SBCM_ID: -- return "SBCM"; -- case MLXSW_REG_SBPM_ID: -- return "SBPM"; -- case MLXSW_REG_SBMM_ID: -- return "SBMM"; -- case MLXSW_REG_SBSR_ID: -- return "SBSR"; -- case MLXSW_REG_SBIB_ID: -- return "SBIB"; -- default: -- return "*UNKNOWN*"; -+ const struct mlxsw_reg_info *reg_info; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mlxsw_reg_infos); i++) { -+ reg_info = mlxsw_reg_infos[i]; -+ if (reg_info->id == reg_id) -+ return reg_info->name; - } -+ return "*UNKNOWN*"; - } - - /* PUDE - Port Up / Down Event -diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h -new file mode 100644 -index 0000000..99b3415 ---- /dev/null -+++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h -@@ -0,0 +1,152 @@ -+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ -+/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */ -+ -+#ifndef _MLXSW_RESOURCES_H -+#define _MLXSW_RESOURCES_H -+ -+#include -+#include -+ -+enum mlxsw_res_id { -+ MLXSW_RES_ID_KVD_SIZE, -+ MLXSW_RES_ID_KVD_SINGLE_MIN_SIZE, -+ MLXSW_RES_ID_KVD_DOUBLE_MIN_SIZE, -+ MLXSW_RES_ID_MAX_KVD_LINEAR_RANGE, -+ MLXSW_RES_ID_MAX_KVD_ACTION_SETS, -+ MLXSW_RES_ID_MAX_TRAP_GROUPS, -+ MLXSW_RES_ID_CQE_V0, -+ MLXSW_RES_ID_CQE_V1, -+ MLXSW_RES_ID_CQE_V2, -+ MLXSW_RES_ID_COUNTER_POOL_SIZE, -+ MLXSW_RES_ID_MAX_SPAN, -+ MLXSW_RES_ID_COUNTER_SIZE_PACKETS_BYTES, -+ MLXSW_RES_ID_COUNTER_SIZE_ROUTER_BASIC, -+ MLXSW_RES_ID_MAX_SYSTEM_PORT, -+ MLXSW_RES_ID_MAX_LAG, -+ MLXSW_RES_ID_MAX_LAG_MEMBERS, -+ MLXSW_RES_ID_MAX_BUFFER_SIZE, -+ MLXSW_RES_ID_CELL_SIZE, -+ MLXSW_RES_ID_ACL_MAX_TCAM_REGIONS, -+ MLXSW_RES_ID_ACL_MAX_TCAM_RULES, -+ MLXSW_RES_ID_ACL_MAX_REGIONS, -+ MLXSW_RES_ID_ACL_MAX_GROUPS, -+ MLXSW_RES_ID_ACL_MAX_GROUP_SIZE, -+ MLXSW_RES_ID_ACL_FLEX_KEYS, -+ MLXSW_RES_ID_ACL_MAX_ACTION_PER_RULE, -+ MLXSW_RES_ID_ACL_ACTIONS_PER_SET, -+ MLXSW_RES_ID_ACL_MAX_ERPT_BANKS, -+ MLXSW_RES_ID_ACL_MAX_ERPT_BANK_SIZE, -+ MLXSW_RES_ID_ACL_MAX_LARGE_KEY_ID, -+ MLXSW_RES_ID_ACL_ERPT_ENTRIES_2KB, -+ MLXSW_RES_ID_ACL_ERPT_ENTRIES_4KB, -+ MLXSW_RES_ID_ACL_ERPT_ENTRIES_8KB, -+ MLXSW_RES_ID_ACL_ERPT_ENTRIES_12KB, -+ MLXSW_RES_ID_MAX_CPU_POLICERS, -+ MLXSW_RES_ID_MAX_VRS, -+ MLXSW_RES_ID_MAX_RIFS, -+ MLXSW_RES_ID_MC_ERIF_LIST_ENTRIES, -+ MLXSW_RES_ID_MAX_LPM_TREES, -+ MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV4, -+ MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV6, -+ -+ /* Internal resources. -+ * Determined by the SW, not queried from the HW. -+ */ -+ MLXSW_RES_ID_KVD_SINGLE_SIZE, -+ MLXSW_RES_ID_KVD_DOUBLE_SIZE, -+ MLXSW_RES_ID_KVD_LINEAR_SIZE, -+ -+ __MLXSW_RES_ID_MAX, -+}; -+ -+static u16 mlxsw_res_ids[] = { -+ [MLXSW_RES_ID_KVD_SIZE] = 0x1001, -+ [MLXSW_RES_ID_KVD_SINGLE_MIN_SIZE] = 0x1002, -+ [MLXSW_RES_ID_KVD_DOUBLE_MIN_SIZE] = 0x1003, -+ [MLXSW_RES_ID_MAX_KVD_LINEAR_RANGE] = 0x1005, -+ [MLXSW_RES_ID_MAX_KVD_ACTION_SETS] = 0x1007, -+ [MLXSW_RES_ID_MAX_TRAP_GROUPS] = 0x2201, -+ [MLXSW_RES_ID_CQE_V0] = 0x2210, -+ [MLXSW_RES_ID_CQE_V1] = 0x2211, -+ [MLXSW_RES_ID_CQE_V2] = 0x2212, -+ [MLXSW_RES_ID_COUNTER_POOL_SIZE] = 0x2410, -+ [MLXSW_RES_ID_MAX_SPAN] = 0x2420, -+ [MLXSW_RES_ID_COUNTER_SIZE_PACKETS_BYTES] = 0x2443, -+ [MLXSW_RES_ID_COUNTER_SIZE_ROUTER_BASIC] = 0x2449, -+ [MLXSW_RES_ID_MAX_SYSTEM_PORT] = 0x2502, -+ [MLXSW_RES_ID_MAX_LAG] = 0x2520, -+ [MLXSW_RES_ID_MAX_LAG_MEMBERS] = 0x2521, -+ [MLXSW_RES_ID_MAX_BUFFER_SIZE] = 0x2802, /* Bytes */ -+ [MLXSW_RES_ID_CELL_SIZE] = 0x2803, /* Bytes */ -+ [MLXSW_RES_ID_ACL_MAX_TCAM_REGIONS] = 0x2901, -+ [MLXSW_RES_ID_ACL_MAX_TCAM_RULES] = 0x2902, -+ [MLXSW_RES_ID_ACL_MAX_REGIONS] = 0x2903, -+ [MLXSW_RES_ID_ACL_MAX_GROUPS] = 0x2904, -+ [MLXSW_RES_ID_ACL_MAX_GROUP_SIZE] = 0x2905, -+ [MLXSW_RES_ID_ACL_FLEX_KEYS] = 0x2910, -+ [MLXSW_RES_ID_ACL_MAX_ACTION_PER_RULE] = 0x2911, -+ [MLXSW_RES_ID_ACL_ACTIONS_PER_SET] = 0x2912, -+ [MLXSW_RES_ID_ACL_MAX_ERPT_BANKS] = 0x2940, -+ [MLXSW_RES_ID_ACL_MAX_ERPT_BANK_SIZE] = 0x2941, -+ [MLXSW_RES_ID_ACL_MAX_LARGE_KEY_ID] = 0x2942, -+ [MLXSW_RES_ID_ACL_ERPT_ENTRIES_2KB] = 0x2950, -+ [MLXSW_RES_ID_ACL_ERPT_ENTRIES_4KB] = 0x2951, -+ [MLXSW_RES_ID_ACL_ERPT_ENTRIES_8KB] = 0x2952, -+ [MLXSW_RES_ID_ACL_ERPT_ENTRIES_12KB] = 0x2953, -+ [MLXSW_RES_ID_MAX_CPU_POLICERS] = 0x2A13, -+ [MLXSW_RES_ID_MAX_VRS] = 0x2C01, -+ [MLXSW_RES_ID_MAX_RIFS] = 0x2C02, -+ [MLXSW_RES_ID_MC_ERIF_LIST_ENTRIES] = 0x2C10, -+ [MLXSW_RES_ID_MAX_LPM_TREES] = 0x2C30, -+ [MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV4] = 0x2E02, -+ [MLXSW_RES_ID_MAX_NVE_MC_ENTRIES_IPV6] = 0x2E03, -+}; -+ -+struct mlxsw_res { -+ bool valid[__MLXSW_RES_ID_MAX]; -+ u64 values[__MLXSW_RES_ID_MAX]; -+}; -+ -+static inline bool mlxsw_res_valid(struct mlxsw_res *res, -+ enum mlxsw_res_id res_id) -+{ -+ return res->valid[res_id]; -+} -+ -+#define MLXSW_RES_VALID(res, short_res_id) \ -+ mlxsw_res_valid(res, MLXSW_RES_ID_##short_res_id) -+ -+static inline u64 mlxsw_res_get(struct mlxsw_res *res, -+ enum mlxsw_res_id res_id) -+{ -+ if (WARN_ON(!res->valid[res_id])) -+ return 0; -+ return res->values[res_id]; -+} -+ -+#define MLXSW_RES_GET(res, short_res_id) \ -+ mlxsw_res_get(res, MLXSW_RES_ID_##short_res_id) -+ -+static inline void mlxsw_res_set(struct mlxsw_res *res, -+ enum mlxsw_res_id res_id, u64 value) -+{ -+ res->valid[res_id] = true; -+ res->values[res_id] = value; -+} -+ -+#define MLXSW_RES_SET(res, short_res_id, value) \ -+ mlxsw_res_set(res, MLXSW_RES_ID_##short_res_id, value) -+ -+static inline void mlxsw_res_parse(struct mlxsw_res *res, u16 id, u64 value) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mlxsw_res_ids); i++) { -+ if (mlxsw_res_ids[i] == id) { -+ mlxsw_res_set(res, i, value); -+ return; -+ } -+ } -+} -+ -+#endif --- -2.1.4 - diff --git a/patch/0032-sonic-update-kernel-config-mlsxw-pci.patch b/patch/0032-sonic-update-kernel-config-mlsxw-pci.patch deleted file mode 100644 index eebdfa2206a2..000000000000 --- a/patch/0032-sonic-update-kernel-config-mlsxw-pci.patch +++ /dev/null @@ -1,26 +0,0 @@ -From f022b1aad3c9bfe2ac13efa8b86020e3779fc82a Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Tue, 15 Jan 2019 21:17:00 +0200 -Subject: [PATCH] sonic update kernel config mlsxw pci - -Signed-off-by: Vadim Pasternak ---- - debian/build/build_amd64_none_amd64/.config | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index 21d0d6f..9169c30 100644 ---- a/debian/build/build_amd64_none_amd64/.config -+++ b/debian/build/build_amd64_none_amd64/.config -@@ -2642,7 +2642,7 @@ CONFIG_MLXSW_CORE=m - CONFIG_MLXSW_CORE_HWMON=y - CONFIG_MLXSW_CORE_THERMAL=y - CONFIG_MLXSW_CORE_QSFP=y --CONFIG_MLXSW_PCI=m -+# CONFIG_MLXSW_PCI is not set - CONFIG_MLXSW_I2C=m - CONFIG_MLXSW_MINIMAL=m - CONFIG_NET_VENDOR_MICREL=y --- -1.7.1 - diff --git a/patch/0033-hwmon-pmbus-Fix-driver-info-initialization-in-probe-.patch b/patch/0033-hwmon-pmbus-Fix-driver-info-initialization-in-probe-.patch deleted file mode 100644 index 261c5f898e53..000000000000 --- a/patch/0033-hwmon-pmbus-Fix-driver-info-initialization-in-probe-.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 81443e4927ec84223f8305e0e4cec647521856e4 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Mon, 21 Jan 2019 14:54:58 +0000 -Subject: [PATCH hwmon] hwmon: (pmbus) Fix driver info initialization in probe - routine - -Fix tps53679_probe() by using dynamically allocated ?pmbus_driver_info? -structure instead of static. Usage of static structures causes -overwritten of the field ?vrm_version? - when the number of tps53679 -devices with the different ?vrm_version? are used within the same -system, the last probed device overwrites this field for all others. - -Fixes: 610526527a13e4c9 ("hwmon: (pmbus) Add support for Texas Instruments tps53679 device") -Signed-off-by: Vadim Pasternak ---- - drivers/hwmon/pmbus/tps53679.c | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) - -diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c -index 85b515c..45eacc5 100644 ---- a/drivers/hwmon/pmbus/tps53679.c -+++ b/drivers/hwmon/pmbus/tps53679.c -@@ -80,7 +80,15 @@ static struct pmbus_driver_info tps53679_info = { - static int tps53679_probe(struct i2c_client *client, - const struct i2c_device_id *id) - { -- return pmbus_do_probe(client, id, &tps53679_info); -+ struct pmbus_driver_info *info; -+ -+ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); -+ if (!info) -+ return -ENOMEM; -+ -+ memcpy(info, &tps53679_info, sizeof(*info)); -+ -+ return pmbus_do_probe(client, id, info); - } - - static const struct i2c_device_id tps53679_id[] = { --- -2.1.4 - diff --git a/patch/0034-mlxsw-thermal-disable-highest-zone-calculation.patch b/patch/0034-mlxsw-thermal-disable-highest-zone-calculation.patch deleted file mode 100644 index 830e1ae52573..000000000000 --- a/patch/0034-mlxsw-thermal-disable-highest-zone-calculation.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 5da6a599af1072f278b5f41ed648bed2142d42f0 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Mon, 21 Jan 2019 19:13:29 +0000 -Subject: [PATCH mlxsw] mlxsw thermal: disable highest zone calculation - -Signed-off-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index 444455c..0a2e7a2 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -433,7 +433,7 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, - return err; - } - mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); -- -+#if 0 - if (thermal->tz_module_arr) { - err = mlxsw_thermal_highest_tz_notify(dev, tzdev, thermal, - thermal->tz_module_num, -@@ -441,7 +441,7 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, - if (err) - dev_err(dev, "Failed to query module temp sensor\n"); - } -- -+#endif - *p_temp = (int) temp; - return 0; - } --- -2.1.4 - diff --git a/patch/0035-platform-x86-mlx-platform-Add-CPLD4-register.patch b/patch/0035-platform-x86-mlx-platform-Add-CPLD4-register.patch deleted file mode 100644 index 5d993b423b77..000000000000 --- a/patch/0035-platform-x86-mlx-platform-Add-CPLD4-register.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 87859cbda6affc45fc8d513c12eb4318e2c81073 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Thu, 24 Jan 2019 09:58:23 +0000 -Subject: [PATCH platform] platform/x86: mlx-platform: Add CPLD4 register - -Signed-off-by: ---- - drivers/platform/x86/mlx-platform.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index fc8d655..a80b968 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -25,6 +25,7 @@ - #define MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET 0x00 - #define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET 0x01 - #define MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET 0x02 -+#define MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET 0x03 - #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 -@@ -1163,6 +1164,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { - .mode = 0444, - }, - { -+ .label = "cpld4_version", -+ .reg = MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET, -+ .bit = GENMASK(7, 0), -+ .mode = 0444, -+ }, -+ { - .label = "reset_long_pb", - .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, - .mask = GENMASK(7, 0) & ~BIT(0), -@@ -1251,7 +1258,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { - .label = "fan_dir", - .reg = MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION, - .bit = GENMASK(7, 0), -- .mode = 0200, -+ .mode = 0444, - }, - }; - -@@ -1531,6 +1538,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: - case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: - case MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET: - case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: - case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET: -@@ -1597,6 +1605,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: - case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: - case MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_CPLD4_VER_OFFSET: - case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: - case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET: --- -2.1.4 - diff --git a/patch/0036-watchdog-mlx-wdt-kernel-upstream-and-wd-type2-change.patch b/patch/0036-watchdog-mlx-wdt-kernel-upstream-and-wd-type2-change.patch deleted file mode 100644 index 456db703e149..000000000000 --- a/patch/0036-watchdog-mlx-wdt-kernel-upstream-and-wd-type2-change.patch +++ /dev/null @@ -1,665 +0,0 @@ -diff -Nur a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c ---- a/drivers/platform/x86/mlx-platform.c 2019-02-21 13:41:06.654605472 +0000 -+++ b/drivers/platform/x86/mlx-platform.c 2019-02-21 13:48:22.670032634 +0000 -@@ -61,9 +61,11 @@ - #define MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET 0xc9 - #define MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET 0xcb - #define MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET 0xcd -+#define MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET 0xce - #define MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET 0xcf - #define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET 0xd1 --#define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd2 -+#define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET 0xd2 -+#define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd3 - #define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3 - #define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4 - #define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5 -@@ -1369,7 +1371,9 @@ - .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data), - }; - --/* Type1 watchdog implementation on MSN2700, MSN2100 and MSN2140 systems */ -+/* Watchdog type1: hardware implementation version1 -+ * (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140 systems). -+ */ - static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type1[] = { - { - .label = "action", -@@ -1422,17 +1426,19 @@ - { - .data = mlxplat_mlxcpld_wd_main_regs_type1, - .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type1), -+ .version = MLX_WDT_TYPE1, - .identity = "mlx-wdt-main", - }, - { - .data = mlxplat_mlxcpld_wd_aux_regs_type1, - .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type1), -+ .version = MLX_WDT_TYPE1, - .identity = "mlx-wdt-aux", - }, - }; - --/* Type2 watchdog implementation on MSB8700 and up systems -- * To differentiate: ping reg == action reg -+/* Watchdog type2: hardware implementation version 2 -+ * (all systems except (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140). - */ - static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type2[] = { - { -@@ -1448,6 +1454,11 @@ - .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, - }, - { -+ .label = "timeleft", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET, -+ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, -+ }, -+ { - .label = "ping", - .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, - .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK, -@@ -1475,6 +1486,11 @@ - .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, - }, - { -+ .label = "timeleft", -+ .reg = MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET, -+ .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, -+ }, -+ { - .label = "ping", - .reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, - .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK, -@@ -1486,11 +1502,13 @@ - { - .data = mlxplat_mlxcpld_wd_main_regs_type2, - .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type2), -+ .version = MLX_WDT_TYPE2, - .identity = "mlx-wdt-main", - }, - { - .data = mlxplat_mlxcpld_wd_aux_regs_type2, - .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type2), -+ .version = MLX_WDT_TYPE2, - .identity = "mlx-wdt-aux", - }, - }; -@@ -1573,8 +1591,10 @@ - case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: - case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET: - case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET: - case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET: - 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_PWM1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: -@@ -1634,7 +1654,9 @@ - case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: - case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: - case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET: - case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: - case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: -@@ -2094,8 +2116,8 @@ - for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) { - if (mlxplat_wd_data[j]) { - mlxplat_wd_data[j]->regmap = mlxplat_hotplug->regmap; -- priv->pdev_wd[j] = platform_device_register_resndata( -- &mlxplat_dev->dev, -+ 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])); -@@ -2115,8 +2137,10 @@ - return 0; - - fail_platform_wd_register: -- while (--j >= 0) -- platform_device_unregister(priv->pdev_wd[j]); -+ while (--j >= 0) { -+ if (priv->pdev_wd[j]) -+ platform_device_unregister(priv->pdev_wd[j]); -+ } - if (mlxplat_fan) - platform_device_unregister(priv->pdev_fan); - fail_platform_io_regs_register: -@@ -2142,16 +2166,16 @@ - struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); - int i; - -+ for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) { -+ if (mlxplat_wd_data[i]) -+ platform_device_unregister(priv->pdev_wd[i]); -+ } - if (priv->pdev_fan) - platform_device_unregister(priv->pdev_fan); - if (priv->pdev_io_regs) - platform_device_unregister(priv->pdev_io_regs); - platform_device_unregister(priv->pdev_led); - platform_device_unregister(priv->pdev_hotplug); -- for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) { -- if (mlxplat_wd_data[i]) -- platform_device_unregister(priv->pdev_wd[i]); -- } - for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) - platform_device_unregister(priv->pdev_mux[i]); - -diff -Nur a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig ---- a/drivers/watchdog/Kconfig 2019-02-21 13:41:44.518903255 +0000 -+++ b/drivers/watchdog/Kconfig 2019-02-21 13:54:11.964775375 +0000 -@@ -141,21 +141,6 @@ - This driver can also be built as a module. If so the module - will be called menf21bmc_wdt. - --config MLX_WDT -- tristate "Mellanox Watchdog" -- select WATCHDOG_CORE -- select REGMAP -- ---help--- -- This is the driver for the hardware watchdog on Mellanox systems. -- If you are going to use it, say Y here, otherwise N. -- This driver can be used together with the watchdog daemon. -- It can also watch your kernel to make sure it doesn't freeze, -- and if it does, it reboots your system after a certain amount of -- time. -- -- To compile this driver as a module, choose M here: the -- module will be called mlx-wdt. -- - config TANGOX_WATCHDOG - tristate "Sigma Designs SMP86xx/SMP87xx watchdog" - select WATCHDOG_CORE -@@ -218,6 +203,22 @@ - To compile this driver as a module, choose M here: the - module will be called ziirave_wdt. - -+config MLX_WDT -+ tristate "Mellanox Watchdog" -+ depends on MELLANOX_PLATFORM -+ select WATCHDOG_CORE -+ select REGMAP -+ help -+ This is the driver for the hardware watchdog on Mellanox systems. -+ If you are going to use it, say Y here, otherwise N. -+ This driver can be used together with the watchdog daemon. -+ It can also watch your kernel to make sure it doesn't freeze, -+ and if it does, it reboots your system after a certain amount of -+ time. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mlx-wdt. -+ - # ALPHA Architecture - - # ARM Architecture -diff -Nur a/drivers/watchdog/mlx_wdt.c b/drivers/watchdog/mlx_wdt.c ---- a/drivers/watchdog/mlx_wdt.c 2019-02-21 13:42:09.119096705 +0000 -+++ b/drivers/watchdog/mlx_wdt.c 2019-02-21 15:36:44.116225080 +0000 -@@ -2,8 +2,8 @@ - /* - * Mellanox watchdog driver - * -- * Copyright (C) 2018 Mellanox Technologies -- * Copyright (C) 2018 Michael Shych -+ * Copyright (C) 2019 Mellanox Technologies -+ * Copyright (C) 2019 Michael Shych - */ - - #include -@@ -21,20 +21,9 @@ - #define MLXREG_WDT_CLOCK_SCALE 1000 - #define MLXREG_WDT_MAX_TIMEOUT_TYPE1 32 - #define MLXREG_WDT_MAX_TIMEOUT_TYPE2 255 --#define MLXREG_WDT_MIN_TIMEOUT 1 --#define MLXREG_WDT_HW_TIMEOUT_CONVERT(hw_timeout) ((1 << (hw_timeout)) \ -- / MLXREG_WDT_CLOCK_SCALE) -- --/** -- * enum mlxreg_wdt_type - type of HW watchdog -- * -- * TYPE1 can be differentiated by different register/mask -- * for WD action set and ping. -- */ --enum mlxreg_wdt_type { -- MLX_WDT_TYPE1, -- MLX_WDT_TYPE2, --}; -+#define MLXREG_WDT_MIN_TIMEOUT 1 -+#define MLXREG_WDT_OPTIONS_BASE (WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | \ -+ WDIOF_SETTIMEOUT) - - /** - * struct mlxreg_wdt - wd private data: -@@ -44,16 +33,12 @@ - * @pdata: data received from platform driver; - * @regmap: register map of parent device; - * @timeout: defined timeout in sec.; -- * @hw_timeout: real timeout set in hw; -- * It will be roundup base of 2 in WD type 1, -- * in WD type 2 it will be same number of sec as timeout; - * @action_idx: index for direct access to action register; - * @timeout_idx:index for direct access to TO register; -+ * @tleft_idx: index for direct access to time left register; - * @ping_idx: index for direct access to ping register; - * @reset_idx: index for direct access to reset cause register; - * @wd_type: watchdog HW type; -- * @hw_timeout: actual HW timeout; -- * @io_lock: spinlock for io access; - */ - struct mlxreg_wdt { - struct watchdog_device wdd; -@@ -61,138 +46,61 @@ - void *regmap; - int action_idx; - int timeout_idx; -+ int tleft_idx; - int ping_idx; - int reset_idx; - enum mlxreg_wdt_type wdt_type; -- u8 hw_timeout; -- spinlock_t io_lock; /* the lock for io operations */ - }; - --static int mlxreg_wdt_roundup_to_base_2(struct mlxreg_wdt *wdt, int timeout) --{ -- timeout *= MLXREG_WDT_CLOCK_SCALE; -- -- wdt->hw_timeout = order_base_2(timeout); -- dev_info(wdt->wdd.parent, -- "watchdog %s timeout %d was rounded up to %lu (msec)\n", -- wdt->wdd.info->identity, timeout, roundup_pow_of_two(timeout)); -- -- return 0; --} -- --static enum mlxreg_wdt_type --mlxreg_wdt_check_watchdog_type(struct mlxreg_wdt *wdt, -- struct mlxreg_core_platform_data *pdata) --{ -- if ((pdata->data[wdt->action_idx].reg == -- pdata->data[wdt->ping_idx].reg) && -- (pdata->data[wdt->action_idx].mask == -- pdata->data[wdt->ping_idx].mask)) -- return MLX_WDT_TYPE2; -- else -- return MLX_WDT_TYPE1; --} -- --static int mlxreg_wdt_check_card_reset(struct mlxreg_wdt *wdt) -+static void mlxreg_wdt_check_card_reset(struct mlxreg_wdt *wdt) - { - struct mlxreg_core_data *reg_data; - u32 regval; - int rc; - - if (wdt->reset_idx == -EINVAL) -- return -EINVAL; -+ return; - - if (!(wdt->wdd.info->options & WDIOF_CARDRESET)) -- return 0; -+ return; - -- spin_lock(&wdt->io_lock); - reg_data = &wdt->pdata->data[wdt->reset_idx]; - rc = regmap_read(wdt->regmap, reg_data->reg, ®val); -- spin_unlock(&wdt->io_lock); -- if (rc) -- goto read_error; -- -- if (regval & ~reg_data->mask) { -- wdt->wdd.bootstatus = WDIOF_CARDRESET; -- dev_info(wdt->wdd.parent, -- "watchdog previously reset the CPU\n"); -+ if (!rc) { -+ if (regval & ~reg_data->mask) { -+ wdt->wdd.bootstatus = WDIOF_CARDRESET; -+ dev_info(wdt->wdd.parent, -+ "watchdog previously reset the CPU\n"); -+ } - } -- --read_error: -- return rc; - } - - static int mlxreg_wdt_start(struct watchdog_device *wdd) - { - struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); - struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->action_idx]; -- u32 regval; -- int rc; -- -- spin_lock(&wdt->io_lock); -- rc = regmap_read(wdt->regmap, reg_data->reg, ®val); -- if (rc) { -- spin_unlock(&wdt->io_lock); -- goto read_error; -- } -- -- regval = (regval & reg_data->mask) | BIT(reg_data->bit); -- rc = regmap_write(wdt->regmap, reg_data->reg, regval); -- spin_unlock(&wdt->io_lock); -- if (!rc) { -- set_bit(WDOG_HW_RUNNING, &wdt->wdd.status); -- dev_info(wdt->wdd.parent, "watchdog %s started\n", -- wdd->info->identity); -- } - --read_error: -- return rc; -+ return regmap_update_bits(wdt->regmap, reg_data->reg, ~reg_data->mask, -+ BIT(reg_data->bit)); - } - - static int mlxreg_wdt_stop(struct watchdog_device *wdd) - { - struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); - struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->action_idx]; -- u32 regval; -- int rc; -- -- spin_lock(&wdt->io_lock); -- rc = regmap_read(wdt->regmap, reg_data->reg, ®val); -- if (rc) { -- spin_unlock(&wdt->io_lock); -- goto read_error; -- } - -- regval = (regval & reg_data->mask) & ~BIT(reg_data->bit); -- rc = regmap_write(wdt->regmap, reg_data->reg, regval); -- spin_unlock(&wdt->io_lock); -- if (!rc) -- dev_info(wdt->wdd.parent, "watchdog %s stopped\n", -- wdd->info->identity); -- --read_error: -- return rc; -+ return regmap_update_bits(wdt->regmap, reg_data->reg, ~reg_data->mask, -+ ~BIT(reg_data->bit)); - } - - static int mlxreg_wdt_ping(struct watchdog_device *wdd) - { - struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); - struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->ping_idx]; -- u32 regval; -- int rc; - -- spin_lock(&wdt->io_lock); -- rc = regmap_read(wdt->regmap, reg_data->reg, ®val); -- if (rc) -- goto read_error; -- -- regval = (regval & reg_data->mask) | BIT(reg_data->bit); -- rc = regmap_write(wdt->regmap, reg_data->reg, regval); -- --read_error: -- spin_unlock(&wdt->io_lock); -- -- return rc; -+ return regmap_update_bits_base(wdt->regmap, reg_data->reg, -+ ~reg_data->mask, BIT(reg_data->bit), -+ NULL, false, true); - } - - static int mlxreg_wdt_set_timeout(struct watchdog_device *wdd, -@@ -200,25 +108,37 @@ - { - struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); - struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->timeout_idx]; -- u32 regval; -+ u32 regval, set_time, hw_timeout; - int rc; - -- spin_lock(&wdt->io_lock); -- - if (wdt->wdt_type == MLX_WDT_TYPE1) { - rc = regmap_read(wdt->regmap, reg_data->reg, ®val); - if (rc) -- goto read_error; -- regval = (regval & reg_data->mask) | wdt->hw_timeout; -+ return rc; -+ -+ hw_timeout = order_base_2(timeout * MLXREG_WDT_CLOCK_SCALE); -+ regval = (regval & reg_data->mask) | hw_timeout; -+ /* Rowndown to actual closest number of sec. */ -+ set_time = BIT(hw_timeout) / MLXREG_WDT_CLOCK_SCALE; - } else { -- wdt->hw_timeout = timeout; -+ set_time = timeout; - regval = timeout; - } - -+ wdd->timeout = set_time; - rc = regmap_write(wdt->regmap, reg_data->reg, regval); - --read_error: -- spin_unlock(&wdt->io_lock); -+ if (!rc) { -+ /* -+ * Restart watchdog with new timeout period -+ * if watchdog is already started. -+ */ -+ if (watchdog_active(wdd)) { -+ rc = mlxreg_wdt_stop(wdd); -+ if (!rc) -+ rc = mlxreg_wdt_start(wdd); -+ } -+ } - - return rc; - } -@@ -226,23 +146,13 @@ - static unsigned int mlxreg_wdt_get_timeleft(struct watchdog_device *wdd) - { - struct mlxreg_wdt *wdt = watchdog_get_drvdata(wdd); -- struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->timeout_idx]; -+ struct mlxreg_core_data *reg_data = &wdt->pdata->data[wdt->tleft_idx]; - u32 regval; - int rc; - -- if (wdt->wdt_type == MLX_WDT_TYPE1) -- return 0; -- -- spin_lock(&wdt->io_lock); - rc = regmap_read(wdt->regmap, reg_data->reg, ®val); -- if (rc) -- rc = 0; -- else -- rc = regval; -- -- spin_unlock(&wdt->io_lock); -- -- return rc; -+ /* Return 0 timeleft in case of failure register read. */ -+ return rc == 0 ? regval : 0; - } - - static const struct watchdog_ops mlxreg_wdt_ops_type1 = { -@@ -263,26 +173,22 @@ - }; - - static const struct watchdog_info mlxreg_wdt_main_info = { -- .options = WDIOF_KEEPALIVEPING -- | WDIOF_MAGICCLOSE -- | WDIOF_SETTIMEOUT -+ .options = MLXREG_WDT_OPTIONS_BASE - | WDIOF_CARDRESET, - .identity = "mlx-wdt-main", - }; - - static const struct watchdog_info mlxreg_wdt_aux_info = { -- .options = WDIOF_KEEPALIVEPING -- | WDIOF_MAGICCLOSE -- | WDIOF_SETTIMEOUT -+ .options = MLXREG_WDT_OPTIONS_BASE - | WDIOF_ALARMONLY, - .identity = "mlx-wdt-aux", - }; - --static int mlxreg_wdt_config(struct mlxreg_wdt *wdt, -- struct mlxreg_core_platform_data *pdata) -+static void mlxreg_wdt_config(struct mlxreg_wdt *wdt, -+ struct mlxreg_core_platform_data *pdata) - { - struct mlxreg_core_data *data = pdata->data; -- int i, timeout; -+ int i; - - wdt->reset_idx = -EINVAL; - for (i = 0; i < pdata->counter; i++, data++) { -@@ -290,6 +196,8 @@ - wdt->action_idx = i; - else if (strnstr(data->label, "timeout", sizeof(data->label))) - wdt->timeout_idx = i; -+ else if (strnstr(data->label, "timeleft", sizeof(data->label))) -+ wdt->tleft_idx = i; - else if (strnstr(data->label, "ping", sizeof(data->label))) - wdt->ping_idx = i; - else if (strnstr(data->label, "reset", sizeof(data->label))) -@@ -303,24 +211,24 @@ - else - wdt->wdd.info = &mlxreg_wdt_aux_info; - -- timeout = pdata->data[wdt->timeout_idx].health_cntr; -- wdt->wdt_type = mlxreg_wdt_check_watchdog_type(wdt, pdata); -+ wdt->wdt_type = pdata->version; - if (wdt->wdt_type == MLX_WDT_TYPE2) { -- wdt->hw_timeout = timeout; - wdt->wdd.ops = &mlxreg_wdt_ops_type2; -- wdt->wdd.timeout = wdt->hw_timeout; - wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE2; - } else { -- mlxreg_wdt_roundup_to_base_2(wdt, timeout); - wdt->wdd.ops = &mlxreg_wdt_ops_type1; -- /* Rowndown to actual closest number of sec. */ -- wdt->wdd.timeout = -- MLXREG_WDT_HW_TIMEOUT_CONVERT(wdt->hw_timeout); - wdt->wdd.max_timeout = MLXREG_WDT_MAX_TIMEOUT_TYPE1; - } - wdt->wdd.min_timeout = MLXREG_WDT_MIN_TIMEOUT; -+} - -- return -EINVAL; -+static int mlxreg_wdt_init_timeout(struct mlxreg_wdt *wdt, -+ struct mlxreg_core_platform_data *pdata) -+{ -+ u32 timeout; -+ -+ timeout = pdata->data[wdt->timeout_idx].health_cntr; -+ return mlxreg_wdt_set_timeout(&wdt->wdd, timeout); - } - - static int mlxreg_wdt_probe(struct platform_device *pdev) -@@ -338,48 +246,38 @@ - if (!wdt) - return -ENOMEM; - -- spin_lock_init(&wdt->io_lock); -- - wdt->wdd.parent = &pdev->dev; - wdt->regmap = pdata->regmap; - mlxreg_wdt_config(wdt, pdata); - -- if ((pdata->features & MLXREG_CORE_WD_FEATURE_NOSTOP_AFTER_START)) -+ if ((pdata->features & MLXREG_CORE_WD_FEATURE_NOWAYOUT)) - watchdog_set_nowayout(&wdt->wdd, WATCHDOG_NOWAYOUT); - watchdog_stop_on_reboot(&wdt->wdd); -- watchdog_init_timeout(&wdt->wdd, 0, &pdev->dev); - watchdog_set_drvdata(&wdt->wdd, wdt); -+ rc = mlxreg_wdt_init_timeout(wdt, pdata); -+ if (rc) -+ goto register_error; - -+ if ((pdata->features & MLXREG_CORE_WD_FEATURE_START_AT_BOOT)) { -+ rc = mlxreg_wdt_start(&wdt->wdd); -+ if (rc) -+ goto register_error; -+ set_bit(WDOG_HW_RUNNING, &wdt->wdd.status); -+ } - mlxreg_wdt_check_card_reset(wdt); - rc = devm_watchdog_register_device(&pdev->dev, &wdt->wdd); -- if (rc) { -+ -+register_error: -+ if (rc) - dev_err(&pdev->dev, - "Cannot register watchdog device (err=%d)\n", rc); -- return rc; -- } -- -- mlxreg_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout); -- if ((pdata->features & MLXREG_CORE_WD_FEATURE_START_AT_BOOT)) -- mlxreg_wdt_start(&wdt->wdd); -- - return rc; - } - --static int mlxreg_wdt_remove(struct platform_device *pdev) --{ -- struct mlxreg_wdt *wdt = dev_get_platdata(&pdev->dev); -- -- mlxreg_wdt_stop(&wdt->wdd); -- watchdog_unregister_device(&wdt->wdd); -- -- return 0; --} -- - static struct platform_driver mlxreg_wdt_driver = { - .probe = mlxreg_wdt_probe, -- .remove = mlxreg_wdt_remove, - .driver = { -- .name = "mlx-wdt", -+ .name = "mlx-wdt", - }, - }; - -diff -Nur a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h ---- a/include/linux/platform_data/mlxreg.h 2019-02-21 13:58:39.410873888 +0000 -+++ b/include/linux/platform_data/mlxreg.h 2019-02-21 13:59:41.015345425 +0000 -@@ -35,8 +35,19 @@ - #define __LINUX_PLATFORM_DATA_MLXREG_H - - #define MLXREG_CORE_LABEL_MAX_SIZE 32 --#define MLXREG_CORE_WD_FEATURE_NOSTOP_AFTER_START BIT(0) --#define MLXREG_CORE_WD_FEATURE_START_AT_BOOT BIT(1) -+#define MLXREG_CORE_WD_FEATURE_NOWAYOUT BIT(0) -+#define MLXREG_CORE_WD_FEATURE_START_AT_BOOT BIT(1) -+ -+/** -+ * enum mlxreg_wdt_type - type of HW watchdog -+ * -+ * TYPE1 HW watchdog implementation exist in old systems. -+ * All new systems have TYPE2 HW watchdog. -+ */ -+enum mlxreg_wdt_type { -+ MLX_WDT_TYPE1, -+ MLX_WDT_TYPE2, -+}; - - /** - * struct mlxreg_hotplug_device - I2C device data: -@@ -115,6 +126,7 @@ - * @regmap: register map of parent device; - * @counter: number of instances; - * @features: supported features of device; -+ * @version: implementation version; - * @identity: device identity name; - */ - struct mlxreg_core_platform_data { -@@ -122,6 +134,7 @@ - void *regmap; - int counter; - u32 features; -+ u32 version; - char identity[MLXREG_CORE_LABEL_MAX_SIZE]; - }; - diff --git a/patch/0037-mlxsw-Align-code-with-kernel-v-5.1.patch b/patch/0037-mlxsw-Align-code-with-kernel-v-5.1.patch deleted file mode 100644 index 59a5c31bb030..000000000000 --- a/patch/0037-mlxsw-Align-code-with-kernel-v-5.1.patch +++ /dev/null @@ -1,564 +0,0 @@ -From 4df1b8e3a873293a8ad59afe276bb4a48dd2f613 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Mon, 25 Feb 2019 07:18:14 +0000 -Subject: [PATCH backport 5.1] mlxsw-Align-code-with-kernel-v-5.1.patch - -Add latest hwmon and thermal ASIC modules amendments. - -Fix LED driver. - -Signed-off-by: Vadim Pasternak ---- - drivers/leds/leds-mlxreg.c | 21 ++- - drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 8 +- - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 168 +-------------------- - drivers/net/ethernet/mellanox/mlxsw/i2c.c | 10 +- - drivers/net/ethernet/mellanox/mlxsw/minimal.c | 85 ++++++----- - 5 files changed, 77 insertions(+), 215 deletions(-) - -diff --git a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c -index 2db200075cfc..0c14a7406c6e 100644 ---- a/drivers/leds/leds-mlxreg.c -+++ b/drivers/leds/leds-mlxreg.c -@@ -22,6 +22,7 @@ - #define MLXREG_LED_AMBER_SOLID 0x09 /* Solid amber */ - #define MLXREG_LED_BLINK_3HZ 167 /* ~167 msec off/on - HW support */ - #define MLXREG_LED_BLINK_6HZ 83 /* ~83 msec off/on - HW support */ -+#define MLXREG_LED_CAPABILITY_CLEAR GENMASK(31, 8) /* Clear mask */ - - /** - * struct mlxreg_led_data - led control data: -@@ -100,7 +101,7 @@ mlxreg_led_get_hw(struct mlxreg_led_data *led_data) - struct mlxreg_core_platform_data *led_pdata = priv->pdata; - struct mlxreg_core_data *data = led_data->data; - u32 regval; -- int ret; -+ int err; - - /* - * Each LED is controlled through low or high nibble of the relevant -@@ -112,10 +113,10 @@ mlxreg_led_get_hw(struct mlxreg_led_data *led_data) - * 0xf0 - lower nibble is to be used (bits from 0 to 3), mask 0x0f - - * higher nibble (bits from 4 to 7). - */ -- ret = regmap_read(led_pdata->regmap, data->reg, ®val); -- if (ret < 0) { -+ err = regmap_read(led_pdata->regmap, data->reg, ®val); -+ if (err < 0) { - dev_warn(led_data->led_cdev.dev, "Failed to get current brightness, error: %d\n", -- ret); -+ err); - /* Assume the LED is OFF */ - return LED_OFF; - } -@@ -125,11 +126,9 @@ mlxreg_led_get_hw(struct mlxreg_led_data *led_data) - data->bit) : ror32(regval, data->bit + 4); - if (regval >= led_data->base_color && - regval <= (led_data->base_color + MLXREG_LED_OFFSET_BLINK_6HZ)) -- ret = LED_FULL; -- else -- ret = LED_OFF; -+ return LED_FULL; - -- return ret; -+ return LED_OFF; - } - - static int -@@ -208,6 +207,12 @@ static int mlxreg_led_config(struct mlxreg_led_priv_data *priv) - } - if (!(regval & data->bit)) - continue; -+ /* -+ * Field "bit" can contain one capability bit in 0 byte -+ * and offset bit in 1-3 bytes. Clear capability bit and -+ * keep only offset bit. -+ */ -+ data->bit &= MLXREG_LED_CAPABILITY_CLEAR; - } - - led_cdev = &led_data->led_cdev; -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -index f1ada4cdbd6b..6956bbebe2f1 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -@@ -208,7 +208,7 @@ static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev, - 1); - err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); - if (err) { -- dev_err(dev, "Failed to query module temprature sensor\n"); -+ dev_err(dev, "Failed to query module temperature sensor\n"); - return err; - } - -@@ -251,7 +251,7 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, - 1); - err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); - if (err) { -- dev_err(dev, "Failed to query module temprature sensor\n"); -+ dev_err(dev, "Failed to query module temperature sensor\n"); - return err; - } - -@@ -291,7 +291,7 @@ mlxsw_hwmon_module_temp_critical_show(struct device *dev, - err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, - SFP_TEMP_HIGH_WARN, &temp); - if (err) { -- dev_err(dev, "Failed to query module temprature thresholds\n"); -+ dev_err(dev, "Failed to query module temperature thresholds\n"); - return err; - } - -@@ -314,7 +314,7 @@ mlxsw_hwmon_module_temp_emergency_show(struct device *dev, - err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, - SFP_TEMP_HIGH_ALARM, &temp); - if (err) { -- dev_err(dev, "Failed to query module temprature thresholds\n"); -+ 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 0a2e7a2f1569..002654918ee9 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -23,7 +23,6 @@ - #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 0xffffffff - #define MLXSW_THERMAL_MAX_STATE 10 - #define MLXSW_THERMAL_MAX_DUTY 255 - /* Minimum and maximum fan allowed speed in percent: from 20% to 100%. Values -@@ -113,8 +112,6 @@ struct mlxsw_thermal { - enum thermal_device_mode mode; - struct mlxsw_thermal_module *tz_module_arr; - unsigned int tz_module_num; -- int tz_highest; -- struct mutex tz_update_lock; - }; - - static inline u8 mlxsw_state_to_duty(int state) -@@ -179,7 +176,7 @@ mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core, - /* According to the system thermal requirements, the thermal zones are - * defined with four trip points. The critical and emergency - * temperature thresholds, provided by QSFP module are set as "active" -- * and "hot" trip points, "normal" and "critical" trip points ar -+ * and "hot" trip points, "normal" and "critical" trip points are - * derived from "active" and "hot" by subtracting or adding double - * hysteresis value. - */ -@@ -199,140 +196,6 @@ mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core, - return 0; - } - --static void mlxsw_thermal_tz_score_get(struct mlxsw_thermal_trip *trips, -- int temp, int *score) --{ -- struct mlxsw_thermal_trip *trip = trips; -- int delta, i, shift = 1; -- -- /* Calculate thermal zone score, if temperature is above the critical -- * threshold score is set to MLXSW_THERMAL_TEMP_SCORE_MAX. -- */ -- *score = MLXSW_THERMAL_TEMP_SCORE_MAX; -- for (i = MLXSW_THERMAL_TEMP_TRIP_NORM; i < MLXSW_THERMAL_NUM_TRIPS; -- i++, trip++) { -- if (temp < trip->temp) { -- delta = DIV_ROUND_CLOSEST(temp, trip->temp - temp); -- *score = delta * shift; -- break; -- } -- shift *= 256; -- } --} -- --static int --mlxsw_thermal_highest_tz_get(struct device *dev, struct mlxsw_thermal *thermal, -- int module_count, unsigned int seed_temp, -- int *max_tz, int *max_score) --{ -- char mtbr_pl[MLXSW_REG_MTBR_LEN]; -- struct mlxsw_thermal_module *tz; -- int i, j, index, off, score; -- u16 temp; -- int err; -- -- mlxsw_thermal_tz_score_get(thermal->trips, seed_temp, max_score); -- /* Read modules temperature. */ -- index = 0; -- while (index < module_count) { -- off = min_t(u8, MLXSW_REG_MTBR_REC_MAX_COUNT, -- module_count - index); -- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + -- index, off); -- err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtbr), mtbr_pl); -- if (err) { -- dev_err(dev, "Failed to get temp from index %d\n", -- off); -- return err; -- } -- -- for (i = 0, j = index; i < off; i++, j++) { -- mlxsw_reg_mtbr_temp_unpack(mtbr_pl, i, &temp, NULL); -- /* Update status and temperature cache. */ -- switch (temp) { -- case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ -- case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ -- case MLXSW_REG_MTBR_INDEX_NA: /* fall-through */ -- case MLXSW_REG_MTBR_BAD_SENS_INFO: -- temp = 0; -- break; -- default: -- tz = &thermal->tz_module_arr[j]; -- if (!tz) -- break; -- /* Reset all trip point. */ -- mlxsw_thermal_module_trips_reset(tz); -- temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp); -- /* Do not consider zero temperature. */ -- if (!temp) -- break; -- -- err = mlxsw_thermal_module_trips_update(dev, -- thermal->core, -- tz); -- if (err) { -- dev_err(dev, "Failed to update trips for %s\n", -- tz->tzdev->type); -- return err; -- } -- -- score = 0; -- mlxsw_thermal_tz_score_get(tz->trips, temp, -- &score); -- if (score > *max_score) { -- *max_score = score; -- *max_tz = j + 1; -- } -- break; -- } -- } -- index += off; -- } -- -- return 0; --} -- --static int --mlxsw_thermal_highest_tz_notify(struct device *dev, -- struct thermal_zone_device *tzdev, -- struct mlxsw_thermal *thermal, -- int module_count, unsigned int temp) --{ -- char env_record[24]; -- char *envp[2] = { env_record, NULL }; -- struct mlxsw_thermal_module *tz_module; -- struct thermal_zone_device *tz; -- int max_tz = 0, max_score = 0; -- int err; -- -- err = mlxsw_thermal_highest_tz_get(dev, thermal, -- thermal->tz_module_num, temp, -- &max_tz, &max_score); -- if (err) { -- dev_err(dev, "Failed to query module temp sensor\n"); -- return err; -- } -- -- if (thermal->tz_highest != max_tz) { -- sprintf(env_record, "TZ_HIGHEST==%u", max_score); -- if (max_tz && (&thermal->tz_module_arr[max_tz - 1])) { -- tz_module = &thermal->tz_module_arr[max_tz - 1]; -- tz = tz_module->tzdev; -- err = kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE, -- envp); -- } else { -- err = kobject_uevent_env(&tzdev->device.kobj, -- KOBJ_CHANGE, envp); -- } -- if (err) -- dev_err(dev, "Error sending uevent %s\n", envp[0]); -- else -- thermal->tz_highest = max_tz; -- } -- -- return 0; --} -- - static int mlxsw_thermal_bind(struct thermal_zone_device *tzdev, - struct thermal_cooling_device *cdev) - { -@@ -398,20 +261,15 @@ static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev, - - mutex_lock(&tzdev->lock); - -- if (mode == THERMAL_DEVICE_ENABLED) { -- thermal->tz_highest = 0; -+ if (mode == THERMAL_DEVICE_ENABLED) - tzdev->polling_delay = thermal->polling_delay; -- } else { -+ else - tzdev->polling_delay = 0; -- } - - mutex_unlock(&tzdev->lock); - - thermal->mode = mode; -- -- mutex_lock(&thermal->tz_update_lock); - thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED); -- mutex_unlock(&thermal->tz_update_lock); - - return 0; - } -@@ -433,15 +291,7 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, - return err; - } - mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); --#if 0 -- if (thermal->tz_module_arr) { -- err = mlxsw_thermal_highest_tz_notify(dev, tzdev, thermal, -- thermal->tz_module_num, -- temp); -- if (err) -- dev_err(dev, "Failed to query module temp sensor\n"); -- } --#endif -+ - *p_temp = (int) temp; - return 0; - } -@@ -589,10 +439,7 @@ static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev, - mutex_unlock(&tzdev->lock); - - tz->mode = mode; -- -- mutex_lock(&thermal->tz_update_lock); - thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED); -- mutex_unlock(&thermal->tz_update_lock); - - return 0; - } -@@ -993,7 +840,6 @@ int mlxsw_thermal_init(struct mlxsw_core *core, - - thermal->core = core; - thermal->bus_info = bus_info; -- mutex_init(&thermal->tz_update_lock); - memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips)); - - err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl); -@@ -1028,8 +874,8 @@ int mlxsw_thermal_init(struct mlxsw_core *core, - struct thermal_cooling_device *cdev; - - cdev = thermal_cooling_device_register("mlxsw_fan", -- thermal, -- &mlxsw_cooling_ops); -+ thermal, -+ &mlxsw_cooling_ops); - if (IS_ERR(cdev)) { - err = PTR_ERR(cdev); - dev_err(dev, "Failed to register cooling device\n"); -@@ -1069,6 +915,8 @@ int mlxsw_thermal_init(struct mlxsw_core *core, - *p_thermal = thermal; - return 0; - -+err_unreg_modules_tzdev: -+ mlxsw_thermal_modules_fini(thermal); - err_unreg_tzdev: - if (thermal->tzdev) { - thermal_zone_device_unregister(thermal->tzdev); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c -index b1471c2b6af2..307fd5fcd302 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c -@@ -399,7 +399,10 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, - if (reg_size % MLXSW_I2C_BLK_MAX) - num++; - -- mutex_lock(&mlxsw_i2c->cmd.lock); -+ if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { -+ dev_err(&client->dev, "Could not acquire lock"); -+ return -EINVAL; -+ } - - err = mlxsw_i2c_write(dev, reg_size, in_mbox, num, status); - if (err) -@@ -415,7 +418,10 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, - reg_size = MLXSW_I2C_MAX_DATA_SIZE; - num = reg_size / MLXSW_I2C_BLK_MAX; - -- mutex_lock(&mlxsw_i2c->cmd.lock); -+ if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { -+ dev_err(&client->dev, "Could not acquire lock"); -+ return -EINVAL; -+ } - - err = mlxsw_i2c_write_init_cmd(client, mlxsw_i2c, opcode, - in_mod); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -index 9312f42c8f9b..740b3753de44 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -@@ -1,5 +1,5 @@ - // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 --/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */ -+/* Copyright (c) 2016-2019 Mellanox Technologies. All rights reserved */ - - #include - #include -@@ -50,11 +50,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; -- int err; -- -- err = mlxsw_env_get_module_info(core, mlxsw_m_port->module, modinfo); - -- return err; -+ return mlxsw_env_get_module_info(core, mlxsw_m_port->module, modinfo); - } - - static int -@@ -63,12 +60,9 @@ 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; -- int err; -- -- err = mlxsw_env_get_module_eeprom(netdev, core, -- mlxsw_m_port->module, ee, data); - -- return err; -+ return mlxsw_env_get_module_eeprom(netdev, core, mlxsw_m_port->module, -+ ee, data); - } - - static const struct ethtool_ops mlxsw_m_port_ethtool_ops = { -@@ -199,7 +193,7 @@ static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port, - u8 module, width; - int err; - -- /* Fill out to local port mapping array */ -+ /* Fill out to local port mapping array */ - err = mlxsw_m_port_module_info_get(mlxsw_m, local_port, &module, - &width); - if (err) -@@ -216,57 +210,39 @@ static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port, - return 0; - } - --static int mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 module) -+static void mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 module) - { - mlxsw_m->module_to_port[module] = -1; -- -- return 0; --} -- --static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) --{ -- int i; -- -- for (i = 0; i < mlxsw_m->max_ports; i++) { -- if (mlxsw_m->module_to_port[i] > 0) { -- mlxsw_m_port_remove(mlxsw_m, -- mlxsw_m->module_to_port[i]); -- mlxsw_m_port_module_unmap(mlxsw_m, i); -- } -- } -- -- kfree(mlxsw_m->module_to_port); -- kfree(mlxsw_m->ports); - } - - static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) - { -- unsigned int max_port = mlxsw_core_max_ports(mlxsw_m->core); -- u8 last_module = max_port; -+ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core); -+ u8 last_module = max_ports; - int i; - int err; - -- mlxsw_m->ports = kcalloc(max_port, sizeof(*mlxsw_m->ports), -+ mlxsw_m->ports = kcalloc(max_ports, sizeof(*mlxsw_m->ports), - GFP_KERNEL); - if (!mlxsw_m->ports) - return -ENOMEM; - -- mlxsw_m->module_to_port = kmalloc_array(max_port, sizeof(int), -+ mlxsw_m->module_to_port = kmalloc_array(max_ports, sizeof(int), - GFP_KERNEL); - if (!mlxsw_m->module_to_port) { - err = -ENOMEM; -- goto err_port_create; -+ goto err_module_to_port_alloc; - } - - /* Invalidate the entries of module to local port mapping array */ -- for (i = 0; i < max_port; i++) -+ for (i = 0; i < max_ports; i++) - mlxsw_m->module_to_port[i] = -1; - - /* Fill out module to local port mapping array */ -- for (i = 1; i < max_port; i++) { -+ for (i = 1; i < max_ports; i++) { - err = mlxsw_m_port_module_map(mlxsw_m, i, &last_module); - if (err) -- goto err_port_create; -+ goto err_module_to_port_map; - } - - /* Create port objects for each valid entry */ -@@ -276,17 +252,44 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) - mlxsw_m->module_to_port[i], - i); - if (err) -- goto err_port_create; -+ goto err_module_to_port_create; - } - } - - return 0; - --err_port_create: -- mlxsw_m_ports_remove(mlxsw_m); -+err_module_to_port_create: -+ for (i--; i >= 0; i--) { -+ if (mlxsw_m->module_to_port[i] > 0) -+ mlxsw_m_port_remove(mlxsw_m, -+ mlxsw_m->module_to_port[i]); -+ } -+ i = max_ports; -+err_module_to_port_map: -+ for (i--; i > 0; i--) -+ mlxsw_m_port_module_unmap(mlxsw_m, i); -+ kfree(mlxsw_m->module_to_port); -+err_module_to_port_alloc: -+ kfree(mlxsw_m->ports); - return err; - } - -+static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) -+{ -+ int i; -+ -+ for (i = 0; i < mlxsw_m->max_ports; i++) { -+ if (mlxsw_m->module_to_port[i] > 0) { -+ mlxsw_m_port_remove(mlxsw_m, -+ mlxsw_m->module_to_port[i]); -+ mlxsw_m_port_module_unmap(mlxsw_m, i); -+ } -+ } -+ -+ kfree(mlxsw_m->module_to_port); -+ kfree(mlxsw_m->ports); -+} -+ - static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info) - { --- -2.11.0 - diff --git a/patch/0038-mlxsw-core-Add-check-for-split-port-during-thermal-z.patch b/patch/0038-mlxsw-core-Add-check-for-split-port-during-thermal-z.patch deleted file mode 100644 index 274001b2bc51..000000000000 --- a/patch/0038-mlxsw-core-Add-check-for-split-port-during-thermal-z.patch +++ /dev/null @@ -1,87 +0,0 @@ -From d0e273393dd610f552ffbe9a9d1cf3448c8c028e Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Sun, 3 Mar 2019 08:50:49 +0000 -Subject: [PATCH backport 5.1] mlxsw: core: Add check for split port during - thermal zone initialization - -Skip thermal zone creation in case of split port. - -Overwrite the first byte in base MAC address in -minimal driver. - -Signed-off-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 15 ++++++++++++--- - drivers/net/ethernet/mellanox/mlxsw/minimal.c | 2 +- - 2 files changed, 13 insertions(+), 4 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index 002654918ee9..1f7ef90b2270 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -752,6 +752,9 @@ mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, - - module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); - module_tz = &thermal->tz_module_arr[module]; -+ /* Skip if parent is already set - could in in case of port split. */ -+ if (module_tz->parent) -+ return 0; - module_tz->module = module; - module_tz->parent = thermal; - memcpy(module_tz->trips, default_thermal_trips, -@@ -773,6 +776,7 @@ static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz) - if (module_tz && module_tz->tzdev) { - mlxsw_thermal_module_tz_fini(module_tz->tzdev); - module_tz->tzdev = NULL; -+ module_tz->parent = 0; - } - } - -@@ -781,6 +785,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, - struct mlxsw_thermal *thermal) - { - unsigned int module_count = mlxsw_core_max_ports(core); -+ struct mlxsw_thermal_module *module_tz; - int i, err; - - thermal->tz_module_arr = kcalloc(module_count, -@@ -795,8 +800,12 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, - goto err_unreg_tz_module_arr; - } - -- for (i = 0; i < thermal->tz_module_num; i++) { -- err = mlxsw_thermal_module_tz_init(&thermal->tz_module_arr[i]); -+ module_count -= 1; -+ for (i = 0; i < module_count; i++) { -+ module_tz = &thermal->tz_module_arr[i]; -+ if (!module_tz->parent) -+ continue; -+ err = mlxsw_thermal_module_tz_init(module_tz); - if (err) - goto err_unreg_tz_module_arr; - } -@@ -804,7 +813,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, - return 0; - - err_unreg_tz_module_arr: -- for (i = module_count - 1; i >= 0; i--) -+ for (i = module_count; i >= 0; i--) - mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); - kfree(thermal->tz_module_arr); - return err; -diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -index 740b3753de44..cac36c231864 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -@@ -104,7 +104,7 @@ 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; - return 0; - } - --- -2.11.0 - diff --git a/patch/0039-mlxsw-core-Prevent-reading-unsupported-slave-address.patch b/patch/0039-mlxsw-core-Prevent-reading-unsupported-slave-address.patch deleted file mode 100644 index 29358da4f1db..000000000000 --- a/patch/0039-mlxsw-core-Prevent-reading-unsupported-slave-address.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 7f31d9b833b0c31f5c8d75416758a9f30add6190 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Wed, 15 May 2019 15:22:44 +0000 -Subject: [PATCH backport v5.2] mlxsw: core: Prevent reading unsupported slave - address from SFP EEPROM - -Prevent reading unsupported slave address from SFP EEPROM by testing -Diagnostic Monitoring Type byte in EEPROM. Read only page zero of -EEPROM, in case this byte is zero. - -If some SFP transceiver don't support Digital Optical Monitoring (DOM), -thus reading SFP EEPROM slave address 0x51 could return error. -Availability of DOM support is verified by reading from zero page -Diagnostic Monitoring Type byte describing how diagnostic monitoring is -implemented by transceiver. If bit 6 of this byte is set, it indicates -that digital diagnostic monitoring has been implemented. Otherwise it is -not and transceiver could fail to reply to transaction for slave address -0x51 [1010001X (A2h)], which is used to access measurements page. - -Such issue has been observed when reading cable MCP2M00-xxxx, -MCP7F00-xxxx, and few others. - -Signed-off-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/core_env.c | 18 ++++++++++++++++-- - 1 file changed, 16 insertions(+), 2 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c -index 7a15e932ed2f..edcf1b656cbf 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c -@@ -3,6 +3,7 @@ - - #include - #include -+#include - - #include "core.h" - #include "core_env.h" -@@ -162,7 +163,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, - { - u8 module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE]; - u16 offset = MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE; -- u8 module_rev_id, module_id; -+ u8 module_rev_id, module_id, diag_mon; - unsigned int read_size; - int err; - -@@ -195,8 +196,21 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, - } - break; - case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: -+ /* Verify if transceiver provides digital diagnostic monitoring page */ -+ err = mlxsw_env_query_module_eeprom(mlxsw_core, module, -+ SFP_DIAGMON, 1, &diag_mon, -+ &read_size); -+ if (err) -+ return err; -+ -+ if (read_size < 1) -+ return -EIO; -+ - modinfo->type = ETH_MODULE_SFF_8472; -- modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; -+ if (diag_mon) -+ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; -+ else -+ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN / 2; - break; - default: - return -EINVAL; --- -2.11.0 - diff --git a/patch/0040-mlxsw-core-add-support-for-Gear-Box-temperatures-in-.patch b/patch/0040-mlxsw-core-add-support-for-Gear-Box-temperatures-in-.patch deleted file mode 100644 index e9e1431a9384..000000000000 --- a/patch/0040-mlxsw-core-add-support-for-Gear-Box-temperatures-in-.patch +++ /dev/null @@ -1,650 +0,0 @@ -From 83d2cf92f7fef5df0de2cf19f4235dc6c50f92a5 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Mon, 4 Mar 2019 14:50:48 +0000 -Subject: [PATCH backport 5.1] mlxsw: core: add support for Gear Box - temperatures in hwmon - -Add hwmon interface for inter-connects temperature reading. -This information is a critical for the system equipped with such hardware. -These new attributes are necessary for the system monitoring. - -Such inter-connect devices are equipped on new Mellanox MSN3800 -Ethernet 2U systems with 64xQSFP28 100GbE full bidirectional bandwidth -ports. -The connectivity map is depicted below. - -+------+D01 -| |+-->+--------+ -| | | Die0+--->P01 -| | |Gear +--->P02 -| | |Box | -| S | |01 +--->P03 -| P | | Die1+--->P04 -| E |+-->+--------+ -| C |D02 -| T |... -| R |D15 -| U |+-->+---------+ -| M | | Die0+--->P29 -| 2 | |Gear +--->P30 -| | |Box | -| C | |08 +--->P31 -| H | | Die1+--->P32 -| I |+-->+---------+ -| P |D16 -| |... -| |D31 -| |+-->+---------+ -| | | Die0+--->P61 -| | |Gear +--->P62 -| | |Box | -| | |16 +--->P63 -| | | Die1+--->P64 -| |+-->+---------+ -+------+D32 - -Spectrum-2 chip provides 64 100GbE ports toward the front panel, in 64 -QSFP ports. - -Each D(i) above is a pair of 2x50GBe lanes utilizing PAM4 (Pulse -Amplitude Modulation) technology lanes. - -Each P(k) above is 4x25GBe lanes utilizing NRZ (Non-Return to Zero) -technology. - -Each Gearbox(j) above is a low power 400GbE device supporting data -streams in re-timer mode with PAM-4 modulation or 26.5625Gbps down to -1.25Gbps streams with NRZ modulation. -Each such device is equipped with two dies and each die is equipped -with the temperature sensor for junction temperature measurement. The -operating junction temperature is between 0C and 110C. -These sensors are the subject of this patchset. - -Signed-off-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 85 ++++++++++- - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 165 ++++++++++++++++----- - drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c | 7 + - drivers/net/ethernet/mellanox/mlxsw/reg.h | 56 ++++++- - drivers/platform/mellanox/mlxreg-hotplug.c | 5 +- - drivers/platform/x86/mlx-platform.c | 6 +- - 6 files changed, 276 insertions(+), 48 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -index 6956bbebe2f1..976f81a2bbba 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -@@ -15,6 +15,9 @@ - #define MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT 127 - #define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT * 4 + \ - MLXSW_MFCR_TACHOS_MAX + MLXSW_MFCR_PWMS_MAX) -+#define MLXSW_HWMON_GET_ATTR_INDEX(ind, count) \ -+ (((ind) >= (count)) ? (ind) % (count) + \ -+ MLXSW_REG_MTMP_GBOX_INDEX_MIN : (ind)) - - struct mlxsw_hwmon_attr { - struct device_attribute dev_attr; -@@ -33,6 +36,7 @@ struct mlxsw_hwmon { - struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT]; - unsigned int attrs_count; - u8 sensor_count; -+ u8 module_sensor_count; - }; - - static ssize_t mlxsw_hwmon_temp_show(struct device *dev, -@@ -44,10 +48,12 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, - struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; - char mtmp_pl[MLXSW_REG_MTMP_LEN]; - unsigned int temp; -+ int index; - int err; - -- mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index, -- false, false); -+ index = MLXSW_HWMON_GET_ATTR_INDEX(mlwsw_hwmon_attr->type_index, -+ mlxsw_hwmon->module_sensor_count); -+ mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); - err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); - if (err) { - dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); -@@ -66,10 +72,12 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, - struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; - char mtmp_pl[MLXSW_REG_MTMP_LEN]; - unsigned int temp_max; -+ int index; - int err; - -- mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index, -- false, false); -+ index = MLXSW_HWMON_GET_ATTR_INDEX(mlwsw_hwmon_attr->type_index, -+ mlxsw_hwmon->module_sensor_count); -+ mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); - err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); - if (err) { - dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); -@@ -88,6 +96,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, - struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; - char mtmp_pl[MLXSW_REG_MTMP_LEN]; - unsigned long val; -+ int index; - int err; - - err = kstrtoul(buf, 10, &val); -@@ -96,7 +105,9 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, - if (val != 1) - return -EINVAL; - -- mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index, true, true); -+ index = MLXSW_HWMON_GET_ATTR_INDEX(mlwsw_hwmon_attr->type_index, -+ mlxsw_hwmon->module_sensor_count); -+ mlxsw_reg_mtmp_pack(mtmp_pl, index, true, true); - err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); - if (err) { - dev_err(mlxsw_hwmon->bus_info->dev, "Failed to reset temp sensor history\n"); -@@ -333,6 +344,20 @@ mlxsw_hwmon_module_temp_label_show(struct device *dev, - mlwsw_hwmon_attr->type_index); - } - -+static ssize_t -+mlxsw_hwmon_gbox_temp_label_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = -+ container_of(attr, struct mlxsw_hwmon_attr, dev_attr); -+ struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; -+ int index = mlwsw_hwmon_attr->type_index - -+ mlxsw_hwmon->module_sensor_count + 1; -+ -+ return sprintf(buf, "gearbox %03u\n", index); -+} -+ - enum mlxsw_hwmon_attr_type { - MLXSW_HWMON_ATTR_TYPE_TEMP, - MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, -@@ -345,6 +370,7 @@ enum mlxsw_hwmon_attr_type { - MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, - MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG, - MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL, - }; - - static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon, -@@ -428,6 +454,13 @@ static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon, - snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), - "temp%u_label", num + 1); - break; -+ case MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL: -+ mlxsw_hwmon_attr->dev_attr.show = -+ mlxsw_hwmon_gbox_temp_label_show; -+ mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; -+ snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), -+ "temp%u_label", num + 1); -+ break; - default: - WARN_ON(1); - } -@@ -553,6 +586,43 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) - index, index); - index++; - } -+ mlxsw_hwmon->module_sensor_count = index; -+ -+ return 0; -+} -+ -+static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) -+{ -+ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; -+ int index, max_index; -+ u8 gbox_num; -+ int err; -+ -+ mlxsw_reg_mgpir_pack(mgpir_pl); -+ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); -+ if (err) -+ return 0; -+ -+ mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL); -+ if (!gbox_num) -+ return 0; -+ -+ index = mlxsw_hwmon->module_sensor_count; -+ max_index = mlxsw_hwmon->module_sensor_count + gbox_num; -+ while (index < max_index) { -+ mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP, -+ index, index); -+ mlxsw_hwmon_attr_add(mlxsw_hwmon, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, index, -+ index); -+ mlxsw_hwmon_attr_add(mlxsw_hwmon, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_RST, index, -+ index); -+ mlxsw_hwmon_attr_add(mlxsw_hwmon, -+ MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL, -+ index, index); -+ index++; -+ } - - return 0; - } -@@ -583,6 +653,10 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, - if (err) - goto err_temp_module_init; - -+ err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon); -+ if (err) -+ goto err_temp_gearbox_init; -+ - mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group; - mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs; - -@@ -599,6 +673,7 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, - return 0; - - err_hwmon_register: -+err_temp_gearbox_init: - err_temp_module_init: - err_fans_init: - err_temp_init: -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index 1f7ef90b2270..5f970798ab6a 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -112,6 +112,8 @@ struct mlxsw_thermal { - enum thermal_device_mode mode; - struct mlxsw_thermal_module *tz_module_arr; - unsigned int tz_module_num; -+ struct mlxsw_thermal_module *tz_gearbox_arr; -+ u8 tz_gearbox_num; - }; - - static inline u8 mlxsw_state_to_duty(int state) -@@ -546,62 +548,61 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip, - return 0; - } - --static int mlxsw_thermal_module_trend_get(struct thermal_zone_device *tzdev, -- int trip, enum thermal_trend *trend) -+static struct thermal_zone_params mlxsw_thermal_module_params = { -+ .governor_name = "user_space", -+}; -+ -+static struct thermal_zone_device_ops mlxsw_thermal_module_ops = { -+ .bind = mlxsw_thermal_module_bind, -+ .unbind = mlxsw_thermal_module_unbind, -+ .get_mode = mlxsw_thermal_module_mode_get, -+ .set_mode = mlxsw_thermal_module_mode_set, -+ .get_temp = mlxsw_thermal_module_temp_get, -+ .get_trip_type = mlxsw_thermal_module_trip_type_get, -+ .get_trip_temp = mlxsw_thermal_module_trip_temp_get, -+ .set_trip_temp = mlxsw_thermal_module_trip_temp_set, -+ .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get, -+ .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set, -+}; -+ -+static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, -+ int *p_temp) - { - struct mlxsw_thermal_module *tz = tzdev->devdata; - struct mlxsw_thermal *thermal = tz->parent; -- struct device *dev = thermal->bus_info->dev; -- char *envp[2] = { "TZ_DOWN=1", NULL }; -- int delta, window; -+ char mtmp_pl[MLXSW_REG_MTMP_LEN]; -+ unsigned int temp; -+ u16 index; - int err; - -- if (trip < 0 || trip >= MLXSW_THERMAL_NUM_TRIPS) -- return -EINVAL; -+ index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module; -+ mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); - -- delta = tzdev->last_temperature - tzdev->temperature; -- window = tz->trips[MLXSW_THERMAL_TEMP_TRIP_HIGH].temp - -- tz->trips[MLXSW_THERMAL_TEMP_TRIP_NORM].temp; -- if (delta > window && !window && !tzdev->last_temperature) { -- /* Notify user about fast temperature decreasing by sending -- * hwmon uevent. Fast decreasing could happen when some hot -- * module is removed. In this situation temperature trend could -- * go down once, and then stay in a stable state. -- * Notification will allow user to handle such case, if user -- * supposes to optimize PWM state. -- */ -- err = kobject_uevent_env(&tzdev->device.kobj, KOBJ_CHANGE, -- envp); -- if (err) -- dev_err(dev, "Error sending uevent %s\n", envp[0]); -- } -+ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); -+ if (err) -+ return err; - -- if (tzdev->temperature > tzdev->last_temperature) -- *trend = THERMAL_TREND_RAISING; -- else if (tzdev->temperature < tzdev->last_temperature) -- *trend = THERMAL_TREND_DROPPING; -- else -- *trend = THERMAL_TREND_STABLE; -+ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); - -+ *p_temp = (int) temp; - return 0; - } - --static struct thermal_zone_params mlxsw_thermal_module_params = { -- .governor_name = "user_space", --}; -- --static struct thermal_zone_device_ops mlxsw_thermal_module_ops = { -+static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = { - .bind = mlxsw_thermal_module_bind, - .unbind = mlxsw_thermal_module_unbind, - .get_mode = mlxsw_thermal_module_mode_get, - .set_mode = mlxsw_thermal_module_mode_set, -- .get_temp = mlxsw_thermal_module_temp_get, -+ .get_temp = mlxsw_thermal_gearbox_temp_get, - .get_trip_type = mlxsw_thermal_module_trip_type_get, - .get_trip_temp = mlxsw_thermal_module_trip_temp_get, - .set_trip_temp = mlxsw_thermal_module_trip_temp_set, - .get_trip_hyst = mlxsw_thermal_module_trip_hyst_get, - .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set, -- .get_trend = mlxsw_thermal_module_trend_get, -+}; -+ -+static struct thermal_zone_params mlxsw_thermal_gearbox_params = { -+ .governor_name = "user_space", - }; - - static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev, -@@ -752,7 +753,7 @@ mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, - - module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); - module_tz = &thermal->tz_module_arr[module]; -- /* Skip if parent is already set - could in in case of port split. */ -+ /* Skip if parent is already set (case of port split). */ - if (module_tz->parent) - return 0; - module_tz->module = module; -@@ -776,7 +777,7 @@ static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz) - if (module_tz && module_tz->tzdev) { - mlxsw_thermal_module_tz_fini(module_tz->tzdev); - module_tz->tzdev = NULL; -- module_tz->parent = 0; -+ module_tz->parent = NULL; - } - } - -@@ -830,6 +831,89 @@ mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal) - kfree(thermal->tz_module_arr); - } - -+static int -+mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) -+{ -+ char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; -+ int err; -+ -+ 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, -+ gearbox_tz, -+ &mlxsw_thermal_gearbox_ops, -+ &mlxsw_thermal_gearbox_params, -+ 0, 0); -+ if (IS_ERR(gearbox_tz->tzdev)) { -+ err = PTR_ERR(gearbox_tz->tzdev); -+ return err; -+ } -+ -+ return 0; -+} -+ -+static void -+mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz) -+{ -+ thermal_zone_device_unregister(gearbox_tz->tzdev); -+} -+ -+static int -+mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, -+ struct mlxsw_thermal *thermal) -+{ -+ struct mlxsw_thermal_module *gearbox_tz; -+ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; -+ int i; -+ int err; -+ -+ mlxsw_reg_mgpir_pack(mgpir_pl); -+ err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); -+ if (err) -+ return 0; -+ -+ mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL); -+ if (!thermal->tz_gearbox_num) -+ return 0; -+ -+ thermal->tz_gearbox_arr = kcalloc(thermal->tz_gearbox_num, -+ sizeof(*thermal->tz_gearbox_arr), -+ GFP_KERNEL); -+ if (!thermal->tz_gearbox_arr) -+ return -ENOMEM; -+ -+ for (i = 0; i < thermal->tz_gearbox_num; i++) { -+ gearbox_tz = &thermal->tz_gearbox_arr[i]; -+ memcpy(gearbox_tz->trips, default_thermal_trips, -+ sizeof(thermal->trips)); -+ gearbox_tz->module = i; -+ gearbox_tz->parent = thermal; -+ err = mlxsw_thermal_gearbox_tz_init(gearbox_tz); -+ if (err) -+ goto err_unreg_tz_gearbox; -+ } -+ -+ return 0; -+ -+err_unreg_tz_gearbox: -+ for (i--; i >= 0; i--) -+ mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); -+ kfree(thermal->tz_gearbox_arr); -+ return err; -+} -+ -+static void -+mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal) -+{ -+ int i; -+ -+ for (i = thermal->tz_gearbox_num - 1; i >= 0; i--) -+ mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); -+ kfree(thermal->tz_gearbox_arr); -+} -+ - int mlxsw_thermal_init(struct mlxsw_core *core, - const struct mlxsw_bus_info *bus_info, - struct mlxsw_thermal **p_thermal) -@@ -920,6 +1004,10 @@ int mlxsw_thermal_init(struct mlxsw_core *core, - if (err) - goto err_unreg_tzdev; - -+ mlxsw_thermal_gearboxes_init(dev, core, thermal); -+ if (err) -+ goto err_unreg_modules_tzdev; -+ - thermal->mode = THERMAL_DEVICE_ENABLED; - *p_thermal = thermal; - return 0; -@@ -944,6 +1032,7 @@ void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) - { - int i; - -+ mlxsw_thermal_gearboxes_fini(thermal); - mlxsw_thermal_modules_fini(thermal); - if (thermal->tzdev) { - thermal_zone_device_unregister(thermal->tzdev); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -index bee2a08d372b..347f9823e375 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -@@ -268,6 +268,13 @@ static const struct dmi_system_id mlxsw_qsfp_dmi_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "MSN37"), - }, - }, -+ { -+ .callback = mlxsw_qsfp_dmi_set_qsfp_num, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN38"), -+ }, -+ }, - { } - }; - MODULE_DEVICE_TABLE(dmi, mlxsw_qsfp_dmi_table); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h -index 94407dcfacdb..f16d27e115d2 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/reg.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h -@@ -7589,6 +7589,7 @@ MLXSW_ITEM32(reg, mtcap, sensor_count, 0x00, 0, 7); - */ - #define MLXSW_REG_MTMP_ID 0x900A - #define MLXSW_REG_MTMP_LEN 0x20 -+#define MLXSW_REG_MTMP_GBOX_INDEX_MIN 256 - - MLXSW_REG_DEFINE(mtmp, MLXSW_REG_MTMP_ID, MLXSW_REG_MTMP_LEN); - -@@ -7598,7 +7599,7 @@ MLXSW_REG_DEFINE(mtmp, MLXSW_REG_MTMP_ID, MLXSW_REG_MTMP_LEN); - * (module 0 is mapped to sensor_index 64). - * Access: Index - */ --MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 7); -+MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 11); - - /* Convert to milli degrees Celsius */ - #define MLXSW_REG_MTMP_TEMP_TO_MC(val) (val * 125) -@@ -7660,7 +7661,7 @@ 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, u8 sensor_index, -+static inline void mlxsw_reg_mtmp_pack(char *payload, u16 sensor_index, - bool max_temp_enable, - bool max_temp_reset) - { -@@ -8579,6 +8580,56 @@ static inline void mlxsw_reg_mprs_pack(char *payload, u16 parsing_depth, - mlxsw_reg_mprs_vxlan_udp_dport_set(payload, vxlan_udp_dport); - } - -+/* MGPIR - Management General Peripheral Information Register -+ * ---------------------------------------------------------- -+ * MGPIR register allows software to query the hardware and -+ * firmware general information of peripheral entities. -+ */ -+#define MLXSW_REG_MGPIR_ID 0x9100 -+#define MLXSW_REG_MGPIR_LEN 0xA0 -+ -+MLXSW_REG_DEFINE(mgpir, MLXSW_REG_MGPIR_ID, MLXSW_REG_MGPIR_LEN); -+ -+/* device_type -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, mgpir, device_type, 0x00, 24, 4); -+ -+/* 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 -+ * Number of devices of device_type. -+ * Access: RO -+ */ -+MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8); -+ -+enum mlxsw_reg_mgpir_device_type { -+ MLXSW_REG_MGPIR_TYPE_NONE, -+ MLXSW_REG_MGPIR_TYPE_GEARBOX_DIE, -+}; -+ -+static inline void mlxsw_reg_mgpir_pack(char *payload) -+{ -+ MLXSW_REG_ZERO(mgpir, payload); -+} -+ -+static inline void mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, -+ u8 *device_type, -+ u8 *devices_per_flash) -+{ -+ if (num_of_devices) -+ *num_of_devices = mlxsw_reg_mgpir_num_of_devices_get(payload); -+ if (device_type) -+ *device_type = mlxsw_reg_mgpir_device_type_get(payload); -+ if (devices_per_flash) -+ *devices_per_flash = -+ mlxsw_reg_mgpir_devices_per_flash_get(payload); -+} -+ - /* TNGCR - Tunneling NVE General Configuration Register - * ---------------------------------------------------- - * The TNGCR register is used for setting up the NVE Tunneling configuration. -@@ -9591,6 +9642,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { - MLXSW_REG(mcda), - MLXSW_REG(mgpc), - MLXSW_REG(mprs), -+ MLXSW_REG(mgpir), - MLXSW_REG(tngcr), - MLXSW_REG(tnumt), - MLXSW_REG(tnqcr), -diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c -index 52314a1ffaaf..687ce6817d0d 100644 ---- a/drivers/platform/mellanox/mlxreg-hotplug.c -+++ b/drivers/platform/mellanox/mlxreg-hotplug.c -@@ -248,7 +248,8 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, - struct mlxreg_core_item *item) - { - struct mlxreg_core_data *data; -- u32 asserted, regval, bit; -+ unsigned long asserted; -+ u32 regval, bit; - int ret; - - /* -@@ -281,7 +282,7 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, - asserted = item->cache ^ regval; - item->cache = regval; - -- for_each_set_bit(bit, (unsigned long *)&asserted, 8) { -+ for_each_set_bit(bit, &asserted, 8) { - data = item->data + bit; - if (regval & BIT(bit)) { - if (item->inversed) -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index af033fb2e5d9..d5d2448dc7e4 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -938,6 +938,11 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_led_data[] = { - .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_default_ng_led_data = { -@@ -1361,7 +1366,6 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { - }, - { - .label = "conf", -- .reg = MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET, - .capability = MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET, - }, - }; --- -2.11.0 - diff --git a/patch/0041-mlxsw-minimal-Provide-optimization-for-I2C-bus-acces.patch b/patch/0041-mlxsw-minimal-Provide-optimization-for-I2C-bus-acces.patch deleted file mode 100644 index e624dff559c0..000000000000 --- a/patch/0041-mlxsw-minimal-Provide-optimization-for-I2C-bus-acces.patch +++ /dev/null @@ -1,668 +0,0 @@ -From 8c964a3e17bb41eef69c81d45864d72cbc1185f4 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Fri, 17 May 2019 09:22:21 +0000 -Subject: [PATCH backport 5.2] mlxsw: minimal: Provide optimization for I2C bus - access - -Use register MTMP instead of MTBR. -Use maximum buffer size allowed by I2C adapter. - -Signed-off-by: Vadim Pasternak ---- - drivers/i2c/busses/i2c-mlxcpld.c | 2 +- - drivers/net/ethernet/mellanox/mlxsw/core.c | 6 ++ - drivers/net/ethernet/mellanox/mlxsw/core.h | 2 + - drivers/net/ethernet/mellanox/mlxsw/core_env.c | 29 ++----- - drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 98 +++++++++------------- - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 60 +++++++------ - drivers/net/ethernet/mellanox/mlxsw/i2c.c | 56 +++++++++---- - drivers/net/ethernet/mellanox/mlxsw/minimal.c | 18 ++++ - drivers/net/ethernet/mellanox/mlxsw/reg.h | 7 +- - 9 files changed, 144 insertions(+), 134 deletions(-) - -diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c -index 745ed43a22d6..2fd717d8dd30 100644 ---- a/drivers/i2c/busses/i2c-mlxcpld.c -+++ b/drivers/i2c/busses/i2c-mlxcpld.c -@@ -503,6 +503,7 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) - platform_set_drvdata(pdev, priv); - - priv->dev = &pdev->dev; -+ priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; - - /* Register with i2c layer */ - mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO); -@@ -518,7 +519,6 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) - mlxcpld_i2c_adapter.nr = pdev->id; - priv->adap = mlxcpld_i2c_adapter; - priv->adap.dev.parent = &pdev->dev; -- priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; - i2c_set_adapdata(&priv->adap, priv); - - err = i2c_add_numbered_adapter(&priv->adap); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c -index e420451942e2..9a74ae8beb43 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c -@@ -122,6 +122,12 @@ void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core) - } - EXPORT_SYMBOL(mlxsw_core_driver_priv); - -+bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core) -+{ -+ return mlxsw_core->driver->res_query_enabled; -+} -+EXPORT_SYMBOL(mlxsw_core_res_query_enabled); -+ - struct mlxsw_rx_listener_item { - struct list_head list; - struct mlxsw_rx_listener rxl; -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h -index 76e8fd76ef36..1e1bcfd8d032 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h -@@ -28,6 +28,8 @@ unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core); - - void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core); - -+bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core); -+ - int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver); - void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver); - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c -index edcf1b656cbf..d2c7ce67c300 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c -@@ -92,33 +92,20 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, - u16 temp; - } temp_thresh; - char mcia_pl[MLXSW_REG_MCIA_LEN] = {0}; -- char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; -- u16 module_temp; -+ char mtmp_pl[MLXSW_REG_MTMP_LEN]; -+ unsigned int module_temp; - bool qsfp; - int err; - -- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, -- 1); -- err = mlxsw_reg_query(core, MLXSW_REG(mtbr), mtbr_pl); -+ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, -+ false, false); -+ err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); - if (err) - return err; -- -- /* Don't read temperature thresholds for module with no valid info. */ -- mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &module_temp, NULL); -- switch (module_temp) { -- case MLXSW_REG_MTBR_BAD_SENS_INFO: /* fall-through */ -- case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ -- case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ -- case MLXSW_REG_MTBR_INDEX_NA: -+ mlxsw_reg_mtmp_unpack(mtmp_pl, &module_temp, NULL, NULL); -+ if (!module_temp) { - *temp = 0; - return 0; -- default: -- /* Do not consider thresholds for zero temperature. */ -- if (!MLXSW_REG_MTMP_TEMP_TO_MC(module_temp)) { -- *temp = 0; -- return 0; -- } -- break; - } - - /* Read Free Side Device Temperature Thresholds from page 03h -@@ -196,7 +183,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, - } - break; - case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: -- /* Verify if transceiver provides digital diagnostic monitoring page */ -+ /* Verify if transceiver provides diagnostic monitoring page */ - err = mlxsw_env_query_module_eeprom(mlxsw_core, module, - SFP_DIAGMON, 1, &diag_mon, - &read_size); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -index 976f81a2bbba..a414a09efb5d 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -@@ -15,9 +15,6 @@ - #define MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT 127 - #define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT * 4 + \ - MLXSW_MFCR_TACHOS_MAX + MLXSW_MFCR_PWMS_MAX) --#define MLXSW_HWMON_GET_ATTR_INDEX(ind, count) \ -- (((ind) >= (count)) ? (ind) % (count) + \ -- MLXSW_REG_MTMP_GBOX_INDEX_MIN : (ind)) - - struct mlxsw_hwmon_attr { - struct device_attribute dev_attr; -@@ -26,6 +23,14 @@ struct mlxsw_hwmon_attr { - char name[32]; - }; - -+static int mlxsw_hwmon_get_attr_index(int index, int count) -+{ -+ if (index >= count) -+ return index % count + MLXSW_REG_MTMP_GBOX_INDEX_MIN; -+ -+ return index; -+} -+ - struct mlxsw_hwmon { - struct mlxsw_core *core; - const struct mlxsw_bus_info *bus_info; -@@ -51,7 +56,7 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, - int index; - int err; - -- index = MLXSW_HWMON_GET_ATTR_INDEX(mlwsw_hwmon_attr->type_index, -+ index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, - mlxsw_hwmon->module_sensor_count); - mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); - err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); -@@ -75,7 +80,7 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, - int index; - int err; - -- index = MLXSW_HWMON_GET_ATTR_INDEX(mlwsw_hwmon_attr->type_index, -+ index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, - mlxsw_hwmon->module_sensor_count); - mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); - err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); -@@ -105,7 +110,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, - if (val != 1) - return -EINVAL; - -- index = MLXSW_HWMON_GET_ATTR_INDEX(mlwsw_hwmon_attr->type_index, -+ index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, - mlxsw_hwmon->module_sensor_count); - mlxsw_reg_mtmp_pack(mtmp_pl, index, true, true); - err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); -@@ -209,38 +214,18 @@ static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev, - struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = - container_of(attr, struct mlxsw_hwmon_attr, dev_attr); - struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; -- char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; -- u16 temp; -+ char mtmp_pl[MLXSW_REG_MTMP_LEN]; -+ unsigned int temp; - u8 module; - int err; - - module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; -- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, -- 1); -- err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); -- if (err) { -- dev_err(dev, "Failed to query module temperature sensor\n"); -+ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, -+ false, false); -+ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); -+ if (err) - return err; -- } -- -- mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); -- /* Update status and temperature cache. */ -- switch (temp) { -- case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ -- case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ -- case MLXSW_REG_MTBR_INDEX_NA: -- temp = 0; -- break; -- case MLXSW_REG_MTBR_BAD_SENS_INFO: -- /* Untrusted cable is connected. Reading temperature from its -- * sensor is faulty. -- */ -- temp = 0; -- break; -- default: -- temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp); -- break; -- } -+ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); - - return sprintf(buf, "%u\n", temp); - } -@@ -252,37 +237,18 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, - struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = - container_of(attr, struct mlxsw_hwmon_attr, dev_attr); - struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; -- char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; -+ char mtmp_pl[MLXSW_REG_MTMP_LEN]; - u8 module, fault; -- u16 temp; - int err; - - module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; -- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, -- 1); -- err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); -- if (err) { -- dev_err(dev, "Failed to query module temperature sensor\n"); -- return err; -- } -- -- mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); -- -- /* Update status and temperature cache. */ -- switch (temp) { -- case MLXSW_REG_MTBR_BAD_SENS_INFO: -- /* Untrusted cable is connected. Reading temperature from its -- * sensor is faulty. -- */ -+ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, -+ false, false); -+ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); -+ if (err) - fault = 1; -- break; -- case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ -- case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ -- case MLXSW_REG_MTBR_INDEX_NA: -- default: -+ else - fault = 0; -- break; -- } - - return sprintf(buf, "%u\n", fault); - } -@@ -551,6 +517,9 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) - u8 width; - int err; - -+ if (!mlxsw_core_res_query_enabled(mlxsw_hwmon->core)) -+ return 0; -+ - /* Add extra attributes for module temperature. Sensor index is - * assigned to sensor_count value, while all indexed before - * sensor_count are already utilized by the sensors connected through -@@ -593,8 +562,9 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) - - static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) - { -+ int index, max_index, sensor_index; - char mgpir_pl[MLXSW_REG_MGPIR_LEN]; -- int index, max_index; -+ char mtmp_pl[MLXSW_REG_MTMP_LEN]; - u8 gbox_num; - int err; - -@@ -610,6 +580,16 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) - index = mlxsw_hwmon->module_sensor_count; - max_index = mlxsw_hwmon->module_sensor_count + gbox_num; - while (index < max_index) { -+ sensor_index = index % mlxsw_hwmon->module_sensor_count + -+ MLXSW_REG_MTMP_GBOX_INDEX_MIN; -+ mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, true, true); -+ err = mlxsw_reg_write(mlxsw_hwmon->core, -+ MLXSW_REG(mtmp), mtmp_pl); -+ if (err) { -+ dev_err(mlxsw_hwmon->bus_info->dev, "Failed to setup temp sensor number %d\n", -+ sensor_index); -+ return err; -+ } - mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP, - index, index); - mlxsw_hwmon_attr_add(mlxsw_hwmon, -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index 5f970798ab6a..e9451e447bf0 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -452,36 +452,27 @@ static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, - struct mlxsw_thermal_module *tz = tzdev->devdata; - struct mlxsw_thermal *thermal = tz->parent; - struct device *dev = thermal->bus_info->dev; -- char mtbr_pl[MLXSW_REG_MTBR_LEN]; -- u16 temp; -+ char mtmp_pl[MLXSW_REG_MTMP_LEN]; -+ unsigned int temp; - int err; - - /* Read module temperature. */ -- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + -- tz->module, 1); -- err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtbr), mtbr_pl); -- if (err) -- return err; -- -- mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); -- /* Update temperature. */ -- switch (temp) { -- case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ -- case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ -- case MLXSW_REG_MTBR_INDEX_NA: /* fall-through */ -- case MLXSW_REG_MTBR_BAD_SENS_INFO: -+ mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + -+ tz->module, false, false); -+ err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); -+ if (err) { -+ dev_err(dev, "Failed to query temp sensor\n"); - temp = 0; -- break; -- default: -- temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp); -- /* Reset all trip point. */ -- mlxsw_thermal_module_trips_reset(tz); -- /* Update trip points. */ -+ *p_temp = (int) temp; -+ return 0; -+ } -+ mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); -+ -+ if (temp) { - err = mlxsw_thermal_module_trips_update(dev, thermal->core, - tz); - if (err) - return err; -- break; - } - - *p_temp = (int) temp; -@@ -714,12 +705,12 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz) - snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d", - module_tz->module + 1); - module_tz->tzdev = thermal_zone_device_register(tz_name, -- MLXSW_THERMAL_NUM_TRIPS, -- MLXSW_THERMAL_TRIP_MASK, -- module_tz, -- &mlxsw_thermal_module_ops, -- &mlxsw_thermal_module_params, -- 0, 0); -+ MLXSW_THERMAL_NUM_TRIPS, -+ MLXSW_THERMAL_TRIP_MASK, -+ module_tz, -+ &mlxsw_thermal_module_ops, -+ &mlxsw_thermal_module_params, -+ 0, 0); - if (IS_ERR(module_tz->tzdev)) { - err = PTR_ERR(module_tz->tzdev); - return err; -@@ -789,6 +780,9 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, - struct mlxsw_thermal_module *module_tz; - int i, err; - -+ if (!mlxsw_core_res_query_enabled(core)) -+ return 0; -+ - thermal->tz_module_arr = kcalloc(module_count, - sizeof(*thermal->tz_module_arr), - GFP_KERNEL); -@@ -801,8 +795,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, - goto err_unreg_tz_module_arr; - } - -- module_count -= 1; -- for (i = 0; i < module_count; i++) { -+ for (i = 0; i < module_count - 1; i++) { - module_tz = &thermal->tz_module_arr[i]; - if (!module_tz->parent) - continue; -@@ -814,7 +807,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, - return 0; - - err_unreg_tz_module_arr: -- for (i = module_count; i >= 0; i--) -+ for (i = module_count - 1; i >= 0; i--) - mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); - kfree(thermal->tz_module_arr); - return err; -@@ -826,6 +819,9 @@ mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal) - unsigned int module_count = mlxsw_core_max_ports(thermal->core); - int i; - -+ if (!mlxsw_core_res_query_enabled(thermal->core)) -+ return; -+ - for (i = module_count - 1; i >= 0; i--) - mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); - kfree(thermal->tz_module_arr); -@@ -910,7 +906,7 @@ mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal) - int i; - - for (i = thermal->tz_gearbox_num - 1; i >= 0; i--) -- mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); -+ mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); /*Remove*/ - kfree(thermal->tz_gearbox_arr); - } - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c -index 307fd5fcd302..08c774875d1e 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c -@@ -43,11 +43,10 @@ - #define MLXSW_I2C_PREP_SIZE (MLXSW_I2C_ADDR_WIDTH + 28) - #define MLXSW_I2C_MBOX_SIZE 20 - #define MLXSW_I2C_MBOX_OUT_PARAM_OFF 12 --#define MLXSW_I2C_MAX_BUFF_SIZE 32 - #define MLXSW_I2C_MBOX_OFFSET_BITS 20 - #define MLXSW_I2C_MBOX_SIZE_BITS 12 - #define MLXSW_I2C_ADDR_BUF_SIZE 4 --#define MLXSW_I2C_BLK_MAX 32 -+#define MLXSW_I2C_BLK_DEF 32 - #define MLXSW_I2C_RETRY 5 - #define MLXSW_I2C_TIMEOUT_MSECS 5000 - #define MLXSW_I2C_MAX_DATA_SIZE 256 -@@ -62,6 +61,7 @@ - * @dev: I2C device; - * @core: switch core pointer; - * @bus_info: bus info block; -+ * @block_size: maximum block size allowed to pass to under layer; - */ - struct mlxsw_i2c { - struct { -@@ -74,6 +74,7 @@ struct mlxsw_i2c { - struct device *dev; - struct mlxsw_core *core; - struct mlxsw_bus_info bus_info; -+ u16 block_size; - }; - - #define MLXSW_I2C_READ_MSG(_client, _addr_buf, _buf, _len) { \ -@@ -315,20 +316,26 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num, - struct i2c_client *client = to_i2c_client(dev); - struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); - unsigned long timeout = msecs_to_jiffies(MLXSW_I2C_TIMEOUT_MSECS); -- u8 tran_buf[MLXSW_I2C_MAX_BUFF_SIZE + MLXSW_I2C_ADDR_BUF_SIZE]; - int off = mlxsw_i2c->cmd.mb_off_in, chunk_size, i, j; - unsigned long end; -+ u8 *tran_buf; - struct i2c_msg write_tran = -- MLXSW_I2C_WRITE_MSG(client, tran_buf, MLXSW_I2C_PUSH_CMD_SIZE); -+ MLXSW_I2C_WRITE_MSG(client, NULL, MLXSW_I2C_PUSH_CMD_SIZE); - int err; - -+ tran_buf = kmalloc(mlxsw_i2c->block_size + MLXSW_I2C_ADDR_BUF_SIZE, -+ GFP_KERNEL); -+ if (!tran_buf) -+ return -ENOMEM; -+ -+ write_tran.buf = tran_buf; - for (i = 0; i < num; i++) { -- chunk_size = (in_mbox_size > MLXSW_I2C_BLK_MAX) ? -- MLXSW_I2C_BLK_MAX : in_mbox_size; -+ chunk_size = (in_mbox_size > mlxsw_i2c->block_size) ? -+ mlxsw_i2c->block_size : in_mbox_size; - write_tran.len = MLXSW_I2C_ADDR_WIDTH + chunk_size; - mlxsw_i2c_set_slave_addr(tran_buf, off); - memcpy(&tran_buf[MLXSW_I2C_ADDR_BUF_SIZE], in_mbox + -- MLXSW_I2C_BLK_MAX * i, chunk_size); -+ mlxsw_i2c->block_size * i, chunk_size); - - j = 0; - end = jiffies + timeout; -@@ -342,9 +349,10 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num, - (j++ < MLXSW_I2C_RETRY)); - - if (err != 1) { -- if (!err) -+ if (!err) { - err = -EIO; -- return err; -+ goto mlxsw_i2c_write_exit; -+ } - } - - off += chunk_size; -@@ -355,24 +363,28 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num, - err = mlxsw_i2c_write_cmd(client, mlxsw_i2c, 0); - if (err) { - dev_err(&client->dev, "Could not start transaction"); -- return -EIO; -+ err = -EIO; -+ goto mlxsw_i2c_write_exit; - } - - /* Wait until go bit is cleared. */ - err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, p_status); - if (err) { - dev_err(&client->dev, "HW semaphore is not released"); -- return err; -+ goto mlxsw_i2c_write_exit; - } - - /* Validate transaction completion status. */ - if (*p_status) { - dev_err(&client->dev, "Bad transaction completion status %x\n", - *p_status); -- return -EIO; -+ err = -EIO; - } - -- return 0; -+mlxsw_i2c_write_exit: -+ kfree(tran_buf); -+ -+ return err; - } - - /* Routine executes I2C command. */ -@@ -395,8 +407,8 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, - - if (in_mbox) { - reg_size = mlxsw_i2c_get_reg_size(in_mbox); -- num = reg_size / MLXSW_I2C_BLK_MAX; -- if (reg_size % MLXSW_I2C_BLK_MAX) -+ num = reg_size / mlxsw_i2c->block_size; -+ if (reg_size % mlxsw_i2c->block_size) - num++; - - if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { -@@ -416,7 +428,7 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, - } else { - /* No input mailbox is case of initialization query command. */ - reg_size = MLXSW_I2C_MAX_DATA_SIZE; -- num = reg_size / MLXSW_I2C_BLK_MAX; -+ num = reg_size / mlxsw_i2c->block_size; - - if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) { - dev_err(&client->dev, "Could not acquire lock"); -@@ -432,8 +444,8 @@ mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size, - /* Send read transaction to get output mailbox content. */ - read_tran[1].buf = out_mbox; - for (i = 0; i < num; i++) { -- chunk_size = (reg_size > MLXSW_I2C_BLK_MAX) ? -- MLXSW_I2C_BLK_MAX : reg_size; -+ chunk_size = (reg_size > mlxsw_i2c->block_size) ? -+ mlxsw_i2c->block_size : reg_size; - read_tran[1].len = chunk_size; - mlxsw_i2c_set_slave_addr(tran_buf, off); - -@@ -546,6 +558,7 @@ static const struct mlxsw_bus mlxsw_i2c_bus = { - static int mlxsw_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) - { -+ const struct i2c_adapter_quirks *quirks = client->adapter->quirks; - struct mlxsw_i2c *mlxsw_i2c; - u8 status; - int err; -@@ -554,6 +567,13 @@ static int mlxsw_i2c_probe(struct i2c_client *client, - if (!mlxsw_i2c) - return -ENOMEM; - -+ if (quirks) -+ mlxsw_i2c->block_size = max_t(u16, MLXSW_I2C_BLK_DEF, -+ min_t(u16, quirks->max_read_len, -+ quirks->max_write_len)); -+ else -+ mlxsw_i2c->block_size = MLXSW_I2C_BLK_DEF; -+ - i2c_set_clientdata(client, mlxsw_i2c); - mutex_init(&mlxsw_i2c->cmd.lock); - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -index cac36c231864..5290993ff93f 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -@@ -45,6 +45,23 @@ static const struct net_device_ops mlxsw_m_port_netdev_ops = { - .ndo_stop = mlxsw_m_port_dummy_open_stop, - }; - -+static void mlxsw_m_module_get_drvinfo(struct net_device *dev, -+ struct ethtool_drvinfo *drvinfo) -+{ -+ struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev); -+ struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; -+ -+ strlcpy(drvinfo->driver, mlxsw_m->bus_info->device_kind, -+ sizeof(drvinfo->driver)); -+ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), -+ "%d.%d.%d", -+ mlxsw_m->bus_info->fw_rev.major, -+ mlxsw_m->bus_info->fw_rev.minor, -+ mlxsw_m->bus_info->fw_rev.subminor); -+ strlcpy(drvinfo->bus_info, mlxsw_m->bus_info->device_name, -+ sizeof(drvinfo->bus_info)); -+} -+ - static int mlxsw_m_get_module_info(struct net_device *netdev, - struct ethtool_modinfo *modinfo) - { -@@ -66,6 +83,7 @@ mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee, - } - - static const struct ethtool_ops mlxsw_m_port_ethtool_ops = { -+ .get_drvinfo = mlxsw_m_module_get_drvinfo, - .get_module_info = mlxsw_m_get_module_info, - .get_module_eeprom = mlxsw_m_get_module_eeprom, - }; -diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h -index f16d27e115d2..eb58940d2e9c 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/reg.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h -@@ -7589,17 +7589,18 @@ MLXSW_ITEM32(reg, mtcap, sensor_count, 0x00, 0, 7); - */ - #define MLXSW_REG_MTMP_ID 0x900A - #define MLXSW_REG_MTMP_LEN 0x20 --#define MLXSW_REG_MTMP_GBOX_INDEX_MIN 256 - - MLXSW_REG_DEFINE(mtmp, MLXSW_REG_MTMP_ID, MLXSW_REG_MTMP_LEN); - -+#define MLXSW_REG_MTMP_MODULE_INDEX_MIN 64 -+#define MLXSW_REG_MTMP_GBOX_INDEX_MIN 256 - /* reg_mtmp_sensor_index - * Sensors index to access. - * 64-127 of sensor_index are mapped to the SFP+/QSFP modules sequentially - * (module 0 is mapped to sensor_index 64). - * Access: Index - */ --MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 11); -+MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 12); - - /* Convert to milli degrees Celsius */ - #define MLXSW_REG_MTMP_TEMP_TO_MC(val) (val * 125) -@@ -7710,7 +7711,7 @@ MLXSW_REG_DEFINE(mtbr, MLXSW_REG_MTBR_ID, MLXSW_REG_MTBR_LEN); - * 64-127 are mapped to the SFP+/QSFP modules sequentially). - * Access: Index - */ --MLXSW_ITEM32(reg, mtbr, base_sensor_index, 0x00, 0, 7); -+MLXSW_ITEM32(reg, mtbr, base_sensor_index, 0x00, 0, 12); - - /* reg_mtbr_num_rec - * Request: Number of records to read --- -2.11.0 - diff --git a/patch/0042-mlxsw-core-Skip-port-split-entries-in-hwmon-subsyste.patch b/patch/0042-mlxsw-core-Skip-port-split-entries-in-hwmon-subsyste.patch deleted file mode 100644 index f980053dde5d..000000000000 --- a/patch/0042-mlxsw-core-Skip-port-split-entries-in-hwmon-subsyste.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 3d4e440640d63c5bc599a4ad6802ad84dcd0c329 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Wed, 10 Jul 2019 17:47:56 +0000 -Subject: [PATCH v1 backport] mlxsw: core: Skip port split entries in hwmon - subsystem - -Skip split entries in hwmon. -Run loop for port creation over maximum port counter, otherwise -in some split configuration with holes, some last modules can be -missed. - -Signed-of-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 7 ++++++- - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 2 +- - drivers/net/ethernet/mellanox/mlxsw/minimal.c | 5 +++-- - 3 files changed, 10 insertions(+), 4 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -index a414a09efb5d..95b890298952 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -@@ -512,9 +512,9 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) - static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) - { - unsigned int module_count = mlxsw_core_max_ports(mlxsw_hwmon->core); -+ u8 width, module, last_module = module_count; - char pmlp_pl[MLXSW_REG_PMLP_LEN] = {0}; - int i, index; -- u8 width; - int err; - - if (!mlxsw_core_res_query_enabled(mlxsw_hwmon->core)) -@@ -538,6 +538,11 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) - width = mlxsw_reg_pmlp_width_get(pmlp_pl); - if (!width) - continue; -+ module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); -+ /* Skip, if port belongs to the cluster */ -+ if (module == last_module) -+ continue; -+ last_module = module; - mlxsw_hwmon_attr_add(mlxsw_hwmon, - MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, index, - index); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index 499c82cea1cb..e9451e447bf0 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -906,7 +906,7 @@ mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal) - int i; - - for (i = thermal->tz_gearbox_num - 1; i >= 0; i--) -- mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); /*Remove*/ -+ mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); - kfree(thermal->tz_gearbox_arr); - } - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -index 5290993ff93f..0aa3abc974ff 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -@@ -264,7 +264,7 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) - } - - /* Create port objects for each valid entry */ -- for (i = 0; i < mlxsw_m->max_ports; i++) { -+ for (i = 0; i < max_ports; i++) { - if (mlxsw_m->module_to_port[i] > 0) { - err = mlxsw_m_port_create(mlxsw_m, - mlxsw_m->module_to_port[i], -@@ -294,9 +294,10 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) - - static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) - { -+ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core); - int i; - -- for (i = 0; i < mlxsw_m->max_ports; i++) { -+ for (i = 0; i < max_ports; i++) { - if (mlxsw_m->module_to_port[i] > 0) { - mlxsw_m_port_remove(mlxsw_m, - mlxsw_m->module_to_port[i]); --- -2.11.0 - diff --git a/patch/0043-mellanox-platform-Backporting-Melanox-drivers-from-v.patch b/patch/0043-mellanox-platform-Backporting-Melanox-drivers-from-v.patch deleted file mode 100644 index 60b9fc4cde8b..000000000000 --- a/patch/0043-mellanox-platform-Backporting-Melanox-drivers-from-v.patch +++ /dev/null @@ -1,1181 +0,0 @@ -From e68ab2e54837ba9a84e439c933b1e909270fa739 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Wed, 7 Aug 2019 04:50:34 +0000 -Subject: [PATCH 5.3 backport 1/3] mellanox: platform: Backporting Melanox - drivers from v5.3 - -This patch is required for new Mellanox systems and also contains -bugfixes. - -Patch contains backporting for the next drivers: -drivers/net/ethernet/mellanox/mlxsw/mlxsw_minimal; -drivers/platform/x86/mlx-platform; -drivers/platform/mellanox/mlxreg-hotplug; -drivers/hwmon/mlxreg-fan; - -Signed-off-by: Vadim Pasternak ---- - drivers/hwmon/mlxreg-fan.c | 52 ++- - drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 45 ++- - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 71 ++--- - drivers/net/ethernet/mellanox/mlxsw/i2c.c | 20 +- - drivers/net/ethernet/mellanox/mlxsw/reg.h | 14 +- - drivers/platform/mellanox/mlxreg-hotplug.c | 1 + - drivers/platform/x86/mlx-platform.c | 352 ++++++++++++++++----- - 7 files changed, 389 insertions(+), 166 deletions(-) - -diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c -index 30d2c467b274..7028a4f497b0 100644 ---- a/drivers/hwmon/mlxreg-fan.c -+++ b/drivers/hwmon/mlxreg-fan.c -@@ -27,10 +27,9 @@ - #define MLXREG_FAN_SPEED_MAX (MLXREG_FAN_MAX_STATE * 2) - #define MLXREG_FAN_SPEED_MIN_LEVEL 2 /* 20 percent */ - #define MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF 44 --#define MLXREG_FAN_TACHO_DIVIDER_MIN 283 --#define MLXREG_FAN_TACHO_DIVIDER_DEF (MLXREG_FAN_TACHO_DIVIDER_MIN \ -- * 4) --#define MLXREG_FAN_TACHO_DIVIDER_SCALE_MAX 32 -+#define MLXREG_FAN_TACHO_DIV_MIN 283 -+#define MLXREG_FAN_TACHO_DIV_DEF (MLXREG_FAN_TACHO_DIV_MIN * 4) -+#define MLXREG_FAN_TACHO_DIV_SCALE_MAX 64 - /* - * FAN datasheet defines the formula for RPM calculations as RPM = 15/t-high. - * The logic in a programmable device measures the time t-high by sampling the -@@ -364,8 +363,7 @@ static const struct thermal_cooling_device_ops mlxreg_fan_cooling_ops = { - }; - - static int mlxreg_fan_connect_verify(struct mlxreg_fan *fan, -- struct mlxreg_core_data *data, -- bool *connected) -+ struct mlxreg_core_data *data) - { - u32 regval; - int err; -@@ -377,9 +375,7 @@ static int mlxreg_fan_connect_verify(struct mlxreg_fan *fan, - return err; - } - -- *connected = (regval & data->bit) ? true : false; -- -- return 0; -+ return !!(regval & data->bit); - } - - static int mlxreg_fan_speed_divider_get(struct mlxreg_fan *fan, -@@ -399,10 +395,10 @@ static int mlxreg_fan_speed_divider_get(struct mlxreg_fan *fan, - * Set divider value according to the capability register, in case it - * contains valid value. Otherwise use default value. The purpose of - * this validation is to protect against the old hardware, in which -- * this register can be un-initialized. -+ * this register can return zero. - */ -- if (regval > 0 && regval <= MLXREG_FAN_TACHO_DIVIDER_SCALE_MAX) -- fan->divider = regval * MLXREG_FAN_TACHO_DIVIDER_MIN; -+ if (regval > 0 && regval <= MLXREG_FAN_TACHO_DIV_SCALE_MAX) -+ fan->divider = regval * MLXREG_FAN_TACHO_DIV_MIN; - - return 0; - } -@@ -411,12 +407,12 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, - struct mlxreg_core_platform_data *pdata) - { - struct mlxreg_core_data *data = pdata->data; -- bool configured = false, connected = false; -+ bool configured = false; - int tacho_num = 0, i; - int err; - - fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF; -- fan->divider = MLXREG_FAN_TACHO_DIVIDER_DEF; -+ fan->divider = MLXREG_FAN_TACHO_DIV_DEF; - for (i = 0; i < pdata->counter; i++, data++) { - if (strnstr(data->label, "tacho", sizeof(data->label))) { - if (tacho_num == MLXREG_FAN_MAX_TACHO) { -@@ -426,11 +422,10 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, - } - - if (data->capability) { -- err = mlxreg_fan_connect_verify(fan, data, -- &connected); -- if (err) -+ err = mlxreg_fan_connect_verify(fan, data); -+ if (err < 0) - return err; -- if (!connected) { -+ else if (!err) { - tacho_num++; - continue; - } -@@ -464,8 +459,10 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, - if (err) - return err; - } else { -- fan->samples = data->mask; -- fan->divider = data->bit; -+ if (data->mask) -+ fan->samples = data->mask; -+ if (data->bit) -+ fan->divider = data->bit; - } - configured = true; - } else { -@@ -486,21 +483,22 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, - static int mlxreg_fan_probe(struct platform_device *pdev) - { - struct mlxreg_core_platform_data *pdata; -+ struct device *dev = &pdev->dev; - struct mlxreg_fan *fan; - struct device *hwm; - int err; - -- pdata = dev_get_platdata(&pdev->dev); -+ pdata = dev_get_platdata(dev); - if (!pdata) { -- dev_err(&pdev->dev, "Failed to get platform data.\n"); -+ dev_err(dev, "Failed to get platform data.\n"); - return -EINVAL; - } - -- fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL); -+ fan = devm_kzalloc(dev, sizeof(*fan), GFP_KERNEL); - if (!fan) - return -ENOMEM; - -- fan->dev = &pdev->dev; -+ fan->dev = dev; - fan->regmap = pdata->regmap; - platform_set_drvdata(pdev, fan); - -@@ -508,12 +506,12 @@ static int mlxreg_fan_probe(struct platform_device *pdev) - if (err) - return err; - -- hwm = devm_hwmon_device_register_with_info(&pdev->dev, "mlxreg_fan", -+ hwm = devm_hwmon_device_register_with_info(dev, "mlxreg_fan", - fan, - &mlxreg_fan_hwmon_chip_info, - NULL); - if (IS_ERR(hwm)) { -- dev_err(&pdev->dev, "Failed to register hwmon device\n"); -+ dev_err(dev, "Failed to register hwmon device\n"); - return PTR_ERR(hwm); - } - -@@ -521,7 +519,7 @@ static int mlxreg_fan_probe(struct platform_device *pdev) - fan->cdev = thermal_cooling_device_register("mlxreg_fan", fan, - &mlxreg_fan_cooling_ops); - if (IS_ERR(fan->cdev)) { -- dev_err(&pdev->dev, "Failed to register cooling device\n"); -+ dev_err(dev, "Failed to register cooling device\n"); - return PTR_ERR(fan->cdev); - } - } -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -index 95b890298952..5bd08650e0fc 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -@@ -52,8 +52,7 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, - container_of(attr, struct mlxsw_hwmon_attr, dev_attr); - struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; - char mtmp_pl[MLXSW_REG_MTMP_LEN]; -- unsigned int temp; -- int index; -+ int temp, index; - int err; - - index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, -@@ -65,7 +64,7 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, - return err; - } - mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); -- return sprintf(buf, "%u\n", temp); -+ return sprintf(buf, "%d\n", temp); - } - - static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, -@@ -76,8 +75,7 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, - container_of(attr, struct mlxsw_hwmon_attr, dev_attr); - struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; - char mtmp_pl[MLXSW_REG_MTMP_LEN]; -- unsigned int temp_max; -- int index; -+ int temp_max, index; - int err; - - index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, -@@ -89,7 +87,7 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, - return err; - } - mlxsw_reg_mtmp_unpack(mtmp_pl, NULL, &temp_max, NULL); -- return sprintf(buf, "%u\n", temp_max); -+ return sprintf(buf, "%d\n", temp_max); - } - - static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, -@@ -215,8 +213,8 @@ static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev, - container_of(attr, struct mlxsw_hwmon_attr, dev_attr); - struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; - char mtmp_pl[MLXSW_REG_MTMP_LEN]; -- unsigned int temp; - u8 module; -+ int temp; - int err; - - module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; -@@ -227,7 +225,7 @@ static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev, - return err; - mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); - -- return sprintf(buf, "%u\n", temp); -+ return sprintf(buf, "%d\n", temp); - } - - static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, -@@ -237,18 +235,37 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, - struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = - container_of(attr, struct mlxsw_hwmon_attr, dev_attr); - struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; -- char mtmp_pl[MLXSW_REG_MTMP_LEN]; -+ 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; -- mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, -- false, false); -- err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); -- if (err) -+ mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, -+ 1); -+ err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); -+ if (err) { -+ dev_err(dev, "Failed to query module temperature sensor\n"); -+ return err; -+ } -+ -+ mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL); -+ -+ /* Update status and temperature cache. */ -+ switch (temp) { -+ case MLXSW_REG_MTBR_BAD_SENS_INFO: -+ /* Untrusted cable is connected. Reading temperature from its -+ * sensor is faulty. -+ */ - fault = 1; -- else -+ break; -+ case MLXSW_REG_MTBR_NO_CONN: /* fall-through */ -+ case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */ -+ case MLXSW_REG_MTBR_INDEX_NA: -+ default: - fault = 0; -+ break; -+ } - - return sprintf(buf, "%u\n", fault); - } -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index e9451e447bf0..8051b62af38a 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -98,7 +98,7 @@ struct mlxsw_thermal_module { - struct thermal_zone_device *tzdev; - struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; - enum thermal_device_mode mode; -- int module; -+ int module; /* Module or gearbox number */ - }; - - struct mlxsw_thermal { -@@ -111,9 +111,10 @@ struct mlxsw_thermal { - struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; - enum thermal_device_mode mode; - struct mlxsw_thermal_module *tz_module_arr; -- unsigned int tz_module_num; - struct mlxsw_thermal_module *tz_gearbox_arr; - u8 tz_gearbox_num; -+ unsigned int tz_highest_score; -+ struct thermal_zone_device *tz_highest_dev; - }; - - static inline u8 mlxsw_state_to_duty(int state) -@@ -282,7 +283,7 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, - struct mlxsw_thermal *thermal = tzdev->devdata; - struct device *dev = thermal->bus_info->dev; - char mtmp_pl[MLXSW_REG_MTMP_LEN]; -- unsigned int temp; -+ int temp; - int err; - - mlxsw_reg_mtmp_pack(mtmp_pl, 0, false, false); -@@ -294,7 +295,7 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, - } - mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); - -- *p_temp = (int) temp; -+ *p_temp = temp; - return 0; - } - -@@ -453,7 +454,7 @@ static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, - struct mlxsw_thermal *thermal = tz->parent; - struct device *dev = thermal->bus_info->dev; - char mtmp_pl[MLXSW_REG_MTMP_LEN]; -- unsigned int temp; -+ int temp; - int err; - - /* Read module temperature. */ -@@ -461,21 +462,22 @@ static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, - tz->module, false, false); - err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); - if (err) { -- dev_err(dev, "Failed to query temp sensor\n"); -+ /* Do not return error - in case of broken module's sensor -+ * it will cause error message flooding. -+ */ - temp = 0; - *p_temp = (int) temp; - return 0; - } - mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); -+ *p_temp = temp; - -- if (temp) { -- err = mlxsw_thermal_module_trips_update(dev, thermal->core, -- tz); -- if (err) -- return err; -- } -+ if (!temp) -+ return 0; -+ -+ /* Update trip points. */ -+ err = mlxsw_thermal_module_trips_update(dev, thermal->core, tz); - -- *p_temp = (int) temp; - return 0; - } - -@@ -539,10 +541,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip, - return 0; - } - --static struct thermal_zone_params mlxsw_thermal_module_params = { -- .governor_name = "user_space", --}; -- - static struct thermal_zone_device_ops mlxsw_thermal_module_ops = { - .bind = mlxsw_thermal_module_bind, - .unbind = mlxsw_thermal_module_unbind, -@@ -562,8 +560,8 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, - struct mlxsw_thermal_module *tz = tzdev->devdata; - struct mlxsw_thermal *thermal = tz->parent; - char mtmp_pl[MLXSW_REG_MTMP_LEN]; -- unsigned int temp; - u16 index; -+ int temp; - int err; - - index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module; -@@ -575,7 +573,7 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, - - mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); - -- *p_temp = (int) temp; -+ *p_temp = temp; - return 0; - } - -@@ -592,10 +590,6 @@ static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = { - .set_trip_hyst = mlxsw_thermal_module_trip_hyst_set, - }; - --static struct thermal_zone_params mlxsw_thermal_gearbox_params = { -- .governor_name = "user_space", --}; -- - static int mlxsw_thermal_get_max_state(struct thermal_cooling_device *cdev, - unsigned long *p_state) - { -@@ -709,13 +703,13 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz) - MLXSW_THERMAL_TRIP_MASK, - module_tz, - &mlxsw_thermal_module_ops, -- &mlxsw_thermal_module_params, -- 0, 0); -+ NULL, 0, 0); - if (IS_ERR(module_tz->tzdev)) { - err = PTR_ERR(module_tz->tzdev); - return err; - } - -+ module_tz->mode = THERMAL_DEVICE_DISABLED; - return 0; - } - -@@ -754,13 +748,7 @@ mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, - /* Initialize all trip point. */ - mlxsw_thermal_module_trips_reset(module_tz); - /* Update trip point according to the module data. */ -- err = mlxsw_thermal_module_trips_update(dev, core, module_tz); -- if (err) -- return err; -- -- thermal->tz_module_num++; -- -- return 0; -+ return mlxsw_thermal_module_trips_update(dev, core, module_tz); - } - - static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz) -@@ -831,7 +819,6 @@ static int - mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) - { - char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; -- int err; - - snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d", - gearbox_tz->module + 1); -@@ -840,13 +827,11 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) - MLXSW_THERMAL_TRIP_MASK, - gearbox_tz, - &mlxsw_thermal_gearbox_ops, -- &mlxsw_thermal_gearbox_params, -- 0, 0); -- if (IS_ERR(gearbox_tz->tzdev)) { -- err = PTR_ERR(gearbox_tz->tzdev); -- return err; -- } -+ NULL, 0, 0); -+ if (IS_ERR(gearbox_tz->tzdev)) -+ return PTR_ERR(gearbox_tz->tzdev); - -+ gearbox_tz->mode = THERMAL_DEVICE_DISABLED; - return 0; - } - -@@ -865,6 +850,9 @@ 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) -@@ -905,6 +893,9 @@ 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); -@@ -1000,7 +991,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core, - if (err) - goto err_unreg_tzdev; - -- mlxsw_thermal_gearboxes_init(dev, core, thermal); -+ err = mlxsw_thermal_gearboxes_init(dev, core, thermal); - if (err) - goto err_unreg_modules_tzdev; - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c -index 08c774875d1e..e04d521d9376 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c -@@ -383,7 +383,6 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num, - - mlxsw_i2c_write_exit: - kfree(tran_buf); -- - return err; - } - -@@ -567,12 +566,21 @@ static int mlxsw_i2c_probe(struct i2c_client *client, - if (!mlxsw_i2c) - return -ENOMEM; - -- if (quirks) -- mlxsw_i2c->block_size = max_t(u16, MLXSW_I2C_BLK_DEF, -- min_t(u16, quirks->max_read_len, -- quirks->max_write_len)); -- else -+ if (quirks) { -+ if ((quirks->max_read_len && -+ quirks->max_read_len < MLXSW_I2C_BLK_DEF) || -+ (quirks->max_write_len && -+ quirks->max_write_len < MLXSW_I2C_BLK_DEF)) { -+ dev_err(&client->dev, "Insufficient transaction buffer length\n"); -+ return -EOPNOTSUPP; -+ } -+ -+ mlxsw_i2c->block_size = max_t(u16, MLXSW_I2C_BLK_DEF, -+ min_t(u16, quirks->max_read_len, -+ quirks->max_write_len)); -+ } else { - mlxsw_i2c->block_size = MLXSW_I2C_BLK_DEF; -+ } - - i2c_set_clientdata(client, mlxsw_i2c); - mutex_init(&mlxsw_i2c->cmd.lock); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h -index eb58940d2e9c..31296d888fb8 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/reg.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h -@@ -7603,7 +7603,10 @@ MLXSW_REG_DEFINE(mtmp, MLXSW_REG_MTMP_ID, MLXSW_REG_MTMP_LEN); - MLXSW_ITEM32(reg, mtmp, sensor_index, 0x00, 0, 12); - - /* Convert to milli degrees Celsius */ --#define MLXSW_REG_MTMP_TEMP_TO_MC(val) (val * 125) -+#define MLXSW_REG_MTMP_TEMP_TO_MC(val) ({ typeof(val) v_ = (val); \ -+ ((v_) >= 0) ? ((v_) * 125) : \ -+ ((s16)((GENMASK(15, 0) + (v_) + 1) \ -+ * 125)); }) - - /* reg_mtmp_temperature - * Temperature reading from the sensor. Reading is in 0.125 Celsius -@@ -7674,11 +7677,10 @@ static inline void mlxsw_reg_mtmp_pack(char *payload, u16 sensor_index, - MLXSW_REG_MTMP_THRESH_HI); - } - --static inline void mlxsw_reg_mtmp_unpack(char *payload, unsigned int *p_temp, -- unsigned int *p_max_temp, -- char *sensor_name) -+static inline void mlxsw_reg_mtmp_unpack(char *payload, int *p_temp, -+ int *p_max_temp, char *sensor_name) - { -- u16 temp; -+ s16 temp; - - if (p_temp) { - temp = mlxsw_reg_mtmp_temperature_get(payload); -@@ -7738,7 +7740,7 @@ 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, u8 base_sensor_index, -+static inline void mlxsw_reg_mtbr_pack(char *payload, u16 base_sensor_index, - u8 num_rec) - { - MLXSW_REG_ZERO(mtbr, payload); -diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c -index 687ce6817d0d..f85a1b9d129b 100644 ---- a/drivers/platform/mellanox/mlxreg-hotplug.c -+++ b/drivers/platform/mellanox/mlxreg-hotplug.c -@@ -694,6 +694,7 @@ static int mlxreg_hotplug_remove(struct platform_device *pdev) - - /* Clean interrupts setup. */ - mlxreg_hotplug_unset_irq(priv); -+ devm_free_irq(&pdev->dev, priv->irq, priv); - - return 0; - } -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index d5d2448dc7e4..c3e75b26fe0b 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -44,6 +44,10 @@ - #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b - #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_ASIC_HEALTH_OFFSET 0x50 - #define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51 - #define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52 -@@ -105,7 +109,9 @@ - MLXPLAT_CPLD_AGGR_FAN_MASK_DEF) - #define MLXPLAT_CPLD_AGGR_ASIC_MASK_NG 0x01 - #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04 --#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 -+#define MLXPLAT_CPLD_AGGR_MASK_COMEX BIT(0) -+#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xe1 -+#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) - #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) -@@ -114,6 +120,12 @@ - #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) - #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) - -+/* Masks for aggregation for comex carriers */ -+#define MLXPLAT_CPLD_AGGR_MASK_CARRIER BIT(1) -+#define MLXPLAT_CPLD_AGGR_MASK_CARR_DEF (MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF | \ -+ MLXPLAT_CPLD_AGGR_MASK_CARRIER) -+#define MLXPLAT_CPLD_LOW_AGGRCX_MASK 0xc1 -+ - /* Default I2C parent bus number */ - #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1 - -@@ -159,6 +171,7 @@ - * @pdev_io_regs - register access platform devices - * @pdev_fan - FAN platform devices - * @pdev_wd - array of watchdog platform devices -+ * @regmap: device register map - */ - struct mlxplat_priv { - struct platform_device *pdev_i2c; -@@ -168,6 +181,7 @@ struct mlxplat_priv { - struct platform_device *pdev_io_regs; - struct platform_device *pdev_fan; - struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS]; -+ void *regmap; - }; - - /* Regions for LPC I2C controller and LPC base register space */ -@@ -181,6 +195,14 @@ static const struct resource mlxplat_lpc_resources[] = { - IORESOURCE_IO), - }; - -+/* Platform next generation systems i2c data */ -+static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = { -+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, -+ .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX, -+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET, -+ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_I2C, -+}; -+ - /* Platform default channels */ - static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = { - { -@@ -262,6 +284,22 @@ static struct i2c_board_info mlxplat_mlxcpld_fan[] = { - }, - }; - -+/* Platform hotplug comex carrier system family data */ -+static struct mlxreg_core_data mlxplat_mlxcpld_comex_psu_items_data[] = { -+ { -+ .label = "psu1", -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, -+ .mask = BIT(0), -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, -+ }, -+ { -+ .label = "psu2", -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, -+ .mask = BIT(1), -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, -+ }, -+}; -+ - /* Platform hotplug default data */ - static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = { - { -@@ -376,6 +414,45 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { - }, - }; - -+static struct mlxreg_core_item mlxplat_mlxcpld_comex_items[] = { -+ { -+ .data = mlxplat_mlxcpld_comex_psu_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER, -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, -+ .mask = MLXPLAT_CPLD_PSU_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), -+ .inversed = 1, -+ .health = false, -+ }, -+ { -+ .data = mlxplat_mlxcpld_default_pwr_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER, -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, -+ .mask = MLXPLAT_CPLD_PWR_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), -+ .inversed = 0, -+ .health = false, -+ }, -+ { -+ .data = mlxplat_mlxcpld_default_fan_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_CARRIER, -+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, -+ .mask = MLXPLAT_CPLD_FAN_MASK, -+ .count = ARRAY_SIZE(mlxplat_mlxcpld_fan), -+ .inversed = 1, -+ .health = false, -+ }, -+ { -+ .data = mlxplat_mlxcpld_default_asic_items_data, -+ .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_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_data = { - .items = mlxplat_mlxcpld_default_items, -@@ -386,6 +463,16 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { - .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, - }; - -+static -+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_comex_data = { -+ .items = mlxplat_mlxcpld_comex_items, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_comex_items), -+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, -+ .mask = MLXPLAT_CPLD_AGGR_MASK_CARR_DEF, -+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET, -+ .mask_low = MLXPLAT_CPLD_LOW_AGGRCX_MASK, -+}; -+ - static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = { - { - .label = "pwr1", -@@ -704,7 +791,7 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { - .items = mlxplat_mlxcpld_default_ng_items, - .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items), - .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, -- .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, -+ .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, - }; -@@ -1113,6 +1200,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_regs_io_data[] = { - .mode = 0444, - }, - { -+ .label = "reset_sff_wd", -+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(6), -+ .mode = 0444, -+ }, -+ { - .label = "psu1_on", - .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, - .mask = GENMASK(7, 0) & ~BIT(0), -@@ -1201,6 +1294,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { - .mode = 0444, - }, - { -+ .label = "reset_from_asic", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(5), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_swb_wd", -+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(6), -+ .mode = 0444, -+ }, -+ { - .label = "reset_asic_thermal", - .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, - .mask = GENMASK(7, 0) & ~BIT(7), -@@ -1213,6 +1318,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { - .mode = 0444, - }, - { -+ .label = "reset_comex_wd", -+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(6), -+ .mode = 0444, -+ }, -+ { - .label = "reset_voltmon_upgrade_fail", - .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, - .mask = GENMASK(7, 0) & ~BIT(0), -@@ -1225,6 +1336,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { - .mode = 0444, - }, - { -+ .label = "reset_comex_thermal", -+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(3), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_reload_bios", -+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(5), -+ .mode = 0444, -+ }, -+ { - .label = "psu1_on", - .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, - .mask = GENMASK(7, 0) & ~BIT(0), -@@ -1531,6 +1654,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: - case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: - case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: - case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: - case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: - case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: -@@ -1578,6 +1702,8 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: - case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: - case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRCO_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: -@@ -1645,6 +1771,8 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: - case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: - case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRCO_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: -@@ -1691,6 +1819,17 @@ static const struct reg_default mlxplat_mlxcpld_regmap_default[] = { - { MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 }, - }; - -+static const struct reg_default mlxplat_mlxcpld_regmap_ng[] = { -+ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, -+ { MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 }, -+}; -+ -+static const struct reg_default mlxplat_mlxcpld_regmap_comex_default[] = { -+ { MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET, -+ MLXPLAT_CPLD_LOW_AGGRCX_MASK }, -+ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, -+}; -+ - struct mlxplat_mlxcpld_regmap_context { - void __iomem *base; - }; -@@ -1729,17 +1868,47 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config = { - .reg_write = mlxplat_mlxcpld_reg_write, - }; - -+static const struct regmap_config mlxplat_mlxcpld_regmap_config_ng = { -+ .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_ng, -+ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_ng), -+ .reg_read = mlxplat_mlxcpld_reg_read, -+ .reg_write = mlxplat_mlxcpld_reg_write, -+}; -+ -+static const struct regmap_config mlxplat_mlxcpld_regmap_config_comex = { -+ .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_comex_default, -+ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_comex_default), -+ .reg_read = mlxplat_mlxcpld_reg_read, -+ .reg_write = mlxplat_mlxcpld_reg_write, -+}; -+ - static struct resource mlxplat_mlxcpld_resources[] = { - [0] = DEFINE_RES_IRQ_NAMED(17, "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; - static struct mlxreg_core_platform_data *mlxplat_regs_io; - static struct mlxreg_core_platform_data *mlxplat_fan; - static struct mlxreg_core_platform_data - *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS]; -+static const struct regmap_config *mlxplat_regmap_config; - - static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) - { -@@ -1834,12 +2003,76 @@ static int __init mlxplat_dmi_qmb7xx_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_ng_data; -+ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng; -+ -+ return 1; -+}; -+ -+static int __init mlxplat_dmi_comex_matched(const struct dmi_system_id *dmi) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -+ mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; -+ mlxplat_mux_data[i].n_values = -+ ARRAY_SIZE(mlxplat_msn21xx_channels); -+ } -+ mlxplat_hotplug = &mlxplat_mlxcpld_comex_data; -+ mlxplat_hotplug->deferred_nr = -+ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; -+ mlxplat_led = &mlxplat_default_led_data; -+ mlxplat_regs_io = &mlxplat_default_regs_io_data; -+ mlxplat_fan = &mlxplat_default_fan_data; -+ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_comex; - - return 1; - }; - - static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { - { -+ .callback = mlxplat_dmi_default_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_msn21xx_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_msn274x_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_msn201x_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_qmb7xx_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_qmb7xx_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0007"), -+ }, -+ }, -+ { -+ .callback = mlxplat_dmi_comex_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0009"), -+ }, -+ }, -+ { - .callback = mlxplat_dmi_msn274x_matched, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -@@ -1916,42 +2149,6 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { - DMI_MATCH(DMI_PRODUCT_NAME, "MSN38"), - }, - }, -- { -- .callback = mlxplat_dmi_default_matched, -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"), -- }, -- }, -- { -- .callback = mlxplat_dmi_msn21xx_matched, -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"), -- }, -- }, -- { -- .callback = mlxplat_dmi_msn274x_matched, -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"), -- }, -- }, -- { -- .callback = mlxplat_dmi_msn201x_matched, -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"), -- }, -- }, -- { -- .callback = mlxplat_dmi_qmb7xx_matched, -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), -- }, -- }, -- { -- .callback = mlxplat_dmi_qmb7xx_matched, -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "VMOD0007"), -- }, -- }, - { } - }; - -@@ -2018,13 +2215,36 @@ 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; -+ } -+ -+ 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_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr; -- priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr, -- NULL, 0); -+ 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), -+ mlxplat_i2c, sizeof(*mlxplat_i2c)); - if (IS_ERR(priv->pdev_i2c)) { - err = PTR_ERR(priv->pdev_i2c); - goto fail_alloc; -@@ -2032,7 +2252,7 @@ static int __init mlxplat_init(void) - - for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { - priv->pdev_mux[i] = platform_device_register_resndata( -- &mlxplat_dev->dev, -+ &priv->pdev_i2c->dev, - "i2c-mux-reg", i, NULL, - 0, &mlxplat_mux_data[i], - sizeof(mlxplat_mux_data[i])); -@@ -2042,21 +2262,8 @@ static int __init mlxplat_init(void) - } - } - -- 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_platform_mux_register; -- } -- -- mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, -- &mlxplat_mlxcpld_regmap_ctx, -- &mlxplat_mlxcpld_regmap_config); -- if (IS_ERR(mlxplat_hotplug->regmap)) { -- err = PTR_ERR(mlxplat_hotplug->regmap); -- goto fail_platform_mux_register; -- } -- -+ /* Add hotplug driver */ -+ mlxplat_hotplug->regmap = priv->regmap; - priv->pdev_hotplug = platform_device_register_resndata( - &mlxplat_dev->dev, "mlxreg-hotplug", - PLATFORM_DEVID_NONE, -@@ -2069,16 +2276,16 @@ static int __init mlxplat_init(void) - } - - /* Set default registers. */ -- for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) { -- err = regmap_write(mlxplat_hotplug->regmap, -- mlxplat_mlxcpld_regmap_default[j].reg, -- mlxplat_mlxcpld_regmap_default[j].def); -+ 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. */ -- mlxplat_led->regmap = mlxplat_hotplug->regmap; -+ mlxplat_led->regmap = priv->regmap; - priv->pdev_led = platform_device_register_resndata( - &mlxplat_dev->dev, "leds-mlxreg", - PLATFORM_DEVID_NONE, NULL, 0, -@@ -2090,7 +2297,7 @@ static int __init mlxplat_init(void) - - /* Add registers io access driver. */ - if (mlxplat_regs_io) { -- mlxplat_regs_io->regmap = mlxplat_hotplug->regmap; -+ mlxplat_regs_io->regmap = priv->regmap; - priv->pdev_io_regs = platform_device_register_resndata( - &mlxplat_dev->dev, "mlxreg-io", - PLATFORM_DEVID_NONE, NULL, 0, -@@ -2104,7 +2311,7 @@ static int __init mlxplat_init(void) - - /* Add FAN driver. */ - if (mlxplat_fan) { -- mlxplat_fan->regmap = mlxplat_hotplug->regmap; -+ mlxplat_fan->regmap = priv->regmap; - priv->pdev_fan = platform_device_register_resndata( - &mlxplat_dev->dev, "mlxreg-fan", - PLATFORM_DEVID_NONE, NULL, 0, -@@ -2119,10 +2326,10 @@ static int __init mlxplat_init(void) - /* Add WD drivers. */ - for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) { - if (mlxplat_wd_data[j]) { -- mlxplat_wd_data[j]->regmap = mlxplat_hotplug->regmap; -- priv->pdev_wd[j] = platform_device_register_resndata -- (&mlxplat_dev->dev, -- "mlx-wdt", j, NULL, 0, -+ mlxplat_wd_data[j]->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])) { -@@ -2133,18 +2340,16 @@ static int __init mlxplat_init(void) - } - - /* Sync registers with hardware. */ -- regcache_mark_dirty(mlxplat_hotplug->regmap); -- err = regcache_sync(mlxplat_hotplug->regmap); -+ 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) { -- if (priv->pdev_wd[j]) -- platform_device_unregister(priv->pdev_wd[j]); -- } -+ while (--j >= 0) -+ platform_device_unregister(priv->pdev_wd[j]); - if (mlxplat_fan) - platform_device_unregister(priv->pdev_fan); - fail_platform_io_regs_register: -@@ -2180,6 +2385,7 @@ static void __exit mlxplat_exit(void) - platform_device_unregister(priv->pdev_io_regs); - platform_device_unregister(priv->pdev_led); - platform_device_unregister(priv->pdev_hotplug); -+ - for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) - platform_device_unregister(priv->pdev_mux[i]); - --- -2.11.0 - diff --git a/patch/0044-mlxsw-minimal-Provide-optimization-for-module-number.patch b/patch/0044-mlxsw-minimal-Provide-optimization-for-module-number.patch deleted file mode 100644 index 2c02518f3e73..000000000000 --- a/patch/0044-mlxsw-minimal-Provide-optimization-for-module-number.patch +++ /dev/null @@ -1,530 +0,0 @@ -From 1a2d774224abf9536be53031f476a1d0411b7f63 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Wed, 7 Aug 2019 09:57:18 +0000 -Subject: [PATCH 5.3 backport 2/3] mlxsw: minimal: Provide optimization for - module number detection -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Use new filed ‘num_of_modules’ in MGPIR register in order to get -the number of modules supported by system directly from system -configuration, instead of getting it from port to module mapping info. - -Taking this info through MGPIR register is faster and also does not -depend on possible dynamic re-configuration of ports. -In case of port dynamic re-configuration some modules can logically -“disappeared” or “appeared” as a result of port split and un-spilt -operations, which can cause missing of some modules, in case this info -is taken from port to module mapping info. - -Signed-off-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 55 +++++------ - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 44 +++++---- - drivers/net/ethernet/mellanox/mlxsw/minimal.c | 104 +++++---------------- - drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c | 41 ++++++-- - drivers/net/ethernet/mellanox/mlxsw/reg.h | 23 +++-- - 5 files changed, 112 insertions(+), 155 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -index 5bd08650e0fc..9cb19ec47e4d 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -@@ -528,56 +528,47 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) - - static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) - { -- unsigned int module_count = mlxsw_core_max_ports(mlxsw_hwmon->core); -- u8 width, module, last_module = module_count; -- char pmlp_pl[MLXSW_REG_PMLP_LEN] = {0}; -- int i, index; -+ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; -+ int index, i; - int 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) -+ return err; -+ -+ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, -+ &mlxsw_hwmon->module_sensor_count); -+ if (!mlxsw_hwmon->module_sensor_count) -+ return 0; -+ - /* Add extra attributes for module temperature. Sensor index is - * assigned to sensor_count value, while all indexed before - * sensor_count are already utilized by the sensors connected through - * mtmp register by mlxsw_hwmon_temp_init(). - */ -- index = mlxsw_hwmon->sensor_count; -- for (i = 1; i < module_count; i++) { -- mlxsw_reg_pmlp_pack(pmlp_pl, i); -- err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(pmlp), -- pmlp_pl); -- if (err) { -- dev_err(mlxsw_hwmon->bus_info->dev, "Failed to read module index %d\n", -- i); -- return err; -- } -- width = mlxsw_reg_pmlp_width_get(pmlp_pl); -- if (!width) -- continue; -- module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); -- /* Skip, if port belongs to the cluster */ -- if (module == last_module) -- continue; -- last_module = module; -+ index = mlxsw_hwmon->sensor_count + mlxsw_hwmon->module_sensor_count; -+ mlxsw_hwmon->module_sensor_count += mlxsw_hwmon->sensor_count; -+ for (i = mlxsw_hwmon->sensor_count; -+ i < mlxsw_hwmon->module_sensor_count; i++) { - mlxsw_hwmon_attr_add(mlxsw_hwmon, -- MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, index, -- index); -+ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, i, i); - mlxsw_hwmon_attr_add(mlxsw_hwmon, - MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT, -- index, index); -+ i, i); - mlxsw_hwmon_attr_add(mlxsw_hwmon, -- MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, -- index, index); -+ MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, i, -+ i); - mlxsw_hwmon_attr_add(mlxsw_hwmon, - MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG, -- index, index); -+ i, i); - mlxsw_hwmon_attr_add(mlxsw_hwmon, - MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL, -- index, index); -- index++; -+ i, i); - } -- mlxsw_hwmon->module_sensor_count = index; - - return 0; - } -@@ -595,7 +586,7 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) - if (err) - return 0; - -- mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL); -+ mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL, NULL); - if (!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 8051b62af38a..17a340aa9f75 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -111,6 +111,7 @@ struct mlxsw_thermal { - struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; - enum thermal_device_mode mode; - struct mlxsw_thermal_module *tz_module_arr; -+ u8 tz_module_num; - struct mlxsw_thermal_module *tz_gearbox_arr; - u8 tz_gearbox_num; - unsigned int tz_highest_score; -@@ -720,23 +721,10 @@ 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 local_port) -+ struct mlxsw_thermal *thermal, u8 module) - { - struct mlxsw_thermal_module *module_tz; -- char pmlp_pl[MLXSW_REG_PMLP_LEN]; -- u8 width, module; -- int err; -- -- mlxsw_reg_pmlp_pack(pmlp_pl, local_port); -- err = mlxsw_reg_query(core, MLXSW_REG(pmlp), pmlp_pl); -- if (err) -- return err; - -- width = mlxsw_reg_pmlp_width_get(pmlp_pl); -- if (!width) -- return 0; -- -- module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); - module_tz = &thermal->tz_module_arr[module]; - /* Skip if parent is already set (case of port split). */ - if (module_tz->parent) -@@ -764,26 +752,36 @@ static int - mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, - struct mlxsw_thermal *thermal) - { -- unsigned int module_count = mlxsw_core_max_ports(core); -+ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; - struct mlxsw_thermal_module *module_tz; - int i, err; - - if (!mlxsw_core_res_query_enabled(core)) - return 0; - -- thermal->tz_module_arr = kcalloc(module_count, -+ mlxsw_reg_mgpir_pack(mgpir_pl); -+ 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); -+ if (!thermal->tz_module_num) -+ return 0; -+ -+ thermal->tz_module_arr = kcalloc(thermal->tz_module_num, - sizeof(*thermal->tz_module_arr), - GFP_KERNEL); - if (!thermal->tz_module_arr) - return -ENOMEM; - -- for (i = 1; i < module_count; i++) { -+ 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; - } - -- for (i = 0; i < module_count - 1; i++) { -+ for (i = 0; i < thermal->tz_module_num; i++) { - module_tz = &thermal->tz_module_arr[i]; - if (!module_tz->parent) - continue; -@@ -795,7 +793,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, - return 0; - - err_unreg_tz_module_arr: -- for (i = module_count - 1; i >= 0; 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); - return err; -@@ -804,13 +802,12 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, - static void - mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal) - { -- unsigned int module_count = mlxsw_core_max_ports(thermal->core); - int i; - - if (!mlxsw_core_res_query_enabled(thermal->core)) - return; - -- for (i = module_count - 1; i >= 0; i--) -+ for (i = thermal->tz_module_num - 1; i >= 0; i--) - mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); - kfree(thermal->tz_module_arr); - } -@@ -858,7 +855,8 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, - if (err) - return 0; - -- mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL); -+ mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL, -+ NULL); - if (!thermal->tz_gearbox_num) - return 0; - -@@ -995,7 +993,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core, - if (err) - goto err_unreg_modules_tzdev; - -- thermal->mode = THERMAL_DEVICE_ENABLED; -+ thermal->mode = THERMAL_DEVICE_DISABLED; - *p_thermal = thermal; - return 0; - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -index 0aa3abc974ff..564b85c06a9a 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -@@ -89,23 +89,6 @@ static const struct ethtool_ops mlxsw_m_port_ethtool_ops = { - }; - - static int --mlxsw_m_port_module_info_get(struct mlxsw_m *mlxsw_m, u8 local_port, -- u8 *p_module, u8 *p_width) --{ -- char pmlp_pl[MLXSW_REG_PMLP_LEN]; -- int err; -- -- mlxsw_reg_pmlp_pack(pmlp_pl, local_port); -- err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(pmlp), pmlp_pl); -- if (err) -- return err; -- *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); -- *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl); -- -- return 0; --} -- --static int - mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port) - { - struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; -@@ -158,7 +141,7 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) - mlxsw_m_port = netdev_priv(dev); - mlxsw_m_port->dev = dev; - mlxsw_m_port->mlxsw_m = mlxsw_m; -- mlxsw_m_port->local_port = local_port; -+ mlxsw_m_port->local_port = module; - mlxsw_m_port->module = module; - - dev->netdev_ops = &mlxsw_m_port_netdev_ops; -@@ -205,87 +188,48 @@ static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 local_port) - mlxsw_core_port_fini(mlxsw_m->core, local_port); - } - --static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port, -- u8 *last_module) -+static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) - { -- u8 module, width; -+ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; -+ int i; - int err; - -- /* Fill out to local port mapping array */ -- err = mlxsw_m_port_module_info_get(mlxsw_m, local_port, &module, -- &width); -+ mlxsw_reg_mgpir_pack(mgpir_pl); -+ err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mgpir), mgpir_pl); - if (err) - return err; - -- if (!width) -+ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, -+ &mlxsw_m->max_ports); -+ if (!mlxsw_m->max_ports) - return 0; -- /* Skip, if port belongs to the cluster */ -- if (module == *last_module) -- return 0; -- *last_module = module; -- mlxsw_m->module_to_port[module] = ++mlxsw_m->max_ports; -- -- return 0; --} - --static void mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 module) --{ -- mlxsw_m->module_to_port[module] = -1; --} -- --static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) --{ -- unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core); -- u8 last_module = max_ports; -- int i; -- int err; -- -- mlxsw_m->ports = kcalloc(max_ports, sizeof(*mlxsw_m->ports), -+ mlxsw_m->ports = kcalloc(mlxsw_m->max_ports, sizeof(*mlxsw_m->ports), - GFP_KERNEL); - if (!mlxsw_m->ports) - return -ENOMEM; - -- mlxsw_m->module_to_port = kmalloc_array(max_ports, sizeof(int), -+ 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; - } - -- /* Invalidate the entries of module to local port mapping array */ -- for (i = 0; i < max_ports; i++) -- mlxsw_m->module_to_port[i] = -1; -- -- /* Fill out module to local port mapping array */ -- for (i = 1; i < max_ports; i++) { -- err = mlxsw_m_port_module_map(mlxsw_m, i, &last_module); -- if (err) -- goto err_module_to_port_map; -- } -- - /* Create port objects for each valid entry */ -- for (i = 0; i < max_ports; i++) { -- if (mlxsw_m->module_to_port[i] > 0) { -- err = mlxsw_m_port_create(mlxsw_m, -- mlxsw_m->module_to_port[i], -- i); -- if (err) -- goto err_module_to_port_create; -- } -+ 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; - } - - return 0; - - err_module_to_port_create: -- for (i--; i >= 0; i--) { -- if (mlxsw_m->module_to_port[i] > 0) -- mlxsw_m_port_remove(mlxsw_m, -- mlxsw_m->module_to_port[i]); -- } -- i = max_ports; --err_module_to_port_map: -- for (i--; i > 0; i--) -- mlxsw_m_port_module_unmap(mlxsw_m, i); -+ 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); -@@ -294,16 +238,10 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) - - static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) - { -- unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core); - int i; - -- for (i = 0; i < max_ports; i++) { -- if (mlxsw_m->module_to_port[i] > 0) { -- mlxsw_m_port_remove(mlxsw_m, -- mlxsw_m->module_to_port[i]); -- mlxsw_m_port_module_unmap(mlxsw_m, 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); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -index fdf2b796e724..49563a703d75 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c -@@ -279,16 +279,36 @@ static const struct dmi_system_id mlxsw_qsfp_dmi_table[] = { - }; - MODULE_DEVICE_TABLE(dmi, mlxsw_qsfp_dmi_table); - -+static int mlxsw_qsfp_set_module_num(struct mlxsw_qsfp *mlxsw_qsfp) -+{ -+ char pmlp_pl[MLXSW_REG_PMLP_LEN]; -+ u8 width; -+ int i, err; -+ -+ for (i = 1; i <= mlxsw_qsfp_num; i++) { -+ mlxsw_reg_pmlp_pack(pmlp_pl, i); -+ err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(pmlp), -+ pmlp_pl); -+ if (err) -+ return err; -+ width = mlxsw_reg_pmlp_width_get(pmlp_pl); -+ if (!width) -+ continue; -+ mlxsw_qsfp->module_count++; -+ } -+ -+ return 0; -+} -+ - int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info, - struct mlxsw_qsfp **p_qsfp) - { - struct device_attribute *dev_attr, *cpld_dev_attr; -- char pmlp_pl[MLXSW_REG_PMLP_LEN]; -+ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; - struct mlxsw_qsfp *mlxsw_qsfp; - struct bin_attribute *eeprom; - int i, count; -- u8 width; - int err; - - if (!strcmp(mlxsw_bus_info->device_kind, "i2c")) -@@ -305,16 +325,17 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core, - mlxsw_qsfp->bus_info = mlxsw_bus_info; - mlxsw_bus_info->dev->platform_data = mlxsw_qsfp; - -- for (i = 1; i <= mlxsw_qsfp_num; i++) { -- mlxsw_reg_pmlp_pack(pmlp_pl, i); -- err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(pmlp), -- pmlp_pl); -+ mlxsw_reg_mgpir_pack(mgpir_pl); -+ err = mlxsw_reg_query(mlxsw_qsfp->core, MLXSW_REG(mgpir), mgpir_pl); -+ if (err) { -+ err = mlxsw_qsfp_set_module_num(mlxsw_qsfp); - if (err) - return err; -- width = mlxsw_reg_pmlp_width_get(pmlp_pl); -- if (!width) -- continue; -- mlxsw_qsfp->module_count++; -+ } else { -+ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, -+ &mlxsw_qsfp->module_count); -+ if (!mlxsw_qsfp->module_count) -+ return 0; - } - - count = mlxsw_qsfp->module_count + 1; -diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h -index 31296d888fb8..a8cd53f068ce 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/reg.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h -@@ -8593,6 +8593,11 @@ static inline void mlxsw_reg_mprs_pack(char *payload, u16 parsing_depth, - - MLXSW_REG_DEFINE(mgpir, MLXSW_REG_MGPIR_ID, MLXSW_REG_MGPIR_LEN); - -+enum mlxsw_reg_mgpir_device_type { -+ MLXSW_REG_MGPIR_DEVICE_TYPE_NONE, -+ MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE, -+}; -+ - /* device_type - * Access: RO - */ -@@ -8610,19 +8615,21 @@ MLXSW_ITEM32(reg, mgpir, devices_per_flash, 0x00, 16, 8); - */ - MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8); - --enum mlxsw_reg_mgpir_device_type { -- MLXSW_REG_MGPIR_TYPE_NONE, -- MLXSW_REG_MGPIR_TYPE_GEARBOX_DIE, --}; -+/* 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) - { - MLXSW_REG_ZERO(mgpir, payload); - } - --static inline void mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, -- u8 *device_type, -- u8 *devices_per_flash) -+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) - { - if (num_of_devices) - *num_of_devices = mlxsw_reg_mgpir_num_of_devices_get(payload); -@@ -8631,6 +8638,8 @@ static inline void mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, - if (devices_per_flash) - *devices_per_flash = - mlxsw_reg_mgpir_devices_per_flash_get(payload); -+ if (num_of_modules) -+ *num_of_modules = mlxsw_reg_mgpir_num_of_modules_get(payload); - } - - /* TNGCR - Tunneling NVE General Configuration Register --- -2.11.0 - diff --git a/patch/0045-mlxsw-minimal-Add-validation-for-FW-version.patch b/patch/0045-mlxsw-minimal-Add-validation-for-FW-version.patch deleted file mode 100644 index 0b6a7fd6cc49..000000000000 --- a/patch/0045-mlxsw-minimal-Add-validation-for-FW-version.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 3b3986744bb9fb8635adf13575534f271fa58676 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Sun, 11 Aug 2019 07:00:03 +0000 -Subject: [PATCH v1 1/1] mlxsw: minimal: Add validation for FW version - -Add validation for FW version in order to prevent driver initialization -in case FW version is older than expected. - -Signed-off-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/core.c | 17 +++++++++-------- - drivers/net/ethernet/mellanox/mlxsw/minimal.c | 25 +++++++++++++++++++++++++ - 2 files changed, 34 insertions(+), 8 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c -index 9a74ae8beb43..a127e0b01e4e 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c -@@ -987,6 +987,12 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, - goto err_devlink_register; - } - -+ if (mlxsw_driver->init) { -+ err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info); -+ if (err) -+ goto err_driver_init; -+ } -+ - err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon); - if (err) - goto err_hwmon_init; -@@ -1001,21 +1007,16 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, - if (err) - goto err_qsfp_init; - -- if (mlxsw_driver->init) { -- err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info); -- if (err) -- goto err_driver_init; -- } -- - return 0; - --err_driver_init: -- mlxsw_qsfp_fini(mlxsw_core->qsfp); - err_qsfp_init: - mlxsw_thermal_fini(mlxsw_core->thermal); - err_thermal_init: - mlxsw_hwmon_fini(mlxsw_core->hwmon); - err_hwmon_init: -+ if (mlxsw_core->driver->fini) -+ mlxsw_core->driver->fini(mlxsw_core); -+err_driver_init: - if (!reload) - devlink_unregister(devlink); - err_devlink_register: -diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -index 564b85c06a9a..504db124ee2f 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c -@@ -17,6 +17,9 @@ - - static const char mlxsw_m_driver_name[] = "mlxsw_minimal"; - -+#define MLXSW_M_FWREV_MINOR 2000 -+#define MLXSW_M_FWREV_SUBMINOR 1886 -+ - struct mlxsw_m_port; - - struct mlxsw_m { -@@ -117,6 +120,24 @@ static void mlxsw_m_port_switchdev_fini(struct mlxsw_m_port *mlxsw_m_port) - { - } - -+static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m) -+{ -+ const struct mlxsw_fw_rev *rev = &mlxsw_m->bus_info->fw_rev; -+ -+ dev_info(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d\n", -+ rev->major, rev->minor, rev->subminor); -+ /* Validate driver & FW are compatible */ -+ if (rev->minor >= MLXSW_M_FWREV_MINOR && -+ rev->subminor >= MLXSW_M_FWREV_SUBMINOR) -+ return 0; -+ -+ dev_info(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n", -+ rev->major, rev->minor, rev->subminor, rev->major, -+ MLXSW_M_FWREV_MINOR, MLXSW_M_FWREV_SUBMINOR); -+ -+ return -EINVAL; -+} -+ - static int - mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) - { -@@ -256,6 +277,10 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, - mlxsw_m->core = mlxsw_core; - mlxsw_m->bus_info = mlxsw_bus_info; - -+ err = mlxsw_m_fw_rev_validate(mlxsw_m); -+ if (err) -+ return err; -+ - err = mlxsw_m_ports_create(mlxsw_m); - if (err) { - dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n"); --- -2.11.0 - diff --git a/patch/0046-mlxsw-core-Extend-QSFP-EEPROM-supported-size-for-eth.patch b/patch/0046-mlxsw-core-Extend-QSFP-EEPROM-supported-size-for-eth.patch deleted file mode 100644 index 5415ea85bad5..000000000000 --- a/patch/0046-mlxsw-core-Extend-QSFP-EEPROM-supported-size-for-eth.patch +++ /dev/null @@ -1,168 +0,0 @@ -From 701662a1dc781e18341974ec6cece31bead06fbd Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Mon, 12 Aug 2019 07:31:57 +0300 -Subject: [PATCH v1 1/1] mlxsw: core: Extend QSFP EEPROM supported size for - ethtool - -Extend size of QSFP EEPROM for the cable type SSF8436, SFF8636 from 256 -to 612 bytes in order to make available all the pages. - -Signed-off-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/core_env.c | 40 ++++++++++++++++++-------- - drivers/net/ethernet/mellanox/mlxsw/reg.h | 5 ++++ - include/uapi/linux/ethtool.h | 3 ++ - 3 files changed, 36 insertions(+), 12 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c -index d2c7ce67c300..0a5495f9f4c7 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c -@@ -44,12 +44,13 @@ 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, -+ u16 offset, u16 size, bool qsfp, void *data, - unsigned int *p_read_size) - { - char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE]; - char mcia_pl[MLXSW_REG_MCIA_LEN]; - u16 i2c_addr; -+ u8 page = 0; - int status; - int err; - -@@ -62,11 +63,19 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, - - i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW; - if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) { -- i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH; -- offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH; -+ if (qsfp) { -+ page = MLXSW_REG_MCIA_PAGE_GET(offset); -+ offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page; -+ if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) -+ size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - -+ offset; -+ } else { -+ i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH; -+ offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH; -+ } - } - -- mlxsw_reg_mcia_pack(mcia_pl, module, 0, 0, offset, size, i2c_addr); -+ mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, offset, size, i2c_addr); - - err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); - if (err) -@@ -152,10 +161,11 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, - u16 offset = MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE; - u8 module_rev_id, module_id, diag_mon; - unsigned int read_size; -+ bool unused = false; - int err; - - err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset, -- module_info, &read_size); -+ unused, module_info, &read_size); - if (err) - return err; - -@@ -168,7 +178,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, - switch (module_id) { - case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: - modinfo->type = ETH_MODULE_SFF_8436; -- modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; -+ modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; - break; - case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */ - case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: -@@ -176,17 +186,17 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, - module_rev_id >= - MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) { - modinfo->type = ETH_MODULE_SFF_8636; -- modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; -+ modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; - } else { - modinfo->type = ETH_MODULE_SFF_8436; -- modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; -+ modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; - } - 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, -- &read_size); -+ SFP_DIAGMON, 1, unused, -+ &diag_mon, &read_size); - if (err) - return err; - -@@ -213,6 +223,7 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev, - { - int offset = ee->offset; - unsigned int read_size; -+ bool qsfp; - int i = 0; - int err; - -@@ -221,10 +232,15 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev, - - memset(data, 0, ee->len); - -+ /* Validate module identifier type. */ -+ err = mlxsw_env_validate_cable_ident(mlxsw_core, module, &qsfp); -+ if (err) -+ return err; -+ - while (i < ee->len) { - err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset, -- ee->len - i, data + i, -- &read_size); -+ ee->len - i, qsfp, -+ data + i, &read_size); - if (err) { - netdev_err(netdev, "Eeprom query failed\n"); - return err; -diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h -index a8cd53f068ce..8d7a58472799 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/reg.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h -@@ -7823,6 +7823,7 @@ MLXSW_ITEM32(reg, mcia, device_address, 0x04, 0, 16); - MLXSW_ITEM32(reg, mcia, size, 0x08, 0, 16); - - #define MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH 256 -+#define MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH 128 - #define MLXSW_REG_MCIA_EEPROM_SIZE 48 - #define MLXSW_REG_MCIA_I2C_ADDR_LOW 0x50 - #define MLXSW_REG_MCIA_I2C_ADDR_HIGH 0x51 -@@ -7858,6 +7859,10 @@ enum mlxsw_reg_mcia_eeprom_module_info { - */ - MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE); - -+#define MLXSW_REG_MCIA_PAGE_GET(off) (((off) - \ -+ 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) -diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h -index 8e547231c1b7..b868569344d1 100644 ---- a/include/uapi/linux/ethtool.h -+++ b/include/uapi/linux/ethtool.h -@@ -1595,6 +1595,9 @@ static inline int ethtool_validate_duplex(__u8 duplex) - #define ETH_MODULE_SFF_8436 0x4 - #define ETH_MODULE_SFF_8436_LEN 256 - -+#define ETH_MODULE_SFF_8636_MAX_LEN 640 -+#define ETH_MODULE_SFF_8436_MAX_LEN 640 -+ - /* Reset flags */ - /* The reset() operation must clear the flags for the components which - * were actually reset. On successful return, the flags indicate the --- -2.11.0 - diff --git a/patch/0047-mfd-lpc-ich-extend-with-additional-chipsets-support.patch b/patch/0047-mfd-lpc-ich-extend-with-additional-chipsets-support.patch deleted file mode 100644 index 7c31078eaa9b..000000000000 --- a/patch/0047-mfd-lpc-ich-extend-with-additional-chipsets-support.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 807b5aab7955b0d8777a3c26af745c6bfa8efd7c Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Sun, 1 Sep 2019 09:36:28 +0300 -Subject: [PATCH backport 5.1] mfd lpc ich: extend with additional chipsets - support - -It extends chipsets types supported by 'lpc_ich' driver - -Signed-off-by: Vadim Pasternak ---- - drivers/mfd/lpc_ich.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c -index c8dee47b45d9..21e4824d6e33 100644 ---- a/drivers/mfd/lpc_ich.c -+++ b/drivers/mfd/lpc_ich.c -@@ -216,6 +216,9 @@ enum lpc_chipsets { - LPC_BRASWELL, /* Braswell SoC */ - LPC_LEWISBURG, /* Lewisburg */ - LPC_9S, /* 9 Series */ -+ LPC_APL, /* Apollo Lake SoC */ -+ LPC_GLK, /* Gemini Lake SoC */ -+ LPC_COUGARMOUNTAIN,/* Cougar Mountain SoC*/ - }; - - static struct lpc_ich_info lpc_chipset_info[] = { -@@ -493,6 +496,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { - [LPC_LPT] = { - .name = "Lynx Point", - .iTCO_version = 2, -+ .gpio_version = ICH_V5_GPIO, - }, - [LPC_LPT_LP] = { - .name = "Lynx Point_LP", -@@ -530,6 +534,18 @@ static struct lpc_ich_info lpc_chipset_info[] = { - [LPC_9S] = { - .name = "9 Series", - .iTCO_version = 2, -+ .gpio_version = ICH_V5_GPIO, -+ }, -+ [LPC_APL] = { -+ .name = "Apollo Lake SoC", -+ .iTCO_version = 5, -+ }, -+ [LPC_GLK] = { -+ .name = "Gemini Lake SoC", -+ }, -+ [LPC_COUGARMOUNTAIN] = { -+ .name = "Cougar Mountain SoC", -+ .iTCO_version = 3, - }, - }; - -@@ -659,6 +675,8 @@ static const struct pci_device_id lpc_ich_ids[] = { - { PCI_VDEVICE(INTEL, 0x2917), LPC_ICH9ME}, - { PCI_VDEVICE(INTEL, 0x2918), LPC_ICH9}, - { PCI_VDEVICE(INTEL, 0x2919), LPC_ICH9M}, -+ { PCI_VDEVICE(INTEL, 0x3197), LPC_GLK}, -+ { PCI_VDEVICE(INTEL, 0x2b9c), LPC_COUGARMOUNTAIN}, - { PCI_VDEVICE(INTEL, 0x3a14), LPC_ICH10DO}, - { PCI_VDEVICE(INTEL, 0x3a16), LPC_ICH10R}, - { PCI_VDEVICE(INTEL, 0x3a18), LPC_ICH10}, -@@ -679,6 +697,7 @@ static const struct pci_device_id lpc_ich_ids[] = { - { PCI_VDEVICE(INTEL, 0x3b14), LPC_3420}, - { PCI_VDEVICE(INTEL, 0x3b16), LPC_3450}, - { PCI_VDEVICE(INTEL, 0x5031), LPC_EP80579}, -+ { PCI_VDEVICE(INTEL, 0x5ae8), LPC_APL}, - { PCI_VDEVICE(INTEL, 0x8c40), LPC_LPT}, - { PCI_VDEVICE(INTEL, 0x8c41), LPC_LPT}, - { PCI_VDEVICE(INTEL, 0x8c42), LPC_LPT}, --- -2.11.0 - diff --git a/patch/0048-mlxsw-core-Skip-thermal-zone-operations-initializati.patch b/patch/0048-mlxsw-core-Skip-thermal-zone-operations-initializati.patch deleted file mode 100644 index aed405ad7fd6..000000000000 --- a/patch/0048-mlxsw-core-Skip-thermal-zone-operations-initializati.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 2a2cd8876916ffaf530053a5e1f05940258eab86 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Tue, 5 Nov 2019 15:25:22 +0200 -Subject: [PATCH v1] mlxsw: core: Skip thermal zone operations initialization - -Skip thermal zones setting for modules to reduce probing time. -It is to be read anyway during thermal zone operations. -Skip thermal zone setting and reading during initialization. - -Decrease i2c controller polling time from 2000usec to 200usec -for the performance improvement. - -Signed-off-by: Vadim Pasternak ---- - drivers/i2c/busses/i2c-mlxcpld.c | 2 +- - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 21 +++++++++++++++++++++ - 2 files changed, 22 insertions(+), 1 deletion(-) - -diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c -index 2fd717d8dd30..41b57027e348 100644 ---- a/drivers/i2c/busses/i2c-mlxcpld.c -+++ b/drivers/i2c/busses/i2c-mlxcpld.c -@@ -51,7 +51,7 @@ - #define MLXCPLD_I2C_MAX_ADDR_LEN 4 - #define MLXCPLD_I2C_RETR_NUM 2 - #define MLXCPLD_I2C_XFER_TO 500000 /* usec */ --#define MLXCPLD_I2C_POLL_TIME 2000 /* usec */ -+#define MLXCPLD_I2C_POLL_TIME 200 /* usec */ - - /* LPC I2C registers */ - #define MLXCPLD_LPCI2C_CPBLTY_REG 0x0 -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index dfaad30ae960..08458e30e171 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -116,6 +116,7 @@ struct mlxsw_thermal { - u8 tz_gearbox_num; - unsigned int tz_highest_score; - struct thermal_zone_device *tz_highest_dev; -+ bool initializing; /* Driver is in initialization stage */ - }; - - static inline u8 mlxsw_state_to_duty(int state) -@@ -287,6 +288,12 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, - int temp; - int err; - -+ /* Do not read temperature in initialization stage. */ -+ if (thermal->initializing) { -+ *p_temp = 0; -+ return 0; -+ } -+ - mlxsw_reg_mtmp_pack(mtmp_pl, 0, false, false); - - err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); -@@ -458,6 +465,12 @@ static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, - int temp; - int err; - -+ /* Do not read temperature in initialization stage. */ -+ if (thermal->initializing) { -+ *p_temp = 0; -+ return 0; -+ } -+ - /* Read module temperature. */ - mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + - tz->module, false, false); -@@ -565,6 +578,12 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, - int temp; - int err; - -+ /* Do not read temperature in initialization stage. */ -+ if (thermal->initializing) { -+ *p_temp = 0; -+ return 0; -+ } -+ - index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module; - mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); - -@@ -919,6 +938,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core, - thermal->core = core; - thermal->bus_info = bus_info; - memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips)); -+ thermal->initializing = true; - - err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl); - if (err) { -@@ -994,6 +1014,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core, - goto err_unreg_modules_tzdev; - - thermal->mode = THERMAL_DEVICE_DISABLED; -+ thermal->initializing = false; - *p_thermal = thermal; - return 0; - --- -2.11.0 - diff --git a/patch/0049-thermal-Fix-use-after-free-when-unregistering-therma.patch b/patch/0049-thermal-Fix-use-after-free-when-unregistering-therma.patch deleted file mode 100644 index 1b48af7d84f0..000000000000 --- a/patch/0049-thermal-Fix-use-after-free-when-unregistering-therma.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 09246e73df900b96b534d6b7ccd26a681facb4d5 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Tue, 26 Nov 2019 09:09:45 +0200 -Subject: [PATCH backport bugfix from v5.3] thermal: Fix use-after-free when - unregistering thermal zone device - -Upstream commit 1851799e1d2978f68eea5d9dff322e121dcf59c1 -Author: Ido Schimmel -Date: Wed Jul 10 13:14:52 2019 +0300 - -thermal: Fix use-after-free when unregistering thermal zone device - -thermal_zone_device_unregister() cancels the delayed work that polls the -thermal zone, but it does not wait for it to finish. This is racy with -respect to the freeing of the thermal zone device, which can result in a -use-after-free [1]. - -Fix this by waiting for the delayed work to finish before freeing the -thermal zone device. Note that thermal_zone_device_set_polling() is -never invoked from an atomic context, so it is safe to call -cancel_delayed_work_sync() that can block. - -[1] -[ +0.002221] ================================================================== -[ +0.000064] BUG: KASAN: use-after-free in __mutex_lock+0x1076/0x11c0 -[ +0.000016] Read of size 8 at addr ffff8881e48e0450 by task kworker/1:0/17 - -[ +0.000023] CPU: 1 PID: 17 Comm: kworker/1:0 Not tainted 5.2.0-rc6-custom-02495-g8e73ca3be4af #1701 -[ +0.000010] Hardware name: Mellanox Technologies Ltd. MSN2100-CB2FO/SA001017, BIOS 5.6.5 06/07/2016 -[ +0.000016] Workqueue: events_freezable_power_ thermal_zone_device_check -[ +0.000012] Call Trace: -[ +0.000021] dump_stack+0xa9/0x10e -[ +0.000020] print_address_description.cold.2+0x9/0x25e -[ +0.000018] __kasan_report.cold.3+0x78/0x9d -[ +0.000016] kasan_report+0xe/0x20 -[ +0.000016] __mutex_lock+0x1076/0x11c0 -[ +0.000014] step_wise_throttle+0x72/0x150 -[ +0.000018] handle_thermal_trip+0x167/0x760 -[ +0.000019] thermal_zone_device_update+0x19e/0x5f0 -[ +0.000019] process_one_work+0x969/0x16f0 -[ +0.000017] worker_thread+0x91/0xc40 -[ +0.000014] kthread+0x33d/0x400 -[ +0.000015] ret_from_fork+0x3a/0x50 - -[ +0.000020] Allocated by task 1: -[ +0.000015] save_stack+0x19/0x80 -[ +0.000015] __kasan_kmalloc.constprop.4+0xc1/0xd0 -[ +0.000014] kmem_cache_alloc_trace+0x152/0x320 -[ +0.000015] thermal_zone_device_register+0x1b4/0x13a0 -[ +0.000015] mlxsw_thermal_init+0xc92/0x23d0 -[ +0.000014] __mlxsw_core_bus_device_register+0x659/0x11b0 -[ +0.000013] mlxsw_core_bus_device_register+0x3d/0x90 -[ +0.000013] mlxsw_pci_probe+0x355/0x4b0 -[ +0.000014] local_pci_probe+0xc3/0x150 -[ +0.000013] pci_device_probe+0x280/0x410 -[ +0.000013] really_probe+0x26a/0xbb0 -[ +0.000013] driver_probe_device+0x208/0x2e0 -[ +0.000013] device_driver_attach+0xfe/0x140 -[ +0.000013] __driver_attach+0x110/0x310 -[ +0.000013] bus_for_each_dev+0x14b/0x1d0 -[ +0.000013] driver_register+0x1c0/0x400 -[ +0.000015] mlxsw_sp_module_init+0x5d/0xd3 -[ +0.000014] do_one_initcall+0x239/0x4dd -[ +0.000013] kernel_init_freeable+0x42b/0x4e8 -[ +0.000012] kernel_init+0x11/0x18b -[ +0.000013] ret_from_fork+0x3a/0x50 - -[ +0.000015] Freed by task 581: -[ +0.000013] save_stack+0x19/0x80 -[ +0.000014] __kasan_slab_free+0x125/0x170 -[ +0.000013] kfree+0xf3/0x310 -[ +0.000013] thermal_release+0xc7/0xf0 -[ +0.000014] device_release+0x77/0x200 -[ +0.000014] kobject_put+0x1a8/0x4c0 -[ +0.000014] device_unregister+0x38/0xc0 -[ +0.000014] thermal_zone_device_unregister+0x54e/0x6a0 -[ +0.000014] mlxsw_thermal_fini+0x184/0x35a -[ +0.000014] mlxsw_core_bus_device_unregister+0x10a/0x640 -[ +0.000013] mlxsw_devlink_core_bus_device_reload+0x92/0x210 -[ +0.000015] devlink_nl_cmd_reload+0x113/0x1f0 -[ +0.000014] genl_family_rcv_msg+0x700/0xee0 -[ +0.000013] genl_rcv_msg+0xca/0x170 -[ +0.000013] netlink_rcv_skb+0x137/0x3a0 -[ +0.000012] genl_rcv+0x29/0x40 -[ +0.000013] netlink_unicast+0x49b/0x660 -[ +0.000013] netlink_sendmsg+0x755/0xc90 -[ +0.000013] __sys_sendto+0x3de/0x430 -[ +0.000013] __x64_sys_sendto+0xe2/0x1b0 -[ +0.000013] do_syscall_64+0xa4/0x4d0 -[ +0.000013] entry_SYSCALL_64_after_hwframe+0x49/0xbe - -[ +0.000017] The buggy address belongs to the object at ffff8881e48e0008 - which belongs to the cache kmalloc-2k of size 2048 -[ +0.000012] The buggy address is located 1096 bytes inside of - 2048-byte region [ffff8881e48e0008, ffff8881e48e0808) -[ +0.000007] The buggy address belongs to the page: -[ +0.000012] page:ffffea0007923800 refcount:1 mapcount:0 mapping:ffff88823680d0c0 index:0x0 compound_mapcount: 0 -[ +0.000020] flags: 0x200000000010200(slab|head) -[ +0.000019] raw: 0200000000010200 ffffea0007682008 ffffea00076ab808 ffff88823680d0c0 -[ +0.000016] raw: 0000000000000000 00000000000d000d 00000001ffffffff 0000000000000000 -[ +0.000007] page dumped because: kasan: bad access detected - -[ +0.000012] Memory state around the buggy address: -[ +0.000012] ffff8881e48e0300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb -[ +0.000012] ffff8881e48e0380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb -[ +0.000012] >ffff8881e48e0400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb -[ +0.000008] ^ -[ +0.000012] ffff8881e48e0480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb -[ +0.000012] ffff8881e48e0500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb -[ +0.000007] ================================================================== - -Fixes: b1569e99c795 ("ACPI: move thermal trip handling to generic thermal layer") -Reported-by: Jiri Pirko -Signed-off-by: Ido Schimmel -Acked-by: Jiri Pirko -Signed-off-by: Zhang Rui - -Signed-off-by: Vadim Pasternak ---- - drivers/thermal/thermal_core.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c -index 226b0b4aced6..7be7017f0d9e 100644 ---- a/drivers/thermal/thermal_core.c -+++ b/drivers/thermal/thermal_core.c -@@ -402,7 +402,7 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz, - mod_delayed_work(system_freezable_wq, &tz->poll_queue, - msecs_to_jiffies(delay)); - else -- cancel_delayed_work(&tz->poll_queue); -+ cancel_delayed_work_sync(&tz->poll_queue); - } - - static void monitor_thermal_zone(struct thermal_zone_device *tz) --- -2.11.0 - diff --git a/patch/0050-mlxsw-core-Drop-creation-of-thermal-to-hwmon-sysfs-i.patch b/patch/0050-mlxsw-core-Drop-creation-of-thermal-to-hwmon-sysfs-i.patch deleted file mode 100644 index cfdc3a09d566..000000000000 --- a/patch/0050-mlxsw-core-Drop-creation-of-thermal-to-hwmon-sysfs-i.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 539b36ac336510610b22b134284af5ecb2dc5009 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Thu, 28 Nov 2019 08:34:22 +0200 -Subject: [PATCH mlxsw: thermal] mlxsw: core: Drop creation of thermal to hwmon - sysfs interface - -Drop creation of "hwmon" interfaces from "thermal". These interfaces -are redundant, since they are created by "core_hwmon" component. -Creation of those interface from "thermal" just causes each temperature -input entry to by created twice in "hwmon" -Add thermal zone platform parameters definition with the field -"no_hwmon" set to true. Use it in thermal_zone_device_register(). -It will indicate that the "thermal" to "hwmon" sysfs interface is not -required. - -Signed-off-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 18 +++++++++++------- - 1 file changed, 11 insertions(+), 7 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index c4a426d01c5e..f234416305fd 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -411,6 +411,10 @@ static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev, - return 0; - } - -+struct thermal_zone_params mlxsw_thermal_params = { -+ .no_hwmon = true, -+}; -+ - static struct thermal_zone_device_ops mlxsw_thermal_ops = { - .bind = mlxsw_thermal_bind, - .unbind = mlxsw_thermal_unbind, -@@ -774,11 +778,11 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz) - snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d", - module_tz->module + 1); - module_tz->tzdev = thermal_zone_device_register(tz_name, -- MLXSW_THERMAL_NUM_TRIPS, -- MLXSW_THERMAL_TRIP_MASK, -- module_tz, -- &mlxsw_thermal_module_ops, -- NULL, 0, 0); -+ MLXSW_THERMAL_NUM_TRIPS, -+ MLXSW_THERMAL_TRIP_MASK, -+ module_tz, -+ &mlxsw_thermal_module_ops, -+ &mlxsw_thermal_params, 0, 0); - if (IS_ERR(module_tz->tzdev)) { - err = PTR_ERR(module_tz->tzdev); - return err; -@@ -898,7 +902,7 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) - MLXSW_THERMAL_TRIP_MASK, - gearbox_tz, - &mlxsw_thermal_gearbox_ops, -- NULL, 0, 0); -+ &mlxsw_thermal_params, 0, 0); - if (IS_ERR(gearbox_tz->tzdev)) - return PTR_ERR(gearbox_tz->tzdev); - -@@ -1052,7 +1056,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core, - MLXSW_THERMAL_TRIP_MASK, - thermal, - &mlxsw_thermal_ops, -- NULL, 0, -+ &mlxsw_thermal_params, 0, - thermal->polling_delay); - if (IS_ERR(thermal->tzdev)) { - err = PTR_ERR(thermal->tzdev); --- -2.11.0 - diff --git a/patch/0051-mlxsw-core-Skip-thermal-zones-threshold-setting-duri.patch b/patch/0051-mlxsw-core-Skip-thermal-zones-threshold-setting-duri.patch deleted file mode 100644 index 255ab716f910..000000000000 --- a/patch/0051-mlxsw-core-Skip-thermal-zones-threshold-setting-duri.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 031b57148672ff229d42fe4401e552c05e14f87a Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Sun, 1 Dec 2019 17:29:02 +0200 -Subject: [PATCH mlxsw: thermal] mlxsw: core: Skip thermal zones threshold - setting during initialization - -Skip modules' thermal zones threshold setting during initialization in -order to reduce driver's probing time. -This setting will be performed at the first operation with the thermal -zones. - -Signed-off-by: Vadim Pasternak vadimp@mellanox.com ---- - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index 7fbb7a24eb63..f234416305fd 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -813,8 +813,8 @@ mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, - sizeof(thermal->trips)); - /* Initialize all trip point. */ - mlxsw_thermal_module_trips_reset(module_tz); -- /* Update trip point according to the module data. */ -- return mlxsw_thermal_module_trips_update(dev, core, module_tz); -+ -+ return 0; - } - - static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz) --- -2.20.1 - diff --git a/patch/0052-platform-x86-mlx-platform-Add-more-detention-for-sys.patch b/patch/0052-platform-x86-mlx-platform-Add-more-detention-for-sys.patch deleted file mode 100644 index 19670ff7a4b2..000000000000 --- a/patch/0052-platform-x86-mlx-platform-Add-more-detention-for-sys.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 5df12806208285231c63a8757208648483aaf395 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Tue, 3 Dec 2019 16:02:08 +0200 -Subject: [PATCH platform] platform/x86: mlx-platform: Add more detention for - system attributes - -Add new attribute for "next-generation" type systems: -"reset_sw_pwr_off" for indication of reset caused by -software power off command. - -Signed-off-by: Vadim Pasternak ---- - drivers/platform/x86/mlx-platform.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index c3e75b26fe0b..765baf99de60 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -1335,6 +1335,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { - .mask = GENMASK(7, 0) & ~BIT(1), - .mode = 0444, - }, -+ { -+ .label = "reset_sw_pwr_off", -+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(2), -+ .mode = 0444, -+ }, - { - .label = "reset_comex_thermal", - .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, --- -2.20.1 - diff --git a/patch/0053-firmware-dmi-Add-access-to-the-SKU-ID-string-backpor.patch b/patch/0053-firmware-dmi-Add-access-to-the-SKU-ID-string-backpor.patch deleted file mode 100644 index 2ac84540deb9..000000000000 --- a/patch/0053-firmware-dmi-Add-access-to-the-SKU-ID-string-backpor.patch +++ /dev/null @@ -1,88 +0,0 @@ -From acc9225e1db4bfc710c83c25f34b2b226060c350 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Thu, 23 Jan 2020 14:58:38 +0200 -Subject: [PATCH backport] firmware: dmi: Add access to the SKU ID string - backport - -Backport of two below upstream commits. - -commit b23908d3c48a37c46c6a26df2cdeab1610b360ba -Author: Simon Glass -Date: Sun Jun 17 14:09:42 2018 +0200 - - firmware: dmi: Add access to the SKU ID string - - This is used in some systems from user space for determining the -identity - of the device. - - Expose this as a file so that that user-space tools don't need to -read - from /sys/firmware/dmi/tables/DMI - - Signed-off-by: Simon Glass - Signed-off-by: Jean Delvare - -commit b23908d3c48a37c46c6a26df2cdeab1610b360ba -Author: Simon Glass -Date: Sun Jun 17 14:09:42 2018 +0200 - -firmware: dmi: Add access to the SKU ID string - - This is used in some systems from user space for determining the -identity - of the device. - - Expose this as a file so that that user-space tools don't need to -read - from /sys/firmware/dmi/tables/DMI - - Signed-off-by: Simon Glass - Signed-off-by: Jean Delvare - -Signed-off-by: Vadim Pasternak ---- - drivers/firmware/dmi-id.c | 1 + - drivers/firmware/dmi_scan.c | 1 + - include/linux/mod_devicetable.h | 1 + - 3 files changed, 3 insertions(+) - -diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c -index dc269cb288c2..5c864ebe1127 100644 ---- a/drivers/firmware/dmi-id.c -+++ b/drivers/firmware/dmi-id.c -@@ -47,6 +47,7 @@ DEFINE_DMI_ATTR_WITH_SHOW(product_name, 0444, DMI_PRODUCT_NAME); - DEFINE_DMI_ATTR_WITH_SHOW(product_version, 0444, DMI_PRODUCT_VERSION); - DEFINE_DMI_ATTR_WITH_SHOW(product_serial, 0400, DMI_PRODUCT_SERIAL); - DEFINE_DMI_ATTR_WITH_SHOW(product_uuid, 0400, DMI_PRODUCT_UUID); -+DEFINE_DMI_ATTR_WITH_SHOW(product_sku, 0444, DMI_PRODUCT_SKU); - DEFINE_DMI_ATTR_WITH_SHOW(product_family, 0400, DMI_PRODUCT_FAMILY); - DEFINE_DMI_ATTR_WITH_SHOW(board_vendor, 0444, DMI_BOARD_VENDOR); - DEFINE_DMI_ATTR_WITH_SHOW(board_name, 0444, DMI_BOARD_NAME); -diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c -index 150b923ef86d..d2a85a2e5b08 100644 ---- a/drivers/firmware/dmi_scan.c -+++ b/drivers/firmware/dmi_scan.c -@@ -426,6 +426,7 @@ static void __init dmi_decode(const struct dmi_header *dm, void *dummy) - dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); - dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7); - dmi_save_uuid(dm, DMI_PRODUCT_UUID, 8); -+ dmi_save_ident(dm, DMI_PRODUCT_SKU, 25); - dmi_save_ident(dm, DMI_PRODUCT_FAMILY, 26); - break; - case 2: /* Base Board Information */ -diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h -index 616b31a1495d..103c14049a76 100644 ---- a/include/linux/mod_devicetable.h -+++ b/include/linux/mod_devicetable.h -@@ -456,6 +456,7 @@ enum dmi_field { - DMI_PRODUCT_VERSION, - DMI_PRODUCT_SERIAL, - DMI_PRODUCT_UUID, -+ DMI_PRODUCT_SKU, - DMI_PRODUCT_FAMILY, - DMI_BOARD_VENDOR, - DMI_BOARD_NAME, --- -2.20.1 - diff --git a/patch/0054-platform-x86-mlx-platform-Modify-setting-for-new-sys.patch b/patch/0054-platform-x86-mlx-platform-Modify-setting-for-new-sys.patch deleted file mode 100644 index d4b9a98f2bde..000000000000 --- a/patch/0054-platform-x86-mlx-platform-Modify-setting-for-new-sys.patch +++ /dev/null @@ -1,420 +0,0 @@ -From 7facfc1c55a37b8f28d75d0f2ddf51a0f892730a Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Tue, 17 Dec 2019 15:50:22 +0000 -Subject: [PATCH platform backport 1/2] platform/x86: mlx-platform: Modify - setting for new system type - -Modify setting for new Mellanox system types of basic class VMOD0009, -containing Mellanox systems equipped with the switch devices -Spectrum 1 (32x100GbE Ethernet switch) and Switch-IB/Switch-IB2 -(36x100Gbe InfiniBand switch). -These are the Top of the Rack system, equipped with Mellanox Comex -card. - -Signed-off-by: Vadim Pasternak ---- - drivers/platform/x86/mlx-platform.c | 194 ++++++++++++++++++++++++++++++------ - 1 file changed, 165 insertions(+), 29 deletions(-) - -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index 765baf99de60..1a4fecb770ad 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -90,6 +90,7 @@ - #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_PIO_OFFSET 0x10000UL - #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ -@@ -98,6 +99,9 @@ - #define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ - MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \ - 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_PIO_OFFSET) - - /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ - #define MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF 0x04 -@@ -110,7 +114,7 @@ - #define MLXPLAT_CPLD_AGGR_ASIC_MASK_NG 0x01 - #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04 - #define MLXPLAT_CPLD_AGGR_MASK_COMEX BIT(0) --#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xe1 -+#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 - #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) -@@ -131,6 +135,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 - - /* Number of channels in group */ - #define MLXPLAT_CPLD_GRP_CHNL_NUM 8 -@@ -138,9 +143,10 @@ - /* Start channel numbers */ - #define MLXPLAT_CPLD_CH1 2 - #define MLXPLAT_CPLD_CH2 10 -+#define MLXPLAT_CPLD_CH3 18 - - /* Number of LPC attached MUX platform devices */ --#define MLXPLAT_CPLD_LPC_MUX_DEVS 2 -+#define MLXPLAT_CPLD_LPC_MUX_DEVS 3 - - /* Hotplug devices adapter numbers */ - #define MLXPLAT_CPLD_NR_NONE -1 -@@ -221,7 +227,7 @@ static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = { - static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; - - /* Platform mux data */ --static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { -+static struct i2c_mux_reg_platform_data mlxplat_default_mux_data[] = { - { - .parent = 1, - .base_nr = MLXPLAT_CPLD_CH1, -@@ -241,6 +247,40 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { - - }; - -+/* Platform mux configuration variables */ -+static int mlxplat_max_adap_num; -+static int mlxplat_mux_num; -+static struct i2c_mux_reg_platform_data *mlxplat_mux_data; -+ -+/* Platform extended mux data */ -+static struct i2c_mux_reg_platform_data mlxplat_extended_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, -+ }, -+ { -+ .parent = 1, -+ .base_nr = MLXPLAT_CPLD_CH2, -+ .write_only = 1, -+ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG3, -+ .reg_size = 1, -+ .idle_in_use = 1, -+ }, -+ { -+ .parent = 1, -+ .base_nr = MLXPLAT_CPLD_CH3, -+ .write_only = 1, -+ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, -+ .reg_size = 1, -+ .idle_in_use = 1, -+ }, -+ -+}; -+ - /* Platform hotplug devices */ - static struct i2c_board_info mlxplat_mlxcpld_psu[] = { - { -@@ -1037,6 +1077,80 @@ static struct mlxreg_core_platform_data mlxplat_default_ng_led_data = { - .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data), - }; - -+/* Platform led for Comex based 100GbE systems */ -+static struct mlxreg_core_data mlxplat_mlxcpld_comex_100G_led_data[] = { -+ { -+ .label = "status:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "status:red", -+ .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:red", -+ .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, -+ }, -+ { -+ .label = "fan1:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan2:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan2:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan3:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan3:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan4:green", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "fan4:red", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, -+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, -+ }, -+ { -+ .label = "uid:blue", -+ .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET, -+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, -+ }, -+}; -+ -+static struct mlxreg_core_platform_data mlxplat_comex_100G_led_data = { -+ .data = mlxplat_mlxcpld_comex_100G_led_data, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_comex_100G_led_data), -+}; -+ - /* Platform register access default */ - static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { - { -@@ -1661,6 +1775,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_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_ASIC_EVENT_OFFSET: - case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: - case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: -@@ -1710,6 +1825,8 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: - case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET: - case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRCX_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: -@@ -1779,6 +1896,8 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: - case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET: - case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_AGGRCX_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: -@@ -1920,7 +2039,10 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) - { - int i; - -- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); 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_default_channels[i]; - mlxplat_mux_data[i].n_values = - ARRAY_SIZE(mlxplat_default_channels[i]); -@@ -1933,13 +2055,16 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) - mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; - - return 1; --}; -+} - - static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) - { - int i; - -- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); 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); -@@ -1952,13 +2077,16 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) - mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; - - return 1; --}; -+} - - static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) - { - int i; - -- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); 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); -@@ -1971,13 +2099,16 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) - mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; - - return 1; --}; -+} - - static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) - { - int i; - -- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); 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); -@@ -1990,13 +2121,16 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) - mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; - - return 1; --}; -+} - - static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) - { - int i; - -- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); 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); -@@ -2013,27 +2147,31 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) - mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng; - - return 1; --}; -+} - - static int __init mlxplat_dmi_comex_matched(const struct dmi_system_id *dmi) - { - int i; - -- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -+ mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_EXT_ADAPTER_NUM; -+ mlxplat_mux_num = ARRAY_SIZE(mlxplat_extended_mux_data); -+ mlxplat_mux_data = mlxplat_extended_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_comex_data; -- mlxplat_hotplug->deferred_nr = -- mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; -- mlxplat_led = &mlxplat_default_led_data; -- mlxplat_regs_io = &mlxplat_default_regs_io_data; -+ mlxplat_hotplug->deferred_nr = MLXPLAT_CPLD_MAX_PHYS_EXT_ADAPTER_NUM; -+ mlxplat_led = &mlxplat_comex_100G_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_regmap_config = &mlxplat_mlxcpld_regmap_config_comex; - - return 1; --}; -+} - - static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { - { -@@ -2168,7 +2306,7 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr) - /* Scan adapters from expected id to verify it is free. */ - *nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; - for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i < -- MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) { -+ mlxplat_max_adap_num; i++) { - search_adap = i2c_get_adapter(i); - if (search_adap) { - i2c_put_adapter(search_adap); -@@ -2182,12 +2320,12 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr) - } - - /* Return with error if free id for adapter is not found. */ -- if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) -+ if (i == mlxplat_max_adap_num) - return -ENODEV; - - /* Shift adapter ids, since expected parent adapter is not free. */ - *nr = i; -- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -+ 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; -@@ -2243,7 +2381,7 @@ static int __init mlxplat_init(void) - if (nr < 0) - goto fail_alloc; - -- nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr; -+ nr = (nr == mlxplat_max_adap_num) ? -1 : nr; - if (mlxplat_i2c) - mlxplat_i2c->regmap = priv->regmap; - priv->pdev_i2c = platform_device_register_resndata( -@@ -2256,7 +2394,7 @@ static int __init mlxplat_init(void) - goto fail_alloc; - } - -- for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { -+ 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, -@@ -2381,10 +2519,8 @@ static void __exit mlxplat_exit(void) - struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); - int i; - -- for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) { -- if (mlxplat_wd_data[i]) -- platform_device_unregister(priv->pdev_wd[i]); -- } -+ for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) -+ platform_device_unregister(priv->pdev_wd[i]); - if (priv->pdev_fan) - platform_device_unregister(priv->pdev_fan); - if (priv->pdev_io_regs) -@@ -2392,7 +2528,7 @@ static void __exit mlxplat_exit(void) - platform_device_unregister(priv->pdev_led); - platform_device_unregister(priv->pdev_hotplug); - -- for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) -+ for (i = mlxplat_mux_num - 1; i >= 0 ; i--) - platform_device_unregister(priv->pdev_mux[i]); - - platform_device_unregister(priv->pdev_i2c); --- -2.11.0 - diff --git a/patch/0055-platform-x86-mlx-platform-Add-support-for-next-gener.patch b/patch/0055-platform-x86-mlx-platform-Add-support-for-next-gener.patch deleted file mode 100644 index 13cd1bd46a86..000000000000 --- a/patch/0055-platform-x86-mlx-platform-Add-support-for-next-gener.patch +++ /dev/null @@ -1,486 +0,0 @@ -From 4da715b3bea946b1f9d43a7c95c54be4dcb057f2 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Thu, 2 Jan 2020 06:58:09 +0000 -Subject: [PATCH platform] platform/x86: mlx-platform: Add support for next - generation systems - -Add support for new Mellanox system types of basic class VMOD0010, -containing new Mellanox systems equipped with new switch device -Spectrum 3 (32x400GbE/64x200G/128x100G Ethernet switch). -These are the Top of the Rack 1U/2U/4U systems, equipped with -Mellanox Comex card and with the switch board with Mellanox Spectrum-3 -device. -This class of devices can be equipped with two PS units for 1U/2U or -with four PS units for 4U systems. - -Signed-off-by: Vadim Pasternak ---- - drivers/platform/mellanox/mlxreg-hotplug.c | 14 ++ - drivers/platform/x86/mlx-platform.c | 265 +++++++++++++++++++++++++++++ - include/linux/platform_data/mlxreg.h | 2 + - 3 files changed, 281 insertions(+) - -diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c -index f85a1b9d129b..bd34aac2426e 100644 ---- a/drivers/platform/mellanox/mlxreg-hotplug.c -+++ b/drivers/platform/mellanox/mlxreg-hotplug.c -@@ -504,6 +504,20 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) - item = pdata->items; - - for (i = 0; i < pdata->counter; i++, item++) { -+ if (item->capability) { -+ /* -+ * Read group capability register to get actual number -+ * of interrupt capable components and set group mask -+ * accordingly. -+ */ -+ ret = regmap_read(priv->regmap, item->capability, -+ ®val); -+ if (ret) -+ goto out; -+ -+ item->mask = GENMASK((regval & item->mask) - 1, 0); -+ } -+ - /* Clear group presense event. */ - ret = regmap_write(priv->regmap, item->reg + - MLXREG_HOTPLUG_EVENT_OFF, 0); -diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c -index 1a4fecb770ad..c27548fd386a 100644 ---- a/drivers/platform/x86/mlx-platform.c -+++ b/drivers/platform/x86/mlx-platform.c -@@ -35,6 +35,8 @@ - #define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET 0x23 - #define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET 0x24 - #define MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION 0x2a -+#define MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET 0x2b -+#define MLXPLAT_CPLD_LPC_REG_GP0_OFFSET 0x2e - #define MLXPLAT_CPLD_LPC_REG_GP1_OFFSET 0x30 - #define MLXPLAT_CPLD_LPC_REG_WP1_OFFSET 0x31 - #define MLXPLAT_CPLD_LPC_REG_GP2_OFFSET 0x32 -@@ -70,6 +72,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_UFM_VERSION_OFFSET 0xe2 - #define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3 - #define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4 - #define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5 -@@ -87,6 +90,9 @@ - #define MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET 0xf6 - #define MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET 0xf7 - #define MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET 0xf8 -+#define MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET 0xf9 -+#define MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET 0xfb -+#define MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET 0xfc - #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 - #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb - #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda -@@ -118,11 +124,16 @@ - #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) -+#define MLXPLAT_CPLD_PSU_EXT_MASK GENMASK(3, 0) -+#define MLXPLAT_CPLD_PWR_EXT_MASK GENMASK(3, 0) - #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) - #define MLXPLAT_CPLD_ASIC_MASK GENMASK(1, 0) - #define MLXPLAT_CPLD_FAN_NG_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) -+#define MLXPLAT_CPLD_I2C_CAP_BIT 0x04 -+#define MLXPLAT_CPLD_I2C_CAP_MASK GENMASK(5, MLXPLAT_CPLD_I2C_CAP_BIT) - - /* Masks for aggregation for comex carriers */ - #define MLXPLAT_CPLD_AGGR_MASK_CARRIER BIT(1) -@@ -152,6 +163,7 @@ - #define MLXPLAT_CPLD_NR_NONE -1 - #define MLXPLAT_CPLD_PSU_DEFAULT_NR 10 - #define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4 -+#define MLXPLAT_CPLD_PSU_MSNXXXX_NR2 3 - #define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11 - #define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12 - #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13 -@@ -201,8 +213,24 @@ static const struct resource mlxplat_lpc_resources[] = { - IORESOURCE_IO), - }; - -+/* Platform i2c next generation systems data */ -+static struct mlxreg_core_data mlxplat_mlxcpld_i2c_ng_items_data[] = { -+ { -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, -+ .mask = MLXPLAT_CPLD_I2C_CAP_MASK, -+ .bit = MLXPLAT_CPLD_I2C_CAP_BIT, -+ }, -+}; -+ -+static struct mlxreg_core_item mlxplat_mlxcpld_i2c_ng_items[] = { -+ { -+ .data = mlxplat_mlxcpld_i2c_ng_items_data, -+ }, -+}; -+ - /* Platform next generation systems i2c data */ - static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = { -+ .items = mlxplat_mlxcpld_i2c_ng_items, - .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, - .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX, - .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET, -@@ -836,6 +864,116 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { - .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[] = { -+ { -+ .label = "psu1", -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, -+ .mask = BIT(0), -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, -+ }, -+ { -+ .label = "psu2", -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, -+ .mask = BIT(1), -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, -+ }, -+ { -+ .label = "psu3", -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, -+ .mask = BIT(2), -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, -+ }, -+ { -+ .label = "psu4", -+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, -+ .mask = BIT(3), -+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, -+ }, -+}; -+ -+static struct mlxreg_core_data mlxplat_mlxcpld_ext_pwr_items_data[] = { -+ { -+ .label = "pwr1", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, -+ .mask = BIT(0), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[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[1], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, -+ }, -+ { -+ .label = "pwr3", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, -+ .mask = BIT(2), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR2, -+ }, -+ { -+ .label = "pwr4", -+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, -+ .mask = BIT(3), -+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], -+ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR2, -+ }, -+}; -+ -+static struct mlxreg_core_item mlxplat_mlxcpld_ext_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_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, -+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_ext_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[] = { - { -@@ -1344,6 +1482,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_regs_io_data[] = { - .mode = 0200, - }, - { -+ .label = "select_iio", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(6), -+ .mode = 0644, -+ }, -+ { - .label = "asic_health", - .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, - .mask = MLXPLAT_CPLD_ASIC_MASK, -@@ -1432,6 +1576,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { - .mode = 0444, - }, - { -+ .label = "reset_platform", -+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(4), -+ .mode = 0444, -+ }, -+ { -+ .label = "reset_soc", -+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(5), -+ .mode = 0444, -+ }, -+ { - .label = "reset_comex_wd", - .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, - .mask = GENMASK(7, 0) & ~BIT(6), -@@ -1468,6 +1624,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { - .mode = 0444, - }, - { -+ .label = "reset_ac_pwr_fail", -+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(6), -+ .mode = 0444, -+ }, -+ { - .label = "psu1_on", - .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, - .mask = GENMASK(7, 0) & ~BIT(0), -@@ -1510,6 +1672,43 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { - .bit = GENMASK(7, 0), - .mode = 0444, - }, -+ { -+ .label = "voltreg_update_status", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET, -+ .mask = MLXPLAT_CPLD_VOLTREG_UPD_MASK, -+ .bit = 5, -+ .mode = 0444, -+ }, -+ { -+ .label = "vpd_wp", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(3), -+ .mode = 0644, -+ }, -+ { -+ .label = "pcie_asic_reset_dis", -+ .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, -+ .mask = GENMASK(7, 0) & ~BIT(4), -+ .mode = 0644, -+ }, -+ { -+ .label = "config1", -+ .reg = MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET, -+ .bit = GENMASK(7, 0), -+ .mode = 0444, -+ }, -+ { -+ .label = "config2", -+ .reg = MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET, -+ .bit = GENMASK(7, 0), -+ .mode = 0444, -+ }, -+ { -+ .label = "ufm_version", -+ .reg = MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET, -+ .bit = GENMASK(7, 0), -+ .mode = 0444, -+ }, - }; - - static struct mlxreg_core_platform_data mlxplat_default_ng_regs_io_data = { -@@ -1768,6 +1967,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: - case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: - case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET: - case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: -@@ -1815,6 +2015,8 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: - case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: - case MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION: -+ case MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET: - case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: -@@ -1867,6 +2069,10 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET: - case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET: - case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET: - return true; - } - return false; -@@ -1888,6 +2094,8 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: - case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: - case MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION: -+ case MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET: - case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: - case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: - case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: -@@ -1932,6 +2140,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) - case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET: - case MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET: - case MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET: -+ case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET: - return true; - } - return false; -@@ -1955,6 +2167,13 @@ static const struct reg_default mlxplat_mlxcpld_regmap_comex_default[] = { - { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, - }; - -+static const struct reg_default mlxplat_mlxcpld_regmap_ng400[] = { -+ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, -+ { MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, 0x00 }, -+ { MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, 0x00 }, -+ { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 }, -+}; -+ - struct mlxplat_mlxcpld_regmap_context { - void __iomem *base; - }; -@@ -2021,6 +2240,20 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config_comex = { - .reg_write = mlxplat_mlxcpld_reg_write, - }; - -+static const struct regmap_config mlxplat_mlxcpld_regmap_config_ng400 = { -+ .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_ng400, -+ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_ng400), -+ .reg_read = mlxplat_mlxcpld_reg_read, -+ .reg_write = mlxplat_mlxcpld_reg_write, -+}; -+ - static struct resource mlxplat_mlxcpld_resources[] = { - [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"), - }; -@@ -2173,6 +2406,32 @@ static int __init mlxplat_dmi_comex_matched(const struct dmi_system_id *dmi) - return 1; - } - -+static int __init mlxplat_dmi_ng400_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_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_mlxcpld_regmap_config_ng400; -+ -+ return 1; -+} -+ - static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { - { - .callback = mlxplat_dmi_default_matched, -@@ -2217,6 +2476,12 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { - }, - }, - { -+ .callback = mlxplat_dmi_ng400_matched, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0010"), -+ }, -+ }, -+ { - .callback = mlxplat_dmi_msn274x_matched, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), -diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h -index 6d54fe3bcac9..b8da8aef2446 100644 ---- a/include/linux/platform_data/mlxreg.h -+++ b/include/linux/platform_data/mlxreg.h -@@ -101,6 +101,7 @@ struct mlxreg_core_data { - * @aggr_mask: group aggregation mask; - * @reg: group interrupt status register; - * @mask: group interrupt mask; -+ * @capability: group capability register; - * @cache: last status value for elements fro the same group; - * @count: number of available elements in the group; - * @ind: element's index inside the group; -@@ -112,6 +113,7 @@ struct mlxreg_core_item { - u32 aggr_mask; - u32 reg; - u32 mask; -+ u32 capability; - u32 cache; - u8 count; - u8 ind; --- -2.11.0 - diff --git a/patch/0056-mlxsw-core-Add-support-for-new-hardware-device-types.patch b/patch/0056-mlxsw-core-Add-support-for-new-hardware-device-types.patch deleted file mode 100644 index 8f64b9baff12..000000000000 --- a/patch/0056-mlxsw-core-Add-support-for-new-hardware-device-types.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 78c5e6e6d39427868a33d86cc83c1646503a1d78 Mon Sep 17 00:00:00 2001 -From: Vadim Pasternak -Date: Thu, 23 Jan 2020 20:17:36 +0000 -Subject: [PATCH mlxsw] mlxsw: core: Add support for new hardware device types - -Add validation for new device types, provided by MGPIR -register. - -Signed-off-by: Vadim Pasternak ---- - drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 6 ++++-- - drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 8 ++++++-- - drivers/net/ethernet/mellanox/mlxsw/reg.h | 3 +++ - 3 files changed, 13 insertions(+), 4 deletions(-) - -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -index 9cb19ec47e4d..cd1d371edfcf 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c -@@ -575,6 +575,7 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) - - static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) - { -+ 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]; -@@ -586,8 +587,9 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) - if (err) - return 0; - -- mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL, NULL); -- if (!gbox_num) -+ mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, NULL); -+ if ((device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE) || -+ !gbox_num) - return 0; - - index = mlxsw_hwmon->module_sensor_count; -diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -index f234416305fd..690ae0f1820e 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c -@@ -920,8 +920,10 @@ static int - mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, - struct mlxsw_thermal *thermal) - { -+ enum mlxsw_reg_mgpir_device_type device_type; - struct mlxsw_thermal_module *gearbox_tz; - char mgpir_pl[MLXSW_REG_MGPIR_LEN]; -+ u8 num_of_device; - int i; - int err; - -@@ -933,11 +935,13 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, - if (err) - return 0; - -- mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL, -+ mlxsw_reg_mgpir_unpack(mgpir_pl, &num_of_device, &device_type, NULL, - NULL); -- if (!thermal->tz_gearbox_num) -+ if ((device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE) || -+ !num_of_device) - return 0; - -+ thermal->tz_gearbox_num = num_of_device; - thermal->tz_gearbox_arr = kcalloc(thermal->tz_gearbox_num, - sizeof(*thermal->tz_gearbox_arr), - GFP_KERNEL); -diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h -index 8d7a58472799..43e73701a125 100644 ---- a/drivers/net/ethernet/mellanox/mlxsw/reg.h -+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h -@@ -8601,6 +8601,9 @@ MLXSW_REG_DEFINE(mgpir, MLXSW_REG_MGPIR_ID, MLXSW_REG_MGPIR_LEN); - enum mlxsw_reg_mgpir_device_type { - MLXSW_REG_MGPIR_DEVICE_TYPE_NONE, - MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE, -+ MLXSW_REG_MGPIR_DEVICE_TYPE_TILE, -+ MLXSW_REG_MGPIR_DEVICE_TYPE_AGBM, -+ MLXSW_REG_MGPIR_DEVICE_TYPE_XM, - }; - - /* device_type --- -2.11.0 - diff --git a/patch/bridge-add-per-port-broadcast-flood-flag.patch b/patch/bridge-add-per-port-broadcast-flood-flag.patch deleted file mode 100644 index 7f46d25e1951..000000000000 --- a/patch/bridge-add-per-port-broadcast-flood-flag.patch +++ /dev/null @@ -1,120 +0,0 @@ -commit 948010ebbfb6bca0b6345fb4e944ed9d60be03a1 -Author: Jipan Yang -Date: Sat Jan 6 15:22:54 2018 -0800 - - Backport bridge port broadcast flood flag support, excluding netlink parts. - - Signed-off-by: Jipan Yang - - commit 99f906e9ad7b6e79ffeda30f45906a8448b9d6a2 - Author: Mike Manning - Date: Wed Apr 26 14:48:09 2017 +0100 - - bridge: add per-port broadcast flood flag - - Support for l2 multicast flood control was added in commit b6cb5ac8331b - ("net: bridge: add per-port multicast flood flag"). It allows broadcast - as it was introduced specifically for unknown multicast flood control. - But as broadcast is a special case of multicast, this may also need to - be disabled. For this purpose, introduce a flag to disable the flooding - of received l2 broadcasts. This approach is backwards compatible and - provides flexibility in filtering for the desired packet types. - - Cc: Nikolay Aleksandrov - Signed-off-by: Mike Manning - Reviewed-by: Nikolay Aleksandrov - Signed-off-by: David S. Miller - -diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h -index c6587c0..da20877 100644 ---- a/include/linux/if_bridge.h -+++ b/include/linux/if_bridge.h -@@ -47,6 +47,8 @@ struct br_ip_list { - #define BR_PROXYARP_WIFI BIT(10) - #define BR_MCAST_FLOOD BIT(11) - -+#define BR_BCAST_FLOOD BIT(14) -+ - #define BR_DEFAULT_AGEING_TIME (300 * HZ) - - extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); -diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h -index b4fba66..d92f9df 100644 ---- a/include/uapi/linux/if_link.h -+++ b/include/uapi/linux/if_link.h -@@ -319,6 +319,7 @@ enum { - IFLA_BRPORT_MULTICAST_ROUTER, - IFLA_BRPORT_PAD, - IFLA_BRPORT_MCAST_FLOOD, -+ IFLA_BRPORT_BCAST_FLOOD, - __IFLA_BRPORT_MAX - }; - #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) -diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c -index 8498e35..3b827c8 100644 ---- a/net/bridge/br_forward.c -+++ b/net/bridge/br_forward.c -@@ -183,13 +183,23 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb, - struct net_bridge_port *p; - - list_for_each_entry_rcu(p, &br->port_list, list) { -- /* Do not flood unicast traffic to ports that turn it off */ -- if (pkt_type == BR_PKT_UNICAST && !(p->flags & BR_FLOOD)) -- continue; -- /* Do not flood if mc off, except for traffic we originate */ -- if (pkt_type == BR_PKT_MULTICAST && -- !(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev) -- continue; -+ /* Do not flood unicast traffic to ports that turn it off, nor -+ * other traffic if flood off, except for traffic we originate -+ */ -+ switch (pkt_type) { -+ case BR_PKT_UNICAST: -+ if (!(p->flags & BR_FLOOD)) -+ continue; -+ break; -+ case BR_PKT_MULTICAST: -+ if (!(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev) -+ continue; -+ break; -+ case BR_PKT_BROADCAST: -+ if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev) -+ continue; -+ break; -+ } - - /* Do not flood to ports that enable proxy ARP */ - if (p->flags & BR_PROXYARP) -diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c -index ed0dd33..d175e42 100644 ---- a/net/bridge/br_if.c -+++ b/net/bridge/br_if.c -@@ -362,7 +362,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, - p->path_cost = port_cost(dev); - p->priority = 0x8000 >> BR_PORT_BITS; - p->port_no = index; -- p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD; -+ p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; - br_init_port(p); - br_set_state(p, BR_STATE_DISABLED); - br_stp_port_timer_init(p); -diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c -index 8bd5696..09e44d6 100644 ---- a/net/bridge/br_sysfs_if.c -+++ b/net/bridge/br_sysfs_if.c -@@ -172,6 +172,7 @@ BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD); - BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP); - BRPORT_ATTR_FLAG(proxyarp_wifi, BR_PROXYARP_WIFI); - BRPORT_ATTR_FLAG(multicast_flood, BR_MCAST_FLOOD); -+BRPORT_ATTR_FLAG(broadcast_flood, BR_BCAST_FLOOD); - - #ifdef CONFIG_BRIDGE_IGMP_SNOOPING - static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) -@@ -218,6 +219,7 @@ static const struct brport_attribute *brport_attrs[] = { - &brport_attr_proxyarp, - &brport_attr_proxyarp_wifi, - &brport_attr_multicast_flood, -+ &brport_attr_broadcast_flood, - NULL - }; - diff --git a/patch/config-arista-7060-cx32s.patch b/patch/config-arista-7060-cx32s.patch index 78ae4b934392..91ecbf1eb840 100644 --- a/patch/config-arista-7060-cx32s.patch +++ b/patch/config-arista-7060-cx32s.patch @@ -8,10 +8,10 @@ From: Guohan Lu 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index c9881a9..b0402b3 100644 +index 81d8f192a..045f760ee 100644 --- a/debian/build/build_amd64_none_amd64/.config +++ b/debian/build/build_amd64_none_amd64/.config -@@ -3912,7 +3912,7 @@ CONFIG_SENSORS_MAX6639=m +@@ -4238,7 +4238,7 @@ CONFIG_SENSORS_MAX6639=m CONFIG_SENSORS_MAX6642=m CONFIG_SENSORS_MAX6650=m CONFIG_SENSORS_MAX6620=m @@ -19,4 +19,4 @@ index c9881a9..b0402b3 100644 +CONFIG_SENSORS_MAX6697=m # CONFIG_SENSORS_MAX31790 is not set # CONFIG_SENSORS_MCP3021 is not set - CONFIG_SENSORS_MENF21BMC_HWMON=m + # CONFIG_SENSORS_TC654 is not set diff --git a/patch/config-arista-dps1900.patch b/patch/config-arista-dps1900.patch index c5aca6fce5e8..15c1284fd43f 100644 --- a/patch/config-arista-dps1900.patch +++ b/patch/config-arista-dps1900.patch @@ -8,14 +8,14 @@ From: gulv 1 file changed, 1 insertion(+) diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index 29bcb1f..d59a9e0 100644 +index 9b25a9ed9..81d8f192a 100644 --- a/debian/build/build_amd64_none_amd64/.config +++ b/debian/build/build_amd64_none_amd64/.config -@@ -3956,6 +3956,7 @@ CONFIG_SENSORS_DNI_DPS460=m - CONFIG_SENSORS_TPS53679=m - CONFIG_SENSORS_UCD9000=m - CONFIG_SENSORS_UCD9200=m +@@ -4198,6 +4198,7 @@ CONFIG_SENSORS_DS620=m + CONFIG_SENSORS_DS1621=m + CONFIG_SENSORS_DELL_SMM=m + CONFIG_SENSORS_DNI_DPS460=m +CONFIG_SENSORS_DPS1900=m - # CONFIG_SENSORS_ZL6100 is not set - # CONFIG_SENSORS_SHT15 is not set - CONFIG_SENSORS_SHT21=m + CONFIG_SENSORS_I5K_AMB=m + CONFIG_SENSORS_F71805F=m + CONFIG_SENSORS_F71882FG=m diff --git a/patch/config-cig-cs6436-serail_new.patch b/patch/config-cig-cs6436-serail_new.patch old mode 100755 new mode 100644 index f7ca5ae453a7..b4b8349c2820 --- a/patch/config-cig-cs6436-serail_new.patch +++ b/patch/config-cig-cs6436-serail_new.patch @@ -1,10 +1,22 @@ ---- a/debian/build/build_amd64_none_amd64/.config 2019-02-01 22:54:58.401770842 +0800 -+++ b/debian/build/build_amd64_none_amd64/.config 2019-02-01 23:00:57.297956961 +0800 -@@ -3477,7 +3477,7 @@ CONFIG_SERIAL_8250_RSA=y - # CONFIG_SERIAL_8250_FSL is not set +enale CONFIG_SERIAL_8250_LPSS + +From: Guohan + + +--- + debian/build/build_amd64_none_amd64/.config | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config +index cba593aa3..978a6d49d 100644 +--- a/debian/build/build_amd64_none_amd64/.config ++++ b/debian/build/build_amd64_none_amd64/.config +@@ -3770,7 +3770,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y + CONFIG_SERIAL_8250_RSA=y CONFIG_SERIAL_8250_DW=y # CONFIG_SERIAL_8250_RT288X is not set -# CONFIG_SERIAL_8250_LPSS is not set +CONFIG_SERIAL_8250_LPSS=m CONFIG_SERIAL_8250_MID=y CONFIG_SERIAL_8250_MOXA=m + diff --git a/patch/config-dell-s6000.patch b/patch/config-dell-s6000.patch index 94c4abb6bf8d..1220888b3945 100644 --- a/patch/config-dell-s6000.patch +++ b/patch/config-dell-s6000.patch @@ -25,10 +25,10 @@ CONFIG_STRICT_DEVMEM is not set 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index e927c8d..74d6692 100644 +index 4a7d314fc..b0db81d4f 100644 --- a/debian/build/build_amd64_none_amd64/.config +++ b/debian/build/build_amd64_none_amd64/.config -@@ -580,8 +580,7 @@ CONFIG_MTRR=y +@@ -393,8 +393,7 @@ CONFIG_MTRR=y CONFIG_MTRR_SANITIZER=y CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=0 CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT=1 @@ -37,34 +37,42 @@ index e927c8d..74d6692 100644 +# CONFIG_X86_PAT is not set CONFIG_ARCH_RANDOM=y CONFIG_X86_SMAP=y - CONFIG_X86_INTEL_MPX=y -@@ -2036,6 +2035,7 @@ CONFIG_EEPROM_LEGACY=m + CONFIG_X86_INTEL_UMIP=y +@@ -2236,6 +2235,7 @@ CONFIG_EEPROM_LEGACY=m CONFIG_EEPROM_MAX6875=m CONFIG_EEPROM_93CX6=m # CONFIG_EEPROM_93XX46 is not set +CONFIG_EEPROM_SFF_8436=m + # CONFIG_EEPROM_IDT_89HPESX is not set CONFIG_CB710_CORE=m # CONFIG_CB710_DEBUG is not set - CONFIG_CB710_DEBUG_ASSUMPTIONS=y -@@ -3567,7 +3567,7 @@ CONFIG_I2C_MUX=m +@@ -3869,7 +3869,7 @@ CONFIG_I2C_MUX=m # # Multiplexer I2C Chip support # -# CONFIG_I2C_MUX_GPIO is not set +CONFIG_I2C_MUX_GPIO=m + # CONFIG_I2C_MUX_LTC4306 is not set # CONFIG_I2C_MUX_PCA9541 is not set # CONFIG_I2C_MUX_PCA954x is not set - # CONFIG_I2C_MUX_PINCTRL is not set -@@ -3743,7 +3743,7 @@ CONFIG_GPIO_AMDPT=m +@@ -4051,7 +4051,7 @@ CONFIG_GPIO_EXAR=m # # CONFIG_GPIO_F7188X is not set # CONFIG_GPIO_IT87 is not set -# CONFIG_GPIO_SCH is not set +CONFIG_GPIO_SCH=m # CONFIG_GPIO_SCH311X is not set - - # -@@ -3911,6 +3911,7 @@ CONFIG_SENSORS_MAX1668=m + # CONFIG_GPIO_WINBOND is not set + # CONFIG_GPIO_WS16C48 is not set +@@ -4197,6 +4197,7 @@ CONFIG_SENSORS_ATXP1=m + CONFIG_SENSORS_DS620=m + CONFIG_SENSORS_DS1621=m + CONFIG_SENSORS_DELL_SMM=m ++CONFIG_SENSORS_DNI_DPS460=m + CONFIG_SENSORS_I5K_AMB=m + CONFIG_SENSORS_F71805F=m + CONFIG_SENSORS_F71882FG=m +@@ -4235,6 +4236,7 @@ CONFIG_SENSORS_MAX1668=m CONFIG_SENSORS_MAX6639=m CONFIG_SENSORS_MAX6642=m CONFIG_SENSORS_MAX6650=m @@ -72,21 +80,13 @@ index e927c8d..74d6692 100644 # CONFIG_SENSORS_MAX6697 is not set # CONFIG_SENSORS_MAX31790 is not set # CONFIG_SENSORS_MCP3021 is not set -@@ -3949,6 +3950,7 @@ CONFIG_SENSORS_LM25066=m - # CONFIG_SENSORS_MAX16064 is not set - # CONFIG_SENSORS_MAX20751 is not set - # CONFIG_SENSORS_MAX34440 is not set -+CONFIG_SENSORS_DNI_DPS460=m - # CONFIG_SENSORS_MAX8688 is not set - # CONFIG_SENSORS_TPS40422 is not set - CONFIG_SENSORS_TPS53679=m -@@ -7536,8 +7538,7 @@ CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y - # CONFIG_ARCH_WANTS_UBSAN_NO_NULL is not set +@@ -8604,8 +8606,7 @@ CONFIG_HAVE_ARCH_KGDB=y + CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y # CONFIG_UBSAN is not set CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y -CONFIG_STRICT_DEVMEM=y -CONFIG_IO_STRICT_DEVMEM=y +# CONFIG_STRICT_DEVMEM is not set + CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_X86_VERBOSE_BOOTUP is not set CONFIG_EARLY_PRINTK=y - # CONFIG_EARLY_PRINTK_DBGP is not set diff --git a/patch/config-dell-z9100.patch b/patch/config-dell-z9100.patch index d60fbea15c6c..7aa19beb7a5b 100644 --- a/patch/config-dell-z9100.patch +++ b/patch/config-dell-z9100.patch @@ -8,15 +8,15 @@ From: Guohan Lu 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index 74d6692..6e78364 100644 +index b0db81d4f..4f42f12e4 100644 --- a/debian/build/build_amd64_none_amd64/.config +++ b/debian/build/build_amd64_none_amd64/.config -@@ -3569,7 +3569,7 @@ CONFIG_I2C_MUX=m - # +@@ -3872,7 +3872,7 @@ CONFIG_I2C_MUX=m CONFIG_I2C_MUX_GPIO=m + # CONFIG_I2C_MUX_LTC4306 is not set # CONFIG_I2C_MUX_PCA9541 is not set -# CONFIG_I2C_MUX_PCA954x is not set +CONFIG_I2C_MUX_PCA954x=m - # CONFIG_I2C_MUX_PINCTRL is not set - CONFIG_I2C_MUX_REG=m - CONFIG_I2C_MUX_MLXCPLD=m + # CONFIG_I2C_MUX_REG is not set + # CONFIG_I2C_MUX_MLXCPLD is not set + CONFIG_I2C_HELPER_AUTO=y diff --git a/patch/config-ingrasys-s9100.patch b/patch/config-ingrasys-s9100.patch index 590e6a7d3bcf..ffe28f5d8bd9 100644 --- a/patch/config-ingrasys-s9100.patch +++ b/patch/config-ingrasys-s9100.patch @@ -4,28 +4,29 @@ From: wadelnn --- - debian/build/build_amd64_none_amd64/.config | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) + debian/build/build_amd64_none_amd64/.config | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index 01f96e7..f92e015 100644 +index 4f42f12e4..22df53c2a 100644 --- a/debian/build/build_amd64_none_amd64/.config +++ b/debian/build/build_amd64_none_amd64/.config -@@ -3617,7 +3617,7 @@ CONFIG_I2C_DESIGNWARE_PLATFORM=m +@@ -3921,7 +3921,8 @@ CONFIG_I2C_DESIGNWARE_PLATFORM=y CONFIG_I2C_DESIGNWARE_PCI=m - # CONFIG_I2C_DESIGNWARE_BAYTRAIL is not set + CONFIG_I2C_DESIGNWARE_BAYTRAIL=y # CONFIG_I2C_EMEV2 is not set -# CONFIG_I2C_GPIO is not set +CONFIG_I2C_GPIO=m ++# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set CONFIG_I2C_KEMPLD=m CONFIG_I2C_OCORES=m CONFIG_I2C_PCA_PLATFORM=m -@@ -3752,7 +3752,7 @@ CONFIG_GPIO_SCH=m +@@ -4062,7 +4063,7 @@ CONFIG_GPIO_SCH=m # CONFIG_GPIO_ADP5588 is not set # CONFIG_GPIO_MAX7300 is not set # CONFIG_GPIO_MAX732X is not set -# CONFIG_GPIO_PCA953X is not set +CONFIG_GPIO_PCA953X=m # CONFIG_GPIO_PCF857X is not set - # CONFIG_GPIO_SX150X is not set # CONFIG_GPIO_TPIC2810 is not set + diff --git a/patch/config-inventec-d7032.patch b/patch/config-inventec-d7032.patch index 2e2f0d19a292..f133c9b93759 100644 --- a/patch/config-inventec-d7032.patch +++ b/patch/config-inventec-d7032.patch @@ -1,13 +1,22 @@ +enable GPIO_ICH + +From: klhuang + + +--- + debian/build/build_amd64_none_amd64/.config | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index db20034..5ea7aef 100644 +index ec7b693b8..cba593aa3 100644 --- a/debian/build/build_amd64_none_amd64/.config +++ b/debian/build/build_amd64_none_amd64/.config -@@ -3736,7 +3736,7 @@ CONFIG_GPIO_GENERIC=m - CONFIG_GPIO_AMDPT=m +@@ -4041,7 +4041,7 @@ CONFIG_GPIO_AMDPT=m # CONFIG_GPIO_DWAPB is not set + CONFIG_GPIO_EXAR=m # CONFIG_GPIO_GENERIC_PLATFORM is not set -# CONFIG_GPIO_ICH is not set +CONFIG_GPIO_ICH=m # CONFIG_GPIO_LYNXPOINT is not set + # CONFIG_GPIO_MB86S7X is not set # CONFIG_GPIO_MOCKUP is not set - # CONFIG_GPIO_VX855 is not set diff --git a/patch/config-l3mdev-cgroup.patch b/patch/config-l3mdev-cgroup.patch deleted file mode 100644 index 6c7afc2665b2..000000000000 --- a/patch/config-l3mdev-cgroup.patch +++ /dev/null @@ -1,34 +0,0 @@ -enable CONFIG_CGROUP_L3MDEV=y - -From: Guohan Lu - - ---- - debian/build/build_amd64_none_amd64/.config | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index b7bcf15..a8d64a7 100644 ---- a/debian/build/build_amd64_none_amd64/.config -+++ b/debian/build/build_amd64_none_amd64/.config -@@ -1493,6 +1492,7 @@ CONFIG_MPLS_IPTUNNEL=m - # CONFIG_HSR is not set - # CONFIG_NET_SWITCHDEV is not set - CONFIG_NET_L3_MASTER_DEV=y -+CONFIG_CGROUP_L3MDEV=y - # CONFIG_NET_NCSI is not set - CONFIG_RPS=y - CONFIG_RFS_ACCEL=y -diff --git a/debian/build/build_armhf_none_armmp/.config b/debian/build/build_armhf_none_armmp/.config -index 32a2698..d50fff8 100644 ---- a/debian/build/build_armhf_none_armmp/.config -+++ b/debian/build/build_armhf_none_armmp/.config -@@ -1544,7 +1544,7 @@ CONFIG_MPLS_IPTUNNEL=m - # CONFIG_HSR is not set - CONFIG_NET_SWITCHDEV=y - CONFIG_NET_L3_MASTER_DEV=y --# CONFIG_CGROUP_L3MDEV is not set -+CONFIG_CGROUP_L3MDEV=y - # CONFIG_NET_NCSI is not set - CONFIG_RPS=y - CONFIG_RFS_ACCEL=y diff --git a/patch/config-mitac-ly1200.patch b/patch/config-mitac-ly1200.patch index e420b28c72e8..d2e90a3d6e47 100644 --- a/patch/config-mitac-ly1200.patch +++ b/patch/config-mitac-ly1200.patch @@ -8,15 +8,15 @@ From: Eddy.Weng 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index 9aac028..5bc6c67 100644 +index 045f760ee..85b06c135 100644 --- a/debian/build/build_amd64_none_amd64/.config +++ b/debian/build/build_amd64_none_amd64/.config -@@ -3913,7 +3913,7 @@ CONFIG_SENSORS_MAX6642=m +@@ -4239,7 +4239,7 @@ CONFIG_SENSORS_MAX6642=m CONFIG_SENSORS_MAX6650=m CONFIG_SENSORS_MAX6620=m CONFIG_SENSORS_MAX6697=m -# CONFIG_SENSORS_MAX31790 is not set +CONFIG_SENSORS_MAX31790=m # CONFIG_SENSORS_MCP3021 is not set + # CONFIG_SENSORS_TC654 is not set CONFIG_SENSORS_MENF21BMC_HWMON=m - CONFIG_SENSORS_ADCXX=m diff --git a/patch/config-optoe.patch b/patch/config-optoe.patch index 3a305e9d9e5f..ba3ef994631a 100644 --- a/patch/config-optoe.patch +++ b/patch/config-optoe.patch @@ -8,29 +8,14 @@ From: Guohan Lu 1 file changed, 1 insertion(+) diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index 5bc6c67..0a94577 100644 +index 85b06c135..ec7b693b8 100644 --- a/debian/build/build_amd64_none_amd64/.config +++ b/debian/build/build_amd64_none_amd64/.config -@@ -2036,6 +2036,7 @@ CONFIG_EEPROM_MAX6875=m +@@ -2236,6 +2236,7 @@ CONFIG_EEPROM_MAX6875=m CONFIG_EEPROM_93CX6=m # CONFIG_EEPROM_93XX46 is not set CONFIG_EEPROM_SFF_8436=m +CONFIG_EEPROM_OPTOE=m + # CONFIG_EEPROM_IDT_89HPESX is not set CONFIG_CB710_CORE=m # CONFIG_CB710_DEBUG is not set - CONFIG_CB710_DEBUG_ASSUMPTIONS=y -diff --git a/debian/build/build_armhf_none_armmp/.config b/debian/build/build_armhf_none_armmp/.config -index 69288eb..6224070 100644 ---- a/debian/build/build_armhf_none_armmp/.config -+++ b/debian/build/build_armhf_none_armmp/.config -@@ -2019,8 +2019,8 @@ CONFIG_EEPROM_LEGACY=m - CONFIG_EEPROM_MAX6875=m - CONFIG_EEPROM_93CX6=m - # CONFIG_EEPROM_93XX46 is not set --# CONFIG_EEPROM_SFF_8436 is not set --# CONFIG_EEPROM_OPTOE is not set -+CONFIG_EEPROM_SFF_8436=m -+CONFIG_EEPROM_OPTOE=m - CONFIG_CB710_CORE=m - # CONFIG_CB710_DEBUG is not set - CONFIG_CB710_DEBUG_ASSUMPTIONS=y diff --git a/patch/driver-arista-disable-smbus-mux-for-hudson2.patch b/patch/driver-arista-disable-smbus-mux-for-hudson2.patch index e6210b12a435..e4d3bc46ea63 100644 --- a/patch/driver-arista-disable-smbus-mux-for-hudson2.patch +++ b/patch/driver-arista-disable-smbus-mux-for-hudson2.patch @@ -14,10 +14,10 @@ Signed-off-by: Samuel Angebault 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c -index e34d82e..563a63c 100644 +index 90946a8b9..2e1f55aee 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c -@@ -731,8 +731,16 @@ static int piix4_add_adapters_sb800(struct pci_dev *dev, unsigned short smba) +@@ -869,8 +869,16 @@ static int piix4_add_adapters_sb800(struct pci_dev *dev, unsigned short smba, struct i2c_piix4_adapdata *adapdata; int port; int retval; @@ -32,6 +32,6 @@ index e34d82e..563a63c 100644 + adapters = 1; + + for (port = 0; port < adapters; port++) { - retval = piix4_add_adapter(dev, smba, true, port, + retval = piix4_add_adapter(dev, smba, true, port, notify_imc, piix4_main_port_names_sb800[port], &piix4_main_adapters[port]); diff --git a/patch/driver-arista-net-tg3-access-regs-indirectly.patch b/patch/driver-arista-net-tg3-access-regs-indirectly.patch index fc581466fc74..759f85d068b0 100644 --- a/patch/driver-arista-net-tg3-access-regs-indirectly.patch +++ b/patch/driver-arista-net-tg3-access-regs-indirectly.patch @@ -1,11 +1,15 @@ Fix kernel hangs seen and easily reproducable using ethtool -t + This issue is seen at least on Arista DCS-7050QX-32 SKUs +--- + drivers/net/ethernet/broadcom/tg3.c | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) -Index: linux-4.9/drivers/net/ethernet/broadcom/tg3.c -=================================================================== ---- linux-4.9.orig/drivers/net/ethernet/broadcom/tg3.c -+++ linux-4.9/drivers/net/ethernet/broadcom/tg3.c -@@ -998,6 +998,7 @@ static void tg3_disable_ints(struct tg3 +diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c +index d54ba3f75..8b543a27b 100644 +--- a/drivers/net/ethernet/broadcom/tg3.c ++++ b/drivers/net/ethernet/broadcom/tg3.c +@@ -1016,6 +1016,7 @@ static void tg3_disable_ints(struct tg3 *tp) static void tg3_enable_ints(struct tg3 *tp) { int i; @@ -13,7 +17,7 @@ Index: linux-4.9/drivers/net/ethernet/broadcom/tg3.c tp->irq_sync = 0; wmb(); -@@ -1010,6 +1011,22 @@ static void tg3_enable_ints(struct tg3 *tp) +@@ -1028,6 +1029,22 @@ static void tg3_enable_ints(struct tg3 *tp) struct tg3_napi *tnapi = &tp->napi[i]; tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); @@ -36,7 +40,7 @@ Index: linux-4.9/drivers/net/ethernet/broadcom/tg3.c if (tg3_flag(tp, 1SHOT_MSI)) tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); -@@ -16298,6 +16315,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) +@@ -16381,6 +16398,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) if ((tp->pdev->bus->number == 0) && (tp->pdev->devfn == PCI_DEVFN(0x14, 0x6))) { tg3_flag_set(tp, 4G_DMA_ONLY); @@ -44,7 +48,7 @@ Index: linux-4.9/drivers/net/ethernet/broadcom/tg3.c } } -@@ -16557,13 +16575,6 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) +@@ -16640,13 +16658,6 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) tp->write32_mbox = tg3_write_indirect_mbox; tp->write32_tx_mbox = tg3_write_indirect_mbox; tp->write32_rx_mbox = tg3_write_indirect_mbox; diff --git a/patch/driver-arista-net-tg3-disallow-broadcom-default-mac.patch b/patch/driver-arista-net-tg3-disallow-broadcom-default-mac.patch index 1f27d097791f..cf7500edfe1b 100644 --- a/patch/driver-arista-net-tg3-disallow-broadcom-default-mac.patch +++ b/patch/driver-arista-net-tg3-disallow-broadcom-default-mac.patch @@ -1,12 +1,16 @@ For Arista platforms, after calling kexec in fast-reboot, the MAC address + of management interface is reset to 00:10:18:00:00:00. This patch can recover the MAC with the one previously saved by Arista Aboot. +--- + drivers/net/ethernet/broadcom/tg3.c | 37 +++++++++++++++++------------------ + 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c -index 3f3d205..13b513d 100644 +index 2e6a88094..d54ba3f75 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c -@@ -9340,6 +9340,15 @@ static int tg3_halt(struct tg3 *tp, int kind, bool silent) +@@ -9367,6 +9367,15 @@ static int tg3_halt(struct tg3 *tp, int kind, bool silent) return err; } @@ -22,7 +26,7 @@ index 3f3d205..13b513d 100644 static int tg3_set_mac_addr(struct net_device *dev, void *p) { struct tg3 *tp = netdev_priv(dev); -@@ -16974,28 +16983,18 @@ static int tg3_get_device_address(struct tg3 *tp) +@@ -17080,28 +17089,18 @@ static int tg3_get_device_address(struct tg3 *tp) dev->dev_addr[5] = (lo >> 0) & 0xff; /* Some old bootcode may report a 0 MAC address in SRAM */ diff --git a/patch/driver-arista-net-tg3-dma-mask-4g-sb800.patch b/patch/driver-arista-net-tg3-dma-mask-4g-sb800.patch index 070935cc5d08..7daea94b1ab8 100644 --- a/patch/driver-arista-net-tg3-dma-mask-4g-sb800.patch +++ b/patch/driver-arista-net-tg3-dma-mask-4g-sb800.patch @@ -1,11 +1,16 @@ Force DMA accesses to be done in the 4G range due to a SB800 limitation + This issue is seen on Arista DCS-7050QX-32 SKUs +--- + drivers/net/ethernet/broadcom/tg3.c | 17 ++++++++++++++--- + drivers/net/ethernet/broadcom/tg3.h | 1 + + 2 files changed, 15 insertions(+), 3 deletions(-) -Index: linux-4.9/drivers/net/ethernet/broadcom/tg3.c -=================================================================== ---- linux-4.9.orig/drivers/net/ethernet/broadcom/tg3.c -+++ linux-4.9/drivers/net/ethernet/broadcom/tg3.c -@@ -16264,6 +16264,16 @@ static int tg3_get_invariants(struct tg3 +diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c +index 1af4e1607..2e6a88094 100644 +--- a/drivers/net/ethernet/broadcom/tg3.c ++++ b/drivers/net/ethernet/broadcom/tg3.c +@@ -16365,6 +16365,16 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) } while (bridge); } @@ -22,7 +27,7 @@ Index: linux-4.9/drivers/net/ethernet/broadcom/tg3.c if (tg3_asic_rev(tp) == ASIC_REV_5704 || tg3_asic_rev(tp) == ASIC_REV_5714) tp->pdev_peer = tg3_find_peer(tp); -@@ -16816,8 +16826,9 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) +@@ -16892,8 +16902,9 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) if (tg3_asic_rev(tp) == ASIC_REV_5705 && (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 || @@ -34,7 +39,7 @@ Index: linux-4.9/drivers/net/ethernet/broadcom/tg3.c if (!tg3_flag(tp, IS_5788) && tg3_asic_rev(tp) != ASIC_REV_5700) -@@ -17730,7 +17741,7 @@ static int tg3_init_one(struct pci_dev *pdev, +@@ -17804,7 +17815,7 @@ static int tg3_init_one(struct pci_dev *pdev, * On 64-bit systems without IOMMU, use 64-bit dma_mask and * do DMA address check in tg3_start_xmit(). */ @@ -44,10 +49,10 @@ Index: linux-4.9/drivers/net/ethernet/broadcom/tg3.c else if (tg3_flag(tp, 40BIT_DMA_BUG)) { persist_dma_mask = dma_mask = DMA_BIT_MASK(40); diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h -index 3b5e98e..b61cbb1 100644 +index a772a33b6..09eda72ab 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h -@@ -3102,6 +3102,7 @@ enum TG3_FLAGS { +@@ -3120,6 +3120,7 @@ enum TG3_FLAGS { TG3_FLAG_ROBOSWITCH, TG3_FLAG_ONE_DMA_AT_ONCE, TG3_FLAG_RGMII_MODE, diff --git a/patch/driver-hwmon-max6620-fix-rpm-calc.patch b/patch/driver-hwmon-max6620-fix-rpm-calc.patch index e5401626d774..9f6fd3166cdb 100644 --- a/patch/driver-hwmon-max6620-fix-rpm-calc.patch +++ b/patch/driver-hwmon-max6620-fix-rpm-calc.patch @@ -10,7 +10,7 @@ more accuracy. 1 file changed, 46 insertions(+), 59 deletions(-) diff --git a/drivers/hwmon/max6620.c b/drivers/hwmon/max6620.c -index 3c337c7..76c1f7f 100644 +index 3c337c7b0..76c1f7f54 100644 --- a/drivers/hwmon/max6620.c +++ b/drivers/hwmon/max6620.c @@ -46,6 +46,8 @@ diff --git a/patch/driver-hwmon-max6620-update.patch b/patch/driver-hwmon-max6620-update.patch index b4cfe0cf4be2..3060afe318a6 100644 --- a/patch/driver-hwmon-max6620-update.patch +++ b/patch/driver-hwmon-max6620-update.patch @@ -8,7 +8,7 @@ From: Shuotian Cheng 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/hwmon/max6620.c b/drivers/hwmon/max6620.c -index 76c1f7f..fb49195 100644 +index 76c1f7f54..fb4919520 100644 --- a/drivers/hwmon/max6620.c +++ b/drivers/hwmon/max6620.c @@ -183,7 +183,7 @@ static struct i2c_driver max6620_driver = { diff --git a/patch/driver-hwmon-max6620.patch b/patch/driver-hwmon-max6620.patch index fcbcc6f45ed4..6e7c0922d8a2 100644 --- a/patch/driver-hwmon-max6620.patch +++ b/patch/driver-hwmon-max6620.patch @@ -11,10 +11,10 @@ From: Cumulus Networks create mode 100644 drivers/hwmon/max6620.c diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 45cef3d..62d3be7 100644 +index c7adaca2a..d0b4b1b34 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig -@@ -875,6 +875,16 @@ config SENSORS_MAX6650 +@@ -905,6 +905,16 @@ config SENSORS_MAX6650 This driver can also be built as a module. If so, the module will be called max6650. @@ -32,10 +32,10 @@ index 45cef3d..62d3be7 100644 tristate "Maxim MAX6697 and compatibles" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index aecf4ba..348bb1d 100644 +index 93f7f41ea..6eca4ea6d 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile -@@ -118,6 +118,7 @@ obj-$(CONFIG_SENSORS_MAX31722) += max31722.o +@@ -124,6 +124,7 @@ obj-$(CONFIG_SENSORS_MAX6621) += max6621.o obj-$(CONFIG_SENSORS_MAX6639) += max6639.o obj-$(CONFIG_SENSORS_MAX6642) += max6642.o obj-$(CONFIG_SENSORS_MAX6650) += max6650.o @@ -45,7 +45,7 @@ index aecf4ba..348bb1d 100644 obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o diff --git a/drivers/hwmon/max6620.c b/drivers/hwmon/max6620.c new file mode 100644 -index 0000000..3c337c7 +index 000000000..3c337c7b0 --- /dev/null +++ b/drivers/hwmon/max6620.c @@ -0,0 +1,702 @@ diff --git a/patch/driver-hwmon-max6658-fix-write-convrate.patch b/patch/driver-hwmon-max6658-fix-write-convrate.patch index 66e26f38cf15..eddb5a5f6d55 100644 --- a/patch/driver-hwmon-max6658-fix-write-convrate.patch +++ b/patch/driver-hwmon-max6658-fix-write-convrate.patch @@ -1,8 +1,20 @@ +Fix false alarm when writing convrate on max6658 + +We found that the max6658 sometimes issues a false alarm when its +convrate is changed, with the current hwmon driver. This workaround +will fix it by stopping the conversion before setting the convrate. + +From: byu343 + +--- + drivers/hwmon/lm90.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 48 insertions(+), 4 deletions(-) + diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c -index 841f2428..d3e1cc2e 100644 +index c2f411c29..9d1a68d99 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c -@@ -486,6 +486,33 @@ static inline int lm90_select_remote_channel(struct i2c_client *client, +@@ -580,6 +580,33 @@ static inline int lm90_select_remote_channel(struct i2c_client *client, return 0; } @@ -36,7 +48,7 @@ index 841f2428..d3e1cc2e 100644 /* * Set conversion rate. * client->update_lock must be held when calling this function (unless we are -@@ -506,7 +533,11 @@ static int lm90_set_convrate(struct i2c_client *client, struct lm90_data *data, +@@ -600,7 +627,11 @@ static int lm90_set_convrate(struct i2c_client *client, struct lm90_data *data, if (interval >= update_interval * 3 / 4) break; @@ -49,7 +61,7 @@ index 841f2428..d3e1cc2e 100644 data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64); return err; } -@@ -1512,8 +1543,11 @@ static void lm90_restore_conf(void *_data) +@@ -1606,8 +1637,11 @@ static void lm90_restore_conf(void *_data) struct i2c_client *client = data->client; /* Restore initial configuration */ @@ -63,7 +75,7 @@ index 841f2428..d3e1cc2e 100644 i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, data->config_orig); } -@@ -1521,6 +1555,7 @@ static void lm90_restore_conf(void *_data) +@@ -1615,6 +1649,7 @@ static void lm90_restore_conf(void *_data) static int lm90_init_client(struct i2c_client *client, struct lm90_data *data) { int config, convrate; @@ -71,7 +83,7 @@ index 841f2428..d3e1cc2e 100644 convrate = lm90_read_reg(client, LM90_REG_R_CONVRATE); if (convrate < 0) -@@ -1530,12 +1565,21 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data) +@@ -1624,12 +1659,21 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data) /* * Start the conversions. */ diff --git a/patch/driver-hwmon-pmbus-dni_dps460-update-pmbus-core.patch b/patch/driver-hwmon-pmbus-dni_dps460-update-pmbus-core.patch index 4cd7ca2e7777..0389ef0b9e00 100644 --- a/patch/driver-hwmon-pmbus-dni_dps460-update-pmbus-core.patch +++ b/patch/driver-hwmon-pmbus-dni_dps460-update-pmbus-core.patch @@ -10,7 +10,7 @@ Update this data structure to meet current kernel (3.16.x) implementation. 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/drivers/hwmon/pmbus/dni_dps460.c b/drivers/hwmon/pmbus/dni_dps460.c -index ad29134..7332480 100644 +index ad29134c4..7332480d4 100644 --- a/drivers/hwmon/pmbus/dni_dps460.c +++ b/drivers/hwmon/pmbus/dni_dps460.c @@ -39,41 +39,32 @@ enum chips { dni_dps460 }; diff --git a/patch/driver-hwmon-pmbus-dni_dps460.patch b/patch/driver-hwmon-pmbus-dni_dps460.patch index 9918450cd4f6..ac249dced87a 100644 --- a/patch/driver-hwmon-pmbus-dni_dps460.patch +++ b/patch/driver-hwmon-pmbus-dni_dps460.patch @@ -11,10 +11,10 @@ From: Cumulus Networks create mode 100644 drivers/hwmon/pmbus/dni_dps460.c diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig -index 61938ea..8c39a51 100644 +index a82018aaf..720945848 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig -@@ -105,6 +105,16 @@ config SENSORS_MAX34440 +@@ -135,6 +135,16 @@ config SENSORS_MAX34440 This driver can also be built as a module. If so, the module will be called max34440. @@ -32,12 +32,12 @@ index 61938ea..8c39a51 100644 tristate "Maxim MAX8688" default n diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile -index b912fec..0624729 100644 +index ea0e39518..c67f5a290 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile -@@ -11,6 +11,7 @@ obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o - obj-$(CONFIG_SENSORS_MAX16064) += max16064.o +@@ -15,6 +15,7 @@ obj-$(CONFIG_SENSORS_MAX16064) += max16064.o obj-$(CONFIG_SENSORS_MAX20751) += max20751.o + obj-$(CONFIG_SENSORS_MAX31785) += max31785.o obj-$(CONFIG_SENSORS_MAX34440) += max34440.o +obj-$(CONFIG_SENSORS_DNI_DPS460) += dni_dps460.o obj-$(CONFIG_SENSORS_MAX8688) += max8688.o @@ -45,7 +45,7 @@ index b912fec..0624729 100644 obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o diff --git a/drivers/hwmon/pmbus/dni_dps460.c b/drivers/hwmon/pmbus/dni_dps460.c new file mode 100644 -index 0000000..ad29134 +index 000000000..ad29134c4 --- /dev/null +++ b/drivers/hwmon/pmbus/dni_dps460.c @@ -0,0 +1,253 @@ @@ -76,7 +76,7 @@ index 0000000..ad29134 +#include +#include +#include -+#include ++#include +#include +#include +#include "pmbus.h" diff --git a/patch/driver-hwmon-pmbus-dps1900.patch b/patch/driver-hwmon-pmbus-dps1900.patch index 03e10e6025b0..206ca5015bd6 100644 --- a/patch/driver-hwmon-pmbus-dps1900.patch +++ b/patch/driver-hwmon-pmbus-dps1900.patch @@ -1,8 +1,19 @@ +dps1900 module to support Delta DPS1900 devices. + +From: deni64k + +--- + drivers/hwmon/pmbus/Kconfig | 10 ++++++ + drivers/hwmon/pmbus/Makefile | 1 + + drivers/hwmon/pmbus/dps1900.c | 70 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 81 insertions(+) + create mode 100644 drivers/hwmon/pmbus/dps1900.c + diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig -index 510f055..f8ca77e 100644 +index 720945848..505ca2be0 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig -@@ -131,4 +131,14 @@ config SENSORS_ZL6100 +@@ -208,4 +208,14 @@ config SENSORS_ZL6100 This driver can also be built as a module. If so, the module will be called zl6100. @@ -18,17 +29,17 @@ index 510f055..f8ca77e 100644 + endif # PMBUS diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile -index be70828..8276d89 100644 +index c67f5a290..c76820a4d 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile -@@ -14,3 +14,4 @@ obj-$(CONFIG_SENSORS_MAX8688) += max8688.o +@@ -22,3 +22,4 @@ obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o +obj-$(CONFIG_SENSORS_DPS1900) += dps1900.o diff --git a/drivers/hwmon/pmbus/dps1900.c b/drivers/hwmon/pmbus/dps1900.c new file mode 100644 -index 0000000..8f90c04 +index 000000000..b26c1952f --- /dev/null +++ b/drivers/hwmon/pmbus/dps1900.c @@ -0,0 +1,70 @@ @@ -38,7 +49,7 @@ index 0000000..8f90c04 +#include +#include +#include -+#include ++#include +#include "pmbus.h" + +static int dps1900_read_word_data(struct i2c_client *client, int page, int reg) diff --git a/patch/driver-i2c-bus-intel-ismt-add-delay-param.patch b/patch/driver-i2c-bus-intel-ismt-add-delay-param.patch index 75b366b1573c..31e9394a6954 100644 --- a/patch/driver-i2c-bus-intel-ismt-add-delay-param.patch +++ b/patch/driver-i2c-bus-intel-ismt-add-delay-param.patch @@ -10,7 +10,7 @@ timed out' error message. 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c -index f573448..d2243e4 100644 +index 0d1c3ec8c..5f78de34d 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -66,6 +66,7 @@ @@ -36,9 +36,9 @@ index f573448..d2243e4 100644 /** * __ismt_desc_dump() - dump the contents of a specific descriptor -@@ -389,6 +393,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, - struct ismt_priv *priv = i2c_get_adapdata(adap); +@@ -397,6 +401,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, struct device *dev = &priv->pci_dev->dev; + u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); + if (delay > 0) + udelay(delay); @@ -46,7 +46,7 @@ index f573448..d2243e4 100644 desc = &priv->hw[priv->head]; /* Initialize the DMA buffer */ -@@ -754,7 +761,7 @@ static void ismt_hw_init(struct ismt_priv *priv) +@@ -761,7 +768,7 @@ static void ismt_hw_init(struct ismt_priv *priv) bus_speed = 1000; break; } diff --git a/patch/driver-ixgbe-external-phy.patch b/patch/driver-ixgbe-external-phy.patch old mode 100755 new mode 100644 index 9abb51a2352c..6b6f9f8ef6ea --- a/patch/driver-ixgbe-external-phy.patch +++ b/patch/driver-ixgbe-external-phy.patch @@ -1,13 +1,19 @@ -From: Jostar Yang Signed-off-by: Jostar Yang +From: Jostar Yang + + +--- + drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 3 +++ + drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 2 ++ + 2 files changed, 5 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c -index b17464e..29d267d 100644 +index 919a7af84..83865b150 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c -@@ -429,6 +429,9 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) - case X557_PHY_ID: +@@ -379,6 +379,9 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) + case X557_PHY_ID2: phy_type = ixgbe_phy_x550em_ext_t; break; + case BCM54616S_E_PHY_ID: @@ -17,41 +23,15 @@ index b17464e..29d267d 100644 phy_type = ixgbe_phy_unknown; break; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h -index 31d82e3..94d6306 100644 +index 41bcbb337..c6280ec7b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h -@@ -1401,6 +1401,7 @@ struct ixgbe_thermal_sensor_data { +@@ -1404,6 +1404,8 @@ struct ixgbe_nvm_version { + #define ATH_PHY_ID 0x03429050 + #define AQ_FW_REV 0x20 - /* PHY Types */ - #define IXGBE_M88E1145_E_PHY_ID 0x01410CD0 +#define BCM54616S_E_PHY_ID 0x03625D10 - ++ /* Special PHY Init Routine */ #define IXGBE_PHY_INIT_OFFSET_NL 0x002B -@@ -3060,6 +3061,7 @@ enum ixgbe_phy_type { - ixgbe_phy_x550em_kr, - ixgbe_phy_x550em_kx4, - ixgbe_phy_x550em_ext_t, -+ ixgbe_phy_ext_1g_t, - ixgbe_phy_cu_unknown, - ixgbe_phy_qt, - ixgbe_phy_xaui, -diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c -index 8466f38..033b2eb 100644 ---- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c -+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c -@@ -1716,8 +1716,12 @@ static s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw, - else - *speed = IXGBE_LINK_SPEED_10GB_FULL; - } else { -- *speed = IXGBE_LINK_SPEED_10GB_FULL | -- IXGBE_LINK_SPEED_1GB_FULL; -+ if (hw->phy.type == ixgbe_phy_ext_1g_t) { -+ *speed = IXGBE_LINK_SPEED_1GB_FULL; -+ } else { -+ *speed = IXGBE_LINK_SPEED_10GB_FULL | -+ IXGBE_LINK_SPEED_1GB_FULL; -+ } - *autoneg = true; - } - return 0; + #define IXGBE_PHY_INIT_END_NL 0xFFFF diff --git a/patch/driver-l3mdev-cgroup.patch b/patch/driver-l3mdev-cgroup.patch deleted file mode 100644 index 026e9f83ce40..000000000000 --- a/patch/driver-l3mdev-cgroup.patch +++ /dev/null @@ -1,338 +0,0 @@ -Add cgroup to assoicate tasks with L3 networking domains. AF_INET{6} -sockets opened by tasks associated with an l3mdev cgroup are bound to -the associated master device when the socket is created. This allows a -user to run a command (and its children) within an L3 networking context. - -The master-device for an l3mdev cgroup must be an L3 master device -(e.g., VRF), and it must be set before attaching tasks to the cgroup. Once -set the master-device can not change. Nested l3mdev cgroups are not -supported. The root (aka default) l3mdev cgroup can not be bound to a -master device. - -Example: - ip link add vrf-red type vrf table vrf-red - ip link set dev vrf-red up - ip link set dev eth1 master vrf-red - - cgcreate -g l3mdev:vrf-red - cgset -r l3mdev.master-device=vrf-red vrf-red - cgexec -g l3mdev:vrf-red bash - -At this point the current shell and its child processes are attached to -the vrf-red L3 domain. Any AF_INET and AF_INET6 sockets opened by the -tasks are bound to the vrf-red device. - -TO-DO: -- how to auto-create the cgroup when a VRF device is created and auto-deleted - when a VRF device is destroyed - -Signed-off-by: David Ahern ---- - include/linux/cgroup_subsys.h | 4 + - include/net/l3mdev_cgroup.h | 27 ++++++ - net/core/sock.c | 2 - net/l3mdev/Kconfig | 12 +++ - net/l3mdev/Makefile | 1 - net/l3mdev/l3mdev_cgroup.c | 195 +++++++++++++++++++++++++++++++++++++++++ - 6 files changed, 241 insertions(+) - create mode 100644 include/net/l3mdev_cgroup.h - create mode 100644 net/l3mdev/l3mdev_cgroup.c - -diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h -index 0df0336..72c220a 100644 ---- a/include/linux/cgroup_subsys.h -+++ b/include/linux/cgroup_subsys.h -@@ -48,6 +48,10 @@ SUBSYS(perf_event) - SUBSYS(net_prio) - #endif - -+#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) -+SUBSYS(l3mdev) -+#endif -+ - #if IS_ENABLED(CONFIG_CGROUP_HUGETLB) - SUBSYS(hugetlb) - #endif -diff --git a/include/net/l3mdev_cgroup.h b/include/net/l3mdev_cgroup.h -new file mode 100644 -index 0000000..7d2bef1 ---- /dev/null -+++ b/include/net/l3mdev_cgroup.h -@@ -0,0 +1,27 @@ -+/* -+ * l3mdev_cgroup.h Control Group for L3 Master Device -+ * -+ * Copyright (c) 2015 Cumulus Networks. All rights reserved. -+ * Copyright (c) 2015 David Ahern -+ * -+ * 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 _L3MDEV_CGROUP_H -+#define _L3MDEV_CGROUP_H -+ -+#if IS_ENABLED(CONFIG_CGROUP_L3MDEV) -+ -+void sock_update_l3mdev(struct sock *sk); -+ -+#else /* !CONFIG_CGROUP_L3MDEV */ -+ -+static inline void sock_update_l3mdev(struct sock *sk) -+{ -+} -+ -+#endif /* CONFIG_CGROUP_L3MDEV */ -+#endif /* _L3MDEV_CGROUP_H */ -diff --git a/net/core/sock.c b/net/core/sock.c -index 1c4c434..ebb25ca 100644 ---- a/net/core/sock.c -+++ b/net/core/sock.c -@@ -131,6 +131,7 @@ - #include - #include - #include -+#include - #include - - #include -@@ -1402,6 +1403,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, - cgroup_sk_alloc(&sk->sk_cgrp_data); - sock_update_classid(&sk->sk_cgrp_data); - sock_update_netprioidx(&sk->sk_cgrp_data); -+ sock_update_l3mdev(sk); - } - - return sk; -diff --git a/net/l3mdev/Kconfig b/net/l3mdev/Kconfig -index 5d47325..3142d81 100644 ---- a/net/l3mdev/Kconfig -+++ b/net/l3mdev/Kconfig -@@ -8,3 +8,15 @@ config NET_L3_MASTER_DEV - ---help--- - This module provides glue between core networking code and device - drivers to support L3 master devices like VRF. -+ -+config CGROUP_L3MDEV -+ bool "L3 Master Device cgroup" -+ depends on CGROUPS -+ depends on NET_L3_MASTER_DEV -+ ---help--- -+ Cgroup subsystem for assigning processes to an L3 domain. -+ When a process is assigned to an l3mdev domain all AF_INET and -+ AF_INET6 sockets opened by the process are bound to the L3 master -+ device. -+ -+ -diff --git a/net/l3mdev/Makefile b/net/l3mdev/Makefile -index 84a53a6..ae74eba 100644 ---- a/net/l3mdev/Makefile -+++ b/net/l3mdev/Makefile -@@ -3,3 +3,4 @@ - # - - obj-$(CONFIG_NET_L3_MASTER_DEV) += l3mdev.o -+obj-$(CONFIG_CGROUP_L3MDEV) += l3mdev_cgroup.o -diff --git a/net/l3mdev/l3mdev_cgroup.c b/net/l3mdev/l3mdev_cgroup.c -new file mode 100644 -index 0000000..b5fea03 ---- /dev/null -+++ b/net/l3mdev/l3mdev_cgroup.c -@@ -0,0 +1,195 @@ -+/* -+ * net/l3mdev/l3mdev_cgroup.c Control Group for L3 Master Devices -+ * -+ * Copyright (c) 2015 Cumulus Networks. All rights reserved. -+ * Copyright (c) 2015 David Ahern -+ * -+ * 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 -+ -+struct l3mdev_cgroup { -+ struct cgroup_subsys_state css; -+ struct net *net; -+ int dev_idx; -+}; -+ -+static inline struct l3mdev_cgroup *css_l3mdev(struct cgroup_subsys_state *css) -+{ -+ return css ? container_of(css, struct l3mdev_cgroup, css) : NULL; -+} -+ -+static void l3mdev_set_bound_dev(struct sock *sk) -+{ -+ struct task_struct *tsk = current; -+ struct l3mdev_cgroup *l3mdev_cgrp; -+ -+ rcu_read_lock(); -+ -+ l3mdev_cgrp = css_l3mdev(task_css(tsk, l3mdev_cgrp_id)); -+ if (l3mdev_cgrp && l3mdev_cgrp->dev_idx) -+ sk->sk_bound_dev_if = l3mdev_cgrp->dev_idx; -+ -+ rcu_read_unlock(); -+} -+ -+void sock_update_l3mdev(struct sock *sk) -+{ -+ switch (sk->sk_family) { -+ case AF_INET: -+ case AF_INET6: -+ l3mdev_set_bound_dev(sk); -+ break; -+ } -+} -+ -+static bool is_root_cgroup(struct cgroup_subsys_state *css) -+{ -+ return !css || !css->parent; -+} -+ -+static struct cgroup_subsys_state * -+l3mdev_css_alloc(struct cgroup_subsys_state *parent_css) -+{ -+ struct l3mdev_cgroup *l3mdev_cgrp; -+ -+ /* nested l3mdev domains are not supportd */ -+ if (!is_root_cgroup(parent_css)) -+ return ERR_PTR(-EINVAL); -+ -+ l3mdev_cgrp = kzalloc(sizeof(*l3mdev_cgrp), GFP_KERNEL); -+ if (!l3mdev_cgrp) -+ return ERR_PTR(-ENOMEM); -+ -+ return &l3mdev_cgrp->css; -+} -+ -+static int l3mdev_css_online(struct cgroup_subsys_state *css) -+{ -+ return 0; -+} -+ -+static void l3mdev_css_free(struct cgroup_subsys_state *css) -+{ -+ kfree(css_l3mdev(css)); -+} -+ -+static int l3mdev_read(struct seq_file *sf, void *v) -+{ -+ struct cgroup_subsys_state *css = seq_css(sf); -+ struct l3mdev_cgroup *l3mdev_cgrp = css_l3mdev(css); -+ -+ if (!l3mdev_cgrp) -+ return -EINVAL; -+ -+ if (l3mdev_cgrp->net) { -+ struct net_device *dev; -+ -+ dev = dev_get_by_index(l3mdev_cgrp->net, l3mdev_cgrp->dev_idx); -+ -+ seq_printf(sf, "net[%u]: device index %d ==> %s\n", -+ l3mdev_cgrp->net->ns.inum, l3mdev_cgrp->dev_idx, -+ dev ? dev->name : ""); -+ -+ if (dev) -+ dev_put(dev); -+ } -+ return 0; -+} -+ -+static ssize_t l3mdev_write(struct kernfs_open_file *of, -+ char *buf, size_t nbytes, loff_t off) -+{ -+ struct cgroup_subsys_state *css = of_css(of); -+ struct l3mdev_cgroup *l3mdev_cgrp = css_l3mdev(css); -+ struct net *net = current->nsproxy->net_ns; -+ struct net_device *dev; -+ char name[IFNAMSIZ]; -+ int rc = -EINVAL; -+ -+ /* once master device is set can not undo. Must delete -+ * cgroup and reset -+ */ -+ if (l3mdev_cgrp->dev_idx) -+ goto out; -+ -+ /* root cgroup does not bind to an L3 domain */ -+ if (is_root_cgroup(css)) -+ goto out; -+ -+ if (sscanf(buf, "%" __stringify(IFNAMSIZ) "s", name) != 1) -+ goto out; -+ -+ dev = dev_get_by_name(net, name); -+ if (!dev) { -+ rc = -ENODEV; -+ goto out; -+ } -+ -+ if (netif_is_l3_master(dev)) { -+ l3mdev_cgrp->net = net; -+ l3mdev_cgrp->dev_idx = dev->ifindex; -+ rc = 0; -+ } -+ -+ dev_put(dev); -+out: -+ return rc ? : nbytes; -+} -+ -+/* make master device is set for non-root cgroups before tasks can be added */ -+static int l3mdev_can_attach(struct cgroup_taskset *tset) -+{ -+ struct cgroup_subsys_state *dst_css; -+ struct task_struct *tsk; -+ int rc = 0; -+ -+ cgroup_taskset_for_each(tsk, dst_css, tset) { -+ struct l3mdev_cgroup *l3mdev_cgrp; -+ -+ l3mdev_cgrp = css_l3mdev(dst_css); -+ if (!is_root_cgroup(dst_css) && !l3mdev_cgrp->dev_idx) { -+ rc = -ENODEV; -+ break; -+ } -+ } -+ -+ return rc; -+} -+ -+static struct cftype ss_files[] = { -+ { -+ .name = "master-device", -+ .seq_show = l3mdev_read, -+ .write = l3mdev_write, -+ }, -+ { } /* terminate */ -+}; -+ -+struct cgroup_subsys l3mdev_cgrp_subsys = { -+ .css_alloc = l3mdev_css_alloc, -+ .css_online = l3mdev_css_online, -+ .css_free = l3mdev_css_free, -+ .can_attach = l3mdev_can_attach, -+ .legacy_cftypes = ss_files, -+}; -+ -+static int __init init_cgroup_l3mdev(void) -+{ -+ return 0; -+} -+ -+subsys_initcall(init_cgroup_l3mdev); -+MODULE_AUTHOR("David Ahern"); -+MODULE_DESCRIPTION("Control Group for L3 Networking Domains"); -+MODULE_LICENSE("GPL"); diff --git a/patch/driver-net-tg3-add-param-short-preamble-and-reset.patch b/patch/driver-net-tg3-add-param-short-preamble-and-reset.patch index d97b9928b925..fc42963ada7d 100644 --- a/patch/driver-net-tg3-add-param-short-preamble-and-reset.patch +++ b/patch/driver-net-tg3-add-param-short-preamble-and-reset.patch @@ -1,18 +1,18 @@ -Subject: [PATCH] Add 2 more parameter for tg3.c. +Subject: [PATCH] Add 2 more parameter for tg3.c. -1. short_preamble: Enable mdio traffic to external PHYs(i.g. BCM54616). +1. short_preamble: Enable mdio traffic to external PHYs(i.g. BCM54616). 2. bcm5718s_reset: Enable BCM5718S reset support. Signed-off-by: roy_lee --- - drivers/net/ethernet/broadcom/tg3.c | 18 ++++++++++++++++++ + drivers/net/ethernet/broadcom/tg3.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c -index d658255..d31c395 100644 +index 8b543a27b..7bc30a48b 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c -@@ -234,6 +234,14 @@ static int tg3_debug = -1; /* -1 == use TG3_DEF_MSG_ENABLE as value */ +@@ -242,6 +242,14 @@ static int tg3_debug = -1; /* -1 == use TG3_DEF_MSG_ENABLE as value */ module_param(tg3_debug, int, 0); MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value"); @@ -27,7 +27,7 @@ index d658255..d31c395 100644 #define TG3_DRV_DATA_FLAG_10_100_ONLY 0x0001 #define TG3_DRV_DATA_FLAG_5705_10_100 0x0002 -@@ -1502,6 +1510,11 @@ static void tg3_mdio_config_5785(struct tg3 *tp) +@@ -1520,6 +1528,11 @@ static void tg3_mdio_config_5785(struct tg3 *tp) static void tg3_mdio_start(struct tg3 *tp) { tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL; @@ -39,7 +39,7 @@ index d658255..d31c395 100644 tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(80); -@@ -2704,6 +2717,11 @@ static int tg3_phy_reset(struct tg3 *tp) +@@ -2722,6 +2735,11 @@ static int tg3_phy_reset(struct tg3 *tp) } } @@ -51,6 +51,3 @@ index d658255..d31c395 100644 if (tg3_flag(tp, 5717_PLUS) && (tp->phy_flags & TG3_PHYFLG_MII_SERDES)) return 0; --- -2.1.4 - diff --git a/patch/driver-pca954x-i2c-mux-force-deselect-on-exit-flag.patch b/patch/driver-pca954x-i2c-mux-force-deselect-on-exit-flag.patch index 0e2985c37cc7..9743569b95c5 100644 --- a/patch/driver-pca954x-i2c-mux-force-deselect-on-exit-flag.patch +++ b/patch/driver-pca954x-i2c-mux-force-deselect-on-exit-flag.patch @@ -8,10 +8,10 @@ From: wadelnn 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c -index 9c4ac26..7dd92a2 100644 +index 24bd9275f..2906afaf5 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c -@@ -120,6 +120,11 @@ static const struct i2c_device_id pca954x_id[] = { +@@ -196,6 +196,11 @@ static const struct i2c_device_id pca954x_id[] = { }; MODULE_DEVICE_TABLE(i2c, pca954x_id); @@ -23,7 +23,7 @@ index 9c4ac26..7dd92a2 100644 #ifdef CONFIG_OF static const struct of_device_id pca954x_of_match[] = { { .compatible = "nxp,pca9540", .data = &chips[pca_9540] }, -@@ -273,7 +278,7 @@ static int pca954x_probe(struct i2c_client *client, +@@ -437,7 +442,7 @@ static int pca954x_probe(struct i2c_client *client, idle_disconnect_pd = pdata->modes[num].deselect_on_exit; } data->deselect |= (idle_disconnect_pd || @@ -31,4 +31,4 @@ index 9c4ac26..7dd92a2 100644 + idle_disconnect_dt || force_deselect_on_exit) << num; ret = i2c_mux_add_adapter(muxc, force, num, class); - + if (ret) diff --git a/patch/driver-sff-8436-use-nvmem-framework.patch b/patch/driver-sff-8436-use-nvmem-framework.patch index 332b24f7622a..086a6615a812 100644 --- a/patch/driver-sff-8436-use-nvmem-framework.patch +++ b/patch/driver-sff-8436-use-nvmem-framework.patch @@ -10,10 +10,10 @@ that the 'eeprom' file in sys is provided by the framework. 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig -index 1df5e28..9582d48 100644 +index e3acc9b2a..05bcf1e1f 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig -@@ -103,6 +103,7 @@ config EEPROM_DIGSY_MTC_CFG +@@ -114,6 +114,7 @@ config EEPROM_IDT_89HPESX config EEPROM_SFF_8436 tristate "SFF-8436 QSFP EEPROMs support" depends on I2C && SYSFS @@ -22,7 +22,7 @@ index 1df5e28..9582d48 100644 If you say yes here you get read-only support for the EEPROM of the QSFPs which are implemented as per SFF-8436. diff --git a/drivers/misc/eeprom/sff_8436_eeprom.c b/drivers/misc/eeprom/sff_8436_eeprom.c -index f5627bf..9e6a7bf 100644 +index f5627bf85..9e6a7bf43 100644 --- a/drivers/misc/eeprom/sff_8436_eeprom.c +++ b/drivers/misc/eeprom/sff_8436_eeprom.c @@ -74,7 +74,6 @@ diff --git a/patch/driver-sff-8436-use-nvmem_device_read.patch b/patch/driver-sff-8436-use-nvmem_device_read.patch index 8be88cd4cd62..fefe9e052c58 100644 --- a/patch/driver-sff-8436-use-nvmem_device_read.patch +++ b/patch/driver-sff-8436-use-nvmem_device_read.patch @@ -10,7 +10,7 @@ memory_accessor in the setup() callback with nvmem API calls. 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/drivers/misc/eeprom/sff_8436_eeprom.c b/drivers/misc/eeprom/sff_8436_eeprom.c -index 28609bb..e959f63 100644 +index 9e6a7bf43..4688597eb 100644 --- a/drivers/misc/eeprom/sff_8436_eeprom.c +++ b/drivers/misc/eeprom/sff_8436_eeprom.c @@ -99,7 +99,6 @@ @@ -80,7 +80,7 @@ index 28609bb..e959f63 100644 return 0; diff --git a/include/linux/i2c/sff-8436.h b/include/linux/i2c/sff-8436.h -index 4df48ad..3e50567 100644 +index 4df48ad89..3e505676f 100644 --- a/include/linux/i2c/sff-8436.h +++ b/include/linux/i2c/sff-8436.h @@ -2,7 +2,7 @@ diff --git a/patch/driver-support-optoe-EOF_fix.patch b/patch/driver-support-optoe-EOF_fix.patch index 762bbbbf3d35..0ca8119c7f08 100644 --- a/patch/driver-support-optoe-EOF_fix.patch +++ b/patch/driver-support-optoe-EOF_fix.patch @@ -1,6 +1,7 @@ From 556c452dcf5706a951ef490327b74bd27a411693 Mon Sep 17 00:00:00 2001 + From: Don Bollinger -Date: Fri, 9 Mar 2018 18:22:33 -0800 + Subject: [PATCH] drivers/misc/eeprom: Improve EOF handling Change -ENXIO error to return zero, which user space sees as EOF @@ -9,11 +10,11 @@ Subject: [PATCH] drivers/misc/eeprom: Improve EOF handling Signed-off-by: Don Bollinger --- - drivers/misc/eeprom/optoe.c | 52 +++++++++++++++++++++++++++++++-------------- + drivers/misc/eeprom/optoe.c | 52 ++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/drivers/misc/eeprom/optoe.c b/drivers/misc/eeprom/optoe.c -index 7425bf6..b3064f0 100644 +index 7425bf60e..b3064f02b 100644 --- a/drivers/misc/eeprom/optoe.c +++ b/drivers/misc/eeprom/optoe.c @@ -158,6 +158,7 @@ struct optoe_platform_data { @@ -144,6 +145,3 @@ index 7425bf6..b3064f0 100644 } static ssize_t optoe_bin_read(struct file *filp, struct kobject *kobj, --- -2.11.0 - diff --git a/patch/driver-support-optoe-QSFP_DD.patch b/patch/driver-support-optoe-QSFP_DD.patch index 03bc368ebfee..5be80f953a4d 100644 --- a/patch/driver-support-optoe-QSFP_DD.patch +++ b/patch/driver-support-optoe-QSFP_DD.patch @@ -1,6 +1,7 @@ From 3e212b8886a21fad8df621992b00b6bd1f5a7f16 Mon Sep 17 00:00:00 2001 + From: Don Bollinger -Date: Sat, 3 Aug 2019 12:06:05 -0700 + Subject: [PATCH] drivers/misc/eeprom: Support QSFP-DD (CMIS) type devices @@ -10,11 +11,11 @@ Subject: [PATCH] drivers/misc/eeprom: Support QSFP-DD (CMIS) type Signed-off-by: Don Bollinger --- - drivers/misc/eeprom/optoe.c | 61 +++++++++++++++++++++++++++++++++++++---- + drivers/misc/eeprom/optoe.c | 61 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/drivers/misc/eeprom/optoe.c b/drivers/misc/eeprom/optoe.c -index c22b92a..16287fd 100644 +index c22b92a29..16287fdc5 100644 --- a/drivers/misc/eeprom/optoe.c +++ b/drivers/misc/eeprom/optoe.c @@ -97,6 +97,13 @@ @@ -144,6 +145,3 @@ index c22b92a..16287fd 100644 err = -EINVAL; goto exit; } --- -2.16.2 - diff --git a/patch/driver-support-optoe-chunk-offset-fix.patch b/patch/driver-support-optoe-chunk-offset-fix.patch index 74a7b3657710..252737cbee11 100644 --- a/patch/driver-support-optoe-chunk-offset-fix.patch +++ b/patch/driver-support-optoe-chunk-offset-fix.patch @@ -10,10 +10,10 @@ Subject: [PATCH] Correct a panic inducing defect which is triggered on a read 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/misc/eeprom/optoe.c b/drivers/misc/eeprom/optoe.c -index 7425bf6..1b64506 100644 +index b3064f02b..c22b92a29 100644 --- a/drivers/misc/eeprom/optoe.c +++ b/drivers/misc/eeprom/optoe.c -@@ -641,6 +641,7 @@ static ssize_t optoe_read_write(struct optoe_data *optoe, +@@ -660,6 +660,7 @@ static ssize_t optoe_read_write(struct optoe_data *optoe, ssize_t retval; size_t pending_len = 0, chunk_len = 0; loff_t chunk_offset = 0, chunk_start_offset = 0; @@ -21,7 +21,7 @@ index 7425bf6..1b64506 100644 dev_dbg(&client->dev, "%s: off %lld len:%ld, opcode:%s\n", -@@ -678,30 +679,30 @@ static ssize_t optoe_read_write(struct optoe_data *optoe, +@@ -699,30 +700,30 @@ static ssize_t optoe_read_write(struct optoe_data *optoe, /* * Compute the offset and number of bytes to be read/write * diff --git a/patch/driver-support-optoe.patch b/patch/driver-support-optoe.patch index bedba851937c..86128666386d 100644 --- a/patch/driver-support-optoe.patch +++ b/patch/driver-support-optoe.patch @@ -18,10 +18,10 @@ Signed-off-by: Don Bollinger create mode 100644 drivers/misc/eeprom/optoe.c diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig -index 9582d48..2d5ab6e 100644 +index 05bcf1e1f..9f444adae 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig -@@ -113,4 +113,22 @@ config EEPROM_SFF_8436 +@@ -124,4 +124,22 @@ config EEPROM_SFF_8436 This driver can also be built as a module. If so, the module will be called sff_8436. @@ -45,17 +45,17 @@ index 9582d48..2d5ab6e 100644 + endmenu diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile -index db9097c..afcf73c 100644 +index 6a6d90ffe..80afa837e 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile -@@ -6,3 +6,4 @@ obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o - obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o +@@ -8,3 +8,4 @@ obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o + obj-$(CONFIG_EEPROM_IDT_89HPESX) += idt_89hpesx.o obj-$(CONFIG_EEPROM_SFF_8436) += sff_8436_eeprom.o -+obj-$(CONFIG_EEPROM_OPTOE) += optoe.o ++obj-$(CONFIG_EEPROM_OPTOE) += optoe.o diff --git a/drivers/misc/eeprom/optoe.c b/drivers/misc/eeprom/optoe.c new file mode 100644 -index 0000000..7425bf6 +index 000000000..7425bf60e --- /dev/null +++ b/drivers/misc/eeprom/optoe.c @@ -0,0 +1,1126 @@ diff --git a/patch/driver-support-sff-8436-eeprom-update.patch b/patch/driver-support-sff-8436-eeprom-update.patch index 3deb7cdbbb9e..d2d7f6e49e04 100644 --- a/patch/driver-support-sff-8436-eeprom-update.patch +++ b/patch/driver-support-sff-8436-eeprom-update.patch @@ -9,7 +9,7 @@ Support newer kernel and remove eeprom_class dependency 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/drivers/misc/eeprom/sff_8436_eeprom.c b/drivers/misc/eeprom/sff_8436_eeprom.c -index 0b6bf31..f5627bf 100644 +index 0b6bf312e..f5627bf85 100644 --- a/drivers/misc/eeprom/sff_8436_eeprom.c +++ b/drivers/misc/eeprom/sff_8436_eeprom.c @@ -82,7 +82,6 @@ @@ -120,7 +120,7 @@ index 0b6bf31..f5627bf 100644 }; diff --git a/include/linux/i2c/sff-8436.h b/include/linux/i2c/sff-8436.h -index cd46896..4df48ad 100644 +index cd4689651..4df48ad89 100644 --- a/include/linux/i2c/sff-8436.h +++ b/include/linux/i2c/sff-8436.h @@ -3,7 +3,6 @@ diff --git a/patch/driver-support-sff-8436-eeprom.patch b/patch/driver-support-sff-8436-eeprom.patch index 4d4f07ceea6d..bd8f40a934da 100644 --- a/patch/driver-support-sff-8436-eeprom.patch +++ b/patch/driver-support-sff-8436-eeprom.patch @@ -13,12 +13,12 @@ From: Cumulus Networks create mode 100644 include/linux/i2c/sff-8436.h diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig -index c4e41c2..1df5e28 100644 +index d382b13c2..e3acc9b2a 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig -@@ -100,4 +100,16 @@ config EEPROM_DIGSY_MTC_CFG - - If unsure, say N. +@@ -111,4 +111,16 @@ config EEPROM_IDT_89HPESX + This driver can also be built as a module. If so, the module + will be called idt_89hpesx. +config EEPROM_SFF_8436 + tristate "SFF-8436 QSFP EEPROMs support" @@ -34,17 +34,17 @@ index c4e41c2..1df5e28 100644 + endmenu diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile -index fc1e81d..db9097c 100644 +index 2aab60ef3..6a6d90ffe 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile -@@ -5,3 +5,4 @@ obj-$(CONFIG_EEPROM_MAX6875) += max6875.o - obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o +@@ -7,3 +7,4 @@ obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o + obj-$(CONFIG_EEPROM_IDT_89HPESX) += idt_89hpesx.o +obj-$(CONFIG_EEPROM_SFF_8436) += sff_8436_eeprom.o diff --git a/drivers/misc/eeprom/sff_8436_eeprom.c b/drivers/misc/eeprom/sff_8436_eeprom.c new file mode 100644 -index 0000000..0b6bf31 +index 000000000..0b6bf312e --- /dev/null +++ b/drivers/misc/eeprom/sff_8436_eeprom.c @@ -0,0 +1,995 @@ @@ -1045,7 +1045,7 @@ index 0000000..0b6bf31 +MODULE_LICENSE("GPL"); diff --git a/include/linux/i2c/sff-8436.h b/include/linux/i2c/sff-8436.h new file mode 100644 -index 0000000..cd46896 +index 000000000..cd4689651 --- /dev/null +++ b/include/linux/i2c/sff-8436.h @@ -0,0 +1,33 @@ diff --git a/patch/driver-support-sff-8436-read-write-fix.patch b/patch/driver-support-sff-8436-read-write-fix.patch index e51e3fec996a..9ae418a443a8 100644 --- a/patch/driver-support-sff-8436-read-write-fix.patch +++ b/patch/driver-support-sff-8436-read-write-fix.patch @@ -1,7 +1,14 @@ Fix calculation of page_len in sff_8436_read_write function +From: yurypm + + +--- + drivers/misc/eeprom/sff_8436_eeprom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + diff --git a/drivers/misc/eeprom/sff_8436_eeprom.c b/drivers/misc/eeprom/sff_8436_eeprom.c -index 4688597..10074f0 100644 +index 4688597eb..10074f03a 100644 --- a/drivers/misc/eeprom/sff_8436_eeprom.c +++ b/drivers/misc/eeprom/sff_8436_eeprom.c @@ -689,7 +689,7 @@ static ssize_t sff_8436_read_write(struct sff_8436_data *sff_8436, diff --git a/patch/driver-support-tun-config-carrier-enable.patch b/patch/driver-support-tun-config-carrier-enable.patch index 961ae9526a5a..41db8ea67356 100644 --- a/patch/driver-support-tun-config-carrier-enable.patch +++ b/patch/driver-support-tun-config-carrier-enable.patch @@ -4,42 +4,40 @@ From: admin Subject: [PATCH] TUNTAP driver support carrier configuration --- - drivers/net/tun.c | 12 ++++++++++++ + drivers/net/tun.c | 10 ++++++++++ include/uapi/linux/if_tun.h | 1 + - 2 files changed, 13 insertions(+) + 2 files changed, 11 insertions(+) diff --git a/drivers/net/tun.c b/drivers/net/tun.c -index a931b73..eef4af7 100644 +index 5fa7047ea..f79f0cf57 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c -@@ -2258,6 +2258,18 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, +@@ -3128,6 +3128,16 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, ret = 0; break; -+ case TUNSETCARRIER: -+ if (arg) { -+ netif_carrier_on(tun->dev); ++ case TUNSETCARRIER: ++ if (arg) { ++ netif_carrier_on(tun->dev); + } else { -+ netif_carrier_off(tun->dev); -+ } -+ -+ tun_debug(KERN_INFO, tun, "carrier %s\n", -+ arg ? "on" : "off"); ++ netif_carrier_off(tun->dev); ++ } + ++ tun_debug(KERN_INFO, tun, "carrier %s\n", arg ? "on" : "off"); + break; -+ - default: - ret = -EINVAL; ++ + case TUNSETSTEERINGEBPF: + ret = tun_set_ebpf(tun, &tun->steering_prog, argp); break; diff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h -index 3cb5e1d..5c62f27 100644 +index ee432cd30..23a6753b3 100644 --- a/include/uapi/linux/if_tun.h +++ b/include/uapi/linux/if_tun.h -@@ -56,6 +56,7 @@ - */ - #define TUNSETVNETBE _IOW('T', 222, int) +@@ -59,6 +59,7 @@ #define TUNGETVNETBE _IOR('T', 223, int) -+#define TUNSETCARRIER _IOW('T', 224, int) + #define TUNSETSTEERINGEBPF _IOR('T', 224, int) + #define TUNSETFILTEREBPF _IOR('T', 225, int) ++#define TUNSETCARRIER _IOW('T', 226, int) /* TUNSETIFF ifr flags */ #define IFF_TUN 0x0001 diff --git a/patch/fix_ismt_alignment_issue.patch b/patch/fix_ismt_alignment_issue.patch deleted file mode 100644 index 6135239638dd..000000000000 --- a/patch/fix_ismt_alignment_issue.patch +++ /dev/null @@ -1,141 +0,0 @@ -From Commit ID: 5cd5f0bb0d9c32876b3d86b70fb45da10d028be7 -Subject: I2C ISMT 16-byte align the DMA buffer address - -Use only a portion of the data buffer for DMA transfers, which is always -16-byte aligned. This makes the DMA buffer address 16-byte aligned and -compensates for spurious hardware parity errors that may appear when the -DMA buffer address is not 16-byte aligned. - -The data buffer is enlarged in order to accommodate any possible 16-byte -alignment offset and changes the DMA code to only use a portion of the -data buffer, which is 16-byte aligned. - -The symptom of the hardware issue is the same as the one addressed in -v3.12-rc2-5-gbf41691 and manifests by transfers failing with EIO, with -bit 9 being set in the ERRSTS register. - -Signed-off-by: Radu Rendec -Acked-by: Neil Horman -Signed-off-by: Wolfram Sang ---- - -diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c -index c97b48c..91c6524 100644 ---- a/drivers/i2c/busses/i2c-ismt.c -+++ b/drivers/i2c/busses/i2c-ismt.c -@@ -173,7 +173,7 @@ struct ismt_priv { - dma_addr_t io_rng_dma; /* descriptor HW base addr */ - u8 head; /* ring buffer head pointer */ - struct completion cmp; /* interrupt completion */ -- u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* temp R/W data buffer */ -+ u8 buffer[I2C_SMBUS_BLOCK_MAX + 16]; /* temp R/W data buffer */ - }; - - /** -@@ -324,7 +324,7 @@ static int ismt_process_desc(const struct ismt_desc *desc, - struct ismt_priv *priv, int size, - char read_write) - { -- u8 *dma_buffer = priv->dma_buffer; -+ u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); - - dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n"); - __ismt_desc_dump(&priv->pci_dev->dev, desc); -@@ -397,6 +397,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, - struct ismt_desc *desc; - struct ismt_priv *priv = i2c_get_adapdata(adap); - struct device *dev = &priv->pci_dev->dev; -+ u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); - - if (delay > 0) - udelay(delay); -@@ -404,7 +405,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, - desc = &priv->hw[priv->head]; - - /* Initialize the DMA buffer */ -- memset(priv->dma_buffer, 0, sizeof(priv->dma_buffer)); -+ memset(priv->buffer, 0, sizeof(priv->buffer)); - - /* Initialize the descriptor */ - memset(desc, 0, sizeof(struct ismt_desc)); -@@ -453,8 +454,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, - desc->wr_len_cmd = 2; - dma_size = 2; - dma_direction = DMA_TO_DEVICE; -- priv->dma_buffer[0] = command; -- priv->dma_buffer[1] = data->byte; -+ dma_buffer[0] = command; -+ dma_buffer[1] = data->byte; - } else { - /* Read Byte */ - dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: READ\n"); -@@ -473,9 +474,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, - desc->wr_len_cmd = 3; - dma_size = 3; - dma_direction = DMA_TO_DEVICE; -- priv->dma_buffer[0] = command; -- priv->dma_buffer[1] = data->word & 0xff; -- priv->dma_buffer[2] = data->word >> 8; -+ dma_buffer[0] = command; -+ dma_buffer[1] = data->word & 0xff; -+ dma_buffer[2] = data->word >> 8; - } else { - /* Read Word */ - dev_dbg(dev, "I2C_SMBUS_WORD_DATA: READ\n"); -@@ -493,9 +494,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, - desc->rd_len = 2; - dma_size = 3; - dma_direction = DMA_BIDIRECTIONAL; -- priv->dma_buffer[0] = command; -- priv->dma_buffer[1] = data->word & 0xff; -- priv->dma_buffer[2] = data->word >> 8; -+ dma_buffer[0] = command; -+ dma_buffer[1] = data->word & 0xff; -+ dma_buffer[2] = data->word >> 8; - break; - - case I2C_SMBUS_BLOCK_DATA: -@@ -506,8 +507,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, - dma_direction = DMA_TO_DEVICE; - desc->wr_len_cmd = dma_size; - desc->control |= ISMT_DESC_BLK; -- priv->dma_buffer[0] = command; -- memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1); -+ dma_buffer[0] = command; -+ memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); - } else { - /* Block Read */ - dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n"); -@@ -534,8 +535,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, - dma_direction = DMA_TO_DEVICE; - desc->wr_len_cmd = dma_size; - desc->control |= ISMT_DESC_I2C; -- priv->dma_buffer[0] = command; -- memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1); -+ dma_buffer[0] = command; -+ memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); - } else { - /* i2c Block Read */ - dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n"); -@@ -564,18 +565,18 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, - if (dma_size != 0) { - dev_dbg(dev, " dev=%p\n", dev); - dev_dbg(dev, " data=%p\n", data); -- dev_dbg(dev, " dma_buffer=%p\n", priv->dma_buffer); -+ dev_dbg(dev, " dma_buffer=%p\n", dma_buffer); - dev_dbg(dev, " dma_size=%d\n", dma_size); - dev_dbg(dev, " dma_direction=%d\n", dma_direction); - - dma_addr = dma_map_single(dev, -- priv->dma_buffer, -+ dma_buffer, - dma_size, - dma_direction); - - if (dma_mapping_error(dev, dma_addr)) { - dev_err(dev, "Error in mapping dma buffer %p\n", -- priv->dma_buffer); -+ dma_buffer); - return -EIO; - } - diff --git a/patch/kernel-add-kexec-reboot-string.patch b/patch/kernel-add-kexec-reboot-string.patch index 114cd316278b..c95bc07cbc35 100644 --- a/patch/kernel-add-kexec-reboot-string.patch +++ b/patch/kernel-add-kexec-reboot-string.patch @@ -8,10 +8,10 @@ Subject: [PATCH] Add kexec reboot string 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c -index 5616755..ac8a106 100644 +index 23a83a4da..6c05e6516 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c -@@ -1531,7 +1531,7 @@ int kernel_kexec(void) +@@ -1154,7 +1154,7 @@ int kernel_kexec(void) #endif { kexec_in_progress = true; diff --git a/patch/kernel-enable-psample-and-act_sample-drivers.patch b/patch/kernel-enable-psample-and-act_sample-drivers.patch deleted file mode 100644 index aa1f57163878..000000000000 --- a/patch/kernel-enable-psample-and-act_sample-drivers.patch +++ /dev/null @@ -1,49 +0,0 @@ -From: Rakesh Datta -Date: Thu, 27 Jun 2019 11:07:08 +0100 -Subject: [PATCH] net: Introduce psample and sample modules - adding the below config: - -CONFIG_PSAMPLE=m -CONFIG_NET_ACT_SAMPLE=m - -Signed-off-by: Rakesh Datta ---- - debian/build/build_amd64_none_amd64/.config | 2 + - 1 file changed, 2 insertion(+) - -diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config -index db2a5c1..9851a0c 100644 ---- a/debian/build/build_amd64_none_amd64/.config -+++ b/debian/build/build_amd64_none_amd64/.config -@@ -47,6 +47,8 @@ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" - CONFIG_IRQ_WORK=y - CONFIG_BUILDTIME_EXTABLE_SORT=y - CONFIG_THREAD_INFO_IN_TASK=y -+CONFIG_PSAMPLE=m -+CONFIG_NET_ACT_SAMPLE=m - - # - # General setup -diff --git a/debian/build/build_armhf_none_armmp/.config b/debian/build/build_armhf_none_armmp/.config -index d50fff8..e997934 100644 ---- a/debian/build/build_armhf_none_armmp/.config -+++ b/debian/build/build_armhf_none_armmp/.config -@@ -1501,7 +1501,7 @@ CONFIG_NET_ACT_POLICE=m - CONFIG_NET_ACT_GACT=m - CONFIG_GACT_PROB=y - CONFIG_NET_ACT_MIRRED=m --# CONFIG_NET_ACT_SAMPLE is not set -+CONFIG_NET_ACT_SAMPLE=m - CONFIG_NET_ACT_IPT=m - CONFIG_NET_ACT_NAT=m - CONFIG_NET_ACT_PEDIT=m -@@ -1718,7 +1718,7 @@ CONFIG_NFC_PN533=m - CONFIG_NFC_PN533_USB=m - # CONFIG_NFC_PN533_I2C is not set - # CONFIG_NFC_ST95HF is not set --# CONFIG_PSAMPLE is not set -+CONFIG_PSAMPLE=m - CONFIG_LWTUNNEL=y - CONFIG_DST_CACHE=y - CONFIG_NET_DEVLINK=m --- -2.7.4 diff --git a/patch/linux-4.13-thermal-intel_pch_thermal-Fix-enable-check-on.patch b/patch/linux-4.13-thermal-intel_pch_thermal-Fix-enable-check-on.patch deleted file mode 100644 index be99c9441c58..000000000000 --- a/patch/linux-4.13-thermal-intel_pch_thermal-Fix-enable-check-on.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 595536e0b2475a9eac23709cd461143178c12e0e Mon Sep 17 00:00:00 2001 -From: Ed Swierk -Date: Wed, 19 Jul 2017 17:44:40 -0700 -Subject: [PATCH] thermal: intel_pch_thermal: Fix enable check on Broadwell-DE - -Using the TSDSS flag to determine whether the thermal sensor is -enabled is problematic. Broadwell-DE (Xeon D-1500) does not support -dynamic shutdown and the TSDSS flag always reads 0 (contrary to the -current datasheet). Even on hardware supporting dynamic shutdown, the -driver does nothing to configure it, and the dynamic shutdown state -should not prevent the driver from loading. The ETS flag itself -indicates whether the thermal sensor is enabled, so use it instead of -the TSDSS flag on all hardware platforms. - -Signed-off-by: Ed Swierk -Reviewed-by: Srinivas Pandruvada -Signed-off-by: Zhang Rui ---- - drivers/thermal/intel_pch_thermal.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/thermal/intel_pch_thermal.c b/drivers/thermal/intel_pch_thermal.c -index 9e8fb782b521..c60b1cfcc64e 100644 ---- a/drivers/thermal/intel_pch_thermal.c -+++ b/drivers/thermal/intel_pch_thermal.c -@@ -125,7 +125,7 @@ static int pch_wpt_init(struct pch_thermal_device *ptd, int *nr_trips) - *nr_trips = 0; - - /* Check if BIOS has already enabled thermal sensor */ -- if (WPT_TSS_TSDSS & readb(ptd->hw_base + WPT_TSS)) { -+ if (WPT_TSEL_ETS & readb(ptd->hw_base + WPT_TSEL)) { - ptd->bios_enabled = true; - goto read_trips; - } -@@ -141,7 +141,7 @@ static int pch_wpt_init(struct pch_thermal_device *ptd, int *nr_trips) - } - - writeb(tsel|WPT_TSEL_ETS, ptd->hw_base + WPT_TSEL); -- if (!(WPT_TSS_TSDSS & readb(ptd->hw_base + WPT_TSS))) { -+ if (!(WPT_TSEL_ETS & readb(ptd->hw_base + WPT_TSEL))) { - dev_err(&ptd->pdev->dev, "Sensor can't be enabled\n"); - return -ENODEV; - } --- -2.17.0 - diff --git a/patch/linux-4.16-firmware-dmi-handle-missing-DMI-data-gracefully.patch b/patch/linux-4.16-firmware-dmi-handle-missing-DMI-data-gracefully.patch deleted file mode 100644 index bc49bf1f42ae..000000000000 --- a/patch/linux-4.16-firmware-dmi-handle-missing-DMI-data-gracefully.patch +++ /dev/null @@ -1,63 +0,0 @@ -From a81114d03e4a529c4b68293249f75438b3c1783f Mon Sep 17 00:00:00 2001 -From: Ard Biesheuvel -Date: Sat, 3 Feb 2018 11:25:20 +0100 -Subject: [PATCH] firmware: dmi: handle missing DMI data gracefully -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Currently, when booting a kernel with DMI support on a platform that has -no DMI tables, the following output is emitted into the kernel log: - - [ 0.128818] DMI not present or invalid. - ... - [ 1.306659] dmi: Firmware registration failed. - ... - [ 2.908681] dmi-sysfs: dmi entry is absent. - -The first one is a pr_info(), but the subsequent ones are pr_err()s that -complain about a condition that is not really an error to begin with. - -So let's clean this up, and give up silently if dma_available is not set. - -Signed-off-by: Ard Biesheuvel -Acked-by: Martin Hundebøll -Signed-off-by: Jean Delvare ---- - drivers/firmware/dmi-sysfs.c | 2 +- - drivers/firmware/dmi_scan.c | 6 ++---- - 2 files changed, 3 insertions(+), 5 deletions(-) - -diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c -index ef76e5eecf0b..d401d69ee2a7 100644 ---- a/drivers/firmware/dmi-sysfs.c -+++ b/drivers/firmware/dmi-sysfs.c -@@ -651,7 +651,7 @@ static int __init dmi_sysfs_init(void) - int val; - - if (!dmi_kobj) { -- pr_err("dmi-sysfs: dmi entry is absent.\n"); -+ pr_debug("dmi-sysfs: dmi entry is absent.\n"); - error = -ENODATA; - goto err; - } -diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c -index 42844c318445..74a6a3c5185c 100644 ---- a/drivers/firmware/dmi_scan.c -+++ b/drivers/firmware/dmi_scan.c -@@ -686,10 +686,8 @@ static int __init dmi_init(void) - u8 *dmi_table; - int ret = -ENOMEM; - -- if (!dmi_available) { -- ret = -ENODATA; -- goto err; -- } -+ if (!dmi_available) -+ return 0; - - /* - * Set up dmi directory at /sys/firmware/dmi. This entry should stay --- -2.21.0 - diff --git a/patch/mellanox-backport-introduce-psample-a-new-genetlink-channel.patch b/patch/mellanox-backport-introduce-psample-a-new-genetlink-channel.patch deleted file mode 100644 index bcd771a8d61a..000000000000 --- a/patch/mellanox-backport-introduce-psample-a-new-genetlink-channel.patch +++ /dev/null @@ -1,538 +0,0 @@ -From 6ae0a6286171154661b74f7f550f9441c6008424 Mon Sep 17 00:00:00 2001 -From: Yotam Gigi -Date: Mon, 23 Jan 2017 11:07:08 +0100 -Subject: [PATCH] net: Introduce psample, a new genetlink channel for packet - sampling - -Add a general way for kernel modules to sample packets, without being tied -to any specific subsystem. This netlink channel can be used by tc, -iptables, etc. and allow to standardize packet sampling in the kernel. - -For every sampled packet, the psample module adds the following metadata -fields: - -PSAMPLE_ATTR_IIFINDEX - the packets input ifindex, if applicable - -PSAMPLE_ATTR_OIFINDEX - the packet output ifindex, if applicable - -PSAMPLE_ATTR_ORIGSIZE - the packet's original size, in case it has been - truncated during sampling - -PSAMPLE_ATTR_SAMPLE_GROUP - the packet's sample group, which is set by the - user who initiated the sampling. This field allows the user to - differentiate between several samplers working simultaneously and - filter packets relevant to him - -PSAMPLE_ATTR_GROUP_SEQ - sequence counter of last sent packet. The - sequence is kept for each group - -PSAMPLE_ATTR_SAMPLE_RATE - the sampling rate used for sampling the packets - -PSAMPLE_ATTR_DATA - the actual packet bits - -The sampled packets are sent to the PSAMPLE_NL_MCGRP_SAMPLE multicast -group. In addition, add the GET_GROUPS netlink command which allows the -user to see the current sample groups, their refcount and sequence number. -This command currently supports only netlink dump mode. - -Signed-off-by: Yotam Gigi -Signed-off-by: Jiri Pirko -Reviewed-by: Jamal Hadi Salim -Reviewed-by: Simon Horman -Signed-off-by: David S. Miller ---- - MAINTAINERS | 7 + - include/net/psample.h | 36 ++++++ - include/uapi/linux/Kbuild | 1 + - include/uapi/linux/psample.h | 35 +++++ - net/Kconfig | 1 + - net/Makefile | 1 + - net/psample/Kconfig | 15 +++ - net/psample/Makefile | 5 + - net/psample/psample.c | 301 +++++++++++++++++++++++++++++++++++++++++++ - 9 files changed, 402 insertions(+) - create mode 100644 include/net/psample.h - create mode 100644 include/uapi/linux/psample.h - create mode 100644 net/psample/Kconfig - create mode 100644 net/psample/Makefile - create mode 100644 net/psample/psample.c - -diff --git a/MAINTAINERS b/MAINTAINERS -index 3c84a8f..d76fccd 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -9957,6 +9957,13 @@ L: linuxppc-dev@lists.ozlabs.org - S: Maintained - F: drivers/block/ps3vram.c - -+PSAMPLE PACKET SAMPLING SUPPORT: -+M: Yotam Gigi -+S: Maintained -+F: net/psample -+F: include/net/psample.h -+F: include/uapi/linux/psample.h -+ - PSTORE FILESYSTEM - M: Anton Vorontsov - M: Colin Cross -diff --git a/include/net/psample.h b/include/net/psample.h -new file mode 100644 -index 0000000..8888b0e ---- /dev/null -+++ b/include/net/psample.h -@@ -0,0 +1,36 @@ -+#ifndef __NET_PSAMPLE_H -+#define __NET_PSAMPLE_H -+ -+#include -+#include -+#include -+ -+struct psample_group { -+ struct list_head list; -+ struct net *net; -+ u32 group_num; -+ u32 refcount; -+ u32 seq; -+}; -+ -+struct psample_group *psample_group_get(struct net *net, u32 group_num); -+void psample_group_put(struct psample_group *group); -+ -+#if IS_ENABLED(CONFIG_PSAMPLE) -+ -+void psample_sample_packet(struct psample_group *group, struct sk_buff *skb, -+ u32 trunc_size, int in_ifindex, int out_ifindex, -+ u32 sample_rate); -+ -+#else -+ -+static inline void psample_sample_packet(struct psample_group *group, -+ struct sk_buff *skb, u32 trunc_size, -+ int in_ifindex, int out_ifindex, -+ u32 sample_rate) -+{ -+} -+ -+#endif -+ -+#endif /* __NET_PSAMPLE_H */ -diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild -index e600b50..80ad741 100644 ---- a/include/uapi/linux/Kbuild -+++ b/include/uapi/linux/Kbuild -@@ -305,6 +305,7 @@ header-y += netrom.h - header-y += net_namespace.h - header-y += net_tstamp.h - header-y += nfc.h -+header-y += psample.h - header-y += nfs2.h - header-y += nfs3.h - header-y += nfs4.h -diff --git a/include/uapi/linux/psample.h b/include/uapi/linux/psample.h -new file mode 100644 -index 0000000..ed48996 ---- /dev/null -+++ b/include/uapi/linux/psample.h -@@ -0,0 +1,35 @@ -+#ifndef __UAPI_PSAMPLE_H -+#define __UAPI_PSAMPLE_H -+ -+enum { -+ /* sampled packet metadata */ -+ PSAMPLE_ATTR_IIFINDEX, -+ PSAMPLE_ATTR_OIFINDEX, -+ PSAMPLE_ATTR_ORIGSIZE, -+ PSAMPLE_ATTR_SAMPLE_GROUP, -+ PSAMPLE_ATTR_GROUP_SEQ, -+ PSAMPLE_ATTR_SAMPLE_RATE, -+ PSAMPLE_ATTR_DATA, -+ -+ /* commands attributes */ -+ PSAMPLE_ATTR_GROUP_REFCOUNT, -+ -+ __PSAMPLE_ATTR_MAX -+}; -+ -+enum psample_command { -+ PSAMPLE_CMD_SAMPLE, -+ PSAMPLE_CMD_GET_GROUP, -+ PSAMPLE_CMD_NEW_GROUP, -+ PSAMPLE_CMD_DEL_GROUP, -+}; -+ -+/* Can be overridden at runtime by module option */ -+#define PSAMPLE_ATTR_MAX (__PSAMPLE_ATTR_MAX - 1) -+ -+#define PSAMPLE_NL_MCGRP_CONFIG_NAME "config" -+#define PSAMPLE_NL_MCGRP_SAMPLE_NAME "packets" -+#define PSAMPLE_GENL_NAME "psample" -+#define PSAMPLE_GENL_VERSION 1 -+ -+#endif -diff --git a/net/Kconfig b/net/Kconfig -index 92ae150..ce4aee6 100644 ---- a/net/Kconfig -+++ b/net/Kconfig -@@ -390,6 +390,7 @@ source "net/9p/Kconfig" - source "net/caif/Kconfig" - source "net/ceph/Kconfig" - source "net/nfc/Kconfig" -+source "net/psample/Kconfig" - - config LWTUNNEL - bool "Network light weight tunnels" -diff --git a/net/Makefile b/net/Makefile -index 5d6e0e5f..7d41de4 100644 ---- a/net/Makefile -+++ b/net/Makefile -@@ -70,6 +70,7 @@ obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/ - obj-$(CONFIG_CEPH_LIB) += ceph/ - obj-$(CONFIG_BATMAN_ADV) += batman-adv/ - obj-$(CONFIG_NFC) += nfc/ -+obj-$(CONFIG_PSAMPLE) += psample/ - obj-$(CONFIG_OPENVSWITCH) += openvswitch/ - obj-$(CONFIG_VSOCKETS) += vmw_vsock/ - obj-$(CONFIG_MPLS) += mpls/ -diff --git a/net/psample/Kconfig b/net/psample/Kconfig -new file mode 100644 -index 0000000..d850246 ---- /dev/null -+++ b/net/psample/Kconfig -@@ -0,0 +1,15 @@ -+# -+# psample packet sampling configuration -+# -+ -+menuconfig PSAMPLE -+ depends on NET -+ tristate "Packet-sampling netlink channel" -+ default n -+ help -+ Say Y here to add support for packet-sampling netlink channel -+ This netlink channel allows transferring packets alongside some -+ metadata to userspace. -+ -+ To compile this support as a module, choose M here: the module will -+ be called psample. -diff --git a/net/psample/Makefile b/net/psample/Makefile -new file mode 100644 -index 0000000..609b0a7 ---- /dev/null -+++ b/net/psample/Makefile -@@ -0,0 +1,5 @@ -+# -+# Makefile for the psample netlink channel -+# -+ -+obj-$(CONFIG_PSAMPLE) += psample.o -diff --git a/net/psample/psample.c b/net/psample/psample.c -new file mode 100644 -index 0000000..8aa58a9 ---- /dev/null -+++ b/net/psample/psample.c -@@ -0,0 +1,301 @@ -+/* -+ * net/psample/psample.c - Netlink channel for packet sampling -+ * Copyright (c) 2017 Yotam Gigi -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define PSAMPLE_MAX_PACKET_SIZE 0xffff -+ -+static LIST_HEAD(psample_groups_list); -+static DEFINE_SPINLOCK(psample_groups_lock); -+ -+/* multicast groups */ -+enum psample_nl_multicast_groups { -+ PSAMPLE_NL_MCGRP_CONFIG, -+ PSAMPLE_NL_MCGRP_SAMPLE, -+}; -+ -+static const struct genl_multicast_group psample_nl_mcgrps[] = { -+ [PSAMPLE_NL_MCGRP_CONFIG] = { .name = PSAMPLE_NL_MCGRP_CONFIG_NAME }, -+ [PSAMPLE_NL_MCGRP_SAMPLE] = { .name = PSAMPLE_NL_MCGRP_SAMPLE_NAME }, -+}; -+ -+static struct genl_family psample_nl_family __ro_after_init; -+ -+static int psample_group_nl_fill(struct sk_buff *msg, -+ struct psample_group *group, -+ enum psample_command cmd, u32 portid, u32 seq, -+ int flags) -+{ -+ void *hdr; -+ int ret; -+ -+ hdr = genlmsg_put(msg, portid, seq, &psample_nl_family, flags, cmd); -+ if (!hdr) -+ return -EMSGSIZE; -+ -+ ret = nla_put_u32(msg, PSAMPLE_ATTR_SAMPLE_GROUP, group->group_num); -+ if (ret < 0) -+ goto error; -+ -+ ret = nla_put_u32(msg, PSAMPLE_ATTR_GROUP_REFCOUNT, group->refcount); -+ if (ret < 0) -+ goto error; -+ -+ ret = nla_put_u32(msg, PSAMPLE_ATTR_GROUP_SEQ, group->seq); -+ if (ret < 0) -+ goto error; -+ -+ genlmsg_end(msg, hdr); -+ return 0; -+ -+error: -+ genlmsg_cancel(msg, hdr); -+ return -EMSGSIZE; -+} -+ -+static int psample_nl_cmd_get_group_dumpit(struct sk_buff *msg, -+ struct netlink_callback *cb) -+{ -+ struct psample_group *group; -+ int start = cb->args[0]; -+ int idx = 0; -+ int err; -+ -+ spin_lock(&psample_groups_lock); -+ list_for_each_entry(group, &psample_groups_list, list) { -+ if (!net_eq(group->net, sock_net(msg->sk))) -+ continue; -+ if (idx < start) { -+ idx++; -+ continue; -+ } -+ err = psample_group_nl_fill(msg, group, PSAMPLE_CMD_NEW_GROUP, -+ NETLINK_CB(cb->skb).portid, -+ cb->nlh->nlmsg_seq, NLM_F_MULTI); -+ if (err) -+ break; -+ idx++; -+ } -+ -+ spin_unlock(&psample_groups_lock); -+ cb->args[0] = idx; -+ return msg->len; -+} -+ -+static const struct genl_ops psample_nl_ops[] = { -+ { -+ .cmd = PSAMPLE_CMD_GET_GROUP, -+ .dumpit = psample_nl_cmd_get_group_dumpit, -+ /* can be retrieved by unprivileged users */ -+ } -+}; -+ -+static struct genl_family psample_nl_family __ro_after_init = { -+ .name = PSAMPLE_GENL_NAME, -+ .version = PSAMPLE_GENL_VERSION, -+ .maxattr = PSAMPLE_ATTR_MAX, -+ .netnsok = true, -+ .module = THIS_MODULE, -+ .mcgrps = psample_nl_mcgrps, -+ .ops = psample_nl_ops, -+ .n_ops = ARRAY_SIZE(psample_nl_ops), -+ .n_mcgrps = ARRAY_SIZE(psample_nl_mcgrps), -+}; -+ -+static void psample_group_notify(struct psample_group *group, -+ enum psample_command cmd) -+{ -+ struct sk_buff *msg; -+ int err; -+ -+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); -+ if (!msg) -+ return; -+ -+ err = psample_group_nl_fill(msg, group, cmd, 0, 0, NLM_F_MULTI); -+ if (!err) -+ genlmsg_multicast_netns(&psample_nl_family, group->net, msg, 0, -+ PSAMPLE_NL_MCGRP_CONFIG, GFP_ATOMIC); -+ else -+ nlmsg_free(msg); -+} -+ -+static struct psample_group *psample_group_create(struct net *net, -+ u32 group_num) -+{ -+ struct psample_group *group; -+ -+ group = kzalloc(sizeof(*group), GFP_ATOMIC); -+ if (!group) -+ return NULL; -+ -+ group->net = net; -+ group->group_num = group_num; -+ list_add_tail(&group->list, &psample_groups_list); -+ -+ psample_group_notify(group, PSAMPLE_CMD_NEW_GROUP); -+ return group; -+} -+ -+static void psample_group_destroy(struct psample_group *group) -+{ -+ psample_group_notify(group, PSAMPLE_CMD_DEL_GROUP); -+ list_del(&group->list); -+ kfree(group); -+} -+ -+static struct psample_group * -+psample_group_lookup(struct net *net, u32 group_num) -+{ -+ struct psample_group *group; -+ -+ list_for_each_entry(group, &psample_groups_list, list) -+ if ((group->group_num == group_num) && (group->net == net)) -+ return group; -+ return NULL; -+} -+ -+struct psample_group *psample_group_get(struct net *net, u32 group_num) -+{ -+ struct psample_group *group; -+ -+ spin_lock(&psample_groups_lock); -+ -+ group = psample_group_lookup(net, group_num); -+ if (!group) { -+ group = psample_group_create(net, group_num); -+ if (!group) -+ goto out; -+ } -+ group->refcount++; -+ -+out: -+ spin_unlock(&psample_groups_lock); -+ return group; -+} -+EXPORT_SYMBOL_GPL(psample_group_get); -+ -+void psample_group_put(struct psample_group *group) -+{ -+ spin_lock(&psample_groups_lock); -+ -+ if (--group->refcount == 0) -+ psample_group_destroy(group); -+ -+ spin_unlock(&psample_groups_lock); -+} -+EXPORT_SYMBOL_GPL(psample_group_put); -+ -+void psample_sample_packet(struct psample_group *group, struct sk_buff *skb, -+ u32 trunc_size, int in_ifindex, int out_ifindex, -+ u32 sample_rate) -+{ -+ struct sk_buff *nl_skb; -+ int data_len; -+ int meta_len; -+ void *data; -+ int ret; -+ -+ meta_len = (in_ifindex ? nla_total_size(sizeof(u16)) : 0) + -+ (out_ifindex ? nla_total_size(sizeof(u16)) : 0) + -+ nla_total_size(sizeof(u32)) + /* sample_rate */ -+ nla_total_size(sizeof(u32)) + /* orig_size */ -+ nla_total_size(sizeof(u32)) + /* group_num */ -+ nla_total_size(sizeof(u32)); /* seq */ -+ -+ data_len = min(skb->len, trunc_size); -+ if (meta_len + nla_total_size(data_len) > PSAMPLE_MAX_PACKET_SIZE) -+ data_len = PSAMPLE_MAX_PACKET_SIZE - meta_len - NLA_HDRLEN -+ - NLA_ALIGNTO; -+ -+ nl_skb = genlmsg_new(meta_len + data_len, GFP_ATOMIC); -+ if (unlikely(!nl_skb)) -+ return; -+ -+ data = genlmsg_put(nl_skb, 0, 0, &psample_nl_family, 0, -+ PSAMPLE_CMD_SAMPLE); -+ if (unlikely(!data)) -+ goto error; -+ -+ if (in_ifindex) { -+ ret = nla_put_u16(nl_skb, PSAMPLE_ATTR_IIFINDEX, in_ifindex); -+ if (unlikely(ret < 0)) -+ goto error; -+ } -+ -+ if (out_ifindex) { -+ ret = nla_put_u16(nl_skb, PSAMPLE_ATTR_OIFINDEX, out_ifindex); -+ if (unlikely(ret < 0)) -+ goto error; -+ } -+ -+ ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_SAMPLE_RATE, sample_rate); -+ if (unlikely(ret < 0)) -+ goto error; -+ -+ ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_ORIGSIZE, skb->len); -+ if (unlikely(ret < 0)) -+ goto error; -+ -+ ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_SAMPLE_GROUP, group->group_num); -+ if (unlikely(ret < 0)) -+ goto error; -+ -+ ret = nla_put_u32(nl_skb, PSAMPLE_ATTR_GROUP_SEQ, group->seq++); -+ if (unlikely(ret < 0)) -+ goto error; -+ -+ if (data_len) { -+ int nla_len = nla_total_size(data_len); -+ struct nlattr *nla; -+ -+ nla = (struct nlattr *)skb_put(nl_skb, nla_len); -+ nla->nla_type = PSAMPLE_ATTR_DATA; -+ nla->nla_len = nla_attr_size(data_len); -+ -+ if (skb_copy_bits(skb, 0, nla_data(nla), data_len)) -+ goto error; -+ } -+ -+ genlmsg_end(nl_skb, data); -+ genlmsg_multicast_netns(&psample_nl_family, group->net, nl_skb, 0, -+ PSAMPLE_NL_MCGRP_SAMPLE, GFP_ATOMIC); -+ -+ return; -+error: -+ pr_err_ratelimited("Could not create psample log message\n"); -+ nlmsg_free(nl_skb); -+} -+EXPORT_SYMBOL_GPL(psample_sample_packet); -+ -+static int __init psample_module_init(void) -+{ -+ return genl_register_family(&psample_nl_family); -+} -+ -+static void __exit psample_module_exit(void) -+{ -+ genl_unregister_family(&psample_nl_family); -+} -+ -+module_init(psample_module_init); -+module_exit(psample_module_exit); -+ -+MODULE_AUTHOR("Yotam Gigi "); -+MODULE_DESCRIPTION("netlink channel for packet sampling"); -+MODULE_LICENSE("GPL v2"); --- -2.7.4 - diff --git a/patch/mellanox-backport-introduce-tc-sample-action.patch b/patch/mellanox-backport-introduce-tc-sample-action.patch deleted file mode 100644 index 8002102c16b6..000000000000 --- a/patch/mellanox-backport-introduce-tc-sample-action.patch +++ /dev/null @@ -1,457 +0,0 @@ -From 5c5670fae43027778e84b9d9ff3b9d91a10a8131 Mon Sep 17 00:00:00 2001 -From: Yotam Gigi -Date: Mon, 23 Jan 2017 11:07:09 +0100 -Subject: [PATCH] net/sched: Introduce sample tc action - -This action allows the user to sample traffic matched by tc classifier. -The sampling consists of choosing packets randomly and sampling them using -the psample module. The user can configure the psample group number, the -sampling rate and the packet's truncation (to save kernel-user traffic). - -Example: -To sample ingress traffic from interface eth1, one may use the commands: - -tc qdisc add dev eth1 handle ffff: ingress - -tc filter add dev eth1 parent ffff: \ - matchall action sample rate 12 group 4 - -Where the first command adds an ingress qdisc and the second starts -sampling randomly with an average of one sampled packet per 12 packets on -dev eth1 to psample group 4. - -Signed-off-by: Yotam Gigi -Signed-off-by: Jiri Pirko -Acked-by: Jamal Hadi Salim -Reviewed-by: Simon Horman -Signed-off-by: David S. Miller ---- - include/net/tc_act/tc_sample.h | 50 +++++++ - include/uapi/linux/tc_act/Kbuild | 1 + - include/uapi/linux/tc_act/tc_sample.h | 26 ++++ - net/sched/Kconfig | 12 ++ - net/sched/Makefile | 1 + - net/sched/act_sample.c | 274 ++++++++++++++++++++++++++++++++++ - 6 files changed, 364 insertions(+) - create mode 100644 include/net/tc_act/tc_sample.h - create mode 100644 include/uapi/linux/tc_act/tc_sample.h - create mode 100644 net/sched/act_sample.c - -diff --git a/include/net/tc_act/tc_sample.h b/include/net/tc_act/tc_sample.h -new file mode 100644 -index 0000000..89e9305 ---- /dev/null -+++ b/include/net/tc_act/tc_sample.h -@@ -0,0 +1,50 @@ -+#ifndef __NET_TC_SAMPLE_H -+#define __NET_TC_SAMPLE_H -+ -+#include -+#include -+#include -+ -+struct tcf_sample { -+ struct tc_action common; -+ u32 rate; -+ bool truncate; -+ u32 trunc_size; -+ struct psample_group __rcu *psample_group; -+ u32 psample_group_num; -+ struct list_head tcfm_list; -+ struct rcu_head rcu; -+}; -+#define to_sample(a) ((struct tcf_sample *)a) -+ -+static inline bool is_tcf_sample(const struct tc_action *a) -+{ -+#ifdef CONFIG_NET_CLS_ACT -+ return a->ops && a->ops->type == TCA_ACT_SAMPLE; -+#else -+ return false; -+#endif -+} -+ -+static inline __u32 tcf_sample_rate(const struct tc_action *a) -+{ -+ return to_sample(a)->rate; -+} -+ -+static inline bool tcf_sample_truncate(const struct tc_action *a) -+{ -+ return to_sample(a)->truncate; -+} -+ -+static inline int tcf_sample_trunc_size(const struct tc_action *a) -+{ -+ return to_sample(a)->trunc_size; -+} -+ -+static inline struct psample_group * -+tcf_sample_psample_group(const struct tc_action *a) -+{ -+ return rcu_dereference(to_sample(a)->psample_group); -+} -+ -+#endif /* __NET_TC_SAMPLE_H */ -diff --git a/include/uapi/linux/tc_act/Kbuild b/include/uapi/linux/tc_act/Kbuild -index e3db740..ba62ddf 100644 ---- a/include/uapi/linux/tc_act/Kbuild -+++ b/include/uapi/linux/tc_act/Kbuild -@@ -4,6 +4,7 @@ header-y += tc_defact.h - header-y += tc_gact.h - header-y += tc_ipt.h - header-y += tc_mirred.h -+header-y += tc_sample.h - header-y += tc_nat.h - header-y += tc_pedit.h - header-y += tc_skbedit.h -diff --git a/include/uapi/linux/tc_act/tc_sample.h b/include/uapi/linux/tc_act/tc_sample.h -new file mode 100644 -index 0000000..edc9058 ---- /dev/null -+++ b/include/uapi/linux/tc_act/tc_sample.h -@@ -0,0 +1,26 @@ -+#ifndef __LINUX_TC_SAMPLE_H -+#define __LINUX_TC_SAMPLE_H -+ -+#include -+#include -+#include -+ -+#define TCA_ACT_SAMPLE 26 -+ -+struct tc_sample { -+ tc_gen; -+}; -+ -+enum { -+ TCA_SAMPLE_UNSPEC, -+ TCA_SAMPLE_TM, -+ TCA_SAMPLE_PARMS, -+ TCA_SAMPLE_RATE, -+ TCA_SAMPLE_TRUNC_SIZE, -+ TCA_SAMPLE_PSAMPLE_GROUP, -+ TCA_SAMPLE_PAD, -+ __TCA_SAMPLE_MAX -+}; -+#define TCA_SAMPLE_MAX (__TCA_SAMPLE_MAX - 1) -+ -+#endif -diff --git a/net/sched/Kconfig b/net/sched/Kconfig -index a9aa38d..72cfa3a 100644 ---- a/net/sched/Kconfig -+++ b/net/sched/Kconfig -@@ -650,6 +650,18 @@ config NET_ACT_MIRRED - To compile this code as a module, choose M here: the - module will be called act_mirred. - -+config NET_ACT_SAMPLE -+ tristate "Traffic Sampling" -+ depends on NET_CLS_ACT -+ select PSAMPLE -+ ---help--- -+ Say Y here to allow packet sampling tc action. The packet sample -+ action consists of statistically choosing packets and sampling -+ them using the psample module. -+ -+ To compile this code as a module, choose M here: the -+ module will be called act_sample. -+ - config NET_ACT_IPT - tristate "IPtables targets" - depends on NET_CLS_ACT && NETFILTER && IP_NF_IPTABLES -diff --git a/net/sched/Makefile b/net/sched/Makefile -index 4bdda36..7b915d2 100644 ---- a/net/sched/Makefile -+++ b/net/sched/Makefile -@@ -10,6 +10,7 @@ obj-$(CONFIG_NET_CLS_ACT) += act_api.o - obj-$(CONFIG_NET_ACT_POLICE) += act_police.o - obj-$(CONFIG_NET_ACT_GACT) += act_gact.o - obj-$(CONFIG_NET_ACT_MIRRED) += act_mirred.o -+obj-$(CONFIG_NET_ACT_SAMPLE) += act_sample.o - obj-$(CONFIG_NET_ACT_IPT) += act_ipt.o - obj-$(CONFIG_NET_ACT_NAT) += act_nat.o - obj-$(CONFIG_NET_ACT_PEDIT) += act_pedit.o -diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c -new file mode 100644 -index 0000000..3922975 ---- /dev/null -+++ b/net/sched/act_sample.c -@@ -0,0 +1,274 @@ -+/* -+ * net/sched/act_sample.c - Packet sampling tc action -+ * Copyright (c) 2017 Yotam Gigi -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define SAMPLE_TAB_MASK 7 -+static unsigned int sample_net_id; -+static struct tc_action_ops act_sample_ops; -+ -+static const struct nla_policy sample_policy[TCA_SAMPLE_MAX + 1] = { -+ [TCA_SAMPLE_PARMS] = { .len = sizeof(struct tc_sample) }, -+ [TCA_SAMPLE_RATE] = { .type = NLA_U32 }, -+ [TCA_SAMPLE_TRUNC_SIZE] = { .type = NLA_U32 }, -+ [TCA_SAMPLE_PSAMPLE_GROUP] = { .type = NLA_U32 }, -+}; -+ -+static int tcf_sample_init(struct net *net, struct nlattr *nla, -+ struct nlattr *est, struct tc_action **a, int ovr, -+ int bind) -+{ -+ struct tc_action_net *tn = net_generic(net, sample_net_id); -+ struct nlattr *tb[TCA_SAMPLE_MAX + 1]; -+ struct psample_group *psample_group; -+ struct tc_sample *parm; -+ struct tcf_sample *s; -+ bool exists = false; -+ int ret; -+ -+ if (!nla) -+ return -EINVAL; -+ ret = nla_parse_nested(tb, TCA_SAMPLE_MAX, nla, sample_policy); -+ if (ret < 0) -+ return ret; -+ if (!tb[TCA_SAMPLE_PARMS] || !tb[TCA_SAMPLE_RATE] || -+ !tb[TCA_SAMPLE_PSAMPLE_GROUP]) -+ return -EINVAL; -+ -+ parm = nla_data(tb[TCA_SAMPLE_PARMS]); -+ -+ exists = tcf_hash_check(tn, parm->index, a, bind); -+ if (exists && bind) -+ return 0; -+ -+ if (!exists) { -+ ret = tcf_hash_create(tn, parm->index, est, a, -+ &act_sample_ops, bind, false); -+ if (ret) -+ return ret; -+ ret = ACT_P_CREATED; -+ } else { -+ tcf_hash_release(*a, bind); -+ if (!ovr) -+ return -EEXIST; -+ } -+ s = to_sample(*a); -+ -+ ASSERT_RTNL(); -+ s->tcf_action = parm->action; -+ s->rate = nla_get_u32(tb[TCA_SAMPLE_RATE]); -+ s->psample_group_num = nla_get_u32(tb[TCA_SAMPLE_PSAMPLE_GROUP]); -+ psample_group = psample_group_get(net, s->psample_group_num); -+ if (!psample_group) -+ return -ENOMEM; -+ RCU_INIT_POINTER(s->psample_group, psample_group); -+ -+ if (tb[TCA_SAMPLE_TRUNC_SIZE]) { -+ s->truncate = true; -+ s->trunc_size = nla_get_u32(tb[TCA_SAMPLE_TRUNC_SIZE]); -+ } -+ -+ if (ret == ACT_P_CREATED) -+ tcf_hash_insert(tn, *a); -+ return ret; -+} -+ -+static void tcf_sample_cleanup_rcu(struct rcu_head *rcu) -+{ -+ struct tcf_sample *s = container_of(rcu, struct tcf_sample, rcu); -+ struct psample_group *psample_group; -+ -+ psample_group = rcu_dereference_protected(s->psample_group, 1); -+ RCU_INIT_POINTER(s->psample_group, NULL); -+ psample_group_put(psample_group); -+} -+ -+static void tcf_sample_cleanup(struct tc_action *a, int bind) -+{ -+ struct tcf_sample *s = to_sample(a); -+ -+ call_rcu(&s->rcu, tcf_sample_cleanup_rcu); -+} -+ -+static bool tcf_sample_dev_ok_push(struct net_device *dev) -+{ -+ switch (dev->type) { -+ case ARPHRD_TUNNEL: -+ case ARPHRD_TUNNEL6: -+ case ARPHRD_SIT: -+ case ARPHRD_IPGRE: -+ case ARPHRD_VOID: -+ case ARPHRD_NONE: -+ return false; -+ default: -+ return true; -+ } -+} -+ -+static int tcf_sample_act(struct sk_buff *skb, const struct tc_action *a, -+ struct tcf_result *res) -+{ -+ struct tcf_sample *s = to_sample(a); -+ struct psample_group *psample_group; -+ int retval; -+ int size; -+ int iif; -+ int oif; -+ -+ tcf_lastuse_update(&s->tcf_tm); -+ bstats_cpu_update(this_cpu_ptr(s->common.cpu_bstats), skb); -+ retval = READ_ONCE(s->tcf_action); -+ -+ rcu_read_lock(); -+ psample_group = rcu_dereference(s->psample_group); -+ -+ /* randomly sample packets according to rate */ -+ if (psample_group && (prandom_u32() % s->rate == 0)) { -+ if (!skb_at_tc_ingress(skb)) { -+ iif = skb->skb_iif; -+ oif = skb->dev->ifindex; -+ } else { -+ iif = skb->dev->ifindex; -+ oif = 0; -+ } -+ -+ /* on ingress, the mac header gets popped, so push it back */ -+ if (skb_at_tc_ingress(skb) && tcf_sample_dev_ok_push(skb->dev)) -+ skb_push(skb, skb->mac_len); -+ -+ size = s->truncate ? s->trunc_size : skb->len; -+ psample_sample_packet(psample_group, skb, size, iif, oif, -+ s->rate); -+ -+ if (skb_at_tc_ingress(skb) && tcf_sample_dev_ok_push(skb->dev)) -+ skb_pull(skb, skb->mac_len); -+ } -+ -+ rcu_read_unlock(); -+ return retval; -+} -+ -+static int tcf_sample_dump(struct sk_buff *skb, struct tc_action *a, -+ int bind, int ref) -+{ -+ unsigned char *b = skb_tail_pointer(skb); -+ struct tcf_sample *s = to_sample(a); -+ struct tc_sample opt = { -+ .index = s->tcf_index, -+ .action = s->tcf_action, -+ .refcnt = s->tcf_refcnt - ref, -+ .bindcnt = s->tcf_bindcnt - bind, -+ }; -+ struct tcf_t t; -+ -+ if (nla_put(skb, TCA_SAMPLE_PARMS, sizeof(opt), &opt)) -+ goto nla_put_failure; -+ -+ tcf_tm_dump(&t, &s->tcf_tm); -+ if (nla_put_64bit(skb, TCA_SAMPLE_TM, sizeof(t), &t, TCA_SAMPLE_PAD)) -+ goto nla_put_failure; -+ -+ if (nla_put_u32(skb, TCA_SAMPLE_RATE, s->rate)) -+ goto nla_put_failure; -+ -+ if (s->truncate) -+ if (nla_put_u32(skb, TCA_SAMPLE_TRUNC_SIZE, s->trunc_size)) -+ goto nla_put_failure; -+ -+ if (nla_put_u32(skb, TCA_SAMPLE_PSAMPLE_GROUP, s->psample_group_num)) -+ goto nla_put_failure; -+ return skb->len; -+ -+nla_put_failure: -+ nlmsg_trim(skb, b); -+ return -1; -+} -+ -+static int tcf_sample_walker(struct net *net, struct sk_buff *skb, -+ struct netlink_callback *cb, int type, -+ const struct tc_action_ops *ops) -+{ -+ struct tc_action_net *tn = net_generic(net, sample_net_id); -+ -+ return tcf_generic_walker(tn, skb, cb, type, ops); -+} -+ -+static int tcf_sample_search(struct net *net, struct tc_action **a, u32 index) -+{ -+ struct tc_action_net *tn = net_generic(net, sample_net_id); -+ -+ return tcf_hash_search(tn, a, index); -+} -+ -+static struct tc_action_ops act_sample_ops = { -+ .kind = "sample", -+ .type = TCA_ACT_SAMPLE, -+ .owner = THIS_MODULE, -+ .act = tcf_sample_act, -+ .dump = tcf_sample_dump, -+ .init = tcf_sample_init, -+ .cleanup = tcf_sample_cleanup, -+ .walk = tcf_sample_walker, -+ .lookup = tcf_sample_search, -+ .size = sizeof(struct tcf_sample), -+}; -+ -+static __net_init int sample_init_net(struct net *net) -+{ -+ struct tc_action_net *tn = net_generic(net, sample_net_id); -+ -+ return tc_action_net_init(tn, &act_sample_ops, SAMPLE_TAB_MASK); -+} -+ -+static void __net_exit sample_exit_net(struct net *net) -+{ -+ struct tc_action_net *tn = net_generic(net, sample_net_id); -+ -+ tc_action_net_exit(tn); -+} -+ -+static struct pernet_operations sample_net_ops = { -+ .init = sample_init_net, -+ .exit = sample_exit_net, -+ .id = &sample_net_id, -+ .size = sizeof(struct tc_action_net), -+}; -+ -+static int __init sample_init_module(void) -+{ -+ return tcf_register_action(&act_sample_ops, &sample_net_ops); -+} -+ -+static void __exit sample_cleanup_module(void) -+{ -+ tcf_unregister_action(&act_sample_ops, &sample_net_ops); -+} -+ -+module_init(sample_init_module); -+module_exit(sample_cleanup_module); -+ -+MODULE_AUTHOR("Yotam Gigi "); -+MODULE_DESCRIPTION("Packet sampling action"); -+MODULE_LICENSE("GPL v2"); --- -2.7.4 - diff --git a/patch/net-backport-ipv6-missing-route.patch b/patch/net-backport-ipv6-missing-route.patch index 5aa4e319356e..2e5b279dda38 100644 --- a/patch/net-backport-ipv6-missing-route.patch +++ b/patch/net-backport-ipv6-missing-route.patch @@ -2,11 +2,16 @@ The below patch has been backported to fix "ipv6: Handle missing host route in _ https://github.com/torvalds/linux/commit/2d819d250a1393a3e725715425ab70a0e0772a71#diff-0907850728440370acc820310df76f30 +From: Arun Saravanan Balachandran +--- + net/ipv6/addrconf.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c -index cb5aaf4..79c1012 100644 +index c57efd5c5..ea68ecb0a 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c -@@ -5402,13 +5402,20 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) +@@ -5677,13 +5677,20 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) switch (event) { case RTM_NEWADDR: /* @@ -21,9 +26,9 @@ index cb5aaf4..79c1012 100644 + * host route, so nothing to insert. That will be fixed when + * the device is brought up. */ -- if (!rcu_access_pointer(ifp->rt->rt6i_node)) -+ if (ifp->rt && !rcu_access_pointer(ifp->rt->rt6i_node)) { - ip6_ins_rt(ifp->rt); +- if (!rcu_access_pointer(ifp->rt->fib6_node)) ++ if (ifp->rt && !rcu_access_pointer(ifp->rt->fib6_node)) { + ip6_ins_rt(net, ifp->rt); + } else if (!ifp->rt && (ifp->idev->dev->flags & IFF_UP)) { + pr_warn("BUG: Address %pI6c on device %s is missing its host route.\n", + &ifp->addr, ifp->idev->dev->name); diff --git a/patch/net-psample-fix-skb-over-panic.patch b/patch/net-psample-fix-skb-over-panic.patch index d943bb0ed820..b8b996c32f7c 100644 --- a/patch/net-psample-fix-skb-over-panic.patch +++ b/patch/net-psample-fix-skb-over-panic.patch @@ -1,6 +1,7 @@ From 7eb9d7675c08937cd11d32b0b40442d4d731c5ee Mon Sep 17 00:00:00 2001 + From: Nikolay Aleksandrov -Date: Wed, 27 Nov 2019 00:16:44 +0200 + Subject: [PATCH] net: psample: fix skb_over_panic We need to calculate the skb size correctly otherwise we risk triggering @@ -74,14 +75,14 @@ Fixes: 6ae0a6286171 ("net: Introduce psample, a new genetlink channel for packet Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- - net/psample/psample.c | 2 +- + net/psample/psample.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/psample/psample.c b/net/psample/psample.c -index a6ceb0533b5bb..6f2fbc6b9eb2e 100644 +index 64f95624f..13314dea4 100644 --- a/net/psample/psample.c +++ b/net/psample/psample.c -@@ -229,7 +229,7 @@ void psample_sample_packet(struct psample_group *group, struct sk_buff *skb, +@@ -223,7 +223,7 @@ void psample_sample_packet(struct psample_group *group, struct sk_buff *skb, data_len = PSAMPLE_MAX_PACKET_SIZE - meta_len - NLA_HDRLEN - NLA_ALIGNTO; diff --git a/patch/preconfig/series b/patch/preconfig/series index a6030e42ffe7..e69de29bb2d1 100644 --- a/patch/preconfig/series +++ b/patch/preconfig/series @@ -1,2 +0,0 @@ -changelog.patch -packaging-update-abiname-to-11-2.patch diff --git a/patch/series b/patch/series index b13162b0afd0..a79f3cd37810 100755 --- a/patch/series +++ b/patch/series @@ -1,18 +1,8 @@ # This series applies on GIT commit 18c5597832fcf6988111b05a9a1607ae148723c -0001-armhf-default-config-for-the-sonic-patches.patch -0001-arm64-default-config-for-sonic-patches.patch -0001-i2c-mlxcpld-add-master-driver-for-Mellanox-systems.patch -0002-i2c-mux-mlxcpld-add-driver-for-Mellanox-systems.patch -0003-platform-mellanox-Introduce-Mellanox-hardware-platfo.patch -0004-platform-x86-Introduce-support-for-Mellanox-hotplug-.patch -0005-leds-add-driver-for-support-Mellanox-regmap-LEDs-for.patch -0006-Mellanox-switch-drivers-changes.patch -0007-hwmon-pmbus-Add-support-for-Intel-VID-protocol-VR13.patch -0008-hwmon-pmbus-Add-support-for-Texas-Instruments-tps536.patch -0009-platform-mellonox-introduce-mlxreg-io-driver-and-add.patch -0010-config-mellanox-configuration.patch -0011-support-Broadcom-54616-Phy-for-Intel-igb-driver.patch -0012-platform-mellanox-mlxreg-hotplug-driver-add-check-fo.patch +# (marvel) +# 0001-armhf-default-config-for-the-sonic-patches.patch +# 0001-arm64-default-config-for-sonic-patches.patch + driver-arista-net-tg3-dma-mask-4g-sb800.patch driver-arista-net-tg3-disallow-broadcom-default-mac.patch driver-arista-net-tg3-access-regs-indirectly.patch @@ -24,7 +14,6 @@ driver-sff-8436-use-nvmem_device_read.patch driver-support-sff-8436-read-write-fix.patch driver-i2c-bus-intel-ismt-add-delay-param.patch driver-pca954x-i2c-mux-force-deselect-on-exit-flag.patch -driver-l3mdev-cgroup.patch kernel-add-kexec-reboot-string.patch driver-hwmon-max6620.patch driver-hwmon-max6620-fix-rpm-calc.patch @@ -38,7 +27,6 @@ driver-support-optoe.patch driver-support-optoe-EOF_fix.patch driver-support-optoe-chunk-offset-fix.patch driver-support-optoe-QSFP_DD.patch -bridge-add-per-port-broadcast-flood-flag.patch driver-net-tg3-add-param-short-preamble-and-reset.patch config-dell-s6000.patch config-dell-z9100.patch @@ -47,76 +35,24 @@ config-arista-dps1900.patch config-arista-7060-cx32s.patch config-mitac-ly1200.patch config-optoe.patch -config-l3mdev-cgroup.patch config-inventec-d7032.patch config-cig-cs6436-serail_new.patch -0014-mlxsw-qsfp_sysfs-Support-CPLD-version-reading-based-.patch -0015-platform-x86-mlx-platform-Add-support-for-new-msn201.patch -0016-platform-mellanox-mlxreg-hotplug-add-extra-run-cycle.patch -0017-platform-mellanox-add-new-OEM-system-types-to-mlx-pl.patch -0018-platform-x86-mlx-platform-fix-module-aliases.patch -0019-platform-x86-mlx-platform-Add-bus-detection-and-diff.patch -0020-i2c-busses-Add-capabilities-to-i2c-mlxcpld.patch -linux-4.13-thermal-intel_pch_thermal-Fix-enable-check-on.patch -0021-Mellanox-backport-patchwork-from-kernels-4.17-4.19.patch -0022-platform-x86-mlx-platform-backport-from-4.19.patch -0023-platform-x86-mlx-platform-Add-support-for-register-a.patch -0024-config-mellanox-fan-configuration.patch -0025-net-udp_l3mdev_accept-support.patch -0026-mlxsw-qsfp_sysfs-Support-extended-port-numbers-for-S.patch -0027-mlxsw-thermal-monitoring-amendments.patch -0028-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch -0029-mlxsw-qsfp_sysfs-Support-port-numbers-initialization.patch -0030-update-kernel-config.patch -0031-mlxsw-Align-code-with-kernel-v-5.0.patch -0032-sonic-update-kernel-config-mlsxw-pci.patch -0033-hwmon-pmbus-Fix-driver-info-initialization-in-probe-.patch -0034-mlxsw-thermal-disable-highest-zone-calculation.patch -0035-platform-x86-mlx-platform-Add-CPLD4-register.patch -0036-watchdog-mlx-wdt-kernel-upstream-and-wd-type2-change.patch -0037-mlxsw-Align-code-with-kernel-v-5.1.patch -0038-mlxsw-core-Add-check-for-split-port-during-thermal-z.patch -0039-mlxsw-core-Prevent-reading-unsupported-slave-address.patch -0040-mlxsw-core-add-support-for-Gear-Box-temperatures-in-.patch -0041-mlxsw-minimal-Provide-optimization-for-I2C-bus-acces.patch -0042-mlxsw-core-Skip-port-split-entries-in-hwmon-subsyste.patch -0043-mellanox-platform-Backporting-Melanox-drivers-from-v.patch -0044-mlxsw-minimal-Provide-optimization-for-module-number.patch -0045-mlxsw-minimal-Add-validation-for-FW-version.patch -0046-mlxsw-core-Extend-QSFP-EEPROM-supported-size-for-eth.patch -0047-mfd-lpc-ich-extend-with-additional-chipsets-support.patch -0048-mlxsw-core-Skip-thermal-zone-operations-initializati.patch -0049-thermal-Fix-use-after-free-when-unregistering-therma.patch -0050-mlxsw-core-Drop-creation-of-thermal-to-hwmon-sysfs-i.patch -0051-mlxsw-core-Skip-thermal-zones-threshold-setting-duri.patch -0052-platform-x86-mlx-platform-Add-more-detention-for-sys.patch -0053-firmware-dmi-Add-access-to-the-SKU-ID-string-backpor.patch -0054-platform-x86-mlx-platform-Modify-setting-for-new-sys.patch -0055-platform-x86-mlx-platform-Add-support-for-next-gener.patch -0056-mlxsw-core-Add-support-for-new-hardware-device-types.patch -0057-mlxsw-minimal-Fix-validation-for-FW-minor-version.patch -0058-mlxsw-core-thermal-Set-default-thermal-trips-at-init.patch -0059-mlxsw-core-Add-the-hottest-thermal-zone-detection.patch -0060-hwmon-pmbus-core-Add-support-for-vid-mode-detecti.patch -0061-i2c-busses-i2c-mlxcpld-Increase-transaction-pooli.patch -0062-platform-mellanox-mlxreg-hotplug-Use-capability-r.patch -0063-platform-mellanox-mlxreg-io-Add-support-for-compl.patch -0064-Add-config-for-sensor-xdpe122-and-modify-mlx_wdt-.patch -linux-4.16-firmware-dmi-handle-missing-DMI-data-gracefully.patch -mellanox-backport-introduce-psample-a-new-genetlink-channel.patch -mellanox-backport-introduce-tc-sample-action.patch -kernel-enable-psample-and-act_sample-drivers.patch -0042-Marvell-a385-Micron-4G-flash-support.patch -0042-armhf-additional-configs.patch -0042-armhf-proc-dma-kconfig.patch +# (mellanox) +# 0058-mlxsw-core-thermal-Set-default-thermal-trips-at-init.patch +# 0059-mlxsw-core-Add-the-hottest-thermal-zone-detection.patch +# 0060-hwmon-pmbus-core-Add-support-for-vid-mode-detecti.patch +# 0061-i2c-busses-i2c-mlxcpld-Increase-transaction-pooli.patch +# 0062-platform-mellanox-mlxreg-hotplug-Use-capability-r.patch +# 0063-platform-mellanox-mlxreg-io-Add-support-for-compl.patch +# 0064-Add-config-for-sensor-xdpe122-and-modify-mlx_wdt-.patch +# (Marvel) +# 0042-Marvell-a385-Micron-4G-flash-support.patch +# 0042-armhf-additional-configs.patch +# 0042-armhf-proc-dma-kconfig.patch net-psample-fix-skb-over-panic.patch -0000-net-Fix-netdev-adjacency-tracking.patch -0000-net-ipv6-ll-anycast-mcast-routes-on-dev.patch -0001-net-ipv6-Allow-shorthand-delete-of-all-nexthops-in-m.patch net-backport-ipv6-missing-route.patch -Support-for-fullcone-nat.patch +# Support-for-fullcone-nat.patch driver-ixgbe-external-phy.patch -fix_ismt_alignment_issue.patch net-fix-skb-csum-update-in-inet_proto_csum_replace16.patch # # This series applies on GIT commit 1451b36b2b0d62178e42f648d8a18131af18f7d8 @@ -128,3 +64,11 @@ net-fix-skb-csum-update-in-inet_proto_csum_replace16.patch # Tdriver-hwmon-pmbus-ucd9200-mlnx.patch # Trtnetlink-catch-EOPNOTSUPP-errors.patch # Tbridge-per-port-multicast-broadcast-flood-flags.patch +# +# Mellanox patches for 4.19 +0001-v4.19-6-Mellanox-platform-Backport-patches-for-new-M.patch +0002-config-mellanox-configuration.patch +0003-mlxsw-minimal-Fix-validation-for-FW-minor-version.patch +0004-mlxsw-core-Add-the-hottest-thermal-zone-detection.patch +0005-hwmon-pmbus-core-Add-support-for-vid-mode-detection-.patch +0006-platform-mellanox-mlxreg-hotplug-Use-capability-r.patch