mirror of
https://github.com/Telecominfraproject/OpenNetworkLinux.git
synced 2025-12-25 09:17:08 +00:00
Add ONL based on Debian 9 and kernel 4.9.30 support for Mellanox platforms MSN2700, MSN2410, MSN2100.
Signed-off-by: Michael Shych <michaelsh@mellanox.com>
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
- usbutils
|
||||
- mtd-utils
|
||||
- i2c-tools
|
||||
- kmod
|
||||
- isc-dhcp-client
|
||||
- ntp
|
||||
- wget
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
- grub2
|
||||
- onl-upgrade
|
||||
- hw-management
|
||||
- sx-kernel
|
||||
- onl-kernel-3.16-lts-x86-64-all-modules
|
||||
- onl-kernel-4.9-lts-x86-64-all-modules
|
||||
- efibootmgr
|
||||
- gdisk
|
||||
|
||||
@@ -399,7 +399,6 @@ CONFIG_X86_EXTENDED_PLATFORM=y
|
||||
# CONFIG_X86_VSMP is not set
|
||||
# CONFIG_X86_GOLDFISH is not set
|
||||
# CONFIG_X86_INTEL_MID is not set
|
||||
# CONFIG_MLX_PLATFORM is not set
|
||||
# CONFIG_X86_INTEL_LPSS is not set
|
||||
# CONFIG_X86_AMD_PLATFORM_DEVICE is not set
|
||||
# CONFIG_IOSF_MBI is not set
|
||||
@@ -1143,6 +1142,7 @@ CONFIG_DEBUG_DEVRES=y
|
||||
CONFIG_GENERIC_CPU_AUTOPROBE=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_I2C=y
|
||||
CONFIG_REGMAP_SPI=y
|
||||
CONFIG_DMA_SHARED_BUFFER=y
|
||||
# CONFIG_FENCE_TRACE is not set
|
||||
|
||||
@@ -1207,17 +1207,21 @@ CONFIG_VIRTIO_BLK=y
|
||||
# CONFIG_SENSORS_APDS990X is not set
|
||||
# CONFIG_HMC6352 is not set
|
||||
# CONFIG_DS1682 is not set
|
||||
# CONFIG_TI_DAC7512 is not set
|
||||
# CONFIG_USB_SWITCH_FSA9480 is not set
|
||||
# CONFIG_LATTICE_ECP3_CONFIG is not set
|
||||
# CONFIG_SRAM is not set
|
||||
# CONFIG_C2PORT is not set
|
||||
|
||||
#
|
||||
# EEPROM support
|
||||
#
|
||||
# CONFIG_EEPROM_AT24 is not set
|
||||
CONFIG_EEPROM_AT24=m
|
||||
# CONFIG_EEPROM_AT25 is not set
|
||||
# CONFIG_EEPROM_LEGACY is not set
|
||||
# CONFIG_EEPROM_MAX6875 is not set
|
||||
# CONFIG_EEPROM_93CX6 is not set
|
||||
# CONFIG_EEPROM_93XX46 is not set
|
||||
# CONFIG_CB710_CORE is not set
|
||||
|
||||
#
|
||||
@@ -1580,11 +1584,21 @@ CONFIG_NET_VENDOR_MELLANOX=y
|
||||
# CONFIG_MLX4_EN is not set
|
||||
# CONFIG_MLX4_CORE 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_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_NET_VENDOR_MYRI=y
|
||||
# CONFIG_MYRI10GE is not set
|
||||
# CONFIG_FEALNX is not set
|
||||
@@ -1704,6 +1718,7 @@ CONFIG_PHYLIB=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
|
||||
@@ -1827,6 +1842,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
|
||||
@@ -1899,6 +1915,8 @@ 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_ATMEL_MXT is not set
|
||||
# CONFIG_TOUCHSCREEN_BU21013 is not set
|
||||
@@ -1933,6 +1951,7 @@ 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_SILEAD is not set
|
||||
# CONFIG_TOUCHSCREEN_ST1232 is not set
|
||||
@@ -2038,6 +2057,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
|
||||
@@ -2086,8 +2107,15 @@ CONFIG_I2C=y
|
||||
CONFIG_ACPI_I2C_OPREGION=y
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
CONFIG_I2C_COMPAT=y
|
||||
# CONFIG_I2C_CHARDEV is not set
|
||||
# CONFIG_I2C_MUX is not set
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
CONFIG_I2C_MUX=y
|
||||
|
||||
#
|
||||
# Multiplexer I2C Chip support
|
||||
#
|
||||
# CONFIG_I2C_MUX_PCA9541 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
|
||||
@@ -2142,12 +2170,38 @@ CONFIG_I2C_I801=y
|
||||
#
|
||||
# Other I2C/SMBus bus drivers
|
||||
#
|
||||
CONFIG_I2C_MLXCPLD=y
|
||||
# CONFIG_I2C_STUB is not set
|
||||
# CONFIG_I2C_SLAVE is not set
|
||||
# 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
|
||||
|
||||
#
|
||||
# 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_PXA2XX is not set
|
||||
# CONFIG_SPI_PXA2XX_PCI 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_SPMI is not set
|
||||
# CONFIG_HSI is not set
|
||||
|
||||
@@ -2183,6 +2237,7 @@ CONFIG_PTP_1588_CLOCK=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_BATTERY_DS2780 is not set
|
||||
# CONFIG_BATTERY_DS2781 is not set
|
||||
@@ -2205,6 +2260,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
|
||||
@@ -2213,6 +2269,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
|
||||
@@ -2239,8 +2296,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
|
||||
@@ -2253,19 +2311,23 @@ 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_MAX6639 is not set
|
||||
# CONFIG_SENSORS_MAX6642 is not set
|
||||
# CONFIG_SENSORS_MAX6650 is not set
|
||||
# CONFIG_SENSORS_MAX6697 is not set
|
||||
# CONFIG_SENSORS_MAX31790 is not set
|
||||
# CONFIG_SENSORS_MCP3021 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
|
||||
@@ -2286,7 +2348,21 @@ CONFIG_HWMON=y
|
||||
# CONFIG_SENSORS_NCT7802 is not set
|
||||
# CONFIG_SENSORS_NCT7904 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_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_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_SHT21 is not set
|
||||
# CONFIG_SENSORS_SHT3x is not set
|
||||
# CONFIG_SENSORS_SHTC1 is not set
|
||||
@@ -2305,13 +2381,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_TMP401 is not set
|
||||
# CONFIG_SENSORS_TMP421 is not set
|
||||
@@ -2356,6 +2433,7 @@ CONFIG_X86_PKG_TEMP_THERMAL=m
|
||||
#
|
||||
# CONFIG_INT340X_THERMAL is not set
|
||||
# CONFIG_INTEL_PCH_THERMAL is not set
|
||||
# CONFIG_GENERIC_ADC_THERMAL is not set
|
||||
CONFIG_WATCHDOG=y
|
||||
# CONFIG_WATCHDOG_CORE is not set
|
||||
# CONFIG_WATCHDOG_NOWAYOUT is not set
|
||||
@@ -2441,6 +2519,7 @@ CONFIG_BCMA_POSSIBLE=y
|
||||
# CONFIG_MFD_AXP20X_I2C is not set
|
||||
# CONFIG_MFD_CROS_EC 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
|
||||
@@ -2448,6 +2527,7 @@ CONFIG_BCMA_POSSIBLE=y
|
||||
# CONFIG_MFD_DA9150 is not set
|
||||
# CONFIG_MFD_DLN2 is not set
|
||||
# CONFIG_MFD_EXYNOS_LPASS is not set
|
||||
# CONFIG_MFD_MC13XXX_SPI is not set
|
||||
# CONFIG_MFD_MC13XXX_I2C is not set
|
||||
# CONFIG_HTC_PASIC3 is not set
|
||||
# CONFIG_LPC_ICH is not set
|
||||
@@ -2468,6 +2548,7 @@ CONFIG_BCMA_POSSIBLE=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
|
||||
@@ -2496,6 +2577,7 @@ CONFIG_BCMA_POSSIBLE=y
|
||||
# CONFIG_MFD_TPS65218 is not set
|
||||
# CONFIG_MFD_TPS6586X 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
|
||||
@@ -2504,8 +2586,10 @@ CONFIG_BCMA_POSSIBLE=y
|
||||
# CONFIG_MFD_TMIO 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
|
||||
@@ -2806,6 +2890,7 @@ CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0
|
||||
CONFIG_SND_HDA_CORE=y
|
||||
CONFIG_SND_HDA_I915=y
|
||||
CONFIG_SND_HDA_PREALLOC_SIZE=64
|
||||
# CONFIG_SND_SPI is not set
|
||||
CONFIG_SND_USB=y
|
||||
# CONFIG_SND_USB_AUDIO is not set
|
||||
# CONFIG_SND_USB_UA101 is not set
|
||||
@@ -2961,6 +3046,7 @@ CONFIG_USB_EHCI_PCI=y
|
||||
# CONFIG_USB_ISP116X_HCD is not set
|
||||
# CONFIG_USB_ISP1362_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
|
||||
@@ -3079,6 +3165,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_TCA6507 is not set
|
||||
@@ -3090,12 +3177,15 @@ CONFIG_LEDS_CLASS=y
|
||||
#
|
||||
# CONFIG_LEDS_BLINKM is not set
|
||||
# CONFIG_LEDS_MLXCPLD is not set
|
||||
CONFIG_LEDS_MLXREG=y
|
||||
# CONFIG_LEDS_USER is not set
|
||||
# CONFIG_LEDS_NIC78BX is not set
|
||||
|
||||
#
|
||||
# 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
|
||||
@@ -3165,6 +3255,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
|
||||
|
||||
#
|
||||
@@ -3289,7 +3394,10 @@ 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=y
|
||||
# CONFIG_CHROME_PLATFORMS is not set
|
||||
CONFIG_MELLANOX_PLATFORM=y
|
||||
CONFIG_MLXREG_HOTPLUG=y
|
||||
|
||||
#
|
||||
# Hardware Spinlock drivers
|
||||
@@ -3344,7 +3452,269 @@ 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_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_BMA180 is not set
|
||||
# CONFIG_BMA220 is not set
|
||||
# CONFIG_BMC150_ACCEL is not set
|
||||
# CONFIG_DMARD09 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_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_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_INA2XX_ADC is not set
|
||||
# CONFIG_LTC2485 is not set
|
||||
# CONFIG_MAX1027 is not set
|
||||
CONFIG_MAX1363=y
|
||||
# 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_ADC12138 is not set
|
||||
# CONFIG_TI_ADC128S052 is not set
|
||||
# CONFIG_TI_ADC161S626 is not set
|
||||
# CONFIG_TI_ADS1015 is not set
|
||||
|
||||
#
|
||||
# Amplifiers
|
||||
#
|
||||
# CONFIG_AD8366 is not set
|
||||
|
||||
#
|
||||
# Chemical Sensors
|
||||
#
|
||||
# CONFIG_ATLAS_PH_SENSOR 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
|
||||
|
||||
#
|
||||
# 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_AD5686 is not set
|
||||
# CONFIG_AD5755 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_M62332 is not set
|
||||
# CONFIG_MAX517 is not set
|
||||
# CONFIG_MCP4725 is not set
|
||||
# CONFIG_MCP4922 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_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
|
||||
|
||||
#
|
||||
# Humidity sensors
|
||||
#
|
||||
# CONFIG_AM2315 is not set
|
||||
# CONFIG_HDC100X 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
|
||||
|
||||
#
|
||||
# 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_ISL29125 is not set
|
||||
# CONFIG_JSA1212 is not set
|
||||
# CONFIG_RPR0521 is not set
|
||||
# CONFIG_LTR501 is not set
|
||||
# CONFIG_MAX44000 is not set
|
||||
# CONFIG_OPT3001 is not set
|
||||
# CONFIG_PA12203001 is not set
|
||||
# CONFIG_SI1145 is not set
|
||||
# CONFIG_STK3310 is not set
|
||||
# CONFIG_TCS3414 is not set
|
||||
# CONFIG_TCS3472 is not set
|
||||
# CONFIG_SENSORS_TSL2563 is not set
|
||||
# CONFIG_TSL4531 is not set
|
||||
# CONFIG_US5182D is not set
|
||||
# CONFIG_VCNL4000 is not set
|
||||
# CONFIG_VEML6070 is not set
|
||||
|
||||
#
|
||||
# Magnetometer sensors
|
||||
#
|
||||
# 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
|
||||
|
||||
#
|
||||
# Inclinometer sensors
|
||||
#
|
||||
|
||||
#
|
||||
# Triggers - standalone
|
||||
#
|
||||
# CONFIG_IIO_INTERRUPT_TRIGGER is not set
|
||||
# CONFIG_IIO_SYSFS_TRIGGER is not set
|
||||
|
||||
#
|
||||
# Digital potentiometers
|
||||
#
|
||||
# CONFIG_DS1803 is not set
|
||||
# CONFIG_MAX5487 is not set
|
||||
# CONFIG_MCP4131 is not set
|
||||
# CONFIG_MCP4531 is not set
|
||||
# CONFIG_TPL0102 is not set
|
||||
|
||||
#
|
||||
# Pressure sensors
|
||||
#
|
||||
# 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 sensors
|
||||
#
|
||||
# CONFIG_LIDAR_LITE_V2 is not set
|
||||
# CONFIG_SX9500 is not set
|
||||
|
||||
#
|
||||
# Temperature sensors
|
||||
#
|
||||
# CONFIG_MAXIM_THERMOCOUPLE is not set
|
||||
# CONFIG_MLX90614 is not set
|
||||
# CONFIG_TMP006 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
|
||||
@@ -3375,7 +3745,7 @@ CONFIG_RAS=y
|
||||
#
|
||||
# CONFIG_ANDROID is not set
|
||||
# CONFIG_LIBNVDIMM is not set
|
||||
# CONFIG_NVMEM is not set
|
||||
CONFIG_NVMEM=m
|
||||
# CONFIG_STM is not set
|
||||
# CONFIG_INTEL_TH is not set
|
||||
|
||||
|
||||
@@ -0,0 +1,544 @@
|
||||
Linux backport patch. Includes following commits:
|
||||
899e11216e1c215b97f2f8f92c7b010a4e88f38e
|
||||
|
||||
|
||||
diff -Nur a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
|
||||
--- a/drivers/i2c/busses/Kconfig 2017-11-12 08:08:32.136039784 +0000
|
||||
+++ b/drivers/i2c/busses/Kconfig 2017-11-12 08:08:40.776039899 +0000
|
||||
@@ -1150,6 +1150,17 @@
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-elektor.
|
||||
|
||||
+config I2C_MLXCPLD
|
||||
+ tristate "Mellanox I2C driver"
|
||||
+ depends on X86_64
|
||||
+ help
|
||||
+ This exposes the Mellanox platform I2C busses to the linux I2C layer
|
||||
+ for X86 based systems.
|
||||
+ Controller is implemented as CPLD logic.
|
||||
+
|
||||
+ This driver can also be built as a module. If so, the module will be
|
||||
+ called as i2c-mlxcpld.
|
||||
+
|
||||
config I2C_PCA_ISA
|
||||
tristate "PCA9564/PCA9665 on an ISA bus"
|
||||
depends on ISA
|
||||
diff -Nur a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
|
||||
--- a/drivers/i2c/busses/Makefile 2017-11-12 08:08:32.140039784 +0000
|
||||
+++ b/drivers/i2c/busses/Makefile 2017-11-12 08:08:40.780039899 +0000
|
||||
@@ -116,6 +116,7 @@
|
||||
obj-$(CONFIG_I2C_BRCMSTB) += i2c-brcmstb.o
|
||||
obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o
|
||||
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
|
||||
+obj-$(CONFIG_I2C_MLXCPLD) += i2c-mlxcpld.o
|
||||
obj-$(CONFIG_I2C_OPAL) += i2c-opal.o
|
||||
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
|
||||
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
|
||||
diff -Nur a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c
|
||||
--- a/drivers/i2c/busses/i2c-mlxcpld.c 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ b/drivers/i2c/busses/i2c-mlxcpld.c 2017-11-12 08:08:40.780039899 +0000
|
||||
@@ -0,0 +1,504 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
|
||||
+ * Copyright (c) 2016 Michael Shych <michaels@mellanox.com>
|
||||
+ *
|
||||
+ * 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 <linux/delay.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+/* General defines */
|
||||
+#define MLXPLAT_CPLD_LPC_I2C_BASE_ADDR 0x2000
|
||||
+#define MLXCPLD_I2C_DEVICE_NAME "i2c_mlxcpld"
|
||||
+#define MLXCPLD_I2C_VALID_FLAG (I2C_M_RECV_LEN | I2C_M_RD)
|
||||
+#define MLXCPLD_I2C_BUS_NUM 1
|
||||
+#define MLXCPLD_I2C_DATA_REG_SZ 36
|
||||
+#define MLXCPLD_I2C_MAX_ADDR_LEN 4
|
||||
+#define MLXCPLD_I2C_RETR_NUM 2
|
||||
+#define MLXCPLD_I2C_XFER_TO 500000 /* usec */
|
||||
+#define MLXCPLD_I2C_POLL_TIME 2000 /* usec */
|
||||
+
|
||||
+/* LPC I2C registers */
|
||||
+#define MLXCPLD_LPCI2C_LPF_REG 0x0
|
||||
+#define MLXCPLD_LPCI2C_CTRL_REG 0x1
|
||||
+#define MLXCPLD_LPCI2C_HALF_CYC_REG 0x4
|
||||
+#define MLXCPLD_LPCI2C_I2C_HOLD_REG 0x5
|
||||
+#define MLXCPLD_LPCI2C_CMD_REG 0x6
|
||||
+#define MLXCPLD_LPCI2C_NUM_DAT_REG 0x7
|
||||
+#define MLXCPLD_LPCI2C_NUM_ADDR_REG 0x8
|
||||
+#define MLXCPLD_LPCI2C_STATUS_REG 0x9
|
||||
+#define MLXCPLD_LPCI2C_DATA_REG 0xa
|
||||
+
|
||||
+/* LPC I2C masks and parametres */
|
||||
+#define MLXCPLD_LPCI2C_RST_SEL_MASK 0x1
|
||||
+#define MLXCPLD_LPCI2C_TRANS_END 0x1
|
||||
+#define MLXCPLD_LPCI2C_STATUS_NACK 0x10
|
||||
+#define MLXCPLD_LPCI2C_NO_IND 0
|
||||
+#define MLXCPLD_LPCI2C_ACK_IND 1
|
||||
+#define MLXCPLD_LPCI2C_NACK_IND 2
|
||||
+
|
||||
+struct mlxcpld_i2c_curr_xfer {
|
||||
+ u8 cmd;
|
||||
+ u8 addr_width;
|
||||
+ u8 data_len;
|
||||
+ u8 msg_num;
|
||||
+ struct i2c_msg *msg;
|
||||
+};
|
||||
+
|
||||
+struct mlxcpld_i2c_priv {
|
||||
+ struct i2c_adapter adap;
|
||||
+ u32 base_addr;
|
||||
+ struct mutex lock;
|
||||
+ struct mlxcpld_i2c_curr_xfer xfer;
|
||||
+ struct device *dev;
|
||||
+};
|
||||
+
|
||||
+static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < len - len % 4; i += 4)
|
||||
+ outl(*(u32 *)(data + i), addr + i);
|
||||
+ for (; i < len; ++i)
|
||||
+ outb(*(data + i), addr + i);
|
||||
+}
|
||||
+
|
||||
+static void mlxcpld_i2c_lpc_read_buf(u8 *data, u8 len, u32 addr)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < len - len % 4; i += 4)
|
||||
+ *(u32 *)(data + i) = inl(addr + i);
|
||||
+ for (; i < len; ++i)
|
||||
+ *(data + i) = inb(addr + i);
|
||||
+}
|
||||
+
|
||||
+static void mlxcpld_i2c_read_comm(struct mlxcpld_i2c_priv *priv, u8 offs,
|
||||
+ u8 *data, u8 datalen)
|
||||
+{
|
||||
+ u32 addr = priv->base_addr + offs;
|
||||
+
|
||||
+ switch (datalen) {
|
||||
+ case 1:
|
||||
+ *(data) = inb(addr);
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ *((u16 *)data) = inw(addr);
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ *((u16 *)data) = inw(addr);
|
||||
+ *(data + 2) = inb(addr + 2);
|
||||
+ break;
|
||||
+ case 4:
|
||||
+ *((u32 *)data) = inl(addr);
|
||||
+ break;
|
||||
+ default:
|
||||
+ mlxcpld_i2c_lpc_read_buf(data, datalen, addr);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void mlxcpld_i2c_write_comm(struct mlxcpld_i2c_priv *priv, u8 offs,
|
||||
+ u8 *data, u8 datalen)
|
||||
+{
|
||||
+ u32 addr = priv->base_addr + offs;
|
||||
+
|
||||
+ switch (datalen) {
|
||||
+ case 1:
|
||||
+ outb(*(data), addr);
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ outw(*((u16 *)data), addr);
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ outw(*((u16 *)data), addr);
|
||||
+ outb(*(data + 2), addr + 2);
|
||||
+ break;
|
||||
+ case 4:
|
||||
+ outl(*((u32 *)data), addr);
|
||||
+ break;
|
||||
+ default:
|
||||
+ mlxcpld_i2c_lpc_write_buf(data, datalen, addr);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Check validity of received i2c messages parameters.
|
||||
+ * Returns 0 if OK, other - in case of invalid parameters.
|
||||
+ */
|
||||
+static int mlxcpld_i2c_check_msg_params(struct mlxcpld_i2c_priv *priv,
|
||||
+ struct i2c_msg *msgs, int num)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ if (!num) {
|
||||
+ dev_err(priv->dev, "Incorrect 0 num of messages\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ if (unlikely(msgs[0].addr > 0x7f)) {
|
||||
+ dev_err(priv->dev, "Invalid address 0x%03x\n",
|
||||
+ msgs[0].addr);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < num; ++i) {
|
||||
+ if (unlikely(!msgs[i].buf)) {
|
||||
+ dev_err(priv->dev, "Invalid buf in msg[%d]\n",
|
||||
+ i);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ if (unlikely(msgs[0].addr != msgs[i].addr)) {
|
||||
+ dev_err(priv->dev, "Invalid addr in msg[%d]\n",
|
||||
+ i);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Check if transfer is completed and status of operation.
|
||||
+ * Returns 0 - transfer completed (both ACK or NACK),
|
||||
+ * negative - transfer isn't finished.
|
||||
+ */
|
||||
+static int mlxcpld_i2c_check_status(struct mlxcpld_i2c_priv *priv, int *status)
|
||||
+{
|
||||
+ u8 val;
|
||||
+
|
||||
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_STATUS_REG, &val, 1);
|
||||
+
|
||||
+ if (val & MLXCPLD_LPCI2C_TRANS_END) {
|
||||
+ if (val & MLXCPLD_LPCI2C_STATUS_NACK)
|
||||
+ /*
|
||||
+ * The slave is unable to accept the data. No such
|
||||
+ * slave, command not understood, or unable to accept
|
||||
+ * any more data.
|
||||
+ */
|
||||
+ *status = MLXCPLD_LPCI2C_NACK_IND;
|
||||
+ else
|
||||
+ *status = MLXCPLD_LPCI2C_ACK_IND;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ *status = MLXCPLD_LPCI2C_NO_IND;
|
||||
+
|
||||
+ return -EIO;
|
||||
+}
|
||||
+
|
||||
+static void mlxcpld_i2c_set_transf_data(struct mlxcpld_i2c_priv *priv,
|
||||
+ struct i2c_msg *msgs, int num,
|
||||
+ u8 comm_len)
|
||||
+{
|
||||
+ priv->xfer.msg = msgs;
|
||||
+ priv->xfer.msg_num = num;
|
||||
+
|
||||
+ /*
|
||||
+ * All upper layers currently are never use transfer with more than
|
||||
+ * 2 messages. Actually, it's also not so relevant in Mellanox systems
|
||||
+ * because of HW limitation. Max size of transfer is not more than 32
|
||||
+ * bytes in the current x86 LPCI2C bridge.
|
||||
+ */
|
||||
+ priv->xfer.cmd = msgs[num - 1].flags & I2C_M_RD;
|
||||
+
|
||||
+ if (priv->xfer.cmd == I2C_M_RD && comm_len != msgs[0].len) {
|
||||
+ priv->xfer.addr_width = msgs[0].len;
|
||||
+ priv->xfer.data_len = comm_len - priv->xfer.addr_width;
|
||||
+ } else {
|
||||
+ priv->xfer.addr_width = 0;
|
||||
+ priv->xfer.data_len = comm_len;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Reset CPLD LPCI2C block */
|
||||
+static void mlxcpld_i2c_reset(struct mlxcpld_i2c_priv *priv)
|
||||
+{
|
||||
+ u8 val;
|
||||
+
|
||||
+ mutex_lock(&priv->lock);
|
||||
+
|
||||
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CTRL_REG, &val, 1);
|
||||
+ val &= ~MLXCPLD_LPCI2C_RST_SEL_MASK;
|
||||
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_CTRL_REG, &val, 1);
|
||||
+
|
||||
+ mutex_unlock(&priv->lock);
|
||||
+}
|
||||
+
|
||||
+/* Make sure the CPLD is ready to start transmitting. */
|
||||
+static int mlxcpld_i2c_check_busy(struct mlxcpld_i2c_priv *priv)
|
||||
+{
|
||||
+ u8 val;
|
||||
+
|
||||
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_STATUS_REG, &val, 1);
|
||||
+
|
||||
+ if (val & MLXCPLD_LPCI2C_TRANS_END)
|
||||
+ return 0;
|
||||
+
|
||||
+ return -EIO;
|
||||
+}
|
||||
+
|
||||
+static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv)
|
||||
+{
|
||||
+ int timeout = 0;
|
||||
+
|
||||
+ do {
|
||||
+ if (!mlxcpld_i2c_check_busy(priv))
|
||||
+ break;
|
||||
+ usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME);
|
||||
+ timeout += MLXCPLD_I2C_POLL_TIME;
|
||||
+ } while (timeout <= MLXCPLD_I2C_XFER_TO);
|
||||
+
|
||||
+ if (timeout > MLXCPLD_I2C_XFER_TO)
|
||||
+ return -ETIMEDOUT;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Wait for master transfer to complete.
|
||||
+ * It puts current process to sleep until we get interrupt or timeout expires.
|
||||
+ * Returns the number of transferred or read bytes or error (<0).
|
||||
+ */
|
||||
+static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv)
|
||||
+{
|
||||
+ int status, i, timeout = 0;
|
||||
+ u8 datalen;
|
||||
+
|
||||
+ do {
|
||||
+ usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME);
|
||||
+ if (!mlxcpld_i2c_check_status(priv, &status))
|
||||
+ break;
|
||||
+ timeout += MLXCPLD_I2C_POLL_TIME;
|
||||
+ } while (status == 0 && timeout < MLXCPLD_I2C_XFER_TO);
|
||||
+
|
||||
+ switch (status) {
|
||||
+ case MLXCPLD_LPCI2C_NO_IND:
|
||||
+ return -ETIMEDOUT;
|
||||
+
|
||||
+ case MLXCPLD_LPCI2C_ACK_IND:
|
||||
+ if (priv->xfer.cmd != I2C_M_RD)
|
||||
+ return (priv->xfer.addr_width + priv->xfer.data_len);
|
||||
+
|
||||
+ if (priv->xfer.msg_num == 1)
|
||||
+ i = 0;
|
||||
+ else
|
||||
+ i = 1;
|
||||
+
|
||||
+ if (!priv->xfer.msg[i].buf)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /*
|
||||
+ * Actual read data len will be always the same as
|
||||
+ * requested len. 0xff (line pull-up) will be returned
|
||||
+ * if slave has no data to return. Thus don't read
|
||||
+ * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD.
|
||||
+ */
|
||||
+ datalen = priv->xfer.data_len;
|
||||
+
|
||||
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG,
|
||||
+ priv->xfer.msg[i].buf, datalen);
|
||||
+
|
||||
+ return datalen;
|
||||
+
|
||||
+ case MLXCPLD_LPCI2C_NACK_IND:
|
||||
+ return -ENXIO;
|
||||
+
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv)
|
||||
+{
|
||||
+ int i, len = 0;
|
||||
+ u8 cmd;
|
||||
+
|
||||
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG,
|
||||
+ &priv->xfer.data_len, 1);
|
||||
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG,
|
||||
+ &priv->xfer.addr_width, 1);
|
||||
+
|
||||
+ for (i = 0; i < priv->xfer.msg_num; i++) {
|
||||
+ if ((priv->xfer.msg[i].flags & I2C_M_RD) != I2C_M_RD) {
|
||||
+ /* Don't write to CPLD buffer in read transaction */
|
||||
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_DATA_REG +
|
||||
+ len, priv->xfer.msg[i].buf,
|
||||
+ priv->xfer.msg[i].len);
|
||||
+ len += priv->xfer.msg[i].len;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Set target slave address with command for master transfer.
|
||||
+ * It should be latest executed function before CPLD transaction.
|
||||
+ */
|
||||
+ cmd = (priv->xfer.msg[0].addr << 1) | priv->xfer.cmd;
|
||||
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_CMD_REG, &cmd, 1);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Generic lpc-i2c transfer.
|
||||
+ * Returns the number of processed messages or error (<0).
|
||||
+ */
|
||||
+static int mlxcpld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
+ int num)
|
||||
+{
|
||||
+ struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap);
|
||||
+ u8 comm_len = 0;
|
||||
+ int i, err;
|
||||
+
|
||||
+ err = mlxcpld_i2c_check_msg_params(priv, msgs, num);
|
||||
+ if (err) {
|
||||
+ dev_err(priv->dev, "Incorrect message\n");
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < num; ++i)
|
||||
+ comm_len += msgs[i].len;
|
||||
+
|
||||
+ /* Check bus state */
|
||||
+ if (mlxcpld_i2c_wait_for_free(priv)) {
|
||||
+ dev_err(priv->dev, "LPCI2C bridge is busy\n");
|
||||
+
|
||||
+ /*
|
||||
+ * Usually it means something serious has happened.
|
||||
+ * We can not have unfinished previous transfer
|
||||
+ * so it doesn't make any sense to try to stop it.
|
||||
+ * Probably we were not able to recover from the
|
||||
+ * previous error.
|
||||
+ * The only reasonable thing - is soft reset.
|
||||
+ */
|
||||
+ mlxcpld_i2c_reset(priv);
|
||||
+ if (mlxcpld_i2c_check_busy(priv)) {
|
||||
+ dev_err(priv->dev, "LPCI2C bridge is busy after reset\n");
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ mlxcpld_i2c_set_transf_data(priv, msgs, num, comm_len);
|
||||
+
|
||||
+ mutex_lock(&priv->lock);
|
||||
+
|
||||
+ /* Do real transfer. Can't fail */
|
||||
+ mlxcpld_i2c_xfer_msg(priv);
|
||||
+
|
||||
+ /* Wait for transaction complete */
|
||||
+ err = mlxcpld_i2c_wait_for_tc(priv);
|
||||
+
|
||||
+ mutex_unlock(&priv->lock);
|
||||
+
|
||||
+ return err < 0 ? err : num;
|
||||
+}
|
||||
+
|
||||
+static u32 mlxcpld_i2c_func(struct i2c_adapter *adap)
|
||||
+{
|
||||
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA;
|
||||
+}
|
||||
+
|
||||
+static const struct i2c_algorithm mlxcpld_i2c_algo = {
|
||||
+ .master_xfer = mlxcpld_i2c_xfer,
|
||||
+ .functionality = mlxcpld_i2c_func
|
||||
+};
|
||||
+
|
||||
+static struct i2c_adapter_quirks mlxcpld_i2c_quirks = {
|
||||
+ .flags = I2C_AQ_COMB_WRITE_THEN_READ,
|
||||
+ .max_read_len = MLXCPLD_I2C_DATA_REG_SZ - MLXCPLD_I2C_MAX_ADDR_LEN,
|
||||
+ .max_write_len = MLXCPLD_I2C_DATA_REG_SZ,
|
||||
+ .max_comb_1st_msg_len = 4,
|
||||
+};
|
||||
+
|
||||
+static struct i2c_adapter mlxcpld_i2c_adapter = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .name = "i2c-mlxcpld",
|
||||
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
+ .algo = &mlxcpld_i2c_algo,
|
||||
+ .quirks = &mlxcpld_i2c_quirks,
|
||||
+ .retries = MLXCPLD_I2C_RETR_NUM,
|
||||
+ .nr = MLXCPLD_I2C_BUS_NUM,
|
||||
+};
|
||||
+
|
||||
+static int mlxcpld_i2c_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct mlxcpld_i2c_priv *priv;
|
||||
+ int err;
|
||||
+
|
||||
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ mutex_init(&priv->lock);
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+
|
||||
+ priv->dev = &pdev->dev;
|
||||
+
|
||||
+ /* Register with i2c layer */
|
||||
+ mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO);
|
||||
+ priv->adap = mlxcpld_i2c_adapter;
|
||||
+ priv->adap.dev.parent = &pdev->dev;
|
||||
+ priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR;
|
||||
+ i2c_set_adapdata(&priv->adap, priv);
|
||||
+
|
||||
+ err = i2c_add_numbered_adapter(&priv->adap);
|
||||
+ if (err)
|
||||
+ mutex_destroy(&priv->lock);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int mlxcpld_i2c_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct mlxcpld_i2c_priv *priv = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ i2c_del_adapter(&priv->adap);
|
||||
+ mutex_destroy(&priv->lock);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver mlxcpld_i2c_driver = {
|
||||
+ .probe = mlxcpld_i2c_probe,
|
||||
+ .remove = mlxcpld_i2c_remove,
|
||||
+ .driver = {
|
||||
+ .name = MLXCPLD_I2C_DEVICE_NAME,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(mlxcpld_i2c_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Michael Shych <michaels@mellanox.com>");
|
||||
+MODULE_DESCRIPTION("Mellanox I2C-CPLD controller driver");
|
||||
+MODULE_LICENSE("Dual BSD/GPL");
|
||||
+MODULE_ALIAS("platform:i2c-mlxcpld");
|
||||
@@ -0,0 +1,317 @@
|
||||
Linux backport patch. Includes following commits:
|
||||
e3448e71adb1fdd7f403c568ef5c2ed5adf2b197
|
||||
c3bb77620da428884807fb2f6f3485644e146f84
|
||||
db5f807ee3dcc779b78f59982cc3e89863069e9c
|
||||
|
||||
|
||||
diff -Nur a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
|
||||
--- a/drivers/i2c/muxes/Kconfig 2017-11-12 08:13:59.176044126 +0000
|
||||
+++ b/drivers/i2c/muxes/Kconfig 2017-11-12 08:14:27.992044509 +0000
|
||||
@@ -82,4 +82,15 @@
|
||||
demultiplexer that uses the pinctrl subsystem. This is useful if you
|
||||
want to change the I2C master at run-time depending on features.
|
||||
|
||||
+config I2C_MUX_MLXCPLD
|
||||
+ tristate "Mellanox CPLD based I2C multiplexer"
|
||||
+ help
|
||||
+ If you say yes to this option, support will be included for a
|
||||
+ CPLD based I2C multiplexer. This driver provides access to
|
||||
+ I2C busses connected through a MUX, which is controlled
|
||||
+ by a CPLD register.
|
||||
+
|
||||
+ This driver can also be built as a module. If so, the module
|
||||
+ will be called i2c-mux-mlxcpld.
|
||||
+
|
||||
endmenu
|
||||
diff -Nur a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
|
||||
--- a/drivers/i2c/muxes/Makefile 2017-11-12 08:13:59.176044126 +0000
|
||||
+++ b/drivers/i2c/muxes/Makefile 2017-11-12 08:14:27.992044509 +0000
|
||||
@@ -6,6 +6,7 @@
|
||||
obj-$(CONFIG_I2C_DEMUX_PINCTRL) += i2c-demux-pinctrl.o
|
||||
|
||||
obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
|
||||
+obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o
|
||||
obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o
|
||||
obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o
|
||||
obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o
|
||||
diff -Nur a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c
|
||||
--- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c 2017-11-12 08:14:27.992044509 +0000
|
||||
@@ -0,0 +1,221 @@
|
||||
+/*
|
||||
+ * drivers/i2c/muxes/i2c-mux-mlxcpld.c
|
||||
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
|
||||
+ * Copyright (c) 2016 Michael Shych <michaels@mellanox.com>
|
||||
+ *
|
||||
+ * 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 <linux/device.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/i2c-mux.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/i2c/mlxcpld.h>
|
||||
+
|
||||
+#define CPLD_MUX_MAX_NCHANS 8
|
||||
+
|
||||
+/* mlxcpld_mux - mux control structure:
|
||||
+ * @last_chan - last register value
|
||||
+ * @client - I2C device client
|
||||
+ */
|
||||
+struct mlxcpld_mux {
|
||||
+ u8 last_chan;
|
||||
+ struct i2c_client *client;
|
||||
+};
|
||||
+
|
||||
+/* MUX logic description.
|
||||
+ * Driver can support different mux control logic, according to CPLD
|
||||
+ * implementation.
|
||||
+ *
|
||||
+ * Connectivity schema.
|
||||
+ *
|
||||
+ * i2c-mlxcpld Digital Analog
|
||||
+ * driver
|
||||
+ * *--------* * -> mux1 (virt bus2) -> mux -> |
|
||||
+ * | I2CLPC | i2c physical * -> mux2 (virt bus3) -> mux -> |
|
||||
+ * | bridge | bus 1 *---------* |
|
||||
+ * | logic |---------------------> * mux reg * |
|
||||
+ * | in CPLD| *---------* |
|
||||
+ * *--------* i2c-mux-mlxpcld ^ * -> muxn (virt busn) -> mux -> |
|
||||
+ * | driver | |
|
||||
+ * | *---------------* | Devices
|
||||
+ * | * CPLD (i2c bus)* select |
|
||||
+ * | * registers for *--------*
|
||||
+ * | * mux selection * deselect
|
||||
+ * | *---------------*
|
||||
+ * | |
|
||||
+ * <--------> <----------->
|
||||
+ * i2c cntrl Board cntrl reg
|
||||
+ * reg space space (mux select,
|
||||
+ * IO, LED, WD, info)
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+static const struct i2c_device_id mlxcpld_mux_id[] = {
|
||||
+ { "mlxcpld_mux_module", 0 },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(i2c, mlxcpld_mux_id);
|
||||
+
|
||||
+/* Write to mux register. Don't use i2c_transfer() and i2c_smbus_xfer()
|
||||
+ * for this as they will try to lock adapter a second time.
|
||||
+ */
|
||||
+static int mlxcpld_mux_reg_write(struct i2c_adapter *adap,
|
||||
+ struct i2c_client *client, u8 val)
|
||||
+{
|
||||
+ struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev);
|
||||
+ int ret = -ENODEV;
|
||||
+
|
||||
+ if (adap->algo->master_xfer) {
|
||||
+ struct i2c_msg msg;
|
||||
+ u8 msgbuf[] = {pdata->sel_reg_addr, val};
|
||||
+
|
||||
+ msg.addr = client->addr;
|
||||
+ msg.flags = 0;
|
||||
+ msg.len = 2;
|
||||
+ msg.buf = msgbuf;
|
||||
+ ret = __i2c_transfer(adap, &msg, 1);
|
||||
+
|
||||
+ if (ret >= 0 && ret != 1)
|
||||
+ ret = -EREMOTEIO;
|
||||
+ } else if (adap->algo->smbus_xfer) {
|
||||
+ union i2c_smbus_data data;
|
||||
+
|
||||
+ data.byte = val;
|
||||
+ ret = adap->algo->smbus_xfer(adap, client->addr,
|
||||
+ client->flags, I2C_SMBUS_WRITE,
|
||||
+ pdata->sel_reg_addr,
|
||||
+ I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
|
||||
+{
|
||||
+ struct mlxcpld_mux *data = i2c_mux_priv(muxc);
|
||||
+ struct i2c_client *client = data->client;
|
||||
+ u8 regval = chan + 1;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ /* Only select the channel if its different from the last channel */
|
||||
+ if (data->last_chan != regval) {
|
||||
+ err = mlxcpld_mux_reg_write(muxc->parent, client, regval);
|
||||
+ data->last_chan = err < 0 ? 0 : regval;
|
||||
+ }
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int mlxcpld_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
|
||||
+{
|
||||
+ struct mlxcpld_mux *data = i2c_mux_priv(muxc);
|
||||
+ struct i2c_client *client = data->client;
|
||||
+
|
||||
+ /* Deselect active channel */
|
||||
+ data->last_chan = 0;
|
||||
+
|
||||
+ return mlxcpld_mux_reg_write(muxc->parent, client, data->last_chan);
|
||||
+}
|
||||
+
|
||||
+/* Probe/reomove functions */
|
||||
+static int mlxcpld_mux_probe(struct i2c_client *client,
|
||||
+ const struct i2c_device_id *id)
|
||||
+{
|
||||
+ struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
+ struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev);
|
||||
+ struct i2c_mux_core *muxc;
|
||||
+ int num, force;
|
||||
+ struct mlxcpld_mux *data;
|
||||
+ int err;
|
||||
+
|
||||
+ if (!pdata)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ muxc = i2c_mux_alloc(adap, &client->dev, CPLD_MUX_MAX_NCHANS,
|
||||
+ sizeof(*data), 0, mlxcpld_mux_select_chan,
|
||||
+ mlxcpld_mux_deselect);
|
||||
+ if (!muxc)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ data = i2c_mux_priv(muxc);
|
||||
+ i2c_set_clientdata(client, muxc);
|
||||
+ data->client = client;
|
||||
+ data->last_chan = 0; /* force the first selection */
|
||||
+
|
||||
+ /* Create an adapter for each channel. */
|
||||
+ for (num = 0; num < CPLD_MUX_MAX_NCHANS; num++) {
|
||||
+ if (num >= pdata->num_adaps)
|
||||
+ /* discard unconfigured channels */
|
||||
+ break;
|
||||
+
|
||||
+ force = pdata->adap_ids[num];
|
||||
+
|
||||
+ err = i2c_mux_add_adapter(muxc, force, num, 0);
|
||||
+ if (err)
|
||||
+ goto virt_reg_failed;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+virt_reg_failed:
|
||||
+ i2c_mux_del_adapters(muxc);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int mlxcpld_mux_remove(struct i2c_client *client)
|
||||
+{
|
||||
+ struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
+
|
||||
+ i2c_mux_del_adapters(muxc);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct i2c_driver mlxcpld_mux_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "mlxcpld-mux",
|
||||
+ },
|
||||
+ .probe = mlxcpld_mux_probe,
|
||||
+ .remove = mlxcpld_mux_remove,
|
||||
+ .id_table = mlxcpld_mux_id,
|
||||
+};
|
||||
+
|
||||
+module_i2c_driver(mlxcpld_mux_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Michael Shych (michaels@mellanox.com)");
|
||||
+MODULE_DESCRIPTION("Mellanox I2C-CPLD-MUX driver");
|
||||
+MODULE_LICENSE("Dual BSD/GPL");
|
||||
+MODULE_ALIAS("platform:i2c-mux-mlxcpld");
|
||||
diff -Nur a/include/linux/i2c/mlxcpld.h b/include/linux/i2c/mlxcpld.h
|
||||
--- a/include/linux/i2c/mlxcpld.h 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ b/include/linux/i2c/mlxcpld.h 2017-11-12 08:17:03.032046568 +0000
|
||||
@@ -0,0 +1,52 @@
|
||||
+/*
|
||||
+ * mlxcpld.h - Mellanox I2C multiplexer support in CPLD
|
||||
+ *
|
||||
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
|
||||
+ * Copyright (c) 2016 Michael Shych <michaels@mellanox.com>
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions are met:
|
||||
+ *
|
||||
+ * 1. Redistributions of source code must retain the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer.
|
||||
+ * 2. Redistributions in binary form must reproduce the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer in the
|
||||
+ * documentation and/or other materials provided with the distribution.
|
||||
+ * 3. Neither the names of the copyright holders nor the names of its
|
||||
+ * contributors may be used to endorse or promote products derived from
|
||||
+ * this software without specific prior written permission.
|
||||
+ *
|
||||
+ * Alternatively, this software may be distributed under the terms of the
|
||||
+ * GNU General Public License ("GPL") version 2 as published by the Free
|
||||
+ * Software Foundation.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
+ * POSSIBILITY OF SUCH DAMAGE.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _LINUX_I2C_MLXCPLD_H
|
||||
+#define _LINUX_I2C_MLXCPLD_H
|
||||
+
|
||||
+/* Platform data for the CPLD I2C multiplexers */
|
||||
+
|
||||
+/* mlxcpld_mux_plat_data - per mux data, used with i2c_register_board_info
|
||||
+ * @adap_ids - adapter array
|
||||
+ * @num_adaps - number of adapters
|
||||
+ * @sel_reg_addr - mux select register offset in CPLD space
|
||||
+ */
|
||||
+struct mlxcpld_mux_plat_data {
|
||||
+ int *adap_ids;
|
||||
+ int num_adaps;
|
||||
+ int sel_reg_addr;
|
||||
+};
|
||||
+
|
||||
+#endif /* _LINUX_I2C_MLXCPLD_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,905 @@
|
||||
Linux backport patch. Includes following commits:
|
||||
2926024b5081fc8d4b086677bafa1ac55ea0b911
|
||||
6124fdf76488681713f278f3fdf2ba2dfe760211
|
||||
c84002d15210ca130263e23911cc399202124eb4
|
||||
07b89c2b2a5e8ce30166b96f87b324c6b419f108
|
||||
91973760712f350048a0fa8e0363e260bf874313
|
||||
c2e714e56360e34f88e0a75ee74e467d8b82de75
|
||||
af4779be0f2cec63f4cb15d3db78c5de3523756a
|
||||
d53bc5dc941653f0ed93b11a647bd6ff40f40ef2
|
||||
|
||||
|
||||
diff -Nur a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig
|
||||
--- a/drivers/platform/mellanox/Kconfig 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ b/drivers/platform/mellanox/Kconfig 2017-11-12 08:54:58.200076777 +0000
|
||||
@@ -0,0 +1,25 @@
|
||||
+#
|
||||
+# Platform support for Mellanox hardware
|
||||
+#
|
||||
+
|
||||
+menuconfig MELLANOX_PLATFORM
|
||||
+ bool "Platform support for Mellanox hardware"
|
||||
+ depends on X86 || ARM || COMPILE_TEST
|
||||
+ ---help---
|
||||
+ Say Y here to get to see options for platform support for
|
||||
+ Mellanox systems. This option alone does not add any kernel code.
|
||||
+
|
||||
+ If you say N, all options in this submenu will be skipped and disabled.
|
||||
+
|
||||
+if MELLANOX_PLATFORM
|
||||
+
|
||||
+config MLXREG_HOTPLUG
|
||||
+ tristate "Mellanox platform hotplug driver support"
|
||||
+ depends on REGMAP
|
||||
+ depends on HWMON
|
||||
+ depends on I2C
|
||||
+ ---help---
|
||||
+ This driver handles hot-plug events for the power suppliers, power
|
||||
+ cables and fans on the wide range Mellanox IB and Ethernet systems.
|
||||
+
|
||||
+endif # MELLANOX_PLATFORM
|
||||
diff -Nur a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile
|
||||
--- a/drivers/platform/mellanox/Makefile 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ b/drivers/platform/mellanox/Makefile 2017-11-12 08:54:58.200076777 +0000
|
||||
@@ -0,0 +1 @@
|
||||
+obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
|
||||
diff -Nur a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
|
||||
--- a/drivers/platform/mellanox/mlxreg-hotplug.c 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c 2017-11-12 08:54:58.200076777 +0000
|
||||
@@ -0,0 +1,710 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
|
||||
+ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
|
||||
+ *
|
||||
+ * 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 <linux/bitops.h>
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/hwmon.h>
|
||||
+#include <linux/hwmon-sysfs.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of_device.h>
|
||||
+#include <linux/platform_data/mlxreg.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+
|
||||
+/* Offset of event and mask registers from status register. */
|
||||
+#define MLXREG_HOTPLUG_EVENT_OFF 1
|
||||
+#define MLXREG_HOTPLUG_MASK_OFF 2
|
||||
+#define MLXREG_HOTPLUG_AGGR_MASK_OFF 1
|
||||
+
|
||||
+/* ASIC health parameters. */
|
||||
+#define MLXREG_HOTPLUG_HEALTH_MASK 0x02
|
||||
+#define MLXREG_HOTPLUG_RST_CNTR 3
|
||||
+
|
||||
+#define MLXREG_HOTPLUG_PROP_OKAY "okay"
|
||||
+#define MLXREG_HOTPLUG_PROP_DISABLED "disabled"
|
||||
+#define MLXREG_HOTPLUG_PROP_STATUS "status"
|
||||
+
|
||||
+#define MLXREG_HOTPLUG_ATTRS_MAX 24
|
||||
+
|
||||
+/**
|
||||
+ * struct mlxreg_hotplug_priv_data - platform private data:
|
||||
+ * @irq: platform device interrupt number;
|
||||
+ * @pdev: platform device;
|
||||
+ * @plat: platform data;
|
||||
+ * @dwork: delayed work template;
|
||||
+ * @lock: spin lock;
|
||||
+ * @hwmon: hwmon device;
|
||||
+ * @mlxreg_hotplug_attr: sysfs attributes array;
|
||||
+ * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array;
|
||||
+ * @group: sysfs attribute group;
|
||||
+ * @groups: list of sysfs attribute group for hwmon registration;
|
||||
+ * @cell: location of top aggregation interrupt register;
|
||||
+ * @mask: top aggregation interrupt common mask;
|
||||
+ * @aggr_cache: last value of aggregation register status;
|
||||
+ */
|
||||
+struct mlxreg_hotplug_priv_data {
|
||||
+ int irq;
|
||||
+ struct device *dev;
|
||||
+ struct platform_device *pdev;
|
||||
+ struct mlxreg_hotplug_platform_data *plat;
|
||||
+ struct regmap *regmap;
|
||||
+ struct delayed_work dwork_irq;
|
||||
+ struct delayed_work dwork;
|
||||
+ spinlock_t lock; /* sync with interrupt */
|
||||
+ struct device *hwmon;
|
||||
+ struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
|
||||
+ struct sensor_device_attribute_2
|
||||
+ mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
|
||||
+ struct attribute_group group;
|
||||
+ const struct attribute_group *groups[2];
|
||||
+ u32 cell;
|
||||
+ u32 mask;
|
||||
+ u32 aggr_cache;
|
||||
+ bool after_probe;
|
||||
+};
|
||||
+
|
||||
+#if defined(CONFIG_OF_DYNAMIC)
|
||||
+/**
|
||||
+ * struct mlxreg_hotplug_device_en - Open Firmware property for enabling device
|
||||
+ *
|
||||
+ * @name - property name;
|
||||
+ * @value - property value string;
|
||||
+ * @length - length of proprty value string;
|
||||
+ *
|
||||
+ * The structure is used for the devices, which require some dynamic
|
||||
+ * selection operation allowing access to them.
|
||||
+ */
|
||||
+static struct property mlxreg_hotplug_device_en = {
|
||||
+ .name = MLXREG_HOTPLUG_PROP_STATUS,
|
||||
+ .value = MLXREG_HOTPLUG_PROP_OKAY,
|
||||
+ .length = sizeof(MLXREG_HOTPLUG_PROP_OKAY),
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * struct mlxreg_hotplug_device_dis - Open Firmware property for disabling
|
||||
+ * device
|
||||
+ *
|
||||
+ * @name - property name;
|
||||
+ * @value - property value string;
|
||||
+ * @length - length of proprty value string;
|
||||
+ *
|
||||
+ * The structure is used for the devices, which require some dynamic
|
||||
+ * selection operation disallowing access to them.
|
||||
+ */
|
||||
+static struct property mlxreg_hotplug_device_dis = {
|
||||
+ .name = MLXREG_HOTPLUG_PROP_STATUS,
|
||||
+ .value = MLXREG_HOTPLUG_PROP_DISABLED,
|
||||
+ .length = sizeof(MLXREG_HOTPLUG_PROP_DISABLED),
|
||||
+};
|
||||
+
|
||||
+static int mlxreg_hotplug_of_device_create(struct mlxreg_core_data *data)
|
||||
+{
|
||||
+ return of_update_property(data->np, &mlxreg_hotplug_device_en);
|
||||
+}
|
||||
+
|
||||
+static void mlxreg_hotplug_of_device_destroy(struct mlxreg_core_data *data)
|
||||
+{
|
||||
+ of_update_property(data->np, &mlxreg_hotplug_device_dis);
|
||||
+ of_node_clear_flag(data->np, OF_POPULATED);
|
||||
+}
|
||||
+#else
|
||||
+static int mlxreg_hotplug_of_device_create(struct mlxreg_core_data *data)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void mlxreg_hotplug_of_device_destroy(struct mlxreg_core_data *data)
|
||||
+{
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static int mlxreg_hotplug_device_create(struct mlxreg_core_data *data)
|
||||
+{
|
||||
+ data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
|
||||
+ if (!data->hpdev.adapter)
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ data->hpdev.client = i2c_new_device(data->hpdev.adapter,
|
||||
+ data->hpdev.brdinfo);
|
||||
+ if (!data->hpdev.client) {
|
||||
+ i2c_put_adapter(data->hpdev.adapter);
|
||||
+ data->hpdev.adapter = NULL;
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data)
|
||||
+{
|
||||
+ if (data->hpdev.client) {
|
||||
+ i2c_unregister_device(data->hpdev.client);
|
||||
+ data->hpdev.client = NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (data->hpdev.adapter) {
|
||||
+ i2c_put_adapter(data->hpdev.adapter);
|
||||
+ data->hpdev.adapter = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int mlxreg_hotplug_dev_enable(struct mlxreg_core_data *data)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ /* Enable and create device. */
|
||||
+ if (data->np)
|
||||
+ err = mlxreg_hotplug_of_device_create(data);
|
||||
+ else
|
||||
+ err = mlxreg_hotplug_device_create(data);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static void mlxreg_hotplug_dev_disable(struct mlxreg_core_data *data)
|
||||
+{
|
||||
+ /* Disable and unregister platform device. */
|
||||
+ if (data->np)
|
||||
+ mlxreg_hotplug_of_device_destroy(data);
|
||||
+ else
|
||||
+ mlxreg_hotplug_device_destroy(data);
|
||||
+}
|
||||
+
|
||||
+static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
|
||||
+ struct device_attribute *attr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev);
|
||||
+ struct mlxreg_core_hotplug_platform_data *pdata;
|
||||
+ int index = to_sensor_dev_attr_2(attr)->index;
|
||||
+ int nr = to_sensor_dev_attr_2(attr)->nr;
|
||||
+ struct mlxreg_core_item *item;
|
||||
+ struct mlxreg_core_data *data;
|
||||
+ u32 regval;
|
||||
+ int ret;
|
||||
+
|
||||
+ pdata = dev_get_platdata(&priv->pdev->dev);
|
||||
+ item = pdata->items + nr;
|
||||
+ data = item->data + index;
|
||||
+
|
||||
+ ret = regmap_read(priv->regmap, data->reg, ®val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (item->health) {
|
||||
+ regval &= data->mask;
|
||||
+ } else {
|
||||
+ /* Bit = 0 : functional if item->inversed is true. */
|
||||
+ if (item->inversed)
|
||||
+ regval = !(regval & data->mask);
|
||||
+ else
|
||||
+ regval = !!(regval & data->mask);
|
||||
+ }
|
||||
+
|
||||
+ return sprintf(buf, "%u\n", regval);
|
||||
+}
|
||||
+
|
||||
+#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
|
||||
+#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
|
||||
+
|
||||
+static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
|
||||
+{
|
||||
+ struct mlxreg_core_hotplug_platform_data *pdata;
|
||||
+ struct mlxreg_core_item *item;
|
||||
+ struct mlxreg_core_data *data;
|
||||
+ int num_attrs = 0, id = 0, i, j;
|
||||
+
|
||||
+ pdata = dev_get_platdata(&priv->pdev->dev);
|
||||
+ item = pdata->items;
|
||||
+
|
||||
+ /* Go over all kinds of items - psu, pwr, fan. */
|
||||
+ for (i = 0; i < pdata->counter; i++, item++) {
|
||||
+ num_attrs += item->count;
|
||||
+ data = item->data;
|
||||
+ /* Go over all units within the item. */
|
||||
+ for (j = 0; j < item->count; j++, data++, id++) {
|
||||
+ PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
|
||||
+ PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
|
||||
+ GFP_KERNEL,
|
||||
+ data->label);
|
||||
+
|
||||
+ if (!PRIV_ATTR(id)->name) {
|
||||
+ dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
|
||||
+ id);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ PRIV_DEV_ATTR(id).dev_attr.attr.name =
|
||||
+ PRIV_ATTR(id)->name;
|
||||
+ PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444;
|
||||
+ PRIV_DEV_ATTR(id).dev_attr.show =
|
||||
+ mlxreg_hotplug_attr_show;
|
||||
+ PRIV_DEV_ATTR(id).nr = i;
|
||||
+ PRIV_DEV_ATTR(id).index = j;
|
||||
+ sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs *
|
||||
+ sizeof(struct attribute *),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!priv->group.attrs)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ priv->group.attrs = priv->mlxreg_hotplug_attr;
|
||||
+ priv->groups[0] = &priv->group;
|
||||
+ priv->groups[1] = NULL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
|
||||
+ struct mlxreg_core_item *item)
|
||||
+{
|
||||
+ struct mlxreg_core_data *data;
|
||||
+ u32 asserted, regval, bit;
|
||||
+ int ret;
|
||||
+
|
||||
+ /*
|
||||
+ * Validate if item related to received signal type is valid.
|
||||
+ * It should never happen, excepted the situation when some
|
||||
+ * piece of hardware is broken. In such situation just produce
|
||||
+ * error message and return. Caller must continue to handle the
|
||||
+ * signals from other devices if any.
|
||||
+ */
|
||||
+ if (unlikely(!item)) {
|
||||
+ dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n",
|
||||
+ item->reg, item->mask);
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Mask event. */
|
||||
+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
|
||||
+ 0);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ /* Read status. */
|
||||
+ ret = regmap_read(priv->regmap, item->reg, ®val);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ /* Set asserted bits and save last status. */
|
||||
+ regval &= item->mask;
|
||||
+ asserted = item->cache ^ regval;
|
||||
+ item->cache = regval;
|
||||
+
|
||||
+ for_each_set_bit(bit, (unsigned long *)&asserted, 8) {
|
||||
+ data = item->data + bit;
|
||||
+ if (regval & BIT(bit)) {
|
||||
+ if (item->inversed)
|
||||
+ mlxreg_hotplug_dev_disable(data);
|
||||
+ else
|
||||
+ mlxreg_hotplug_dev_enable(data);
|
||||
+ } else {
|
||||
+ if (item->inversed)
|
||||
+ mlxreg_hotplug_dev_enable(data);
|
||||
+ else
|
||||
+ mlxreg_hotplug_dev_disable(data);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Acknowledge event. */
|
||||
+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF,
|
||||
+ 0);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ /* Unmask event. */
|
||||
+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
|
||||
+ item->mask);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+access_error:
|
||||
+ dev_err(priv->dev, "Failed to complete workqueue.\n");
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
|
||||
+ struct mlxreg_core_item *item)
|
||||
+{
|
||||
+ struct mlxreg_core_data *data = item->data;
|
||||
+ u32 regval;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ for (i = 0; i < item->count; i++, data++) {
|
||||
+ /* Mask event. */
|
||||
+ ret = regmap_write(priv->regmap, data->reg +
|
||||
+ MLXREG_HOTPLUG_MASK_OFF, 0);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ /* Read status. */
|
||||
+ ret = regmap_read(priv->regmap, data->reg, ®val);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ regval &= data->mask;
|
||||
+ item->cache = regval;
|
||||
+ if (regval == MLXREG_HOTPLUG_HEALTH_MASK) {
|
||||
+ if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) ||
|
||||
+ !priv->after_probe) {
|
||||
+ mlxreg_hotplug_dev_enable(data);
|
||||
+ data->attached = true;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (data->attached) {
|
||||
+ mlxreg_hotplug_dev_disable(data);
|
||||
+ data->attached = false;
|
||||
+ data->health_cntr = 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Acknowledge event. */
|
||||
+ ret = regmap_write(priv->regmap, data->reg +
|
||||
+ MLXREG_HOTPLUG_EVENT_OFF, 0);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ /* Unmask event. */
|
||||
+ ret = regmap_write(priv->regmap, data->reg +
|
||||
+ MLXREG_HOTPLUG_MASK_OFF, data->mask);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+ }
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+access_error:
|
||||
+ dev_err(priv->dev, "Failed to complete workqueue.\n");
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * mlxreg_hotplug_work_handler - performs traversing of device interrupt
|
||||
+ * registers according to the below hierarchy schema:
|
||||
+ *
|
||||
+ * Aggregation registers (status/mask)
|
||||
+ * PSU registers: *---*
|
||||
+ * *-----------------* | |
|
||||
+ * |status/event/mask|-----> | * |
|
||||
+ * *-----------------* | |
|
||||
+ * Power registers: | |
|
||||
+ * *-----------------* | |
|
||||
+ * |status/event/mask|-----> | * |
|
||||
+ * *-----------------* | |
|
||||
+ * FAN registers: | |--> CPU
|
||||
+ * *-----------------* | |
|
||||
+ * |status/event/mask|-----> | * |
|
||||
+ * *-----------------* | |
|
||||
+ * ASIC registers: | |
|
||||
+ * *-----------------* | |
|
||||
+ * |status/event/mask|-----> | * |
|
||||
+ * *-----------------* | |
|
||||
+ * *---*
|
||||
+ *
|
||||
+ * In case some system changed are detected: FAN in/out, PSU in/out, power
|
||||
+ * cable attached/detached, ASIC helath good/bad, relevant device is created
|
||||
+ * or destroyed.
|
||||
+ */
|
||||
+static void mlxreg_hotplug_work_handler(struct work_struct *work)
|
||||
+{
|
||||
+ struct mlxreg_hotplug_priv_data *priv = container_of(work,
|
||||
+ struct mlxreg_hotplug_priv_data, dwork_irq.work);
|
||||
+ struct mlxreg_core_hotplug_platform_data *pdata;
|
||||
+ struct mlxreg_core_item *item;
|
||||
+ unsigned long flags;
|
||||
+ u32 regval, aggr_asserted;
|
||||
+ int i;
|
||||
+ int ret;
|
||||
+
|
||||
+ pdata = dev_get_platdata(&priv->pdev->dev);
|
||||
+ item = pdata->items;
|
||||
+ /* Mask aggregation event. */
|
||||
+ ret = regmap_write(priv->regmap, pdata->cell +
|
||||
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
|
||||
+ if (ret < 0)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ /* Read aggregation status. */
|
||||
+ ret = regmap_read(priv->regmap, pdata->cell, ®val);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ regval &= pdata->mask;
|
||||
+ aggr_asserted = priv->aggr_cache ^ regval;
|
||||
+ priv->aggr_cache = regval;
|
||||
+
|
||||
+ /* Handle topology and health configuration changes. */
|
||||
+ for (i = 0; i < pdata->counter; i++, item++) {
|
||||
+ if (aggr_asserted & item->aggr_mask) {
|
||||
+ if (item->health)
|
||||
+ mlxreg_hotplug_health_work_helper(priv, item);
|
||||
+ else
|
||||
+ mlxreg_hotplug_work_helper(priv, item);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (aggr_asserted) {
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+
|
||||
+ /*
|
||||
+ * It is possible, that some signals have been inserted, while
|
||||
+ * interrupt has been masked by mlxreg_hotplug_work_handler.
|
||||
+ * In this case such signals will be missed. In order to handle
|
||||
+ * these signals delayed work is canceled and work task
|
||||
+ * re-scheduled for immediate execution. It allows to handle
|
||||
+ * missed signals, if any. In other case work handler just
|
||||
+ * validates that no new signals have been received during
|
||||
+ * masking.
|
||||
+ */
|
||||
+ cancel_delayed_work(&priv->dwork_irq);
|
||||
+ schedule_delayed_work(&priv->dwork_irq, 0);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Unmask aggregation event (no need acknowledge). */
|
||||
+ ret = regmap_write(priv->regmap, pdata->cell +
|
||||
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+access_error:
|
||||
+ dev_err(priv->dev, "Failed to complete workqueue.\n");
|
||||
+}
|
||||
+
|
||||
+static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
|
||||
+{
|
||||
+ struct mlxreg_core_hotplug_platform_data *pdata;
|
||||
+ struct mlxreg_core_item *item;
|
||||
+ int i;
|
||||
+ int ret;
|
||||
+
|
||||
+ pdata = dev_get_platdata(&priv->pdev->dev);
|
||||
+ item = pdata->items;
|
||||
+
|
||||
+ for (i = 0; i < pdata->counter; i++, item++) {
|
||||
+ /* Clear group presense event. */
|
||||
+ ret = regmap_write(priv->regmap, item->reg +
|
||||
+ MLXREG_HOTPLUG_EVENT_OFF, 0);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ /* Set group initial status as mask and unmask group event. */
|
||||
+ if (item->inversed) {
|
||||
+ item->cache = item->mask;
|
||||
+ ret = regmap_write(priv->regmap, item->reg +
|
||||
+ MLXREG_HOTPLUG_MASK_OFF,
|
||||
+ item->mask);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Keep aggregation initial status as zero and unmask events. */
|
||||
+ ret = regmap_write(priv->regmap, pdata->cell +
|
||||
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ /* Keep low aggregation initial status as zero and unmask events. */
|
||||
+ ret = regmap_write(priv->regmap, pdata->cell_low +
|
||||
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask_low);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ /* Invoke work handler for initializing hot plug devices setting. */
|
||||
+ mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
|
||||
+
|
||||
+ enable_irq(priv->irq);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+access_error:
|
||||
+ dev_err(priv->dev, "Failed to set interrupts.\n");
|
||||
+
|
||||
+ enable_irq(priv->irq);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
|
||||
+{
|
||||
+ struct mlxreg_core_hotplug_platform_data *pdata;
|
||||
+ struct mlxreg_core_item *item;
|
||||
+ struct mlxreg_core_data *data;
|
||||
+ int count, i, j;
|
||||
+
|
||||
+ pdata = dev_get_platdata(&priv->pdev->dev);
|
||||
+ item = pdata->items;
|
||||
+ disable_irq(priv->irq);
|
||||
+ cancel_delayed_work_sync(&priv->dwork_irq);
|
||||
+
|
||||
+ /* Mask low aggregation event. */
|
||||
+ regmap_write(priv->regmap, pdata->cell_low +
|
||||
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
|
||||
+
|
||||
+ /* Mask aggregation event. */
|
||||
+ regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
|
||||
+ 0);
|
||||
+
|
||||
+ /* Clear topology configurations. */
|
||||
+ for (i = 0; i < pdata->counter; i++, item++) {
|
||||
+ data = item->data;
|
||||
+ /* Mask group presense event. */
|
||||
+ regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
|
||||
+ 0);
|
||||
+ /* Clear group presense event. */
|
||||
+ regmap_write(priv->regmap, data->reg +
|
||||
+ MLXREG_HOTPLUG_EVENT_OFF, 0);
|
||||
+
|
||||
+ /* Remove all the attached devices in group. */
|
||||
+ count = item->count;
|
||||
+ for (j = 0; j < count; j++, data++)
|
||||
+ mlxreg_hotplug_dev_disable(data);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
|
||||
+{
|
||||
+ struct mlxreg_hotplug_priv_data *priv =
|
||||
+ (struct mlxreg_hotplug_priv_data *)dev;
|
||||
+
|
||||
+ /* Schedule work task for immediate execution.*/
|
||||
+ schedule_delayed_work(&priv->dwork_irq, 0);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static int mlxreg_hotplug_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct mlxreg_core_hotplug_platform_data *pdata;
|
||||
+ struct mlxreg_hotplug_priv_data *priv;
|
||||
+ int err;
|
||||
+
|
||||
+ pdata = dev_get_platdata(&pdev->dev);
|
||||
+ if (!pdata) {
|
||||
+ dev_err(&pdev->dev, "Failed to get platform data.\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ if (pdata->irq) {
|
||||
+ priv->irq = pdata->irq;
|
||||
+ } else {
|
||||
+ priv->irq = platform_get_irq(pdev, 0);
|
||||
+ if (priv->irq < 0) {
|
||||
+ dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
|
||||
+ priv->irq);
|
||||
+ return priv->irq;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ priv->regmap = pdata->regmap;
|
||||
+ priv->dev = pdev->dev.parent;
|
||||
+ priv->pdev = pdev;
|
||||
+
|
||||
+ err = devm_request_irq(&pdev->dev, priv->irq,
|
||||
+ mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
|
||||
+ | IRQF_SHARED, "mlxreg-hotplug", priv);
|
||||
+ if (err) {
|
||||
+ dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ disable_irq(priv->irq);
|
||||
+ spin_lock_init(&priv->lock);
|
||||
+ INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
|
||||
+ /* Perform initial interrupts setup. */
|
||||
+ mlxreg_hotplug_set_irq(priv);
|
||||
+
|
||||
+ priv->after_probe = true;
|
||||
+ dev_set_drvdata(&pdev->dev, priv);
|
||||
+
|
||||
+ err = mlxreg_hotplug_attr_init(priv);
|
||||
+ if (err) {
|
||||
+ dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
|
||||
+ err);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
|
||||
+ "mlxreg_hotplug", priv, priv->groups);
|
||||
+ if (IS_ERR(priv->hwmon)) {
|
||||
+ dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
|
||||
+ PTR_ERR(priv->hwmon));
|
||||
+ return PTR_ERR(priv->hwmon);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int mlxreg_hotplug_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
|
||||
+
|
||||
+ /* Clean interrupts setup. */
|
||||
+ mlxreg_hotplug_unset_irq(priv);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver mlxreg_hotplug_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "mlxreg-hotplug",
|
||||
+ },
|
||||
+ .probe = mlxreg_hotplug_probe,
|
||||
+ .remove = mlxreg_hotplug_remove,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(mlxreg_hotplug_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
|
||||
+MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver");
|
||||
+MODULE_LICENSE("Dual BSD/GPL");
|
||||
+MODULE_ALIAS("platform:mlxreg-hotplug");
|
||||
diff -Nur a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h
|
||||
--- a/include/linux/platform_data/mlxreg.h 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ b/include/linux/platform_data/mlxreg.h 2017-11-12 09:04:09.796084101 +0000
|
||||
@@ -0,0 +1,142 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
|
||||
+ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions are met:
|
||||
+ *
|
||||
+ * 1. Redistributions of source code must retain the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer.
|
||||
+ * 2. Redistributions in binary form must reproduce the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer in the
|
||||
+ * documentation and/or other materials provided with the distribution.
|
||||
+ * 3. Neither the names of the copyright holders nor the names of its
|
||||
+ * contributors may be used to endorse or promote products derived from
|
||||
+ * this software without specific prior written permission.
|
||||
+ *
|
||||
+ * Alternatively, this software may be distributed under the terms of the
|
||||
+ * GNU General Public License ("GPL") version 2 as published by the Free
|
||||
+ * Software Foundation.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
+ * POSSIBILITY OF SUCH DAMAGE.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __LINUX_PLATFORM_DATA_MLXREG_H
|
||||
+#define __LINUX_PLATFORM_DATA_MLXREG_H
|
||||
+
|
||||
+#define MLXREG_CORE_LABEL_MAX_SIZE 32
|
||||
+
|
||||
+/**
|
||||
+ * struct mlxreg_hotplug_device - I2C device data:
|
||||
+ *
|
||||
+ * @adapter: I2C device adapter;
|
||||
+ * @client: I2C device client;
|
||||
+ * @brdinfo: device board information;
|
||||
+ * @nr: I2C device adapter number, to which device is to be attached;
|
||||
+ *
|
||||
+ * Structure represents I2C hotplug device static data (board topology) and
|
||||
+ * dynamic data (related kernel objects handles).
|
||||
+ */
|
||||
+struct mlxreg_hotplug_device {
|
||||
+ struct i2c_adapter *adapter;
|
||||
+ struct i2c_client *client;
|
||||
+ struct i2c_board_info *brdinfo;
|
||||
+ int nr;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * struct mlxreg_core_data - attributes control data:
|
||||
+ *
|
||||
+ * @label: attribute label;
|
||||
+ * @label: attribute register offset;
|
||||
+ * @reg: attribute register;
|
||||
+ * @mask: attribute access mask;
|
||||
+ * @bit: attribute effective bit;
|
||||
+ * @np - pointer to node platform associated with attribute;
|
||||
+ * @hpdev - hotplug device data;
|
||||
+ * @health_cntr: dynamic device health indication counter;
|
||||
+ * @attached: true if device has been attached after good helath indication;
|
||||
+ */
|
||||
+struct mlxreg_core_data {
|
||||
+ char label[MLXREG_CORE_LABEL_MAX_SIZE];
|
||||
+ u32 reg;
|
||||
+ u32 mask;
|
||||
+ u32 bit;
|
||||
+ struct device_node *np;
|
||||
+ struct mlxreg_hotplug_device hpdev;
|
||||
+ u8 health_cntr;
|
||||
+ bool attached;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * struct mlxreg_core_item - same type components controlled by the driver:
|
||||
+ *
|
||||
+ * @data: component data;
|
||||
+ * @aggr_mask: group aggregation mask;
|
||||
+ * @reg: group interrupt status register;
|
||||
+ * @mask: group interrupt mask;
|
||||
+ * @cache: last status value for elements fro the same group;
|
||||
+ * @count: number of available elements in the group;
|
||||
+ * @ind: element's index inside the group;
|
||||
+ * @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK;
|
||||
+ * @health: true if device has health indication, false in other case;
|
||||
+ */
|
||||
+struct mlxreg_core_item {
|
||||
+ struct mlxreg_core_data *data;
|
||||
+ u32 aggr_mask;
|
||||
+ u32 reg;
|
||||
+ u32 mask;
|
||||
+ u32 cache;
|
||||
+ u8 count;
|
||||
+ u8 ind;
|
||||
+ u8 inversed;
|
||||
+ u8 health;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * struct mlxreg_core_led_platform_data - led platform data:
|
||||
+ *
|
||||
+ * @led_data: led private data;
|
||||
+ * @regmap: register map of parent device;
|
||||
+ * @counter: number of led instances;
|
||||
+ */
|
||||
+struct mlxreg_core_led_platform_data {
|
||||
+ struct mlxreg_core_data *data;
|
||||
+ void *regmap;
|
||||
+ int counter;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * struct mlxreg_core_hotplug_platform_data - hotplug platform data:
|
||||
+ *
|
||||
+ * @items: same type components with the hotplug capability;
|
||||
+ * @irq: platform interrupt number;
|
||||
+ * @regmap: register map of parent device;
|
||||
+ * @counter: number of the components with the hotplug capability;
|
||||
+ * @cell: location of top aggregation interrupt register;
|
||||
+ * @mask: top aggregation interrupt common mask;
|
||||
+ * @cell_low: location of low aggregation interrupt register;
|
||||
+ * @mask_low: low aggregation interrupt common mask;
|
||||
+ */
|
||||
+struct mlxreg_core_hotplug_platform_data {
|
||||
+ struct mlxreg_core_item *items;
|
||||
+ int irq;
|
||||
+ void *regmap;
|
||||
+ int counter;
|
||||
+ u32 cell;
|
||||
+ u32 mask;
|
||||
+ u32 cell_low;
|
||||
+ u32 mask_low;
|
||||
+};
|
||||
+
|
||||
+#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */
|
||||
@@ -0,0 +1,398 @@
|
||||
Linux backport patch. Includes following commits:
|
||||
7dc37aeb560416771cbdc286357157c7565dc1fe
|
||||
9244ef4cb79a8411656cb8fc2366f32f2294a0c9
|
||||
daf155fe70c9d69c28bba632b6a758ac8feab6e7
|
||||
|
||||
|
||||
diff -Nur a/drivers/leds/Kconfig b/drivers/leds/Kconfig
|
||||
--- a/drivers/leds/Kconfig 2017-11-12 09:08:40.740087699 +0000
|
||||
+++ b/drivers/leds/Kconfig 2017-11-12 09:06:54.580086289 +0000
|
||||
@@ -659,6 +659,35 @@
|
||||
This option enabled support for the LEDs on the Mellanox
|
||||
boards. Say Y to enabled these.
|
||||
|
||||
+config LEDS_MLXREG
|
||||
+ tristate "LED support for the Mellanox BMC cards"
|
||||
+ depends on LEDS_CLASS
|
||||
+ help
|
||||
+ This option enabled support for the LEDs on the Mellanox BMC cards.
|
||||
+ The driver can be activated from the device tree or by the direct
|
||||
+ platform device add call. Say Y to enabled these. To compile this
|
||||
+ driver as a module, choose 'M' here: the module will be called
|
||||
+ leds-mlxreg.
|
||||
+
|
||||
+config LEDS_USER
|
||||
+ tristate "Userspace LED support"
|
||||
+ depends on LEDS_CLASS
|
||||
+ help
|
||||
+ This option enables support for userspace LEDs. Say 'y' to enable this
|
||||
+ support in kernel. To compile this driver as a module, choose 'm' here:
|
||||
+ the module will be called uleds.
|
||||
+
|
||||
+config LEDS_NIC78BX
|
||||
+ tristate "LED support for NI PXI NIC78bx devices"
|
||||
+ depends on LEDS_CLASS
|
||||
+ depends on X86 && ACPI
|
||||
+ help
|
||||
+ This option enables support for the User1 and User2 LEDs on NI
|
||||
+ PXI NIC78bx devices.
|
||||
+
|
||||
+ To compile this driver as a module, choose M here: the module
|
||||
+ will be called leds-nic78bx.
|
||||
+
|
||||
comment "LED Triggers"
|
||||
source "drivers/leds/trigger/Kconfig"
|
||||
|
||||
diff -Nur a/drivers/leds/Makefile b/drivers/leds/Makefile
|
||||
--- a/drivers/leds/Makefile 2017-11-12 09:08:40.740087699 +0000
|
||||
+++ b/drivers/leds/Makefile 2017-11-12 09:06:54.580086289 +0000
|
||||
@@ -71,6 +71,7 @@
|
||||
obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o
|
||||
obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o
|
||||
obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o
|
||||
+obj-$(CONFIG_LEDS_MLXREG) += leds-mlxreg.o
|
||||
|
||||
# LED SPI Drivers
|
||||
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
|
||||
diff -Nur a/drivers/leds/leds-mlxcpld.c b/drivers/leds/leds-mlxcpld.c
|
||||
--- a/drivers/leds/leds-mlxcpld.c 2017-11-12 09:08:40.740087699 +0000
|
||||
+++ b/drivers/leds/leds-mlxcpld.c 2017-11-12 09:08:05.620087233 +0000
|
||||
@@ -400,6 +400,9 @@
|
||||
struct platform_device *pdev;
|
||||
int err;
|
||||
|
||||
+ if (!dmi_match(DMI_CHASSIS_VENDOR, "Mellanox Technologies Ltd."))
|
||||
+ return -ENODEV;
|
||||
+
|
||||
pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
|
||||
if (IS_ERR(pdev)) {
|
||||
pr_err("Device allocation failed\n");
|
||||
@@ -426,5 +429,5 @@
|
||||
|
||||
MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
|
||||
MODULE_DESCRIPTION("Mellanox board LED driver");
|
||||
-MODULE_LICENSE("GPL v2");
|
||||
+MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_ALIAS("platform:leds_mlxcpld");
|
||||
diff -Nur a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c
|
||||
--- a/drivers/leds/leds-mlxreg.c 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ b/drivers/leds/leds-mlxreg.c 2017-11-12 09:06:54.580086289 +0000
|
||||
@@ -0,0 +1,318 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
|
||||
+ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
|
||||
+ *
|
||||
+ * 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 <linux/bitops.h>
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/leds.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of_device.h>
|
||||
+#include <linux/platform_data/mlxreg.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+/* Codes for LEDs. */
|
||||
+#define MLXREG_LED_OFFSET_BLINK_3HZ 0x01 /* Offset from solid: 3Hz blink */
|
||||
+#define MLXREG_LED_OFFSET_BLINK_6HZ 0x02 /* Offset from solid: 6Hz blink */
|
||||
+#define MLXREG_LED_IS_OFF 0x00 /* Off */
|
||||
+#define MLXREG_LED_RED_SOLID 0x05 /* Solid red */
|
||||
+#define MLXREG_LED_GREEN_SOLID 0x0D /* Solid green */
|
||||
+#define MLXREG_LED_AMBER_SOLID 0x09 /* Solid amber */
|
||||
+#define MLXREG_LED_BLINK_3HZ 167 /* ~167 msec off/on - HW support */
|
||||
+#define MLXREG_LED_BLINK_6HZ 83 /* ~83 msec off/on - HW support */
|
||||
+
|
||||
+/**
|
||||
+ * struct mlxreg_led_data - led control data:
|
||||
+ *
|
||||
+ * @data: led configuration data;
|
||||
+ * @led_classdev: led class data;
|
||||
+ * @base_color: base led color (other colors have constant offset from base);
|
||||
+ * @led_data: led data;
|
||||
+ * @data_parent: pointer to private device control data of parent;
|
||||
+ */
|
||||
+struct mlxreg_led_data {
|
||||
+ struct mlxreg_core_data *data;
|
||||
+ struct led_classdev led_cdev;
|
||||
+ u8 base_color;
|
||||
+ void *data_parent;
|
||||
+ char led_cdev_name[MLXREG_CORE_LABEL_MAX_SIZE];
|
||||
+};
|
||||
+
|
||||
+#define cdev_to_priv(c) container_of(c, struct mlxreg_led_data, led_cdev)
|
||||
+
|
||||
+/**
|
||||
+ * struct mlxreg_led_priv_data - platform private data:
|
||||
+ *
|
||||
+ * @pdev: platform device;
|
||||
+ * @pdata: platform data;
|
||||
+ * @access_lock: mutex for attribute IO access;
|
||||
+ */
|
||||
+struct mlxreg_led_priv_data {
|
||||
+ struct platform_device *pdev;
|
||||
+ struct mlxreg_core_led_platform_data *pdata;
|
||||
+ struct mutex access_lock; /* protect IO operations */
|
||||
+};
|
||||
+
|
||||
+static int
|
||||
+mlxreg_led_store_hw(struct mlxreg_led_data *led_data, u8 vset)
|
||||
+{
|
||||
+ struct mlxreg_led_priv_data *priv = led_data->data_parent;
|
||||
+ struct mlxreg_core_led_platform_data *led_pdata = priv->pdata;
|
||||
+ struct mlxreg_core_data *data = led_data->data;
|
||||
+ u32 regval;
|
||||
+ u32 nib;
|
||||
+ int ret;
|
||||
+
|
||||
+ /*
|
||||
+ * Each LED is controlled through low or high nibble of the relevant
|
||||
+ * register byte. Register offset is specified by off parameter.
|
||||
+ * Parameter vset provides color code: 0x0 for off, 0x5 for solid red,
|
||||
+ * 0x6 for 3Hz blink red, 0xd for solid green, 0xe for 3Hz blink
|
||||
+ * green.
|
||||
+ * Parameter mask specifies which nibble is used for specific LED: mask
|
||||
+ * 0xf0 - lower nibble is to be used (bits from 0 to 3), mask 0x0f -
|
||||
+ * higher nibble (bits from 4 to 7).
|
||||
+ */
|
||||
+ mutex_lock(&priv->access_lock);
|
||||
+
|
||||
+ ret = regmap_read(led_pdata->regmap, data->reg, ®val);
|
||||
+ if (ret)
|
||||
+ goto access_error;
|
||||
+
|
||||
+ nib = (ror32(data->mask, data->bit) == 0xf0) ? rol32(vset, data->bit) :
|
||||
+ rol32(vset, data->bit + 4);
|
||||
+ regval = (regval & data->mask) | nib;
|
||||
+
|
||||
+ ret = regmap_write(led_pdata->regmap, data->reg, regval);
|
||||
+
|
||||
+access_error:
|
||||
+ mutex_unlock(&priv->access_lock);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static enum led_brightness
|
||||
+mlxreg_led_get_hw(struct mlxreg_led_data *led_data)
|
||||
+{
|
||||
+ struct mlxreg_led_priv_data *priv = led_data->data_parent;
|
||||
+ struct mlxreg_core_led_platform_data *led_pdata = priv->pdata;
|
||||
+ struct mlxreg_core_data *data = led_data->data;
|
||||
+ u32 regval;
|
||||
+ int ret;
|
||||
+
|
||||
+ /*
|
||||
+ * Each LED is controlled through low or high nibble of the relevant
|
||||
+ * register byte. Register offset is specified by off parameter.
|
||||
+ * Parameter vset provides color code: 0x0 for off, 0x5 for solid red,
|
||||
+ * 0x6 for 3Hz blink red, 0xd for solid green, 0xe for 3Hz blink
|
||||
+ * green.
|
||||
+ * Parameter mask specifies which nibble is used for specific LED: mask
|
||||
+ * 0xf0 - lower nibble is to be used (bits from 0 to 3), mask 0x0f -
|
||||
+ * higher nibble (bits from 4 to 7).
|
||||
+ */
|
||||
+ ret = regmap_read(led_pdata->regmap, data->reg, ®val);
|
||||
+ if (ret < 0) {
|
||||
+ dev_warn(led_data->led_cdev.dev, "Failed to get current brightness, error: %d\n",
|
||||
+ ret);
|
||||
+ /* Assume the LED is OFF */
|
||||
+ return LED_OFF;
|
||||
+ }
|
||||
+
|
||||
+ regval = regval & ~data->mask;
|
||||
+ regval = (ror32(data->mask, data->bit) == 0xf0) ? ror32(regval,
|
||||
+ data->bit) : ror32(regval, data->bit + 4);
|
||||
+ if (regval >= led_data->base_color &&
|
||||
+ regval <= (led_data->base_color + MLXREG_LED_OFFSET_BLINK_6HZ))
|
||||
+ ret = LED_FULL;
|
||||
+ else
|
||||
+ ret = LED_OFF;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mlxreg_led_brightness_set(struct led_classdev *cled, enum led_brightness value)
|
||||
+{
|
||||
+ struct mlxreg_led_data *led_data = cdev_to_priv(cled);
|
||||
+
|
||||
+ if (value)
|
||||
+ return mlxreg_led_store_hw(led_data, led_data->base_color);
|
||||
+ else
|
||||
+ return mlxreg_led_store_hw(led_data, MLXREG_LED_IS_OFF);
|
||||
+}
|
||||
+
|
||||
+static enum led_brightness
|
||||
+mlxreg_led_brightness_get(struct led_classdev *cled)
|
||||
+{
|
||||
+ struct mlxreg_led_data *led_data = cdev_to_priv(cled);
|
||||
+
|
||||
+ return mlxreg_led_get_hw(led_data);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mlxreg_led_blink_set(struct led_classdev *cled, unsigned long *delay_on,
|
||||
+ unsigned long *delay_off)
|
||||
+{
|
||||
+ struct mlxreg_led_data *led_data = cdev_to_priv(cled);
|
||||
+ int err;
|
||||
+
|
||||
+ /*
|
||||
+ * HW supports two types of blinking: full (6Hz) and half (3Hz).
|
||||
+ * For delay on/off zero LED is setting to solid color. For others
|
||||
+ * combination blinking is to be controlled by the software timer.
|
||||
+ */
|
||||
+ if (!(*delay_on == 0 && *delay_off == 0) &&
|
||||
+ !(*delay_on == MLXREG_LED_BLINK_3HZ &&
|
||||
+ *delay_off == MLXREG_LED_BLINK_3HZ) &&
|
||||
+ !(*delay_on == MLXREG_LED_BLINK_6HZ &&
|
||||
+ *delay_off == MLXREG_LED_BLINK_6HZ))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (*delay_on == MLXREG_LED_BLINK_6HZ)
|
||||
+ err = mlxreg_led_store_hw(led_data, led_data->base_color +
|
||||
+ MLXREG_LED_OFFSET_BLINK_6HZ);
|
||||
+ else if (*delay_on == MLXREG_LED_BLINK_3HZ)
|
||||
+ err = mlxreg_led_store_hw(led_data, led_data->base_color +
|
||||
+ MLXREG_LED_OFFSET_BLINK_3HZ);
|
||||
+ else
|
||||
+ err = mlxreg_led_store_hw(led_data, led_data->base_color);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int mlxreg_led_config(struct mlxreg_led_priv_data *priv)
|
||||
+{
|
||||
+ struct mlxreg_core_led_platform_data *led_pdata = priv->pdata;
|
||||
+ struct mlxreg_core_data *data = led_pdata->data;
|
||||
+ struct mlxreg_led_data *led_data;
|
||||
+ struct led_classdev *led_cdev;
|
||||
+ int brightness;
|
||||
+ int i;
|
||||
+ int err;
|
||||
+
|
||||
+ for (i = 0; i < led_pdata->counter; i++, data++) {
|
||||
+ led_data = devm_kzalloc(&priv->pdev->dev, sizeof(*led_data),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!led_data)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ led_cdev = &led_data->led_cdev;
|
||||
+ led_data->data_parent = priv;
|
||||
+ if (strstr(data->label, "red") ||
|
||||
+ strstr(data->label, "orange")) {
|
||||
+ brightness = LED_OFF;
|
||||
+ led_data->base_color = MLXREG_LED_RED_SOLID;
|
||||
+ } else if (strstr(data->label, "amber")) {
|
||||
+ brightness = LED_OFF;
|
||||
+ led_data->base_color = MLXREG_LED_AMBER_SOLID;
|
||||
+ } else {
|
||||
+ brightness = LED_OFF;
|
||||
+ led_data->base_color = MLXREG_LED_GREEN_SOLID;
|
||||
+ }
|
||||
+ sprintf(led_data->led_cdev_name, "%s:%s", "mlxreg",
|
||||
+ data->label);
|
||||
+ led_cdev->name = led_data->led_cdev_name;
|
||||
+ led_cdev->brightness = brightness;
|
||||
+ led_cdev->max_brightness = 1;
|
||||
+ led_cdev->brightness_set_blocking =
|
||||
+ mlxreg_led_brightness_set;
|
||||
+ led_cdev->brightness_get = mlxreg_led_brightness_get;
|
||||
+ led_cdev->blink_set = mlxreg_led_blink_set;
|
||||
+ led_cdev->flags = LED_CORE_SUSPENDRESUME;
|
||||
+ led_data->data = data;
|
||||
+ err = devm_led_classdev_register(&priv->pdev->dev, led_cdev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (led_cdev->brightness)
|
||||
+ mlxreg_led_brightness_set(led_cdev,
|
||||
+ led_cdev->brightness);
|
||||
+ dev_info(led_cdev->dev, "label: %s, mask: 0x%02x, offset:0x%02x\n",
|
||||
+ data->label, data->mask, data->reg);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int mlxreg_led_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct mlxreg_core_led_platform_data *led_pdata;
|
||||
+ struct mlxreg_led_priv_data *priv;
|
||||
+
|
||||
+ led_pdata = dev_get_platdata(&pdev->dev);
|
||||
+ if (!led_pdata) {
|
||||
+ dev_err(&pdev->dev, "Failed to get platform data.\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ mutex_init(&priv->access_lock);
|
||||
+ priv->pdev = pdev;
|
||||
+ priv->pdata = led_pdata;
|
||||
+
|
||||
+ return mlxreg_led_config(priv);
|
||||
+}
|
||||
+
|
||||
+static int mlxreg_led_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct mlxreg_led_priv_data *priv = dev_get_drvdata(&pdev->dev);
|
||||
+
|
||||
+ mutex_destroy(&priv->access_lock);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id mlxreg_led_dt_match[] = {
|
||||
+ { .compatible = "mellanox,leds-mlxreg" },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, mlxreg_led_dt_match);
|
||||
+
|
||||
+static struct platform_driver mlxreg_led_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "leds-mlxreg",
|
||||
+ .of_match_table = of_match_ptr(mlxreg_led_dt_match),
|
||||
+ },
|
||||
+ .probe = mlxreg_led_probe,
|
||||
+ .remove = mlxreg_led_remove,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(mlxreg_led_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
|
||||
+MODULE_DESCRIPTION("Mellanox LED regmap driver");
|
||||
+MODULE_LICENSE("Dual BSD/GPL");
|
||||
+MODULE_ALIAS("platform:leds-mlxreg");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
Linux backport patch. Includes following commits:
|
||||
a4dffccb72a7fa46bb0d7f29e607375387e09956
|
||||
|
||||
|
||||
diff -Nur a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
|
||||
--- a/drivers/hwmon/pmbus/pmbus.h 2017-11-09 16:25:22.760993964 +0000
|
||||
+++ b/drivers/hwmon/pmbus/pmbus.h 2017-11-09 16:26:02.568994492 +0000
|
||||
@@ -341,7 +341,7 @@
|
||||
#define PMBUS_HAVE_STATUS_VMON BIT(19)
|
||||
|
||||
enum pmbus_data_format { linear = 0, direct, vid };
|
||||
-enum vrm_version { vr11 = 0, vr12 };
|
||||
+enum vrm_version { vr11 = 0, vr12, vr13 };
|
||||
|
||||
struct pmbus_driver_info {
|
||||
int pages; /* Total number of pages */
|
||||
diff -Nur a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
|
||||
--- a/drivers/hwmon/pmbus/pmbus_core.c 2017-11-09 16:25:22.760993964 +0000
|
||||
+++ b/drivers/hwmon/pmbus/pmbus_core.c 2017-11-09 16:26:02.568994492 +0000
|
||||
@@ -531,6 +531,10 @@
|
||||
if (val >= 0x01)
|
||||
rv = 250 + (val - 1) * 5;
|
||||
break;
|
||||
+ case vr13:
|
||||
+ if (val >= 0x01)
|
||||
+ rv = 500 + (val - 1) * 10;
|
||||
+ break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
Linux backport patch. Includes following commits:
|
||||
f7caf758e26ab84b2b9def9ec68235c85d645597
|
||||
|
||||
|
||||
diff -Nur a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
|
||||
--- a/drivers/hwmon/pmbus/Kconfig 2017-11-09 16:34:05.269000902 +0000
|
||||
+++ b/drivers/hwmon/pmbus/Kconfig 2017-11-09 16:35:49.701002288 +0000
|
||||
@@ -125,6 +125,15 @@
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called tps40422.
|
||||
|
||||
+config SENSORS_TPS53679
|
||||
+ tristate "TI TPS53679"
|
||||
+ help
|
||||
+ If you say yes here you get hardware monitoring support for TI
|
||||
+ TPS53679.
|
||||
+
|
||||
+ This driver can also be built as a module. If so, the module will
|
||||
+ be called tps53679.
|
||||
+
|
||||
config SENSORS_UCD9000
|
||||
tristate "TI UCD90120, UCD90124, UCD90160, UCD9090, UCD90910"
|
||||
default n
|
||||
diff -Nur a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
|
||||
--- a/drivers/hwmon/pmbus/Makefile 2017-11-09 16:34:05.269000902 +0000
|
||||
+++ b/drivers/hwmon/pmbus/Makefile 2017-11-09 16:35:49.701002288 +0000
|
||||
@@ -13,6 +13,7 @@
|
||||
obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
|
||||
obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
|
||||
obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
|
||||
+obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o
|
||||
obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o
|
||||
obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o
|
||||
obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o
|
||||
diff -Nur a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c
|
||||
--- a/drivers/hwmon/pmbus/tps53679.c 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ b/drivers/hwmon/pmbus/tps53679.c 2017-11-09 16:35:49.701002288 +0000
|
||||
@@ -0,0 +1,113 @@
|
||||
+/*
|
||||
+ * Hardware monitoring driver for Texas Instruments TPS53679
|
||||
+ *
|
||||
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
|
||||
+ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation; either version 2 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include "pmbus.h"
|
||||
+
|
||||
+#define TPS53679_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */
|
||||
+#define TPS53679_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */
|
||||
+#define TPS53679_PROT_VR13_10MV 0x04 /* VR13.0 mode, 10-mV DAC */
|
||||
+#define TPS53679_PROT_IMVP8_5MV 0x05 /* IMVP8 mode, 5-mV DAC */
|
||||
+#define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */
|
||||
+#define TPS53679_PAGE_NUM 2
|
||||
+
|
||||
+static int tps53679_identify(struct i2c_client *client,
|
||||
+ struct pmbus_driver_info *info)
|
||||
+{
|
||||
+ u8 vout_params;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Read the register with VOUT scaling value.*/
|
||||
+ ret = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ vout_params = ret & GENMASK(4, 0);
|
||||
+
|
||||
+ switch (vout_params) {
|
||||
+ case TPS53679_PROT_VR13_10MV:
|
||||
+ case TPS53679_PROT_VR12_5_10MV:
|
||||
+ info->vrm_version = vr13;
|
||||
+ break;
|
||||
+ case TPS53679_PROT_VR13_5MV:
|
||||
+ case TPS53679_PROT_VR12_5MV:
|
||||
+ case TPS53679_PROT_IMVP8_5MV:
|
||||
+ info->vrm_version = vr12;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct pmbus_driver_info tps53679_info = {
|
||||
+ .pages = TPS53679_PAGE_NUM,
|
||||
+ .format[PSC_VOLTAGE_IN] = linear,
|
||||
+ .format[PSC_VOLTAGE_OUT] = vid,
|
||||
+ .format[PSC_TEMPERATURE] = linear,
|
||||
+ .format[PSC_CURRENT_OUT] = linear,
|
||||
+ .format[PSC_POWER] = linear,
|
||||
+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
|
||||
+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
|
||||
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
|
||||
+ PMBUS_HAVE_POUT,
|
||||
+ .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
|
||||
+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
|
||||
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
|
||||
+ PMBUS_HAVE_POUT,
|
||||
+ .identify = tps53679_identify,
|
||||
+};
|
||||
+
|
||||
+static int tps53679_probe(struct i2c_client *client,
|
||||
+ const struct i2c_device_id *id)
|
||||
+{
|
||||
+ return pmbus_do_probe(client, id, &tps53679_info);
|
||||
+}
|
||||
+
|
||||
+static const struct i2c_device_id tps53679_id[] = {
|
||||
+ {"tps53679", 0},
|
||||
+ {}
|
||||
+};
|
||||
+
|
||||
+MODULE_DEVICE_TABLE(i2c, tps53679_id);
|
||||
+
|
||||
+static const struct of_device_id tps53679_of_match[] = {
|
||||
+ {.compatible = "ti,tps53679"},
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, tps53679_of_match);
|
||||
+
|
||||
+static struct i2c_driver tps53679_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "tps53679",
|
||||
+ .of_match_table = of_match_ptr(tps53679_of_match),
|
||||
+ },
|
||||
+ .probe = tps53679_probe,
|
||||
+ .remove = pmbus_do_remove,
|
||||
+ .id_table = tps53679_id,
|
||||
+};
|
||||
+
|
||||
+module_i2c_driver(tps53679_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
|
||||
+MODULE_DESCRIPTION("PMBus driver for Texas Instruments TPS53679");
|
||||
+MODULE_LICENSE("GPL");
|
||||
@@ -1 +1,9 @@
|
||||
driver-support-intel-igb-bcm5461-phy.patch
|
||||
0001-i2c-mlxcpld-add-master-driver-for-Mellanox-systems.patch
|
||||
0002-i2c-mux-mlxcpld-add-driver-for-Mellanox-systems.patch
|
||||
0003-platform-mellanox-Introduce-Mellanox-hardware-platfo.patch
|
||||
0004-platform-x86-Introduce-support-for-Mellanox-hotplug-.patch
|
||||
0005-leds-add-driver-for-support-Mellanox-regmap-LEDs-for.patch
|
||||
0006-Mellanox-switch-drivers-changes.patch
|
||||
0007-hwmon-pmbus-Add-support-for-Intel-VID-protocol-VR13.patch
|
||||
0008-hwmon-pmbus-Add-support-for-Texas-Instruments-tps536.patch
|
||||
|
||||
@@ -43,6 +43,12 @@
|
||||
#define LED_MODE_BLUE_BLINK "blue_blink"
|
||||
#define LED_MODE_AUTO "cpld_control"
|
||||
|
||||
#define LED_BLINK_PERIOD "100"
|
||||
#define LED_ON "1"
|
||||
#define LED_OFF "0"
|
||||
#define LED_BLINK_PERIOD_LEN 3
|
||||
#define LED_MODE_LEN 1
|
||||
|
||||
#define VALIDATE(_id) \
|
||||
do { \
|
||||
if(!ONLP_OID_IS_LED(_id)) { \
|
||||
@@ -94,6 +100,20 @@ led_light_mode_map_t led_map[] = {
|
||||
{LED_UID, LED_MODE_AUTO, ONLP_LED_MODE_AUTO},
|
||||
};
|
||||
|
||||
typedef struct led_colors {
|
||||
enum onlp_led_id id;
|
||||
const char* color1;
|
||||
const char* color2;
|
||||
} led_colors_t;
|
||||
|
||||
static led_colors_t led_colors_map[] = {
|
||||
{LED_SYSTEM, "green", "red"},
|
||||
{LED_FAN, "green", "red"},
|
||||
{LED_PSU1, "green", "red"},
|
||||
{LED_PSU2, "green", "red"},
|
||||
{LED_UID, "blue", NULL},
|
||||
};
|
||||
|
||||
static char file_names[][10] = /* must map with onlp_led_id */
|
||||
{
|
||||
"reserved",
|
||||
@@ -176,6 +196,57 @@ static char* onlp_to_driver_led_mode(enum onlp_led_id id, onlp_led_mode_t onlp_l
|
||||
return LED_MODE_OFF;
|
||||
}
|
||||
|
||||
static int led_set_mode(onlp_oid_t id, onlp_led_mode_t mode)
|
||||
{
|
||||
int local_id = ONLP_OID_ID_GET(id);
|
||||
char color[10]={0};
|
||||
int blinking = 0;
|
||||
|
||||
switch (mode) {
|
||||
case ONLP_LED_MODE_RED_BLINKING:
|
||||
strcpy(color, "red");
|
||||
blinking = 1;
|
||||
break;
|
||||
case ONLP_LED_MODE_GREEN_BLINKING:
|
||||
strcpy(color, "green");
|
||||
blinking = 1;
|
||||
break;
|
||||
case ONLP_LED_MODE_BLUE_BLINKING:
|
||||
strcpy(color, "blue");
|
||||
blinking = 1;
|
||||
break;
|
||||
case ONLP_LED_MODE_YELLOW_BLINKING:
|
||||
strcpy(color, "yellow");
|
||||
blinking = 1;
|
||||
break;
|
||||
case ONLP_LED_MODE_RED:
|
||||
strcpy(color, "red");
|
||||
break;
|
||||
case ONLP_LED_MODE_GREEN:
|
||||
strcpy(color, "green");
|
||||
break;
|
||||
case ONLP_LED_MODE_BLUE:
|
||||
strcpy(color, "blue");
|
||||
break;
|
||||
case ONLP_LED_MODE_YELLOW:
|
||||
strcpy(color, "yellow");
|
||||
break;
|
||||
default:
|
||||
return ONLP_STATUS_E_PARAM;
|
||||
}
|
||||
|
||||
if (blinking) {
|
||||
onlp_file_write((uint8_t*)LED_BLINK_PERIOD, LED_BLINK_PERIOD_LEN,
|
||||
"%s%s_%s_delay_off", prefix_path, file_names[local_id], color);
|
||||
onlp_file_write((uint8_t*)LED_BLINK_PERIOD, LED_BLINK_PERIOD_LEN,
|
||||
"%s%s_%s_delay_on", prefix_path, file_names[local_id], color);
|
||||
}
|
||||
onlp_file_write((uint8_t*)LED_ON, LED_MODE_LEN,
|
||||
"%s%s_%s", prefix_path, file_names[local_id], color);
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will be called prior to any other onlp_ledi_* functions.
|
||||
*/
|
||||
@@ -183,7 +254,7 @@ int
|
||||
onlp_ledi_init(void)
|
||||
{
|
||||
/*
|
||||
* TODO setting UI LED to off when it will be supported
|
||||
* ONLPD calls it too early before all BSP insfrastructure is set
|
||||
*/
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
@@ -203,6 +274,15 @@ onlp_ledi_info_get(onlp_oid_t id, onlp_led_info_t* info)
|
||||
*info = linfo[ONLP_OID_ID_GET(id)];
|
||||
|
||||
/* Get LED mode */
|
||||
if (onlp_get_kernel_ver() >= KERNEL_VERSION(4,9,30)) {
|
||||
char* cmd = aim_fstrdup("%s%s_state", prefix_path, file_names[local_id]);
|
||||
if(system(cmd) != 0) {
|
||||
aim_free(cmd);
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
aim_free(cmd);
|
||||
}
|
||||
|
||||
if (onlp_file_read(data, sizeof(data), &len, "%s%s",
|
||||
prefix_path, file_names[local_id]) != 0) {
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
@@ -233,7 +313,19 @@ onlp_ledi_set(onlp_oid_t id, int on_or_off)
|
||||
VALIDATE(id);
|
||||
|
||||
if (!on_or_off) {
|
||||
if (onlp_get_kernel_ver() < KERNEL_VERSION(4,9,30))
|
||||
return onlp_ledi_mode_set(id, ONLP_LED_MODE_OFF);
|
||||
else {
|
||||
int i, nsize = sizeof(led_colors_map)/sizeof(led_colors_map[0]);
|
||||
for (i = 0; i < nsize; i++)
|
||||
{
|
||||
if (id == led_colors_map[i].id)
|
||||
break;
|
||||
}
|
||||
if (led_colors_map[i].color1)
|
||||
onlp_file_write((uint8_t*)LED_OFF, LED_MODE_LEN,
|
||||
"%s%s_%s", prefix_path, file_names[id], led_colors_map[i].color1);
|
||||
}
|
||||
}
|
||||
|
||||
return ONLP_STATUS_E_UNSUPPORTED;
|
||||
@@ -249,14 +341,23 @@ int
|
||||
onlp_ledi_mode_set(onlp_oid_t id, onlp_led_mode_t mode)
|
||||
{
|
||||
int local_id;
|
||||
char* driver_led_mode;
|
||||
int nbytes;
|
||||
|
||||
VALIDATE(id);
|
||||
|
||||
if (onlp_get_kernel_ver() < KERNEL_VERSION(4,9,30)) {
|
||||
local_id = ONLP_OID_ID_GET(id);
|
||||
|
||||
if (onlp_file_write((uint8_t*)onlp_to_driver_led_mode(local_id, mode), driver_value_len,
|
||||
driver_led_mode = onlp_to_driver_led_mode(local_id, mode);
|
||||
nbytes = strnlen(driver_led_mode, driver_value_len);
|
||||
if (onlp_file_write((uint8_t*)driver_led_mode, nbytes,
|
||||
"%s%s", prefix_path, file_names[local_id]) != 0) {
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
} else {
|
||||
if (led_set_mode(id, mode) != 0) {
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
|
||||
@@ -27,9 +27,37 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <linux/version.h>
|
||||
#include <AIM/aim.h>
|
||||
#include <onlplib/file.h>
|
||||
#include <sys/mman.h>
|
||||
#include "platform_lib.h"
|
||||
|
||||
/* Nothing on this platform */
|
||||
int
|
||||
onlp_get_kernel_ver()
|
||||
{
|
||||
struct utsname buff;
|
||||
char ver[4];
|
||||
char *p;
|
||||
int i = 0;
|
||||
|
||||
if (uname(&buff) != 0)
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
|
||||
p = buff.release;
|
||||
|
||||
while (*p) {
|
||||
if (isdigit(*p)) {
|
||||
ver[i] = strtol(p, &p, 10);
|
||||
i++;
|
||||
if (i >= 3)
|
||||
break;
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
return KERNEL_VERSION(ver[0], ver[1], ver[2]);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
#define PSU_POWER_PREFIX "/bsp/power/psu%d_%s"
|
||||
#define IDPROM_PATH "/bsp/eeprom/%s%d_info"
|
||||
|
||||
#ifndef KERNEL_VERSION
|
||||
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
|
||||
#endif
|
||||
|
||||
/* LED related data
|
||||
*/
|
||||
enum onlp_led_id
|
||||
@@ -62,5 +66,6 @@ typedef enum psu_type {
|
||||
psu_type_t get_psu_type(int id, char* modelname, int modelname_len);
|
||||
|
||||
int onlp_fani_get_min_rpm(int id);
|
||||
int onlp_get_kernel_ver(void);
|
||||
|
||||
#endif /* __PLATFORM_LIB_H__ */
|
||||
|
||||
@@ -135,7 +135,6 @@ int
|
||||
onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info)
|
||||
{
|
||||
int val = 0;
|
||||
int ret = ONLP_STATUS_OK;
|
||||
int index = ONLP_OID_ID_GET(id);
|
||||
const char psu_model[]=PSU_MODEL;
|
||||
|
||||
@@ -156,14 +155,14 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info)
|
||||
|
||||
if (val != PSU_CABLE_PRESENT) {
|
||||
info->status |= ONLP_PSU_STATUS_UNPLUGGED;
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
else {
|
||||
info->status &= ~ONLP_PSU_STATUS_UNPLUGGED;
|
||||
}
|
||||
|
||||
info->status |= ONLP_PSU_STATUS_PRESENT;
|
||||
_psu_info_get(info);
|
||||
|
||||
ret = _psu_info_get(info);
|
||||
|
||||
return ret;
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -47,13 +47,23 @@ msn2100_sfp_node_read_int(char *node_path, int *value)
|
||||
int data_len = 0, ret = 0;
|
||||
char buf[SFP_SYSFS_VALUE_LEN] = {0};
|
||||
*value = -1;
|
||||
char sfp_present_status[16];
|
||||
char sfp_not_present_status[16];
|
||||
|
||||
if (onlp_get_kernel_ver() >= KERNEL_VERSION(4,9,30)) {
|
||||
strcpy(sfp_present_status, "1");
|
||||
strcpy(sfp_not_present_status, "0");
|
||||
} else {
|
||||
strcpy(sfp_present_status, "good");
|
||||
strcpy(sfp_not_present_status, "not_connected");
|
||||
}
|
||||
|
||||
ret = onlp_file_read((uint8_t*)buf, sizeof(buf), &data_len, node_path);
|
||||
|
||||
if (ret == 0) {
|
||||
if (!strncmp(buf, SFP_PRESENT_STATUS, strlen(SFP_PRESENT_STATUS))) {
|
||||
if (!strncmp(buf, sfp_present_status, strlen(sfp_present_status))) {
|
||||
*value = 1;
|
||||
} else if (!strncmp(buf, SFP_NOT_PRESENT_STATUS, strlen(SFP_NOT_PRESENT_STATUS))) {
|
||||
} else if (!strncmp(buf, sfp_not_present_status, strlen(sfp_not_present_status))) {
|
||||
*value = 0;
|
||||
}
|
||||
}
|
||||
@@ -64,7 +74,10 @@ msn2100_sfp_node_read_int(char *node_path, int *value)
|
||||
static char*
|
||||
msn2100_sfp_get_port_path(int port, char *node_name)
|
||||
{
|
||||
if (node_name)
|
||||
sprintf(sfp_node_path, "/bsp/qsfp/qsfp%d%s", port, node_name);
|
||||
else
|
||||
sprintf(sfp_node_path, "/bsp/qsfp/qsfp%d", port);
|
||||
return sfp_node_path;
|
||||
}
|
||||
|
||||
@@ -136,7 +149,7 @@ onlp_sfpi_presence_bitmap_get(onlp_sfp_bitmap_t* dst)
|
||||
int
|
||||
onlp_sfpi_eeprom_read(int port, uint8_t data[256])
|
||||
{
|
||||
char* path = msn2100_sfp_get_port_path(port, "");
|
||||
char* path = msn2100_sfp_get_port_path(port, NULL);
|
||||
|
||||
/*
|
||||
* Read the SFP eeprom into data[]
|
||||
@@ -194,12 +207,14 @@ onlp_sfpi_dev_readw(int port, uint8_t devaddr, uint8_t addr)
|
||||
int fd;
|
||||
int nrd;
|
||||
|
||||
if (!path)
|
||||
if (!path){
|
||||
return ONLP_STATUS_E_MISSING;
|
||||
}
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
if (fd < 0) {
|
||||
return ONLP_STATUS_E_MISSING;
|
||||
}
|
||||
|
||||
lseek(fd, addr, SEEK_SET);
|
||||
nrd = read(fd, &data, 2);
|
||||
|
||||
@@ -126,13 +126,13 @@ onlp_sysi_onie_info_get(onlp_onie_info_t* onie)
|
||||
int
|
||||
onlp_sysi_platform_manage_leds(void)
|
||||
{
|
||||
int fan_number;
|
||||
onlp_led_mode_t mode;
|
||||
int fan_number, psu_number;
|
||||
onlp_led_mode_t mode, system_mode;
|
||||
int min_fan_speed;
|
||||
enum onlp_led_id fan_led_id = LED_FAN;
|
||||
enum onlp_led_id psu_led_id[2] = { LED_PSU1, LED_PSU2 };
|
||||
int fan_problem = 0;
|
||||
int psu_problem = 0;
|
||||
|
||||
/* after reboot, status LED should blink green, SW set to solid green */
|
||||
onlp_ledi_mode_set(ONLP_OID_TYPE_CREATE(ONLP_OID_TYPE_LED,LED_SYSTEM), ONLP_LED_MODE_GREEN);
|
||||
/*
|
||||
* FAN Indicators
|
||||
*
|
||||
@@ -142,7 +142,6 @@ onlp_sysi_platform_manage_leds(void)
|
||||
*
|
||||
*/
|
||||
mode = ONLP_LED_MODE_GREEN;
|
||||
|
||||
for( fan_number = 1; fan_number<= CHASSIS_FAN_COUNT; fan_number+=2)
|
||||
{
|
||||
/* each 2 fans had same led_fan */
|
||||
@@ -150,9 +149,11 @@ onlp_sysi_platform_manage_leds(void)
|
||||
/* check fans */
|
||||
if(onlp_fani_info_get(ONLP_FAN_ID_CREATE(fan_number), &fi) < 0) {
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else if(fi.status & ONLP_FAN_STATUS_FAILED) {
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -160,6 +161,7 @@ onlp_sysi_platform_manage_leds(void)
|
||||
if( fi.rpm < min_fan_speed)
|
||||
{
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
}
|
||||
/* check fan i+1 */
|
||||
@@ -168,6 +170,7 @@ onlp_sysi_platform_manage_leds(void)
|
||||
}
|
||||
else if(fi.status & ONLP_FAN_STATUS_FAILED) {
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -175,10 +178,35 @@ onlp_sysi_platform_manage_leds(void)
|
||||
if( fi.rpm < min_fan_speed)
|
||||
{
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
onlp_ledi_mode_set(ONLP_OID_TYPE_CREATE(ONLP_OID_TYPE_LED,fan_led_id), mode);
|
||||
onlp_ledi_mode_set(ONLP_OID_TYPE_CREATE(ONLP_OID_TYPE_LED, LED_FAN), mode);
|
||||
|
||||
for (psu_number = 1; psu_number <= CHASSIS_PSU_COUNT; psu_number++)
|
||||
{
|
||||
onlp_psu_info_t pi;
|
||||
mode = ONLP_LED_MODE_GREEN;
|
||||
if(onlp_psui_info_get(ONLP_PSU_ID_CREATE(psu_number), &pi) < 0) {
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
psu_problem = 1;
|
||||
}
|
||||
/* Fixed system, PSU always in. Check only cable plugged. */
|
||||
else if(pi.status & ONLP_PSU_STATUS_UNPLUGGED) {
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
psu_problem = 1;
|
||||
}
|
||||
onlp_ledi_mode_set(ONLP_OID_TYPE_CREATE(ONLP_OID_TYPE_LED, psu_led_id[(psu_number-1)]), mode);
|
||||
}
|
||||
|
||||
/* Set System status LED green if no problem in FANs or PSUs */
|
||||
if (fan_problem || psu_problem)
|
||||
system_mode = ONLP_LED_MODE_RED;
|
||||
else
|
||||
system_mode = ONLP_LED_MODE_GREEN;
|
||||
|
||||
onlp_ledi_mode_set(ONLP_OID_TYPE_CREATE(ONLP_OID_TYPE_LED, LED_SYSTEM), system_mode);
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ x86-64-mlnx-msn2100-r0:
|
||||
--stop=1
|
||||
|
||||
kernel:
|
||||
<<: *kernel-3-16
|
||||
<<: *kernel-4-9
|
||||
|
||||
args: >-
|
||||
nopat
|
||||
|
||||
@@ -244,6 +244,7 @@ _onlp_fani_info_get_fan(int local_id, onlp_fan_info_t* info)
|
||||
snprintf(fullpath, sizeof(fullpath), "%s%s", PREFIX_MODULE_PATH, fan_path[(int)fru_index].status);
|
||||
OPEN_READ_FILE(fullpath, r_data, nbytes, len);
|
||||
if (atoi(r_data) != FAN_STATUS_OK) {
|
||||
info->status &= ~ONLP_FAN_STATUS_PRESENT;
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
info->status |= ONLP_FAN_STATUS_PRESENT;
|
||||
@@ -303,6 +304,7 @@ _onlp_fani_info_get_fan_on_psu(int local_id, int psu_id, onlp_fan_info_t* info)
|
||||
snprintf(fullpath, sizeof(fullpath), "%s%s", PREFIX_MODULE_PATH, fan_path[local_id].status);
|
||||
OPEN_READ_FILE(fullpath, r_data, nbytes, len);
|
||||
if (atoi(r_data) != FAN_STATUS_OK) {
|
||||
info->status &= ~ONLP_FAN_STATUS_PRESENT;
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
info->status |= ONLP_FAN_STATUS_PRESENT;
|
||||
|
||||
@@ -43,6 +43,12 @@
|
||||
#define LED_MODE_BLUE_BLINK "blue_blink"
|
||||
#define LED_MODE_AUTO "cpld_control"
|
||||
|
||||
#define LED_BLINK_PERIOD "100"
|
||||
#define LED_ON "1"
|
||||
#define LED_OFF "0"
|
||||
#define LED_BLINK_PERIOD_LEN 3
|
||||
#define LED_MODE_LEN 1
|
||||
|
||||
#define VALIDATE(_id) \
|
||||
do { \
|
||||
if(!ONLP_OID_IS_LED(_id)) { \
|
||||
@@ -103,6 +109,21 @@ led_light_mode_map_t led_map[] = {
|
||||
{LED_PSU, LED_MODE_AUTO, ONLP_LED_MODE_AUTO}
|
||||
};
|
||||
|
||||
typedef struct led_colors {
|
||||
enum onlp_led_id id;
|
||||
const char* color1;
|
||||
const char* color2;
|
||||
} led_colors_t;
|
||||
|
||||
static led_colors_t led_colors_map[] = {
|
||||
{LED_SYSTEM, "green", "red"},
|
||||
{LED_FAN1, "green", "red"},
|
||||
{LED_FAN2, "green", "red"},
|
||||
{LED_FAN3, "green", "red"},
|
||||
{LED_FAN4, "green", "red"},
|
||||
{LED_PSU, "green", "red"},
|
||||
};
|
||||
|
||||
static char file_names[][10] = /* must map with onlp_led_id */
|
||||
{
|
||||
"reserved",
|
||||
@@ -192,6 +213,57 @@ static char* onlp_to_driver_led_mode(enum onlp_led_id id, onlp_led_mode_t onlp_l
|
||||
return LED_MODE_OFF;
|
||||
}
|
||||
|
||||
static int led_set_mode(onlp_oid_t id, onlp_led_mode_t mode)
|
||||
{
|
||||
int local_id = ONLP_OID_ID_GET(id);
|
||||
char color[10]={0};
|
||||
int blinking = 0;
|
||||
|
||||
switch (mode) {
|
||||
case ONLP_LED_MODE_RED_BLINKING:
|
||||
strcpy(color, "red");
|
||||
blinking = 1;
|
||||
break;
|
||||
case ONLP_LED_MODE_GREEN_BLINKING:
|
||||
strcpy(color, "green");
|
||||
blinking = 1;
|
||||
break;
|
||||
case ONLP_LED_MODE_BLUE_BLINKING:
|
||||
strcpy(color, "blue");
|
||||
blinking = 1;
|
||||
break;
|
||||
case ONLP_LED_MODE_YELLOW_BLINKING:
|
||||
strcpy(color, "yellow");
|
||||
blinking = 1;
|
||||
break;
|
||||
case ONLP_LED_MODE_RED:
|
||||
strcpy(color, "red");
|
||||
break;
|
||||
case ONLP_LED_MODE_GREEN:
|
||||
strcpy(color, "green");
|
||||
break;
|
||||
case ONLP_LED_MODE_BLUE:
|
||||
strcpy(color, "blue");
|
||||
break;
|
||||
case ONLP_LED_MODE_YELLOW:
|
||||
strcpy(color, "yellow");
|
||||
break;
|
||||
default:
|
||||
return ONLP_STATUS_E_PARAM;
|
||||
}
|
||||
|
||||
if (blinking) {
|
||||
onlp_file_write((uint8_t*)LED_BLINK_PERIOD, LED_BLINK_PERIOD_LEN,
|
||||
"%s%s_%s_delay_off", prefix_path, file_names[local_id], color);
|
||||
onlp_file_write((uint8_t*)LED_BLINK_PERIOD, LED_BLINK_PERIOD_LEN,
|
||||
"%s%s_%s_delay_on", prefix_path, file_names[local_id], color);
|
||||
}
|
||||
onlp_file_write((uint8_t*)LED_ON, LED_MODE_LEN,
|
||||
"%s%s_%s", prefix_path, file_names[local_id], color);
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will be called prior to any other onlp_ledi_* functions.
|
||||
*/
|
||||
@@ -199,7 +271,7 @@ int
|
||||
onlp_ledi_init(void)
|
||||
{
|
||||
/*
|
||||
* TODO setting UI LED to off when it will be supported on MSN2410
|
||||
* ONLPD calls it too early before all BSP insfrastructure is set
|
||||
*/
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
@@ -219,6 +291,15 @@ onlp_ledi_info_get(onlp_oid_t id, onlp_led_info_t* info)
|
||||
*info = linfo[ONLP_OID_ID_GET(id)];
|
||||
|
||||
/* Get LED mode */
|
||||
if (onlp_get_kernel_ver() >= KERNEL_VERSION(4,9,30)) {
|
||||
char* cmd = aim_fstrdup("%s%s_state", prefix_path, file_names[local_id]);
|
||||
if(system(cmd) != 0) {
|
||||
aim_free(cmd);
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
aim_free(cmd);
|
||||
}
|
||||
|
||||
if (onlp_file_read(data, sizeof(data), &len, "%s%s",
|
||||
prefix_path, file_names[local_id]) != 0) {
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
@@ -249,7 +330,19 @@ onlp_ledi_set(onlp_oid_t id, int on_or_off)
|
||||
VALIDATE(id);
|
||||
|
||||
if (!on_or_off) {
|
||||
if (onlp_get_kernel_ver() < KERNEL_VERSION(4,9,30))
|
||||
return onlp_ledi_mode_set(id, ONLP_LED_MODE_OFF);
|
||||
else {
|
||||
int i, nsize = sizeof(led_colors_map)/sizeof(led_colors_map[0]);
|
||||
for (i = 0; i < nsize; i++)
|
||||
{
|
||||
if (id == led_colors_map[i].id)
|
||||
break;
|
||||
}
|
||||
if (led_colors_map[i].color1)
|
||||
onlp_file_write((uint8_t*)LED_OFF, LED_MODE_LEN,
|
||||
"%s%s_%s", prefix_path, file_names[id], led_colors_map[i].color1);
|
||||
}
|
||||
}
|
||||
|
||||
return ONLP_STATUS_E_UNSUPPORTED;
|
||||
@@ -265,15 +358,23 @@ int
|
||||
onlp_ledi_mode_set(onlp_oid_t id, onlp_led_mode_t mode)
|
||||
{
|
||||
int local_id;
|
||||
char* driver_led_mode;
|
||||
int nbytes;
|
||||
|
||||
VALIDATE(id);
|
||||
|
||||
if (onlp_get_kernel_ver() < KERNEL_VERSION(4,9,30)) {
|
||||
local_id = ONLP_OID_ID_GET(id);
|
||||
|
||||
if (onlp_file_write((uint8_t*)onlp_to_driver_led_mode(local_id, mode), driver_value_len,
|
||||
"%s%s", prefix_path, file_names[local_id]) != 0)
|
||||
{
|
||||
driver_led_mode = onlp_to_driver_led_mode(local_id, mode);
|
||||
nbytes = strnlen(driver_led_mode, driver_value_len);
|
||||
if (onlp_file_write((uint8_t*)driver_led_mode, nbytes,
|
||||
"%s%s", prefix_path, file_names[local_id]) != 0) {
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
} else {
|
||||
if (led_set_mode(id, mode) != 0) {
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <linux/version.h>
|
||||
#include <AIM/aim.h>
|
||||
#include <onlplib/file.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -77,3 +80,30 @@ psu_read_eeprom(int psu_index, onlp_psu_info_t* psu_info, onlp_fan_info_t* fan_i
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
int
|
||||
onlp_get_kernel_ver()
|
||||
{
|
||||
struct utsname buff;
|
||||
char ver[4];
|
||||
char *p;
|
||||
int i = 0;
|
||||
|
||||
if (uname(&buff) != 0)
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
|
||||
p = buff.release;
|
||||
|
||||
while (*p) {
|
||||
if (isdigit(*p)) {
|
||||
ver[i] = strtol(p, &p, 10);
|
||||
i++;
|
||||
if (i >= 3)
|
||||
break;
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
return KERNEL_VERSION(ver[0], ver[1], ver[2]);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,10 @@
|
||||
#define PSU_POWER_PREFIX "/bsp/power/psu%d_%s"
|
||||
#define IDPROM_PATH "/bsp/eeprom/%s%d_info"
|
||||
|
||||
#ifndef KERNEL_VERSION
|
||||
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
|
||||
#endif
|
||||
|
||||
/* LED related data
|
||||
*/
|
||||
enum onlp_led_id
|
||||
@@ -67,5 +71,6 @@ int psu_read_eeprom(int psu_index, onlp_psu_info_t* psu_info,
|
||||
onlp_fan_info_t* fan_info);
|
||||
|
||||
int onlp_fani_get_min_rpm(int id);
|
||||
int onlp_get_kernel_ver(void);
|
||||
|
||||
#endif /* __PLATFORM_LIB_H__ */
|
||||
|
||||
@@ -174,6 +174,8 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info)
|
||||
info->status |= ONLP_PSU_STATUS_UNPLUGGED;
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
else
|
||||
info->status |= ONLP_PSU_STATUS_PRESENT;
|
||||
|
||||
/* Get the cable preset state */
|
||||
if (psu_module_info_get(index, "pwr_status", &val) != 0) {
|
||||
@@ -185,8 +187,6 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info)
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
info->status |= ONLP_PSU_STATUS_PRESENT;
|
||||
|
||||
ret = _psu_info_get(info);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -47,13 +47,23 @@ msn2410_sfp_node_read_int(char *node_path, int *value)
|
||||
int data_len = 0, ret = 0;
|
||||
char buf[SFP_SYSFS_VALUE_LEN] = {0};
|
||||
*value = -1;
|
||||
char sfp_present_status[16];
|
||||
char sfp_not_present_status[16];
|
||||
|
||||
if (onlp_get_kernel_ver() >= KERNEL_VERSION(4,9,30)) {
|
||||
strcpy(sfp_present_status, "1");
|
||||
strcpy(sfp_not_present_status, "0");
|
||||
} else {
|
||||
strcpy(sfp_present_status, "good");
|
||||
strcpy(sfp_not_present_status, "not_connected");
|
||||
}
|
||||
|
||||
ret = onlp_file_read((uint8_t*)buf, sizeof(buf), &data_len, node_path);
|
||||
|
||||
if (ret == 0) {
|
||||
if (!strncmp(buf, SFP_PRESENT_STATUS, strlen(SFP_PRESENT_STATUS))) {
|
||||
if (!strncmp(buf, sfp_present_status, strlen(sfp_present_status))) {
|
||||
*value = 1;
|
||||
} else if (!strncmp(buf, SFP_NOT_PRESENT_STATUS, strlen(SFP_NOT_PRESENT_STATUS))) {
|
||||
} else if (!strncmp(buf, sfp_not_present_status, strlen(sfp_not_present_status))) {
|
||||
*value = 0;
|
||||
}
|
||||
}
|
||||
@@ -64,7 +74,10 @@ msn2410_sfp_node_read_int(char *node_path, int *value)
|
||||
static char*
|
||||
msn2410_sfp_get_port_path(int port, char *node_name)
|
||||
{
|
||||
if (node_name)
|
||||
sprintf(sfp_node_path, "/bsp/qsfp/qsfp%d%s", port, node_name);
|
||||
else
|
||||
sprintf(sfp_node_path, "/bsp/qsfp/qsfp%d", port);
|
||||
return sfp_node_path;
|
||||
}
|
||||
|
||||
@@ -139,7 +152,7 @@ onlp_sfpi_presence_bitmap_get(onlp_sfp_bitmap_t* dst)
|
||||
int
|
||||
onlp_sfpi_eeprom_read(int port, uint8_t data[256])
|
||||
{
|
||||
char* path = msn2410_sfp_get_port_path(port, "");
|
||||
char* path = msn2410_sfp_get_port_path(port, NULL);
|
||||
|
||||
/*
|
||||
* Read the SFP eeprom into data[]
|
||||
|
||||
@@ -136,13 +136,13 @@ onlp_sysi_onie_info_get(onlp_onie_info_t* onie)
|
||||
int
|
||||
onlp_sysi_platform_manage_leds(void)
|
||||
{
|
||||
int fan_number;
|
||||
onlp_led_mode_t mode;
|
||||
int fan_number, psu_number;
|
||||
onlp_led_mode_t mode, system_mode;
|
||||
int min_fan_speed;
|
||||
enum onlp_led_id fan_led_id[4] = { LED_FAN1, LED_FAN2, LED_FAN3, LED_FAN4 };
|
||||
int fan_problem = 0;
|
||||
int psu_problem = 0;
|
||||
|
||||
/* after reboot, status LED should blink green, SW set to solid green */
|
||||
onlp_ledi_mode_set(ONLP_OID_TYPE_CREATE(ONLP_OID_TYPE_LED,LED_SYSTEM), ONLP_LED_MODE_GREEN);
|
||||
/*
|
||||
* FAN Indicators
|
||||
*
|
||||
@@ -159,13 +159,16 @@ onlp_sysi_platform_manage_leds(void)
|
||||
mode = ONLP_LED_MODE_GREEN;
|
||||
if(onlp_fani_info_get(ONLP_FAN_ID_CREATE(fan_number), &fi) < 0) {
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else if( (fi.status & 0x1) == 0) {
|
||||
else if( (fi.status & ONLP_FAN_STATUS_PRESENT) == 0) {
|
||||
/* Not present */
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else if(fi.status & ONLP_FAN_STATUS_FAILED) {
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -173,18 +176,22 @@ onlp_sysi_platform_manage_leds(void)
|
||||
if( fi.rpm < min_fan_speed)
|
||||
{
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
}
|
||||
/* check fan i+1 */
|
||||
if(onlp_fani_info_get(ONLP_FAN_ID_CREATE(fan_number+1), &fi) < 0) {
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else if( (fi.status & 0x1) == 0) {
|
||||
/* Not present */
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else if(fi.status & ONLP_FAN_STATUS_FAILED) {
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -192,10 +199,41 @@ onlp_sysi_platform_manage_leds(void)
|
||||
if( fi.rpm < min_fan_speed)
|
||||
{
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
}
|
||||
onlp_ledi_mode_set(ONLP_OID_TYPE_CREATE(ONLP_OID_TYPE_LED,fan_led_id[fan_number/2]), mode);
|
||||
}
|
||||
|
||||
for (psu_number = 1; psu_number <= CHASSIS_PSU_COUNT; psu_number++)
|
||||
{
|
||||
onlp_psu_info_t pi;
|
||||
if(onlp_psui_info_get(ONLP_PSU_ID_CREATE(psu_number), &pi) < 0) {
|
||||
psu_problem = 1;
|
||||
}
|
||||
else if((pi.status & ONLP_PSU_STATUS_PRESENT) == 0) {
|
||||
/* Not present */
|
||||
psu_problem = 1;
|
||||
}
|
||||
else if(pi.status & ONLP_PSU_STATUS_UNPLUGGED) {
|
||||
psu_problem = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (psu_problem)
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
else
|
||||
mode = ONLP_LED_MODE_GREEN;
|
||||
onlp_ledi_mode_set(ONLP_OID_TYPE_CREATE(ONLP_OID_TYPE_LED, LED_PSU), mode);
|
||||
|
||||
/* Set System status LED green if no problem in FANs or PSUs */
|
||||
if (fan_problem || psu_problem)
|
||||
system_mode = ONLP_LED_MODE_RED;
|
||||
else
|
||||
system_mode = ONLP_LED_MODE_GREEN;
|
||||
|
||||
onlp_ledi_mode_set(ONLP_OID_TYPE_CREATE(ONLP_OID_TYPE_LED,LED_SYSTEM), system_mode);
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ x86-64-mlnx-msn2410-r0:
|
||||
--stop=1
|
||||
|
||||
kernel:
|
||||
<<: *kernel-3-16
|
||||
<<: *kernel-4-9
|
||||
|
||||
args: >-
|
||||
nopat
|
||||
|
||||
@@ -176,7 +176,8 @@ _onlp_fani_read_fan_eeprom(int local_id, onlp_fan_info_t* info)
|
||||
local_id /= 2;
|
||||
}
|
||||
|
||||
rv = onlp_file_read(data, sizeof(data), &len, IDPROM_PATH, "fan", local_id);
|
||||
rv = onlp_file_read(data, sizeof(data), &len,
|
||||
IDPROM_PATH, "fan", local_id);
|
||||
if (rv < 0) {
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
@@ -243,6 +244,7 @@ _onlp_fani_info_get_fan(int local_id, onlp_fan_info_t* info)
|
||||
snprintf(fullpath, sizeof(fullpath), "%s%s", PREFIX_MODULE_PATH, fan_path[(int)fru_index].status);
|
||||
OPEN_READ_FILE(fullpath, r_data, nbytes, len);
|
||||
if (atoi(r_data) != FAN_STATUS_OK) {
|
||||
info->status &= ~ONLP_FAN_STATUS_PRESENT;
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
info->status |= ONLP_FAN_STATUS_PRESENT;
|
||||
@@ -302,6 +304,7 @@ _onlp_fani_info_get_fan_on_psu(int local_id, int psu_id, onlp_fan_info_t* info)
|
||||
snprintf(fullpath, sizeof(fullpath), "%s%s", PREFIX_MODULE_PATH, fan_path[local_id].status);
|
||||
OPEN_READ_FILE(fullpath, r_data, nbytes, len);
|
||||
if (atoi(r_data) != FAN_STATUS_OK) {
|
||||
info->status &= ~ONLP_FAN_STATUS_PRESENT;
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
info->status |= ONLP_FAN_STATUS_PRESENT;
|
||||
|
||||
@@ -43,6 +43,12 @@
|
||||
#define LED_MODE_BLUE_BLINK "blue_blink"
|
||||
#define LED_MODE_AUTO "cpld_control"
|
||||
|
||||
#define LED_BLINK_PERIOD "100"
|
||||
#define LED_ON "1"
|
||||
#define LED_OFF "0"
|
||||
#define LED_BLINK_PERIOD_LEN 3
|
||||
#define LED_MODE_LEN 1
|
||||
|
||||
#define VALIDATE(_id) \
|
||||
do { \
|
||||
if(!ONLP_OID_IS_LED(_id)) { \
|
||||
@@ -103,6 +109,21 @@ led_light_mode_map_t led_map[] = {
|
||||
{LED_PSU, LED_MODE_AUTO, ONLP_LED_MODE_AUTO}
|
||||
};
|
||||
|
||||
typedef struct led_colors {
|
||||
enum onlp_led_id id;
|
||||
const char* color1;
|
||||
const char* color2;
|
||||
} led_colors_t;
|
||||
|
||||
static led_colors_t led_colors_map[] = {
|
||||
{LED_SYSTEM, "green", "red"},
|
||||
{LED_FAN1, "green", "red"},
|
||||
{LED_FAN2, "green", "red"},
|
||||
{LED_FAN3, "green", "red"},
|
||||
{LED_FAN4, "green", "red"},
|
||||
{LED_PSU, "green", "red"},
|
||||
};
|
||||
|
||||
static char file_names[][10] = /* must map with onlp_led_id */
|
||||
{
|
||||
"reserved",
|
||||
@@ -192,6 +213,57 @@ static char* onlp_to_driver_led_mode(enum onlp_led_id id, onlp_led_mode_t onlp_l
|
||||
return LED_MODE_OFF;
|
||||
}
|
||||
|
||||
static int led_set_mode(onlp_oid_t id, onlp_led_mode_t mode)
|
||||
{
|
||||
int local_id = ONLP_OID_ID_GET(id);
|
||||
char color[10]={0};
|
||||
int blinking = 0;
|
||||
|
||||
switch (mode) {
|
||||
case ONLP_LED_MODE_RED_BLINKING:
|
||||
strcpy(color, "red");
|
||||
blinking = 1;
|
||||
break;
|
||||
case ONLP_LED_MODE_GREEN_BLINKING:
|
||||
strcpy(color, "green");
|
||||
blinking = 1;
|
||||
break;
|
||||
case ONLP_LED_MODE_BLUE_BLINKING:
|
||||
strcpy(color, "blue");
|
||||
blinking = 1;
|
||||
break;
|
||||
case ONLP_LED_MODE_YELLOW_BLINKING:
|
||||
strcpy(color, "yellow");
|
||||
blinking = 1;
|
||||
break;
|
||||
case ONLP_LED_MODE_RED:
|
||||
strcpy(color, "red");
|
||||
break;
|
||||
case ONLP_LED_MODE_GREEN:
|
||||
strcpy(color, "green");
|
||||
break;
|
||||
case ONLP_LED_MODE_BLUE:
|
||||
strcpy(color, "blue");
|
||||
break;
|
||||
case ONLP_LED_MODE_YELLOW:
|
||||
strcpy(color, "yellow");
|
||||
break;
|
||||
default:
|
||||
return ONLP_STATUS_E_PARAM;
|
||||
}
|
||||
|
||||
if (blinking) {
|
||||
onlp_file_write((uint8_t*)LED_BLINK_PERIOD, LED_BLINK_PERIOD_LEN,
|
||||
"%s%s_%s_delay_off", prefix_path, file_names[local_id], color);
|
||||
onlp_file_write((uint8_t*)LED_BLINK_PERIOD, LED_BLINK_PERIOD_LEN,
|
||||
"%s%s_%s_delay_on", prefix_path, file_names[local_id], color);
|
||||
}
|
||||
onlp_file_write((uint8_t*)LED_ON, LED_MODE_LEN,
|
||||
"%s%s_%s", prefix_path, file_names[local_id], color);
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will be called prior to any other onlp_ledi_* functions.
|
||||
*/
|
||||
@@ -199,7 +271,7 @@ int
|
||||
onlp_ledi_init(void)
|
||||
{
|
||||
/*
|
||||
* TODO setting UI LED to off when it will be supported on SN2700
|
||||
* ONLPD calls it too early before all BSP insfrastructure is set
|
||||
*/
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
@@ -219,6 +291,15 @@ onlp_ledi_info_get(onlp_oid_t id, onlp_led_info_t* info)
|
||||
*info = linfo[ONLP_OID_ID_GET(id)];
|
||||
|
||||
/* Get LED mode */
|
||||
if (onlp_get_kernel_ver() >= KERNEL_VERSION(4,9,30)) {
|
||||
char* cmd = aim_fstrdup("%s%s_state", prefix_path, file_names[local_id]);
|
||||
if(system(cmd) != 0) {
|
||||
aim_free(cmd);
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
aim_free(cmd);
|
||||
}
|
||||
|
||||
if (onlp_file_read(data, sizeof(data), &len, "%s%s",
|
||||
prefix_path, file_names[local_id]) != 0) {
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
@@ -249,7 +330,19 @@ onlp_ledi_set(onlp_oid_t id, int on_or_off)
|
||||
VALIDATE(id);
|
||||
|
||||
if (!on_or_off) {
|
||||
if (onlp_get_kernel_ver() < KERNEL_VERSION(4,9,30))
|
||||
return onlp_ledi_mode_set(id, ONLP_LED_MODE_OFF);
|
||||
else {
|
||||
int i, nsize = sizeof(led_colors_map)/sizeof(led_colors_map[0]);
|
||||
for (i = 0; i < nsize; i++)
|
||||
{
|
||||
if (id == led_colors_map[i].id)
|
||||
break;
|
||||
}
|
||||
if (led_colors_map[i].color1)
|
||||
onlp_file_write((uint8_t*)LED_OFF, LED_MODE_LEN,
|
||||
"%s%s_%s", prefix_path, file_names[id], led_colors_map[i].color1);
|
||||
}
|
||||
}
|
||||
|
||||
return ONLP_STATUS_E_UNSUPPORTED;
|
||||
@@ -265,15 +358,23 @@ int
|
||||
onlp_ledi_mode_set(onlp_oid_t id, onlp_led_mode_t mode)
|
||||
{
|
||||
int local_id;
|
||||
char* driver_led_mode;
|
||||
int nbytes;
|
||||
|
||||
VALIDATE(id);
|
||||
|
||||
if (onlp_get_kernel_ver() < KERNEL_VERSION(4,9,30)) {
|
||||
local_id = ONLP_OID_ID_GET(id);
|
||||
|
||||
if (onlp_file_write((uint8_t*)onlp_to_driver_led_mode(local_id, mode), driver_value_len,
|
||||
"%s%s", prefix_path, file_names[local_id]) != 0)
|
||||
{
|
||||
driver_led_mode = onlp_to_driver_led_mode(local_id, mode);
|
||||
nbytes = strnlen(driver_led_mode, driver_value_len);
|
||||
if (onlp_file_write((uint8_t*)driver_led_mode, nbytes,
|
||||
"%s%s", prefix_path, file_names[local_id]) != 0) {
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
} else {
|
||||
if (led_set_mode(id, mode) != 0) {
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <linux/version.h>
|
||||
#include <AIM/aim.h>
|
||||
#include <onlplib/file.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -77,3 +80,30 @@ psu_read_eeprom(int psu_index, onlp_psu_info_t* psu_info, onlp_fan_info_t* fan_i
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
int
|
||||
onlp_get_kernel_ver()
|
||||
{
|
||||
struct utsname buff;
|
||||
char ver[4];
|
||||
char *p;
|
||||
int i = 0;
|
||||
|
||||
if (uname(&buff) != 0)
|
||||
return ONLP_STATUS_E_INTERNAL;
|
||||
|
||||
p = buff.release;
|
||||
|
||||
while (*p) {
|
||||
if (isdigit(*p)) {
|
||||
ver[i] = strtol(p, &p, 10);
|
||||
i++;
|
||||
if (i >= 3)
|
||||
break;
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
return KERNEL_VERSION(ver[0], ver[1], ver[2]);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,10 @@
|
||||
#define PSU_POWER_PREFIX "/bsp/power/psu%d_%s"
|
||||
#define IDPROM_PATH "/bsp/eeprom/%s%d_info"
|
||||
|
||||
#ifndef KERNEL_VERSION
|
||||
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
|
||||
#endif
|
||||
|
||||
/* LED related data
|
||||
*/
|
||||
enum onlp_led_id
|
||||
@@ -67,5 +71,6 @@ int psu_read_eeprom(int psu_index, onlp_psu_info_t* psu_info,
|
||||
onlp_fan_info_t* fan_info);
|
||||
|
||||
int onlp_fani_get_min_rpm(int id);
|
||||
int onlp_get_kernel_ver(void);
|
||||
|
||||
#endif /* __PLATFORM_LIB_H__ */
|
||||
|
||||
@@ -174,6 +174,8 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info)
|
||||
info->status |= ONLP_PSU_STATUS_UNPLUGGED;
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
else
|
||||
info->status |= ONLP_PSU_STATUS_PRESENT;
|
||||
|
||||
/* Get the cable preset state */
|
||||
if (psu_module_info_get(index, "pwr_status", &val) != 0) {
|
||||
@@ -185,8 +187,6 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info)
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
info->status |= ONLP_PSU_STATUS_PRESENT;
|
||||
|
||||
ret = _psu_info_get(info);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -47,13 +47,23 @@ sn2700_sfp_node_read_int(char *node_path, int *value)
|
||||
int data_len = 0, ret = 0;
|
||||
char buf[SFP_SYSFS_VALUE_LEN] = {0};
|
||||
*value = -1;
|
||||
char sfp_present_status[16];
|
||||
char sfp_not_present_status[16];
|
||||
|
||||
if (onlp_get_kernel_ver() >= KERNEL_VERSION(4,9,30)) {
|
||||
strcpy(sfp_present_status, "1");
|
||||
strcpy(sfp_not_present_status, "0");
|
||||
} else {
|
||||
strcpy(sfp_present_status, "good");
|
||||
strcpy(sfp_not_present_status, "not_connected");
|
||||
}
|
||||
|
||||
ret = onlp_file_read((uint8_t*)buf, sizeof(buf), &data_len, node_path);
|
||||
|
||||
if (ret == 0) {
|
||||
if (!strncmp(buf, SFP_PRESENT_STATUS, strlen(SFP_PRESENT_STATUS))) {
|
||||
if (!strncmp(buf, sfp_present_status, strlen(sfp_present_status))) {
|
||||
*value = 1;
|
||||
} else if (!strncmp(buf, SFP_NOT_PRESENT_STATUS, strlen(SFP_NOT_PRESENT_STATUS))) {
|
||||
} else if (!strncmp(buf, sfp_not_present_status, strlen(sfp_not_present_status))) {
|
||||
*value = 0;
|
||||
}
|
||||
}
|
||||
@@ -64,7 +74,10 @@ sn2700_sfp_node_read_int(char *node_path, int *value)
|
||||
static char*
|
||||
sn2700_sfp_get_port_path(int port, char *node_name)
|
||||
{
|
||||
if (node_name)
|
||||
sprintf(sfp_node_path, "/bsp/qsfp/qsfp%d%s", port, node_name);
|
||||
else
|
||||
sprintf(sfp_node_path, "/bsp/qsfp/qsfp%d", port);
|
||||
return sfp_node_path;
|
||||
}
|
||||
|
||||
@@ -139,7 +152,7 @@ onlp_sfpi_presence_bitmap_get(onlp_sfp_bitmap_t* dst)
|
||||
int
|
||||
onlp_sfpi_eeprom_read(int port, uint8_t data[256])
|
||||
{
|
||||
char* path = sn2700_sfp_get_port_path(port, "");
|
||||
char* path = sn2700_sfp_get_port_path(port, NULL);
|
||||
|
||||
/*
|
||||
* Read the SFP eeprom into data[]
|
||||
@@ -197,12 +210,14 @@ onlp_sfpi_dev_readw(int port, uint8_t devaddr, uint8_t addr)
|
||||
int fd;
|
||||
int nrd;
|
||||
|
||||
if (!path)
|
||||
if (!path){
|
||||
return ONLP_STATUS_E_MISSING;
|
||||
}
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
if (fd < 0) {
|
||||
return ONLP_STATUS_E_MISSING;
|
||||
}
|
||||
|
||||
lseek(fd, addr, SEEK_SET);
|
||||
nrd = read(fd, &data, 2);
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
|
||||
#define PREFIX_PATH_ON_CPLD_DEV "/bsp/cpld"
|
||||
#define NUM_OF_CPLD 3
|
||||
|
||||
static char arr_cplddev_name[NUM_OF_CPLD][30] =
|
||||
{
|
||||
"cpld_brd_version",
|
||||
@@ -137,13 +136,13 @@ onlp_sysi_onie_info_get(onlp_onie_info_t* onie)
|
||||
int
|
||||
onlp_sysi_platform_manage_leds(void)
|
||||
{
|
||||
int fan_number;
|
||||
onlp_led_mode_t mode;
|
||||
int fan_number, psu_number;
|
||||
onlp_led_mode_t mode, system_mode;
|
||||
int min_fan_speed;
|
||||
enum onlp_led_id fan_led_id[4] = { LED_FAN1, LED_FAN2, LED_FAN3, LED_FAN4 };
|
||||
int fan_problem = 0;
|
||||
int psu_problem = 0;
|
||||
|
||||
/* after reboot, status LED should blink green, SW set to solid green */
|
||||
onlp_ledi_mode_set(ONLP_OID_TYPE_CREATE(ONLP_OID_TYPE_LED,LED_SYSTEM), ONLP_LED_MODE_GREEN);
|
||||
/*
|
||||
* FAN Indicators
|
||||
*
|
||||
@@ -160,13 +159,16 @@ onlp_sysi_platform_manage_leds(void)
|
||||
mode = ONLP_LED_MODE_GREEN;
|
||||
if(onlp_fani_info_get(ONLP_FAN_ID_CREATE(fan_number), &fi) < 0) {
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else if( (fi.status & 0x1) == 0) {
|
||||
else if( (fi.status & ONLP_FAN_STATUS_PRESENT) == 0) {
|
||||
/* Not present */
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else if(fi.status & ONLP_FAN_STATUS_FAILED) {
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -174,18 +176,22 @@ onlp_sysi_platform_manage_leds(void)
|
||||
if( fi.rpm < min_fan_speed)
|
||||
{
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
}
|
||||
/* check fan i+1 */
|
||||
if(onlp_fani_info_get(ONLP_FAN_ID_CREATE(fan_number+1), &fi) < 0) {
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else if( (fi.status & 0x1) == 0) {
|
||||
/* Not present */
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else if(fi.status & ONLP_FAN_STATUS_FAILED) {
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -193,10 +199,41 @@ onlp_sysi_platform_manage_leds(void)
|
||||
if( fi.rpm < min_fan_speed)
|
||||
{
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
fan_problem = 1;
|
||||
}
|
||||
}
|
||||
onlp_ledi_mode_set(ONLP_OID_TYPE_CREATE(ONLP_OID_TYPE_LED,fan_led_id[fan_number/2]), mode);
|
||||
}
|
||||
|
||||
for (psu_number = 1; psu_number <= CHASSIS_PSU_COUNT; psu_number++)
|
||||
{
|
||||
onlp_psu_info_t pi;
|
||||
if(onlp_psui_info_get(ONLP_PSU_ID_CREATE(psu_number), &pi) < 0) {
|
||||
psu_problem = 1;
|
||||
}
|
||||
else if((pi.status & ONLP_PSU_STATUS_PRESENT) == 0) {
|
||||
/* Not present */
|
||||
psu_problem = 1;
|
||||
}
|
||||
else if(pi.status & ONLP_PSU_STATUS_UNPLUGGED) {
|
||||
psu_problem = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (psu_problem)
|
||||
mode = ONLP_LED_MODE_RED;
|
||||
else
|
||||
mode = ONLP_LED_MODE_GREEN;
|
||||
onlp_ledi_mode_set(ONLP_OID_TYPE_CREATE(ONLP_OID_TYPE_LED, LED_PSU), mode);
|
||||
|
||||
/* Set System status LED green if no problem in FANs or PSUs */
|
||||
if (fan_problem || psu_problem)
|
||||
system_mode = ONLP_LED_MODE_RED;
|
||||
else
|
||||
system_mode = ONLP_LED_MODE_GREEN;
|
||||
|
||||
onlp_ledi_mode_set(ONLP_OID_TYPE_CREATE(ONLP_OID_TYPE_LED,LED_SYSTEM), system_mode);
|
||||
|
||||
return ONLP_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ x86-64-mlnx-msn2700-r0:
|
||||
--stop=1
|
||||
|
||||
kernel:
|
||||
<<: *kernel-3-16
|
||||
<<: *kernel-4-9
|
||||
|
||||
args: >-
|
||||
nopat
|
||||
|
||||
Reference in New Issue
Block a user