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