From 12cf48658a60d425116b112c250c57b0c1ffbb29 Mon Sep 17 00:00:00 2001 From: Michael Shych Date: Thu, 22 Aug 2019 18:22:25 +0300 Subject: [PATCH] Add support of linux kernel 4.19 for all Mellanox switches. This commit includes: 3 linux kernel patches that are backported from latest upstream kernel: 1. Amendments, new systems support and fixes in mellanox platform drivers. 2. New features, amendments in Mellanox switch drivers. 3. Introduce new watchdog driver for Mellanox systems. Multiple changes in default kernel 4.19 config for x86_64 systems. Signed-off-by: Michael Shych --- .../configs/x86_64-all/x86_64-all.config | 944 ++-- ...mendments-fixes-new-kernel-alignmnet.patch | 1704 ++++++ ...-introduce-watchdog-driver-for-Mella.patch | 330 ++ ...ures-amendments-new-kernel-alignment.patch | 4830 +++++++++++++++++ .../base/any/kernels/4.19-lts/patches/series | 3 + 5 files changed, 7481 insertions(+), 330 deletions(-) create mode 100644 packages/base/any/kernels/4.19-lts/patches/0001-mlx-amendments-fixes-new-kernel-alignmnet.patch create mode 100644 packages/base/any/kernels/4.19-lts/patches/0002-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch create mode 100644 packages/base/any/kernels/4.19-lts/patches/0003-mlxsw-new-features-amendments-new-kernel-alignment.patch diff --git a/packages/base/any/kernels/4.19-lts/configs/x86_64-all/x86_64-all.config b/packages/base/any/kernels/4.19-lts/configs/x86_64-all/x86_64-all.config index 195f2e0a..804edfba 100755 --- a/packages/base/any/kernels/4.19-lts/configs/x86_64-all/x86_64-all.config +++ b/packages/base/any/kernels/4.19-lts/configs/x86_64-all/x86_64-all.config @@ -128,6 +128,7 @@ CONFIG_PROC_PID_CPUSET=y CONFIG_CGROUP_CPUACCT=y # CONFIG_CGROUP_PERF is not set # CONFIG_CGROUP_DEBUG is not set +CONFIG_SOCK_CGROUP_DATA=y CONFIG_NAMESPACES=y CONFIG_UTS_NS=y CONFIG_IPC_NS=y @@ -202,7 +203,6 @@ CONFIG_SLAB_MERGE_DEFAULT=y # CONFIG_SLAB_FREELIST_RANDOM is not set # CONFIG_SLAB_FREELIST_HARDENED is not set CONFIG_SLUB_CPU_PARTIAL=y -CONFIG_SYSTEM_DATA_VERIFICATION=y CONFIG_PROFILING=y CONFIG_TRACEPOINTS=y CONFIG_64BIT=y @@ -252,13 +252,15 @@ CONFIG_CC_HAS_SANE_STACKPROTECTOR=y CONFIG_ZONE_DMA=y CONFIG_SMP=y CONFIG_X86_FEATURE_NAMES=y -# CONFIG_X86_X2APIC is not set +CONFIG_X86_X2APIC=y CONFIG_X86_MPPARSE=y # CONFIG_GOLDFISH is not set # CONFIG_RETPOLINE is not set # CONFIG_INTEL_RDT is not set CONFIG_X86_EXTENDED_PLATFORM=y +# CONFIG_X86_NUMACHIP is not set # CONFIG_X86_VSMP is not set +# CONFIG_X86_UV is not set # CONFIG_X86_GOLDFISH is not set # CONFIG_X86_INTEL_MID is not set # CONFIG_X86_INTEL_LPSS is not set @@ -651,7 +653,7 @@ CONFIG_KVM_INTEL=y # CONFIG_KVM_MMU_AUDIT is not set CONFIG_VHOST_NET=y CONFIG_VHOST=y -# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set +CONFIG_VHOST_CROSS_ENDIAN_LEGACY=y # # General architecture-dependent options @@ -915,7 +917,7 @@ CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y -# CONFIG_NET_IPIP is not set +CONFIG_NET_IPIP=y # CONFIG_NET_IPGRE_DEMUX is not set CONFIG_NET_IP_TUNNEL=y CONFIG_IP_MROUTE_COMMON=y @@ -964,6 +966,7 @@ CONFIG_INET6_ESP=y # CONFIG_INET6_IPCOMP is not set # CONFIG_IPV6_MIP6 is not set # CONFIG_IPV6_ILA is not set +CONFIG_INET6_TUNNEL=y CONFIG_INET6_XFRM_MODE_TRANSPORT=y CONFIG_INET6_XFRM_MODE_TUNNEL=y CONFIG_INET6_XFRM_MODE_BEET=y @@ -972,8 +975,9 @@ CONFIG_INET6_XFRM_MODE_BEET=y CONFIG_IPV6_SIT=y # CONFIG_IPV6_SIT_6RD is not set CONFIG_IPV6_NDISC_NODETYPE=y -# CONFIG_IPV6_TUNNEL is not set -# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set # CONFIG_IPV6_MROUTE is not set # CONFIG_IPV6_SEG6_LWTUNNEL is not set # CONFIG_IPV6_SEG6_HMAC is not set @@ -989,9 +993,10 @@ CONFIG_NETFILTER=y # CONFIG_NETFILTER_INGRESS=y CONFIG_NETFILTER_NETLINK=y +CONFIG_NETFILTER_FAMILY_BRIDGE=y CONFIG_NETFILTER_NETLINK_LOG=y CONFIG_NF_CONNTRACK=y -CONFIG_NF_LOG_COMMON=y +CONFIG_NF_LOG_COMMON=m # CONFIG_NF_LOG_NETDEV is not set CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_PROCFS=y @@ -1002,11 +1007,11 @@ CONFIG_NF_CONNTRACK_IRC=y CONFIG_NF_CONNTRACK_SIP=y CONFIG_NF_CT_NETLINK=y # CONFIG_NETFILTER_NETLINK_GLUE_CT is not set -CONFIG_NF_NAT=y +CONFIG_NF_NAT=m CONFIG_NF_NAT_NEEDED=y -CONFIG_NF_NAT_FTP=y -CONFIG_NF_NAT_IRC=y -CONFIG_NF_NAT_SIP=y +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_SIP=m # CONFIG_NF_TABLES is not set CONFIG_NETFILTER_XTABLES=y @@ -1019,8 +1024,8 @@ CONFIG_NETFILTER_XT_MARK=y # Xtables targets # CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y -CONFIG_NETFILTER_XT_TARGET_LOG=y -CONFIG_NETFILTER_XT_NAT=y +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_NAT=m # CONFIG_NETFILTER_XT_TARGET_NETMAP is not set CONFIG_NETFILTER_XT_TARGET_NFLOG=y # CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set @@ -1030,12 +1035,59 @@ CONFIG_NETFILTER_XT_TARGET_TCPMSS=y # # Xtables matches # -CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_STATE=y # CONFIG_IP_SET is not set -# CONFIG_IP_VS is not set +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +# CONFIG_IP_VS_DEBUG is not set +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_FO=m +CONFIG_IP_VS_OVF=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +# CONFIG_IP_VS_MH is not set +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS MH scheduler +# +CONFIG_IP_VS_MH_TAB_INDEX=12 + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_NFCT=y +CONFIG_IP_VS_PE_SIP=m # # IP: Netfilter Configuration @@ -1044,16 +1096,16 @@ CONFIG_NF_DEFRAG_IPV4=y # CONFIG_NF_SOCKET_IPV4 is not set # CONFIG_NF_TPROXY_IPV4 is not set # CONFIG_NF_DUP_IPV4 is not set -CONFIG_NF_LOG_ARP=y -CONFIG_NF_LOG_IPV4=y +CONFIG_NF_LOG_ARP=m +CONFIG_NF_LOG_IPV4=m CONFIG_NF_REJECT_IPV4=y -CONFIG_NF_NAT_IPV4=y +CONFIG_NF_NAT_IPV4=m CONFIG_NF_NAT_MASQUERADE_IPV4=y CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_NAT=y -CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_MANGLE=y # CONFIG_IP_NF_RAW is not set @@ -1064,7 +1116,7 @@ CONFIG_IP_NF_MANGLE=y # CONFIG_NF_TPROXY_IPV6 is not set # CONFIG_NF_DUP_IPV6 is not set CONFIG_NF_REJECT_IPV6=y -CONFIG_NF_LOG_IPV6=y +CONFIG_NF_LOG_IPV6=m CONFIG_IP6_NF_IPTABLES=y CONFIG_IP6_NF_MATCH_IPV6HEADER=y CONFIG_IP6_NF_FILTER=y @@ -1072,6 +1124,27 @@ CONFIG_IP6_NF_TARGET_REJECT=y CONFIG_IP6_NF_MANGLE=y # CONFIG_IP6_NF_RAW is not set CONFIG_NF_DEFRAG_IPV6=y +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_NFLOG=m # CONFIG_BPFILTER is not set # CONFIG_IP_DCCP is not set # CONFIG_IP_SCTP is not set @@ -1079,11 +1152,17 @@ CONFIG_NF_DEFRAG_IPV6=y # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_L2TP is not set -# CONFIG_BRIDGE is not set +CONFIG_STP=y +CONFIG_BRIDGE=y +CONFIG_BRIDGE_IGMP_SNOOPING=y +CONFIG_BRIDGE_VLAN_FILTERING=y CONFIG_HAVE_NET_DSA=y # CONFIG_NET_DSA is not set -# CONFIG_VLAN_8021Q is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set # CONFIG_DECNET is not set +CONFIG_LLC=y # CONFIG_LLC2 is not set # CONFIG_ATALK is not set # CONFIG_X25 is not set @@ -1138,7 +1217,7 @@ CONFIG_NET_CLS=y # CONFIG_NET_CLS_RSVP is not set # CONFIG_NET_CLS_RSVP6 is not set # CONFIG_NET_CLS_FLOW is not set -# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_CLS_CGROUP=m # CONFIG_NET_CLS_BPF is not set # CONFIG_NET_CLS_FLOWER is not set # CONFIG_NET_CLS_MATCHALL is not set @@ -1183,7 +1262,7 @@ CONFIG_RPS=y CONFIG_RFS_ACCEL=y CONFIG_XPS=y # CONFIG_CGROUP_NET_PRIO is not set -# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_CGROUP_NET_CLASSID=y CONFIG_NET_RX_BUSY_POLL=y CONFIG_BQL=y # CONFIG_BPF_JIT is not set @@ -1194,44 +1273,15 @@ CONFIG_NET_FLOW_LIMIT=y # # CONFIG_NET_PKTGEN is not set # CONFIG_NET_DROP_MONITOR is not set -CONFIG_HAMRADIO=y - -# -# Packet Radio protocols -# -# CONFIG_AX25 is not set +# CONFIG_HAMRADIO is not set # CONFIG_CAN is not set # CONFIG_BT is not set # CONFIG_AF_RXRPC is not set # CONFIG_AF_KCM is not set CONFIG_FIB_RULES=y -CONFIG_WIRELESS=y -CONFIG_CFG80211=y -# CONFIG_NL80211_TESTMODE is not set -# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set -CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y -CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y -CONFIG_CFG80211_DEFAULT_PS=y -# CONFIG_CFG80211_DEBUGFS is not set -CONFIG_CFG80211_CRDA_SUPPORT=y -# CONFIG_CFG80211_WEXT is not set -CONFIG_MAC80211=y -CONFIG_MAC80211_HAS_RC=y -CONFIG_MAC80211_RC_MINSTREL=y -CONFIG_MAC80211_RC_MINSTREL_HT=y -CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y -CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" -# CONFIG_MAC80211_MESH is not set -CONFIG_MAC80211_LEDS=y -# CONFIG_MAC80211_DEBUGFS is not set -# CONFIG_MAC80211_MESSAGE_TRACING is not set -# CONFIG_MAC80211_DEBUG_MENU is not set -CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 +# CONFIG_WIRELESS is not set # CONFIG_WIMAX is not set -CONFIG_RFKILL=y -CONFIG_RFKILL_LEDS=y -CONFIG_RFKILL_INPUT=y -# CONFIG_RFKILL_GPIO is not set +# CONFIG_RFKILL is not set # CONFIG_NET_9P is not set # CONFIG_CAIF is not set # CONFIG_CEPH_LIB is not set @@ -1275,6 +1325,7 @@ CONFIG_GENERIC_CPU_AUTOPROBE=y CONFIG_GENERIC_CPU_VULNERABILITIES=y CONFIG_REGMAP=y CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y CONFIG_DMA_SHARED_BUFFER=y # CONFIG_DMA_FENCE_TRACE is not set @@ -1320,7 +1371,9 @@ CONFIG_VIRTIO_BLK=y # # NVME Support # -# CONFIG_BLK_DEV_NVME is not set +CONFIG_NVME_CORE=y +CONFIG_BLK_DEV_NVME=y +CONFIG_NVME_MULTIPATH=y # CONFIG_NVME_FC is not set # @@ -1344,6 +1397,7 @@ CONFIG_VIRTIO_BLK=y # CONFIG_HMC6352 is not set # CONFIG_DS1682 is not set # CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set # CONFIG_SRAM is not set # CONFIG_PCI_ENDPOINT_TEST is not set # CONFIG_C2PORT is not set @@ -1351,10 +1405,12 @@ CONFIG_VIRTIO_BLK=y # # EEPROM support # -# CONFIG_EEPROM_AT24 is not set -# CONFIG_EEPROM_LEGACY is not set +CONFIG_EEPROM_AT24=m +CONFIG_EEPROM_AT25=y +CONFIG_EEPROM_LEGACY=y # CONFIG_EEPROM_MAX6875 is not set # CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set # CONFIG_EEPROM_IDT_89HPESX is not set # CONFIG_CB710_CORE is not set @@ -1586,8 +1642,7 @@ CONFIG_DM_ZERO=y # # CONFIG_FIREWIRE is not set # CONFIG_FIREWIRE_NOSY is not set -CONFIG_MACINTOSH_DRIVERS=y -CONFIG_MAC_EMUMOUSEBTN=y +# CONFIG_MACINTOSH_DRIVERS is not set CONFIG_NETDEVICES=y CONFIG_MII=y CONFIG_NET_CORE=y @@ -1620,6 +1675,7 @@ CONFIG_VIRTIO_NET=y # Distributed Switch Architecture drivers # CONFIG_ETHERNET=y +CONFIG_MDIO=y CONFIG_NET_VENDOR_3COM=y # CONFIG_PCMCIA_3C574 is not set # CONFIG_PCMCIA_3C589 is not set @@ -1711,10 +1767,12 @@ CONFIG_E100=y CONFIG_E1000=y CONFIG_E1000E=y CONFIG_E1000E_HWTS=y -# CONFIG_IGB is not set +CONFIG_IGB=y +CONFIG_IGB_HWMON=y # CONFIG_IGBVF is not set # CONFIG_IXGB is not set -# CONFIG_IXGBE is not set +CONFIG_IXGBE=y +CONFIG_IXGBE_HWMON=y # CONFIG_IXGBEVF is not set # CONFIG_I40E is not set # CONFIG_I40EVF is not set @@ -1729,12 +1787,23 @@ CONFIG_SKY2=y CONFIG_NET_VENDOR_MELLANOX=y # CONFIG_MLX4_EN is not set # CONFIG_MLX5_CORE is not set -# CONFIG_MLXSW_CORE is not set +CONFIG_MLXSW_CORE=y +CONFIG_MLXSW_CORE_HWMON=y +CONFIG_MLXSW_CORE_THERMAL=y +CONFIG_MLXSW_CORE_QSFP=y +# CONFIG_MLXSW_PCI is not set +CONFIG_MLXSW_I2C=y +CONFIG_MLXSW_MINIMAL=y # CONFIG_MLXFW is not set CONFIG_NET_VENDOR_MICREL=y # CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set # CONFIG_KS8851_MLL is not set # CONFIG_KSZ884X_PCI is not set +CONFIG_NET_VENDOR_MICROCHIP=y +# CONFIG_ENC28J60 is not set +# CONFIG_ENCX24J600 is not set +# CONFIG_LAN743X is not set CONFIG_NET_VENDOR_MICROSEMI=y CONFIG_NET_VENDOR_MYRI=y # CONFIG_MYRI10GE is not set @@ -1871,6 +1940,7 @@ CONFIG_REALTEK_PHY=y # CONFIG_TERANETICS_PHY is not set # CONFIG_VITESSE_PHY is not set # CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set CONFIG_USB_NET_DRIVERS=y @@ -1881,89 +1951,8 @@ CONFIG_USB_NET_DRIVERS=y # CONFIG_USB_RTL8152 is not set # CONFIG_USB_LAN78XX is not set # CONFIG_USB_USBNET is not set -# CONFIG_USB_HSO is not set # CONFIG_USB_IPHETH is not set -CONFIG_WLAN=y -CONFIG_WLAN_VENDOR_ADMTEK=y -# CONFIG_ADM8211 is not set -CONFIG_WLAN_VENDOR_ATH=y -# CONFIG_ATH_DEBUG is not set -# CONFIG_ATH5K is not set -# CONFIG_ATH5K_PCI is not set -# CONFIG_ATH9K is not set -# CONFIG_ATH9K_HTC is not set -# CONFIG_CARL9170 is not set -# CONFIG_ATH6KL is not set -# CONFIG_AR5523 is not set -# CONFIG_WIL6210 is not set -# CONFIG_ATH10K is not set -# CONFIG_WCN36XX is not set -CONFIG_WLAN_VENDOR_ATMEL=y -# CONFIG_ATMEL is not set -# CONFIG_AT76C50X_USB is not set -CONFIG_WLAN_VENDOR_BROADCOM=y -# CONFIG_B43 is not set -# CONFIG_B43LEGACY is not set -# CONFIG_BRCMSMAC is not set -# CONFIG_BRCMFMAC is not set -CONFIG_WLAN_VENDOR_CISCO=y -# CONFIG_AIRO is not set -# CONFIG_AIRO_CS is not set -CONFIG_WLAN_VENDOR_INTEL=y -# CONFIG_IPW2100 is not set -# CONFIG_IPW2200 is not set -# CONFIG_IWL4965 is not set -# CONFIG_IWL3945 is not set -# CONFIG_IWLWIFI is not set -CONFIG_WLAN_VENDOR_INTERSIL=y -# CONFIG_HOSTAP is not set -# CONFIG_HERMES is not set -# CONFIG_P54_COMMON is not set -# CONFIG_PRISM54 is not set -CONFIG_WLAN_VENDOR_MARVELL=y -# CONFIG_LIBERTAS is not set -# CONFIG_LIBERTAS_THINFIRM is not set -# CONFIG_MWIFIEX is not set -# CONFIG_MWL8K is not set -CONFIG_WLAN_VENDOR_MEDIATEK=y -# CONFIG_MT7601U is not set -# CONFIG_MT76x0U is not set -# CONFIG_MT76x2E is not set -# CONFIG_MT76x2U is not set -CONFIG_WLAN_VENDOR_RALINK=y -# CONFIG_RT2X00 is not set -CONFIG_WLAN_VENDOR_REALTEK=y -# CONFIG_RTL8180 is not set -# CONFIG_RTL8187 is not set -CONFIG_RTL_CARDS=y -# CONFIG_RTL8192CE is not set -# CONFIG_RTL8192SE is not set -# CONFIG_RTL8192DE is not set -# CONFIG_RTL8723AE is not set -# CONFIG_RTL8723BE is not set -# CONFIG_RTL8188EE is not set -# CONFIG_RTL8192EE is not set -# CONFIG_RTL8821AE is not set -# CONFIG_RTL8192CU is not set -# CONFIG_RTL8XXXU is not set -CONFIG_WLAN_VENDOR_RSI=y -# CONFIG_RSI_91X is not set -CONFIG_WLAN_VENDOR_ST=y -# CONFIG_CW1200 is not set -CONFIG_WLAN_VENDOR_TI=y -# CONFIG_WL1251 is not set -# CONFIG_WL12XX is not set -# CONFIG_WL18XX is not set -# CONFIG_WLCORE is not set -CONFIG_WLAN_VENDOR_ZYDAS=y -# CONFIG_USB_ZD1201 is not set -# CONFIG_ZD1211RW is not set -CONFIG_WLAN_VENDOR_QUANTENNA=y -# CONFIG_QTNFMAC_PEARL_PCIE is not set -# CONFIG_PCMCIA_RAYCS is not set -# CONFIG_PCMCIA_WL3501 is not set -# CONFIG_MAC80211_HWSIM is not set -# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_WLAN is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers @@ -1998,6 +1987,7 @@ CONFIG_INPUT_EVDEV=y # Input Device Drivers # CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADC is not set # CONFIG_KEYBOARD_ADP5588 is not set # CONFIG_KEYBOARD_ADP5589 is not set CONFIG_KEYBOARD_ATKBD=y @@ -2070,6 +2060,7 @@ CONFIG_INPUT_JOYSTICK=y # CONFIG_JOYSTICK_AS5011 is not set # CONFIG_JOYSTICK_JOYDUMP is not set # CONFIG_JOYSTICK_XPAD is not set +# CONFIG_JOYSTICK_PSXPAD_SPI is not set # CONFIG_JOYSTICK_PXRC is not set CONFIG_INPUT_TABLET=y # CONFIG_TABLET_USB_ACECAD is not set @@ -2081,7 +2072,10 @@ CONFIG_INPUT_TABLET=y # CONFIG_TABLET_SERIAL_WACOM4 is not set CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_PROPERTIES=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set # CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_ADC is not set # CONFIG_TOUCHSCREEN_ATMEL_MXT is not set # CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set # CONFIG_TOUCHSCREEN_BU21013 is not set @@ -2123,12 +2117,14 @@ CONFIG_TOUCHSCREEN_PROPERTIES=y # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set # CONFIG_TOUCHSCREEN_TSC_SERIO is not set # CONFIG_TOUCHSCREEN_TSC2004 is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set # CONFIG_TOUCHSCREEN_TSC2007 is not set # CONFIG_TOUCHSCREEN_RM_TS is not set # CONFIG_TOUCHSCREEN_SILEAD is not set # CONFIG_TOUCHSCREEN_SIS_I2C is not set # CONFIG_TOUCHSCREEN_ST1232 is not set # CONFIG_TOUCHSCREEN_STMFTS is not set +# CONFIG_TOUCHSCREEN_SURFACE3_SPI is not set # CONFIG_TOUCHSCREEN_SX8654 is not set # CONFIG_TOUCHSCREEN_TPS6507X is not set # CONFIG_TOUCHSCREEN_ZET6223 is not set @@ -2239,6 +2235,8 @@ CONFIG_SERIAL_8250_MID=y # # Non-8250 serial port support # +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set # CONFIG_SERIAL_UARTLITE is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y @@ -2247,6 +2245,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_SC16IS7XX is not set # CONFIG_SERIAL_ALTERA_JTAGUART is not set # CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set # CONFIG_SERIAL_ARC is not set # CONFIG_SERIAL_RP2 is not set # CONFIG_SERIAL_FSL_LPUART is not set @@ -2299,8 +2298,8 @@ CONFIG_I2C_MUX_GPIO=y # CONFIG_I2C_MUX_PCA9541 is not set CONFIG_I2C_MUX_PCA954x=y CONFIG_I2C_MUX_PCA954X_DESELECT_ON_EXIT=y -# CONFIG_I2C_MUX_REG is not set -# CONFIG_I2C_MUX_MLXCPLD is not set +CONFIG_I2C_MUX_REG=y +CONFIG_I2C_MUX_MLXCPLD=y CONFIG_I2C_HELPER_AUTO=y CONFIG_I2C_SMBUS=y CONFIG_I2C_ALGOBIT=y @@ -2320,7 +2319,7 @@ CONFIG_I2C_ALGOPCA=y # CONFIG_I2C_AMD8111 is not set CONFIG_I2C_I801=y CONFIG_I2C_ISCH=y -CONFIG_I2C_ISMT=y +CONFIG_I2C_ISMT=m # CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_SIS5595 is not set @@ -2332,7 +2331,7 @@ CONFIG_I2C_ISMT=y # # ACPI drivers # -CONFIG_I2C_SCMI=y +# CONFIG_I2C_SCMI is not set # # I2C system bus drivers (mostly embedded / system-on-chip) @@ -2359,13 +2358,41 @@ CONFIG_I2C_PCA_PLATFORM=y # # Other I2C/SMBus bus drivers # -# CONFIG_I2C_MLXCPLD is not set +CONFIG_I2C_MLXCPLD=y # CONFIG_I2C_STUB is not set # CONFIG_I2C_SLAVE is not set -CONFIG_I2C_DEBUG_CORE=y +# CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set -# CONFIG_SPI is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_MEM is not set + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set # CONFIG_SPMI is not set # CONFIG_HSI is not set CONFIG_PPS=y @@ -2444,6 +2471,15 @@ CONFIG_GPIO_SCH=y # CONFIG_GPIO_PCIE_IDIO_24 is not set # CONFIG_GPIO_RDC321X is not set +# +# SPI GPIO expanders +# +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_XRA1403 is not set + # # USB GPIO expanders # @@ -2453,6 +2489,7 @@ CONFIG_GPIO_SCH=y CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set # CONFIG_PDA_POWER is not set +# CONFIG_GENERIC_ADC_BATTERY is not set # CONFIG_TEST_POWER is not set # CONFIG_CHARGER_ADP5061 is not set # CONFIG_BATTERY_DS2780 is not set @@ -2476,6 +2513,7 @@ CONFIG_POWER_SUPPLY=y # CONFIG_BATTERY_GAUGE_LTC2941 is not set # CONFIG_CHARGER_RT9455 is not set CONFIG_HWMON=y +CONFIG_HWMON_VID=y # CONFIG_HWMON_DEBUG_CHIP is not set # @@ -2483,6 +2521,7 @@ CONFIG_HWMON=y # # CONFIG_SENSORS_ABITUGURU is not set # CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7314 is not set # CONFIG_SENSORS_AD7414 is not set # CONFIG_SENSORS_AD7418 is not set # CONFIG_SENSORS_ADM1021 is not set @@ -2491,6 +2530,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_ADM1029 is not set # CONFIG_SENSORS_ADM1031 is not set # CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set # CONFIG_SENSORS_ADT7410 is not set # CONFIG_SENSORS_ADT7411 is not set # CONFIG_SENSORS_ADT7462 is not set @@ -2518,8 +2558,9 @@ CONFIG_HWMON=y # CONFIG_SENSORS_G760A is not set # CONFIG_SENSORS_G762 is not set # CONFIG_SENSORS_HIH6130 is not set +CONFIG_SENSORS_IIO_HWMON=y # CONFIG_SENSORS_I5500 is not set -# CONFIG_SENSORS_CORETEMP is not set +CONFIG_SENSORS_CORETEMP=y # CONFIG_SENSORS_IT87 is not set # CONFIG_SENSORS_JC42 is not set # CONFIG_SENSORS_POWR1220 is not set @@ -2532,29 +2573,34 @@ CONFIG_HWMON=y # CONFIG_SENSORS_LTC4245 is not set # CONFIG_SENSORS_LTC4260 is not set # CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_MAX1111 is not set # CONFIG_SENSORS_MAX16065 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_MAX1668 is not set # CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX31722 is not set # CONFIG_SENSORS_MAX6621 is not set # CONFIG_SENSORS_MAX6639 is not set # CONFIG_SENSORS_MAX6642 is not set # CONFIG_SENSORS_MAX6650 is not set -# CONFIG_SENSORS_MAX6620 is not set +CONFIG_SENSORS_MAX6620=y # CONFIG_SENSORS_MAX6697 is not set # CONFIG_SENSORS_MAX31790 is not set # CONFIG_SENSORS_MCP3021 is not set +CONFIG_SENSORS_MLXREG_FAN=y # CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_ADCXX is not set # CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set # CONFIG_SENSORS_LM73 is not set -# CONFIG_SENSORS_LM75 is not set +CONFIG_SENSORS_LM75=y # CONFIG_SENSORS_LM77 is not set # CONFIG_SENSORS_LM78 is not set # CONFIG_SENSORS_LM80 is not set # CONFIG_SENSORS_LM83 is not set # CONFIG_SENSORS_LM85 is not set -# CONFIG_SENSORS_LM87 is not set -# CONFIG_SENSORS_LM90 is not set +CONFIG_SENSORS_LM87=y +CONFIG_SENSORS_LM90=y # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_LM93 is not set # CONFIG_SENSORS_LM95234 is not set @@ -2569,7 +2615,24 @@ CONFIG_HWMON=y # CONFIG_SENSORS_NCT7904 is not set # CONFIG_SENSORS_NPCM7XX is not set # CONFIG_SENSORS_PCF8591 is not set -# CONFIG_PMBUS is not set +CONFIG_PMBUS=y +CONFIG_SENSORS_PMBUS=y +# CONFIG_SENSORS_ADM1275 is not set +# CONFIG_SENSORS_IBM_CFFPS is not set +# CONFIG_SENSORS_IR35221 is not set +CONFIG_SENSORS_LM25066=y +# 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=y +CONFIG_SENSORS_UCD9000=y +CONFIG_SENSORS_UCD9200=y +# CONFIG_SENSORS_ZL6100 is not set # CONFIG_SENSORS_SHT15 is not set # CONFIG_SENSORS_SHT21 is not set # CONFIG_SENSORS_SHT3x is not set @@ -2589,13 +2652,14 @@ CONFIG_HWMON=y # CONFIG_SENSORS_ADC128D818 is not set # CONFIG_SENSORS_ADS1015 is not set # CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set # CONFIG_SENSORS_AMC6821 is not set # CONFIG_SENSORS_INA209 is not set # CONFIG_SENSORS_INA2XX is not set # CONFIG_SENSORS_INA3221 is not set # CONFIG_SENSORS_TC74 is not set # CONFIG_SENSORS_THMC50 is not set -# CONFIG_SENSORS_TMP102 is not set +CONFIG_SENSORS_TMP102=y # CONFIG_SENSORS_TMP103 is not set # CONFIG_SENSORS_TMP108 is not set # CONFIG_SENSORS_TMP401 is not set @@ -2637,19 +2701,20 @@ CONFIG_THERMAL_GOV_USER_SPACE=y # CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set # CONFIG_THERMAL_EMULATION is not set # CONFIG_INTEL_POWERCLAMP is not set -CONFIG_X86_PKG_TEMP_THERMAL=y +CONFIG_X86_PKG_TEMP_THERMAL=m # CONFIG_INTEL_SOC_DTS_THERMAL is not set # # ACPI INT340X thermal drivers # # CONFIG_INT340X_THERMAL is not set -# CONFIG_INTEL_PCH_THERMAL is not set +CONFIG_INTEL_PCH_THERMAL=m +# CONFIG_GENERIC_ADC_THERMAL is not set CONFIG_WATCHDOG=y -# CONFIG_WATCHDOG_CORE is not set +CONFIG_WATCHDOG_CORE=y # CONFIG_WATCHDOG_NOWAYOUT is not set CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y -# CONFIG_WATCHDOG_SYSFS is not set +CONFIG_WATCHDOG_SYSFS=y # # Watchdog Device Drivers @@ -2658,6 +2723,7 @@ CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y # CONFIG_WDAT_WDT is not set # 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 @@ -2710,6 +2776,7 @@ CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y # # Watchdog Pretimeout Governors # +# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set CONFIG_SSB_POSSIBLE=y # CONFIG_SSB is not set CONFIG_BCMA_POSSIBLE=y @@ -2728,12 +2795,14 @@ CONFIG_MFD_CORE=y # CONFIG_MFD_CROS_EC is not set # CONFIG_MFD_MADERA is not set # CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set # CONFIG_MFD_DA9052_I2C is not set # CONFIG_MFD_DA9055 is not set # CONFIG_MFD_DA9062 is not set # CONFIG_MFD_DA9063 is not set # CONFIG_MFD_DA9150 is not set # CONFIG_MFD_DLN2 is not set +# CONFIG_MFD_MC13XXX_SPI is not set # CONFIG_MFD_MC13XXX_I2C is not set # CONFIG_HTC_PASIC3 is not set # CONFIG_HTC_I2CPLD is not set @@ -2759,6 +2828,7 @@ CONFIG_LPC_SCH=y # CONFIG_MFD_MAX8998 is not set # CONFIG_MFD_MT6397 is not set # CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set # CONFIG_MFD_VIPERBOARD is not set # CONFIG_MFD_RETU is not set # CONFIG_MFD_PCF50633 is not set @@ -2787,6 +2857,7 @@ CONFIG_LPC_SCH=y # CONFIG_MFD_TPS6586X is not set # CONFIG_MFD_TPS65910 is not set # CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set # CONFIG_MFD_TPS80031 is not set # CONFIG_TWL4030_CORE is not set # CONFIG_TWL6040_CORE is not set @@ -2794,8 +2865,10 @@ CONFIG_LPC_SCH=y # CONFIG_MFD_LM3533 is not set # CONFIG_MFD_VX855 is not set # CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set # CONFIG_MFD_WM8400 is not set # CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set # CONFIG_MFD_WM8350_I2C is not set # CONFIG_MFD_WM8994 is not set # CONFIG_REGULATOR is not set @@ -2979,148 +3052,7 @@ CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set CONFIG_LOGO_LINUX_CLUT224=y -CONFIG_SOUND=y -CONFIG_SND=y -CONFIG_SND_TIMER=y -CONFIG_SND_PCM=y -CONFIG_SND_HWDEP=y -CONFIG_SND_SEQ_DEVICE=y -CONFIG_SND_JACK=y -CONFIG_SND_JACK_INPUT_DEV=y -# CONFIG_SND_OSSEMUL is not set -CONFIG_SND_PCM_TIMER=y -CONFIG_SND_HRTIMER=y -# CONFIG_SND_DYNAMIC_MINORS is not set -CONFIG_SND_SUPPORT_OLD_API=y -CONFIG_SND_PROC_FS=y -CONFIG_SND_VERBOSE_PROCFS=y -# CONFIG_SND_VERBOSE_PRINTK is not set -# CONFIG_SND_DEBUG is not set -CONFIG_SND_VMASTER=y -CONFIG_SND_DMA_SGBUF=y -CONFIG_SND_SEQUENCER=y -CONFIG_SND_SEQ_DUMMY=y -CONFIG_SND_SEQ_HRTIMER_DEFAULT=y -CONFIG_SND_DRIVERS=y -# CONFIG_SND_PCSP is not set -# CONFIG_SND_DUMMY is not set -# CONFIG_SND_ALOOP is not set -# CONFIG_SND_VIRMIDI is not set -# CONFIG_SND_MTPAV is not set -# CONFIG_SND_SERIAL_U16550 is not set -# CONFIG_SND_MPU401 is not set -CONFIG_SND_PCI=y -# CONFIG_SND_AD1889 is not set -# CONFIG_SND_ALS300 is not set -# CONFIG_SND_ALS4000 is not set -# CONFIG_SND_ALI5451 is not set -# CONFIG_SND_ASIHPI is not set -# CONFIG_SND_ATIIXP is not set -# CONFIG_SND_ATIIXP_MODEM is not set -# CONFIG_SND_AU8810 is not set -# CONFIG_SND_AU8820 is not set -# CONFIG_SND_AU8830 is not set -# CONFIG_SND_AW2 is not set -# CONFIG_SND_AZT3328 is not set -# CONFIG_SND_BT87X is not set -# CONFIG_SND_CA0106 is not set -# CONFIG_SND_CMIPCI is not set -# CONFIG_SND_OXYGEN is not set -# CONFIG_SND_CS4281 is not set -# CONFIG_SND_CS46XX is not set -# CONFIG_SND_CTXFI is not set -# CONFIG_SND_DARLA20 is not set -# CONFIG_SND_GINA20 is not set -# CONFIG_SND_LAYLA20 is not set -# CONFIG_SND_DARLA24 is not set -# CONFIG_SND_GINA24 is not set -# CONFIG_SND_LAYLA24 is not set -# CONFIG_SND_MONA is not set -# CONFIG_SND_MIA is not set -# CONFIG_SND_ECHO3G is not set -# CONFIG_SND_INDIGO is not set -# CONFIG_SND_INDIGOIO is not set -# CONFIG_SND_INDIGODJ is not set -# CONFIG_SND_INDIGOIOX is not set -# CONFIG_SND_INDIGODJX is not set -# CONFIG_SND_EMU10K1 is not set -# CONFIG_SND_EMU10K1X is not set -# CONFIG_SND_ENS1370 is not set -# CONFIG_SND_ENS1371 is not set -# CONFIG_SND_ES1938 is not set -# CONFIG_SND_ES1968 is not set -# CONFIG_SND_FM801 is not set -# CONFIG_SND_HDSP is not set -# CONFIG_SND_HDSPM is not set -# CONFIG_SND_ICE1712 is not set -# CONFIG_SND_ICE1724 is not set -# CONFIG_SND_INTEL8X0 is not set -# CONFIG_SND_INTEL8X0M is not set -# CONFIG_SND_KORG1212 is not set -# CONFIG_SND_LOLA is not set -# CONFIG_SND_LX6464ES is not set -# CONFIG_SND_MAESTRO3 is not set -# CONFIG_SND_MIXART is not set -# CONFIG_SND_NM256 is not set -# CONFIG_SND_PCXHR is not set -# CONFIG_SND_RIPTIDE is not set -# CONFIG_SND_RME32 is not set -# CONFIG_SND_RME96 is not set -# CONFIG_SND_RME9652 is not set -# CONFIG_SND_SE6X is not set -# CONFIG_SND_SONICVIBES is not set -# CONFIG_SND_TRIDENT is not set -# CONFIG_SND_VIA82XX is not set -# CONFIG_SND_VIA82XX_MODEM is not set -# CONFIG_SND_VIRTUOSO is not set -# CONFIG_SND_VX222 is not set -# CONFIG_SND_YMFPCI is not set - -# -# HD-Audio -# -CONFIG_SND_HDA=y -CONFIG_SND_HDA_INTEL=y -CONFIG_SND_HDA_HWDEP=y -# CONFIG_SND_HDA_RECONFIG is not set -# CONFIG_SND_HDA_INPUT_BEEP is not set -# CONFIG_SND_HDA_PATCH_LOADER is not set -# CONFIG_SND_HDA_CODEC_REALTEK is not set -# CONFIG_SND_HDA_CODEC_ANALOG is not set -# CONFIG_SND_HDA_CODEC_SIGMATEL is not set -# CONFIG_SND_HDA_CODEC_VIA is not set -# CONFIG_SND_HDA_CODEC_HDMI is not set -# CONFIG_SND_HDA_CODEC_CIRRUS is not set -# CONFIG_SND_HDA_CODEC_CONEXANT is not set -# CONFIG_SND_HDA_CODEC_CA0110 is not set -# CONFIG_SND_HDA_CODEC_CA0132 is not set -# CONFIG_SND_HDA_CODEC_CMEDIA is not set -# CONFIG_SND_HDA_CODEC_SI3054 is not set -# CONFIG_SND_HDA_GENERIC is not set -CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 -CONFIG_SND_HDA_CORE=y -CONFIG_SND_HDA_COMPONENT=y -CONFIG_SND_HDA_I915=y -CONFIG_SND_HDA_PREALLOC_SIZE=64 -CONFIG_SND_USB=y -# CONFIG_SND_USB_AUDIO is not set -# CONFIG_SND_USB_UA101 is not set -# CONFIG_SND_USB_USX2Y is not set -# CONFIG_SND_USB_CAIAQ is not set -# CONFIG_SND_USB_US122L is not set -# CONFIG_SND_USB_6FIRE is not set -# CONFIG_SND_USB_HIFACE is not set -# CONFIG_SND_BCD2000 is not set -# CONFIG_SND_USB_POD is not set -# CONFIG_SND_USB_PODHD is not set -# CONFIG_SND_USB_TONEPORT is not set -# CONFIG_SND_USB_VARIAX is not set -CONFIG_SND_PCMCIA=y -# CONFIG_SND_VXPOCKET is not set -# CONFIG_SND_PDAUDIOCF is not set -# CONFIG_SND_SOC is not set -CONFIG_SND_X86=y -# CONFIG_HDMI_LPE_AUDIO is not set +# CONFIG_SOUND is not set # # HID support @@ -3147,7 +3079,6 @@ CONFIG_HID_CHERRY=y CONFIG_HID_CHICONY=y # CONFIG_HID_CORSAIR is not set # CONFIG_HID_COUGAR is not set -# CONFIG_HID_PRODIKEYS is not set # CONFIG_HID_CMEDIA is not set # CONFIG_HID_CP2112 is not set CONFIG_HID_CYPRESS=y @@ -3234,7 +3165,7 @@ CONFIG_USB_HIDDEV=y # # I2C HID support # -# CONFIG_I2C_HID is not set +CONFIG_I2C_HID=y # # Intel ISH HID support @@ -3263,15 +3194,19 @@ CONFIG_USB_MON=y # USB Host Controller Drivers # # CONFIG_USB_C67X00_HCD is not set -# CONFIG_USB_XHCI_HCD is not set +CONFIG_USB_XHCI_HCD=y +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=y +# CONFIG_USB_XHCI_PLATFORM is not set CONFIG_USB_EHCI_HCD=y -# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=y # CONFIG_USB_EHCI_HCD_PLATFORM is not set # CONFIG_USB_OXU210HP_HCD is not set # CONFIG_USB_ISP116X_HCD is not set # CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PCI=y # CONFIG_USB_OHCI_HCD_PLATFORM is not set @@ -3395,6 +3330,7 @@ CONFIG_LEDS_CLASS=y # CONFIG_LEDS_CLEVO_MAIL is not set # CONFIG_LEDS_PCA955X is not set # CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set # CONFIG_LEDS_BD2802 is not set # CONFIG_LEDS_INTEL_SS4200 is not set # CONFIG_LEDS_LT3593 is not set @@ -3407,7 +3343,7 @@ CONFIG_LEDS_CLASS=y # # CONFIG_LEDS_BLINKM is not set # CONFIG_LEDS_MLXCPLD is not set -# CONFIG_LEDS_MLXREG is not set +CONFIG_LEDS_MLXREG=y # CONFIG_LEDS_USER is not set # CONFIG_LEDS_NIC78BX is not set @@ -3415,7 +3351,7 @@ CONFIG_LEDS_CLASS=y # LED Triggers # CONFIG_LEDS_TRIGGERS=y -# CONFIG_LEDS_TRIGGER_TIMER is not set +CONFIG_LEDS_TRIGGER_TIMER=y # CONFIG_LEDS_TRIGGER_ONESHOT is not set # CONFIG_LEDS_TRIGGER_DISK is not set # CONFIG_LEDS_TRIGGER_HEARTBEAT is not set @@ -3504,6 +3440,21 @@ CONFIG_RTC_INTF_DEV=y # # SPI RTC drivers # +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set CONFIG_RTC_I2C_AND_SPI=y # @@ -3596,18 +3547,12 @@ CONFIG_X86_PLATFORM_DEVICES=y # CONFIG_ASUS_LAPTOP is not set # CONFIG_DELL_SMBIOS is not set # CONFIG_DELL_SMO8800 is not set -# CONFIG_DELL_RBTN is not set # CONFIG_FUJITSU_LAPTOP is not set # CONFIG_FUJITSU_TABLET is not set -# CONFIG_AMILO_RFKILL is not set # CONFIG_GPD_POCKET_FAN is not set # CONFIG_HP_ACCEL is not set # CONFIG_HP_WIRELESS is not set -# CONFIG_MSI_LAPTOP is not set # CONFIG_PANASONIC_LAPTOP is not set -# CONFIG_COMPAL_LAPTOP is not set -# CONFIG_SONY_LAPTOP is not set -# CONFIG_IDEAPAD_LAPTOP is not set # CONFIG_THINKPAD_ACPI is not set # CONFIG_SENSORS_HDAPS is not set # CONFIG_INTEL_MENLOW is not set @@ -3625,7 +3570,6 @@ CONFIG_EEEPC_LAPTOP=y # CONFIG_INTEL_PMC_CORE is not set # CONFIG_IBM_RTL is not set # CONFIG_SAMSUNG_LAPTOP is not set -# CONFIG_INTEL_OAKTRAIL is not set # CONFIG_SAMSUNG_Q10 is not set # CONFIG_APPLE_GMUX is not set # CONFIG_INTEL_RST is not set @@ -3634,13 +3578,15 @@ CONFIG_EEEPC_LAPTOP=y # CONFIG_INTEL_PMC_IPC is not set # CONFIG_SURFACE_PRO3_BUTTON is not set # CONFIG_INTEL_PUNIT_IPC is not set -# CONFIG_MLX_PLATFORM is not set +CONFIG_MLX_PLATFORM=y # CONFIG_INTEL_TURBO_MAX_3 is not set # CONFIG_I2C_MULTI_INSTANTIATE is not set # CONFIG_INTEL_ATOMISP2_PM is not set CONFIG_PMC_ATOM=y # CONFIG_CHROME_PLATFORMS is not set -# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_MELLANOX_PLATFORM=y +CONFIG_MLXREG_HOTPLUG=y +CONFIG_MLXREG_IO=y CONFIG_CLKDEV_LOOKUP=y CONFIG_HAVE_CLK_PREPARE=y CONFIG_COMMON_CLK=y @@ -3726,7 +3672,346 @@ CONFIG_INTEL_IOMMU_FLOPPY_WA=y # CONFIG_PM_DEVFREQ is not set # CONFIG_EXTCON is not set # CONFIG_MEMORY is not set -# CONFIG_IIO is not set +CONFIG_IIO=y +CONFIG_IIO_BUFFER=y +# CONFIG_IIO_BUFFER_CB is not set +# CONFIG_IIO_BUFFER_HW_CONSUMER is not set +CONFIG_IIO_KFIFO_BUF=y +CONFIG_IIO_TRIGGERED_BUFFER=y +# CONFIG_IIO_CONFIGFS is not set +CONFIG_IIO_TRIGGER=y +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 +# CONFIG_IIO_SW_DEVICE is not set +# CONFIG_IIO_SW_TRIGGER is not set + +# +# Accelerometers +# +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADXL345_I2C is not set +# CONFIG_ADXL345_SPI is not set +# CONFIG_BMA180 is not set +# CONFIG_BMA220 is not set +# CONFIG_BMC150_ACCEL is not set +# CONFIG_DA280 is not set +# CONFIG_DA311 is not set +# CONFIG_DMARD09 is not set +# CONFIG_DMARD10 is not set +# CONFIG_IIO_CROS_EC_ACCEL_LEGACY is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set +# CONFIG_KXSD9 is not set +# CONFIG_KXCJK1013 is not set +# CONFIG_MC3230 is not set +# CONFIG_MMA7455_I2C is not set +# CONFIG_MMA7455_SPI is not set +# CONFIG_MMA7660 is not set +# CONFIG_MMA8452 is not set +# CONFIG_MMA9551 is not set +# CONFIG_MMA9553 is not set +# CONFIG_MXC4005 is not set +# CONFIG_MXC6255 is not set +# CONFIG_SCA3000 is not set +# CONFIG_STK8312 is not set +# CONFIG_STK8BA50 is not set + +# +# Analog to digital converters +# +# CONFIG_AD7266 is not set +# CONFIG_AD7291 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7766 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7887 is not set +# CONFIG_AD7923 is not set +# CONFIG_AD799X is not set +# CONFIG_HI8435 is not set +# CONFIG_HX711 is not set +# CONFIG_INA2XX_ADC is not set +# CONFIG_LTC2471 is not set +# CONFIG_LTC2485 is not set +# CONFIG_LTC2497 is not set +# CONFIG_MAX1027 is not set +# CONFIG_MAX11100 is not set +# CONFIG_MAX1118 is not set +CONFIG_MAX1363=y +# CONFIG_MAX9611 is not set +# CONFIG_MCP320X is not set +# CONFIG_MCP3422 is not set +# CONFIG_NAU7802 is not set +# CONFIG_TI_ADC081C is not set +# CONFIG_TI_ADC0832 is not set +# CONFIG_TI_ADC084S021 is not set +# CONFIG_TI_ADC12138 is not set +# CONFIG_TI_ADC108S102 is not set +# CONFIG_TI_ADC128S052 is not set +# CONFIG_TI_ADC161S626 is not set +# CONFIG_TI_ADS1015 is not set +# CONFIG_TI_ADS7950 is not set +# CONFIG_TI_TLC4541 is not set + +# +# Analog Front Ends +# + +# +# Amplifiers +# +# CONFIG_AD8366 is not set + +# +# Chemical Sensors +# +# CONFIG_ATLAS_PH_SENSOR is not set +# CONFIG_BME680 is not set +# CONFIG_CCS811 is not set +# CONFIG_IAQCORE is not set +# CONFIG_VZ89X is not set + +# +# Hid Sensor IIO Common +# + +# +# SSP Sensor Common +# +# CONFIG_IIO_SSP_SENSORHUB is not set + +# +# Counters +# + +# +# Digital to analog converters +# +# CONFIG_AD5064 is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5592R is not set +# CONFIG_AD5593R is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_LTC2632 is not set +# CONFIG_AD5686_SPI is not set +# CONFIG_AD5696_I2C is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5758 is not set +# CONFIG_AD5761 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD7303 is not set +# CONFIG_AD8801 is not set +# CONFIG_DS4424 is not set +# CONFIG_M62332 is not set +# CONFIG_MAX517 is not set +# CONFIG_MCP4725 is not set +# CONFIG_MCP4922 is not set +# CONFIG_TI_DAC082S085 is not set +# CONFIG_TI_DAC5571 is not set + +# +# IIO dummy driver +# + +# +# Frequency Synthesizers DDS/PLL +# + +# +# Clock Generator/Distribution +# +# CONFIG_AD9523 is not set + +# +# Phase-Locked Loop (PLL) frequency synthesizers +# +# CONFIG_ADF4350 is not set + +# +# Digital gyroscope sensors +# +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADIS16260 is not set +# CONFIG_ADXRS450 is not set +# CONFIG_BMG160 is not set +# CONFIG_MPU3050_I2C is not set +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_ITG3200 is not set + +# +# Health Sensors +# + +# +# Heart Rate Monitors +# +# CONFIG_AFE4403 is not set +# CONFIG_AFE4404 is not set +# CONFIG_MAX30100 is not set +# CONFIG_MAX30102 is not set + +# +# Humidity sensors +# +# CONFIG_AM2315 is not set +# CONFIG_DHT11 is not set +# CONFIG_HDC100X is not set +# CONFIG_HTS221 is not set +# CONFIG_HTU21 is not set +# CONFIG_SI7005 is not set +# CONFIG_SI7020 is not set + +# +# Inertial measurement units +# +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_BMI160_I2C is not set +# CONFIG_BMI160_SPI is not set +# CONFIG_KMX61 is not set +# CONFIG_INV_MPU6050_I2C is not set +# CONFIG_INV_MPU6050_SPI is not set +# CONFIG_IIO_ST_LSM6DSX is not set + +# +# Light sensors +# +# CONFIG_ACPI_ALS is not set +# CONFIG_ADJD_S311 is not set +# CONFIG_AL3320A is not set +# CONFIG_APDS9300 is not set +# CONFIG_APDS9960 is not set +# CONFIG_BH1750 is not set +# CONFIG_BH1780 is not set +# CONFIG_CM32181 is not set +# CONFIG_CM3232 is not set +# CONFIG_CM3323 is not set +# CONFIG_CM36651 is not set +# CONFIG_GP2AP020A00F is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_ISL29125 is not set +# CONFIG_JSA1212 is not set +# CONFIG_RPR0521 is not set +# CONFIG_LTR501 is not set +# CONFIG_LV0104CS is not set +# CONFIG_MAX44000 is not set +# CONFIG_OPT3001 is not set +# CONFIG_PA12203001 is not set +# CONFIG_SI1133 is not set +# CONFIG_SI1145 is not set +# CONFIG_STK3310 is not set +# CONFIG_ST_UVIS25 is not set +# CONFIG_TCS3414 is not set +# CONFIG_TCS3472 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2772 is not set +# CONFIG_TSL4531 is not set +# CONFIG_US5182D is not set +# CONFIG_VCNL4000 is not set +# CONFIG_VEML6070 is not set +# CONFIG_VL6180 is not set +# CONFIG_ZOPT2201 is not set + +# +# Magnetometer sensors +# +# CONFIG_AK8975 is not set +# CONFIG_AK09911 is not set +# CONFIG_BMC150_MAGN_I2C is not set +# CONFIG_BMC150_MAGN_SPI is not set +# CONFIG_MAG3110 is not set +# CONFIG_MMC35240 is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_SENSORS_HMC5843_I2C is not set +# CONFIG_SENSORS_HMC5843_SPI is not set + +# +# Multiplexers +# + +# +# Inclinometer sensors +# + +# +# Triggers - standalone +# +# CONFIG_IIO_INTERRUPT_TRIGGER is not set +# CONFIG_IIO_SYSFS_TRIGGER is not set + +# +# Digital potentiometers +# +# CONFIG_AD5272 is not set +# CONFIG_DS1803 is not set +# CONFIG_MAX5481 is not set +# CONFIG_MAX5487 is not set +# CONFIG_MCP4018 is not set +# CONFIG_MCP4131 is not set +# CONFIG_MCP4531 is not set +# CONFIG_TPL0102 is not set + +# +# Digital potentiostats +# +# CONFIG_LMP91000 is not set + +# +# Pressure sensors +# +# CONFIG_ABP060MG is not set +# CONFIG_BMP280 is not set +# CONFIG_HP03 is not set +# CONFIG_MPL115_I2C is not set +# CONFIG_MPL115_SPI is not set +# CONFIG_MPL3115 is not set +# CONFIG_MS5611 is not set +# CONFIG_MS5637 is not set +# CONFIG_IIO_ST_PRESS is not set +# CONFIG_T5403 is not set +# CONFIG_HP206C is not set +# CONFIG_ZPA2326 is not set + +# +# Lightning sensors +# +# CONFIG_AS3935 is not set + +# +# Proximity and distance sensors +# +# CONFIG_ISL29501 is not set +# CONFIG_LIDAR_LITE_V2 is not set +# CONFIG_RFD77402 is not set +# CONFIG_SRF04 is not set +# CONFIG_SX9500 is not set +# CONFIG_SRF08 is not set + +# +# Resolver to digital converters +# +# CONFIG_AD2S1200 is not set + +# +# Temperature sensors +# +# CONFIG_MAXIM_THERMOCOUPLE is not set +# CONFIG_MLX90614 is not set +# CONFIG_MLX90632 is not set +# CONFIG_TMP006 is not set +# CONFIG_TMP007 is not set +# CONFIG_TSYS01 is not set +# CONFIG_TSYS02D is not set # CONFIG_NTB is not set # CONFIG_VME_BUS is not set # CONFIG_PWM is not set @@ -3746,6 +4031,7 @@ CONFIG_ARM_GIC_MAX_NR=1 # CONFIG_BCM_KONA_USB2_PHY is not set # CONFIG_PHY_PXA_28NM_HSIC is not set # CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_CPCAP_USB is not set # CONFIG_POWERCAP is not set # CONFIG_MCB is not set @@ -4000,7 +4286,7 @@ CONFIG_SECURITY=y # CONFIG_SECURITYFS is not set CONFIG_SECURITY_NETWORK=y CONFIG_PAGE_TABLE_ISOLATION=y -# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_NETWORK_XFRM=y # CONFIG_SECURITY_PATH is not set # CONFIG_INTEL_TXT is not set CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y @@ -4210,8 +4496,6 @@ CONFIG_ASYMMETRIC_KEY_TYPE=y CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y CONFIG_X509_CERTIFICATE_PARSER=y CONFIG_PKCS7_MESSAGE_PARSER=y -# CONFIG_PKCS7_TEST_KEY is not set -# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set # # Certificates for signature checking @@ -4249,8 +4533,8 @@ CONFIG_CRC32_SLICEBY8=y # CONFIG_CRC64 is not set # CONFIG_CRC4 is not set # CONFIG_CRC7 is not set -# CONFIG_LIBCRC32C is not set -# CONFIG_CRC8 is not set +CONFIG_LIBCRC32C=y +CONFIG_CRC8=y CONFIG_XXHASH=y # CONFIG_RANDOM32_SELFTEST is not set CONFIG_ZLIB_INFLATE=y diff --git a/packages/base/any/kernels/4.19-lts/patches/0001-mlx-amendments-fixes-new-kernel-alignmnet.patch b/packages/base/any/kernels/4.19-lts/patches/0001-mlx-amendments-fixes-new-kernel-alignmnet.patch new file mode 100644 index 00000000..1d9dd3fa --- /dev/null +++ b/packages/base/any/kernels/4.19-lts/patches/0001-mlx-amendments-fixes-new-kernel-alignmnet.patch @@ -0,0 +1,1704 @@ +diff -Nur a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h +--- a/include/linux/platform_data/mlxreg.h 2019-08-20 18:37:02.832555707 +0300 ++++ b/include/linux/platform_data/mlxreg.h 2019-08-20 18:37:46.696900842 +0300 +@@ -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 @@ + * @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 @@ + u32 reg; + u32 mask; + u32 bit; ++ u32 capability; + umode_t mode; + struct device_node *np; + struct mlxreg_hotplug_device hpdev; +@@ -107,14 +122,20 @@ + /** + * 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 -Nur a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +--- a/drivers/platform/x86/mlx-platform.c 2019-08-20 12:29:24.088463031 +0300 ++++ b/drivers/platform/x86/mlx-platform.c 2019-08-20 12:29:48.464663328 +0300 +@@ -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,17 @@ + #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_GP1_OFFSET 0x30 + #define MLXPLAT_CPLD_LPC_REG_WP1_OFFSET 0x31 + #define MLXPLAT_CPLD_LPC_REG_GP2_OFFSET 0x32 +@@ -64,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 +@@ -76,6 +60,16 @@ + #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_PWM1_OFFSET 0xe3 + #define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4 + #define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5 +@@ -89,6 +83,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 +@@ -111,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) +@@ -120,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 + +@@ -145,6 +151,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 +@@ -152,6 +170,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 +180,8 @@ + 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 +195,14 @@ + 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] = { + { +@@ -254,6 +284,22 @@ + }, + }; + ++/* 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 +414,45 @@ + }, + }; + ++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 +463,16 @@ + .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 +670,7 @@ + + 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 +701,48 @@ + .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 +791,7 @@ + .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, + }; +@@ -838,61 +945,90 @@ + .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, + }, + }; + +@@ -1064,6 +1200,12 @@ + .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), +@@ -1101,6 +1243,160 @@ + .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_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_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), ++ .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, ++ }, ++}; ++ ++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 +1407,89 @@ + .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 +1498,148 @@ + .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) { +@@ -1188,6 +1654,7 @@ + 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: +@@ -1196,6 +1663,14 @@ + 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 +1683,17 @@ + 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_GP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: +@@ -1222,6 +1702,8 @@ + 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: +@@ -1234,6 +1716,16 @@ + 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 +1740,10 @@ + 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; +@@ -1258,18 +1754,25 @@ + 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_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_ASIC_HEALTH_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: +@@ -1282,6 +1785,10 @@ + 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 +1803,10 @@ + 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; +@@ -1305,6 +1816,18 @@ + { 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 }, + }; + + struct mlxplat_mlxcpld_regmap_context { +@@ -1345,15 +1868,47 @@ + .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) + { +@@ -1369,6 +1924,7 @@ + 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; + }; +@@ -1387,6 +1943,7 @@ + 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; + }; +@@ -1405,6 +1962,7 @@ + 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; + }; +@@ -1421,8 +1979,9 @@ + 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; + }; +@@ -1439,14 +1998,81 @@ + 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; ++ ++ 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"), +@@ -1499,51 +2125,28 @@ + .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"), + }, + }, + { } +@@ -1612,13 +2215,36 @@ + } + 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; +@@ -1636,21 +2262,8 @@ + } + } + +- 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 +2276,16 @@ + } + + /* 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 +2297,7 @@ + + /* 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 +2311,7 @@ + + /* 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 +2323,33 @@ + } + } + ++ /* 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 +2375,10 @@ + 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) +diff -Nur a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c +--- a/drivers/platform/mellanox/mlxreg-hotplug.c 2019-08-20 12:34:52.127157845 +0300 ++++ b/drivers/platform/mellanox/mlxreg-hotplug.c 2019-08-20 12:41:05.514233420 +0300 +@@ -496,7 +496,9 @@ + { + 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; +@@ -508,6 +510,25 @@ + 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 -Nur a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c +--- a/drivers/leds/leds-mlxreg.c 2019-08-20 13:23:32.187371054 +0300 ++++ b/drivers/leds/leds-mlxreg.c 2019-08-20 13:24:05.035643550 +0300 +@@ -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 @@ + 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 @@ + 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 @@ + 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 -Nur a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c +--- a/drivers/hwmon/mlxreg-fan.c 2019-08-20 13:15:39.547446448 +0300 ++++ b/drivers/hwmon/mlxreg-fan.c 2019-08-20 13:16:38.875939488 +0300 +@@ -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 @@ + .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 @@ + 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 @@ + 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_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 @@ + 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 @@ + 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 -Nur a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c +--- a/drivers/hwmon/pmbus/tps53679.c 2019-08-20 14:18:30.122697819 +0300 ++++ b/drivers/hwmon/pmbus/tps53679.c 2019-08-20 14:18:40.134780540 +0300 +@@ -80,7 +80,15 @@ + 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/packages/base/any/kernels/4.19-lts/patches/0002-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch b/packages/base/any/kernels/4.19-lts/patches/0002-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch new file mode 100644 index 00000000..d3a75dcc --- /dev/null +++ b/packages/base/any/kernels/4.19-lts/patches/0002-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch @@ -0,0 +1,330 @@ +diff -Nur a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig +--- a/drivers/watchdog/Kconfig 2019-08-20 14:26:04.438449328 +0300 ++++ b/drivers/watchdog/Kconfig 2019-08-20 14:22:54.744883819 +0300 +@@ -241,6 +241,22 @@ + 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 -Nur a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile +--- a/drivers/watchdog/Makefile 2019-08-20 14:26:04.438449328 +0300 ++++ b/drivers/watchdog/Makefile 2019-08-20 14:23:27.893157429 +0300 +@@ -139,6 +139,7 @@ + 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 -Nur a/drivers/watchdog/mlx_wdt.c b/drivers/watchdog/mlx_wdt.c +--- a/drivers/watchdog/mlx_wdt.c 1970-01-01 02:00:00.000000000 +0200 ++++ b/drivers/watchdog/mlx_wdt.c 2019-08-20 14:21:55.748396514 +0300 +@@ -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/packages/base/any/kernels/4.19-lts/patches/0003-mlxsw-new-features-amendments-new-kernel-alignment.patch b/packages/base/any/kernels/4.19-lts/patches/0003-mlxsw-new-features-amendments-new-kernel-alignment.patch new file mode 100644 index 00000000..c1a90e40 --- /dev/null +++ b/packages/base/any/kernels/4.19-lts/patches/0003-mlxsw-new-features-amendments-new-kernel-alignment.patch @@ -0,0 +1,4830 @@ +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 2019-08-21 13:26:08.910775042 +0300 ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c 2019-08-21 13:24:59.434212403 +0300 +@@ -78,6 +78,7 @@ + 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 @@ + } + 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 @@ + }; + + 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,12 @@ + goto err_devlink_register; + } + ++ 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,6 +1062,11 @@ + if (err) + 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) +@@ -1058,10 +1076,15 @@ + 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_driver->params_unregister && !reload) ++ mlxsw_driver->params_unregister(mlxsw_core); ++err_register_params: + if (!reload) + devlink_unregister(devlink); + err_devlink_register: +@@ -1100,8 +1123,11 @@ + + 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 +1140,8 @@ + 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 +1899,43 @@ + } + 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 -Nur a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c 1970-01-01 02:00:00.000000000 +0200 ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c 2019-08-21 13:22:51.981180265 +0300 +@@ -0,0 +1,239 @@ ++// 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: ++ *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 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, ++ 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: ++ /* Verify if transceiver provides 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; ++ 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; ++ 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 -Nur a/drivers/net/ethernet/mellanox/mlxsw/core_env.h b/drivers/net/ethernet/mellanox/mlxsw/core_env.h +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.h 1970-01-01 02:00:00.000000000 +0200 ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.h 2019-08-21 13:22:51.981180265 +0300 +@@ -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 -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 2019-08-21 13:26:08.910775042 +0300 ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h 2019-08-21 13:22:51.981180265 +0300 +@@ -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_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 @@ + 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_fw_rev fw_rev; + u8 vsd[MLXSW_CMD_BOARDINFO_VSD_LEN]; + u8 psid[MLXSW_CMD_BOARDINFO_PSID_LEN]; ++ u8 low_frequency; + }; + + struct mlxsw_hwmon; +@@ -390,6 +397,35 @@ + { + } + ++#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 -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 2019-08-21 13:26:08.910775042 +0300 ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c 2019-08-21 13:22:51.981180265 +0300 +@@ -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 @@ + 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 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_count; + }; + + static ssize_t mlxsw_hwmon_temp_show(struct device *dev, +@@ -40,18 +52,19 @@ + 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_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"); + 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 @@ + 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_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"); + 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 @@ + 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 @@ + 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"); +@@ -121,6 +138,27 @@ + 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 @@ + 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_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, + 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 @@ + 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 @@ + 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 @@ + { + 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 @@ + 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 @@ + 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,109 @@ + return 0; + } + ++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; ++ 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 ++ * 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; ++ 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++; ++ } ++ mlxsw_hwmon->module_sensor_count = index; ++ ++ return 0; ++} ++ ++static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) ++{ ++ 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 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) { ++ 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, ++ 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 +651,14 @@ + 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 +675,8 @@ + return 0; + + err_hwmon_register: ++err_temp_gearbox_init: ++err_temp_module_init: + err_fans_init: + err_temp_init: + kfree(mlxsw_hwmon); +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 2019-08-21 13:26:08.910775042 +0300 ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c 2019-08-21 13:22:51.981180265 +0300 +@@ -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 @@ + 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,30 @@ + /* 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; ++ 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) +@@ -93,9 +138,67 @@ + 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 +265,7 @@ + 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,7 +283,7 @@ + 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); +@@ -192,7 +295,7 @@ + } + mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); + +- *p_temp = (int) temp; ++ *p_temp = temp; + return 0; + } + +@@ -227,13 +330,31 @@ + 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, +@@ -243,6 +364,230 @@ + .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; ++ ++ /* 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; ++ ++ 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 +630,51 @@ + 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 +690,217 @@ + .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, ++ 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; ++} ++ ++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]; ++ /* 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); ++ /* Update trip point according to the module data. */ ++ return mlxsw_thermal_module_trips_update(dev, core, module_tz); ++} ++ ++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) ++{ ++ unsigned int module_count = mlxsw_core_max_ports(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); ++ 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 < module_count - 1; 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 = module_count - 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) ++{ ++ 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); ++} ++ ++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, ++ NULL, 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) ++{ ++ struct mlxsw_thermal_module *gearbox_tz; ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; ++ 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 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; ++ ++ 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) +@@ -358,8 +953,9 @@ + 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 +965,47 @@ + } + } + ++ /* 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; ++ ++ err = mlxsw_thermal_gearboxes_init(dev, core, thermal); ++ if (err) ++ goto err_unreg_modules_tzdev; ++ + thermal->mode = THERMAL_DEVICE_ENABLED; + *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 +1019,8 @@ + { + 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 -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 2019-08-21 13:26:08.910775042 +0300 ++++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c 2019-08-21 13:22:51.981180265 +0300 +@@ -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 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 @@ + 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 @@ + 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 @@ + 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 @@ + (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 @@ + 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 @@ + + 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 @@ + { + 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_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 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 @@ + 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 @@ + 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 @@ + 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 -Nur a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig +--- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig 2019-08-21 13:26:08.910775042 +0300 ++++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig 2019-08-21 13:22:51.981180265 +0300 +@@ -28,6 +28,15 @@ + 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 -Nur a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile +--- a/drivers/net/ethernet/mellanox/mlxsw/Makefile 2019-08-21 13:26:08.910775042 +0300 ++++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile 2019-08-21 13:22:51.981180265 +0300 +@@ -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 -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 2019-08-21 13:26:08.910775042 +0300 ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c 2019-08-21 13:22:51.981180265 +0300 +@@ -1,66 +1,405 @@ + // 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; ++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 **ports; ++ int *module_to_port; ++ struct mlxsw_core *core; ++ const struct mlxsw_bus_info *bus_info; ++ u8 base_mac[ETH_ALEN]; ++ u8 max_ports; + }; + +-static const struct i2c_device_id mlxsw_minimal_i2c_id[] = { ++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 int ++mlxsw_m_port_get_phys_port_name(struct net_device *dev, char *name, size_t len) ++{ ++ struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev); ++ struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; ++ u8 local_port = mlxsw_m_port->local_port; ++ ++ return mlxsw_core_port_get_phys_port_name(core, local_port, name, len); ++} ++ ++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, ++ .ndo_get_phys_port_name = mlxsw_m_port_get_phys_port_name, ++}; ++ ++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_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 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) ++{ ++ 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 = local_port; ++ 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; ++ } ++ ++ mlxsw_core_port_eth_set(mlxsw_m->core, mlxsw_m_port->local_port, ++ mlxsw_m_port, dev, module + 1, false, 0); ++ ++ 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_port_module_map(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_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), ++ GFP_KERNEL); ++ if (!mlxsw_m->ports) ++ return -ENOMEM; ++ ++ mlxsw_m->module_to_port = kmalloc_array(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; ++ } ++ } ++ ++ 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); ++ 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) ++{ ++ 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); ++ } ++ } ++ ++ 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_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_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 -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 2019-08-21 13:26:08.910775042 +0300 ++++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c 2019-08-21 13:22:51.981180265 +0300 +@@ -1039,42 +1039,6 @@ + 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 @@ + 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 @@ + { + 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 @@ + 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 -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 02:00:00.000000000 +0200 ++++ b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c 2019-08-21 13:22:51.981180265 +0300 +@@ -0,0 +1,433 @@ ++/* ++ * 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 (120 * 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); ++ ++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; ++ ++ 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; ++ ++ 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++; ++ } ++ ++ 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 -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 2019-08-21 13:26:08.910775042 +0300 ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h 2019-08-21 13:25:31.454471711 +0300 +@@ -295,6 +295,7 @@ + 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 @@ + 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 @@ + 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 @@ + *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 @@ + 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 @@ + * 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 @@ + */ + 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 @@ + */ + 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_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 @@ + *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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + * 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 @@ + */ + 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 @@ + */ + 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 @@ + + 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 @@ + * 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + */ + 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 @@ + 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 @@ + 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 @@ + */ + 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 @@ + *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 @@ + + 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 @@ + */ + 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 @@ + 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 @@ + 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,41 @@ + */ + 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, +@@ -7968,6 +8532,43 @@ + 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 +8880,558 @@ + 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_TYPE_NONE, ++ MLXSW_REG_MGPIR_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); ++ ++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. ++ */ ++#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 +9489,15 @@ + */ + 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 +9515,15 @@ + + 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 +9571,12 @@ + #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 +9586,7 @@ + * 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 +9599,8 @@ + + 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 +9608,7 @@ + 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 +9919,10 @@ + 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 +9971,30 @@ + 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 -Nur a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h +--- a/drivers/net/ethernet/mellanox/mlxsw/resources.h 2019-08-21 13:26:08.910775042 +0300 ++++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h 2019-08-21 13:22:51.981180265 +0300 +@@ -41,11 +41,14 @@ + 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 @@ + [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/packages/base/any/kernels/4.19-lts/patches/series b/packages/base/any/kernels/4.19-lts/patches/series index e0cca5d4..4172a687 100755 --- a/packages/base/any/kernels/4.19-lts/patches/series +++ b/packages/base/any/kernels/4.19-lts/patches/series @@ -3,3 +3,6 @@ 0003-drivers-net-ethernet-broadcom-tg3.patch driver-ixgbe-external-phy.patch driver-hwmon-max6620.patch +0001-mlx-amendments-fixes-new-kernel-alignmnet.patch +0002-watchdog-mlx-wdt-introduce-watchdog-driver-for-Mella.patch +0003-mlxsw-new-features-amendments-new-kernel-alignment.patch