diff --git a/.gitignore b/.gitignore index 85987cbc05..7d355b8ff4 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,12 @@ target/ *.deb *.changes *.buildinfo +*.tar +*.xz +*.gz +*-dbg +*dbg.j2 +*.img # Subdirectories in src src/bash/* @@ -43,6 +49,8 @@ src/libnl3/* !src/libnl3/Makefile src/libteam/* !src/libteam/Makefile +src/libyang/* +!src/libyang/Makefile src/lldpd/* !src/lldpd/Makefile !src/lldpd/patch/ @@ -59,6 +67,8 @@ src/radvd/* !src/radvd/patch/ src/redis/* !src/redis/Makefile +src/smartmontools/* +!src/smartmontools/Makefile src/snmpd/* !src/snmpd/Makefile src/sonic-device-data/src/device/ @@ -66,6 +76,8 @@ src/sonic-device-data/src/debian/ src/supervisor/* !src/supervisor/Makefile !src/supervisor/patch/ +src/swig/* +!src/swig/Makefile src/telemetry/debian/* !src/telemetry/debian/changelog !src/telemetry/debian/compat @@ -109,3 +121,7 @@ src/sonic-config-engine/sonic_config_engine.egg-info src/sonic-daemon-base/**/*.pyc src/sonic-daemon-base/build src/sonic-daemon-base/sonic_daemon_base.egg-info + +# Misc. files +files/initramfs-tools/arista-convertfs +files/initramfs-tools/union-mount diff --git a/.gitmodules b/.gitmodules index 4e230df90d..3d2a8e3f7a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -47,6 +47,7 @@ [submodule "src/sonic-frr/frr"] path = src/sonic-frr/frr url = https://github.com/Azure/sonic-frr.git + branch = frr/7.0 [submodule "platform/p4/p4-hlir/p4-hlir-v1.1"] path = platform/p4/p4-hlir/p4-hlir-v1.1 url = https://github.com/p4lang/p4-hlir.git diff --git a/Makefile b/Makefile index f3908ce55c..c949171a89 100644 --- a/Makefile +++ b/Makefile @@ -1,20 +1,20 @@ # SONiC make file -NOSTRETCH ?= 0 +NOJESSIE ?= 0 %:: @echo "+++ --- Making $@ --- +++" -ifeq ($(NOSTRETCH), 0) - BLDENV=stretch EXTRA_STRETCH_TARGETS=$(notdir $@) make -f Makefile.work stretch +ifeq ($(NOJESSIE), 0) + EXTRA_JESSIE_TARGETS=$(notdir $@) make -f Makefile.work jessie endif - make -f Makefile.work $@ + BLDENV=stretch make -f Makefile.work $@ -stretch: +jessie: @echo "+++ Making $@ +++" -ifeq ($(NOSTRETCH), 0) - BLDENV=stretch make -f Makefile.work stretch +ifeq ($(NOJESSIE), 0) + make -f Makefile.work jessie endif clean reset init configure showtag sonic-slave-build sonic-slave-bash : @echo "+++ Making $@ +++" - make -f Makefile.work $@ + BLDENV=stretch make -f Makefile.work $@ diff --git a/Makefile.work b/Makefile.work index 95e7a2af44..975b9a5dcd 100644 --- a/Makefile.work +++ b/Makefile.work @@ -20,11 +20,10 @@ # * Please note that with current Stretch build structure, # * user of KEEP_SLAVE_ON feature will have to be conscious # * about which docker to stay inside after build is done. -# * - If user desires to stay inside Stretch docker, please issue -# * make KEEP_SLAVE_ON=yes stretch # * - If user desires to stay inside Jessie docker, please issue -# * (a successful "make stretch" may be needed before the following command) -# * make NOSTRETCH=1 KEEP_SLAVE_ON=yes +# * make KEEP_SLAVE_ON=yes jessie +# * - If user desires to stay inside Stretch docker, please issue +# * make NOJESSIE=1 KEEP_SLAVE_ON=yes # * SOURCE_FOLDER: host path to be mount as /var/$(USER)/src, only effective when KEEP_SLAVE_ON=yes # * SONIC_BUILD_JOBS: Specifying number of concurrent build job(s) to run # * VS_PREPARE_MEM: Prepare memory in VS build (drop cache and compact). @@ -123,7 +122,7 @@ SONIC_BUILD_INSTRUCTION := make \ HTTP_PROXY=$(http_proxy) \ HTTPS_PROXY=$(https_proxy) \ SONIC_ENABLE_SYSTEM_TELEMETRY=$(ENABLE_SYSTEM_TELEMETRY) \ - EXTRA_STRETCH_TARGETS=$(EXTRA_STRETCH_TARGETS) \ + EXTRA_JESSIE_TARGETS=$(EXTRA_JESSIE_TARGETS) \ $(SONIC_OVERRIDE_BUILD_VARS) .PHONY: sonic-slave-build sonic-slave-bash init reset diff --git a/README.md b/README.md index 84d08bd664..4f9ed41d22 100644 --- a/README.md +++ b/README.md @@ -71,9 +71,6 @@ To build SONiC installer image and docker images, run the following commands: # Execute make configure once to configure ASIC make configure PLATFORM=[ASIC_VENDOR] - # Build Debian Stretch required targets (Manual execution optional; will also be executed as part of the build) - BLDENV=stretch make stretch - # Build SONiC image make all diff --git a/build_debian.sh b/build_debian.sh index 614f2168e4..35b3882f83 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -160,7 +160,7 @@ sudo chmod +x $FILESYSTEM_ROOT/etc/initramfs-tools/hooks/union-fsck pushd $FILESYSTEM_ROOT/usr/share/initramfs-tools/scripts/init-bottom && sudo patch -p1 < $OLDPWD/files/initramfs-tools/udev.patch; popd ## Install latest intel ixgbe driver -sudo cp target/files/stretch/ixgbe.ko $FILESYSTEM_ROOT/lib/modules/${LINUX_KERNEL_VERSION}-amd64/kernel/drivers/net/ethernet/intel/ixgbe/ixgbe.ko +sudo cp $files_path/ixgbe.ko $FILESYSTEM_ROOT/lib/modules/${LINUX_KERNEL_VERSION}-amd64/kernel/drivers/net/ethernet/intel/ixgbe/ixgbe.ko ## Install docker echo '[INFO] Install docker' @@ -230,6 +230,7 @@ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y in usbutils \ pciutils \ iptables-persistent \ + ebtables \ logrotate \ curl \ kexec-tools \ @@ -247,6 +248,7 @@ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y in tcptraceroute \ mtr-tiny \ locales \ + flashrom \ cgroup-tools #Adds a locale to a debian system in non-interactive mode @@ -305,7 +307,7 @@ check filesystem root-overlay with path / check filesystem var-log with path /var/log if space usage > 90% for 5 times within 10 cycles then alert check system $HOST - if memory usage > 90% for 5 times within 10 cycles then alert + if memory usage > 50% for 5 times within 10 cycles then alert if cpu usage (user) > 90% for 5 times within 10 cycles then alert if cpu usage (system) > 90% for 5 times within 10 cycles then alert EOF @@ -411,6 +413,10 @@ if [ "${enable_organization_extensions}" = "y" ]; then fi fi +## Setup ebtable rules (rule file is in binary format) +sudo sed -i 's/EBTABLES_LOAD_ON_START="no"/EBTABLES_LOAD_ON_START="yes"/g' ${FILESYSTEM_ROOT}/etc/default/ebtables +sudo cp files/image_config/ebtables/ebtables.filter ${FILESYSTEM_ROOT}/etc + ## Remove gcc and python dev pkgs sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y remove gcc libpython2.7-dev diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/hx5-as4630-48x1G+4x25G+2x100G.bcm b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/hx5-as4630-48x1G+4x25G+2x100G.bcm new file mode 100755 index 0000000000..a7f89ba4c6 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/hx5-as4630-48x1G+4x25G+2x100G.bcm @@ -0,0 +1,486 @@ +stable_size=71303168 + +#polarity/lanemap is using TH2 style. +core_clock_frequency=893 +dpp_clock_ratio=2:3 + +ptp_ts_pll_fref=50000000 +ptp_bs_fref_0=50000000 +ptp_bs_fref_1=50000000 + +#oversubscribe_mode=1 + +pbmp_xport_xe=0x1FFFFFFE000000000000 + +parity_enable=0 +mem_cache_enable=1 + +l2_mem_entries=32768 +#l3_mem_entries=49152 +#fpem_mem_entries=16384 +l2xmsg_mode=1 +port_flex_enable=1 + +#3x PM4x10Q (3 * 16 = 48 physical ports) +#Doesn't support oversubscribe in Q mode +#MCQ0 +port_gmii_mode_1=1 #Q mode + +#PHY4 U56 xx1, MDC/MDIO2, PHYADDR:0x00-0x07, 0x08 +port_phy_addr_1=0x40 +port_phy_addr_2=0x41 +port_phy_addr_3=0x42 +port_phy_addr_4=0x43 +port_phy_addr_5=0x44 +port_phy_addr_6=0x45 +port_phy_addr_7=0x46 +port_phy_addr_8=0x47 +phy_port_primary_and_offset_1=0x0100 +phy_port_primary_and_offset_2=0x0101 +phy_port_primary_and_offset_3=0x0102 +phy_port_primary_and_offset_4=0x0103 +phy_port_primary_and_offset_5=0x0104 +phy_port_primary_and_offset_6=0x0105 +phy_port_primary_and_offset_7=0x0106 +phy_port_primary_and_offset_8=0x0107 +dport_map_port_1=26 +dport_map_port_2=25 +dport_map_port_3=28 +dport_map_port_4=27 +dport_map_port_5=30 +dport_map_port_6=29 +dport_map_port_7=32 +dport_map_port_8=31 +portmap_1=1:1 +portmap_2=2:1 +portmap_3=3:1 +portmap_4=4:1 +portmap_5=5:1 +portmap_6=6:1 +portmap_7=7:1 +portmap_8=8:1 +phy_chain_rx_lane_map_physical{1.0}=0x3210 +phy_chain_rx_lane_map_physical{2.0}=0x3210 +phy_chain_rx_lane_map_physical{3.0}=0x3210 +phy_chain_rx_lane_map_physical{4.0}=0x3210 +phy_chain_rx_lane_map_physical{5.0}=0x3210 +phy_chain_rx_lane_map_physical{6.0}=0x3210 +phy_chain_rx_lane_map_physical{7.0}=0x3210 +phy_chain_rx_lane_map_physical{8.0}=0x3210 +phy_chain_tx_lane_map_physical{1.0}=0x3210 +phy_chain_tx_lane_map_physical{2.0}=0x3210 +phy_chain_tx_lane_map_physical{3.0}=0x3210 +phy_chain_tx_lane_map_physical{4.0}=0x3210 +phy_chain_tx_lane_map_physical{5.0}=0x3210 +phy_chain_tx_lane_map_physical{6.0}=0x3210 +phy_chain_tx_lane_map_physical{7.0}=0x3210 +phy_chain_tx_lane_map_physical{8.0}=0x3210 +phy_chain_rx_polarity_flip_physical{1.0}=0x0 +phy_chain_rx_polarity_flip_physical{2.0}=0x0 +phy_chain_rx_polarity_flip_physical{3.0}=0x0 +phy_chain_rx_polarity_flip_physical{4.0}=0x0 +phy_chain_rx_polarity_flip_physical{5.0}=0x0 +phy_chain_rx_polarity_flip_physical{6.0}=0x0 +phy_chain_rx_polarity_flip_physical{7.0}=0x0 +phy_chain_rx_polarity_flip_physical{8.0}=0x0 +phy_chain_tx_polarity_flip_physical{1.0}=0x0 +phy_chain_tx_polarity_flip_physical{2.0}=0x0 +phy_chain_tx_polarity_flip_physical{3.0}=0x0 +phy_chain_tx_polarity_flip_physical{4.0}=0x0 +phy_chain_tx_polarity_flip_physical{5.0}=0x0 +phy_chain_tx_polarity_flip_physical{6.0}=0x0 +phy_chain_tx_polarity_flip_physical{7.0}=0x0 +phy_chain_tx_polarity_flip_physical{8.0}=0x0 + + +#PHY5 U57 x1x, MDC/MDIO2, PHYADDR:0x09-0x10, 0x11 +port_phy_addr_9=0x49 +port_phy_addr_10=0x4A +port_phy_addr_11=0x4B +port_phy_addr_12=0x4C +port_phy_addr_13=0x4D +port_phy_addr_14=0x4E +port_phy_addr_15=0x4F +port_phy_addr_16=0x50 +phy_port_primary_and_offset_9=0x0900 +phy_port_primary_and_offset_10=0x0901 +phy_port_primary_and_offset_11=0x0902 +phy_port_primary_and_offset_12=0x0903 +phy_port_primary_and_offset_13=0x0904 +phy_port_primary_and_offset_14=0x0905 +phy_port_primary_and_offset_15=0x0906 +phy_port_primary_and_offset_16=0x0907 +dport_map_port_9=34 +dport_map_port_10=33 +dport_map_port_11=36 +dport_map_port_12=35 +dport_map_port_13=38 +dport_map_port_14=37 +dport_map_port_15=40 +dport_map_port_16=39 +portmap_9=9:1 +portmap_10=10:1 +portmap_11=11:1 +portmap_12=12:1 +portmap_13=13:1 +portmap_14=14:1 +portmap_15=15:1 +portmap_16=16:1 +phy_chain_rx_lane_map_physical{9.0}=0x3210 +phy_chain_rx_lane_map_physical{10.0}=0x3210 +phy_chain_rx_lane_map_physical{11.0}=0x3210 +phy_chain_rx_lane_map_physical{12.0}=0x3210 +phy_chain_rx_lane_map_physical{13.0}=0x3210 +phy_chain_rx_lane_map_physical{14.0}=0x3210 +phy_chain_rx_lane_map_physical{15.0}=0x3210 +phy_chain_rx_lane_map_physical{16.0}=0x3210 +phy_chain_tx_lane_map_physical{9.0}=0x3210 +phy_chain_tx_lane_map_physical{10.0}=0x3210 +phy_chain_tx_lane_map_physical{11.0}=0x3210 +phy_chain_tx_lane_map_physical{12.0}=0x3210 +phy_chain_tx_lane_map_physical{13.0}=0x3210 +phy_chain_tx_lane_map_physical{14.0}=0x3210 +phy_chain_tx_lane_map_physical{15.0}=0x3210 +phy_chain_tx_lane_map_physical{16.0}=0x3210 +phy_chain_rx_polarity_flip_physical{9.0}=0x0 +phy_chain_rx_polarity_flip_physical{10.0}=0x0 +phy_chain_rx_polarity_flip_physical{11.0}=0x0 +phy_chain_rx_polarity_flip_physical{12.0}=0x0 +phy_chain_rx_polarity_flip_physical{13.0}=0x0 +phy_chain_rx_polarity_flip_physical{14.0}=0x0 +phy_chain_rx_polarity_flip_physical{15.0}=0x0 +phy_chain_rx_polarity_flip_physical{16.0}=0x0 +phy_chain_tx_polarity_flip_physical{9.0}=0x0 +phy_chain_tx_polarity_flip_physical{10.0}=0x0 +phy_chain_tx_polarity_flip_physical{11.0}=0x0 +phy_chain_tx_polarity_flip_physical{12.0}=0x0 +phy_chain_tx_polarity_flip_physical{13.0}=0x0 +phy_chain_tx_polarity_flip_physical{14.0}=0x0 +phy_chain_tx_polarity_flip_physical{15.0}=0x0 +phy_chain_tx_polarity_flip_physical{16.0}=0x0 + +#MCQ1 +port_gmii_mode_17=1 #Q mode + +#PHY6 U58 11x, MDC/MDIO2, PHYADDR:0x12-0x19, 0x1A +port_phy_addr_17=0x52 +port_phy_addr_18=0x53 +port_phy_addr_19=0x54 +port_phy_addr_20=0x55 +port_phy_addr_21=0x56 +port_phy_addr_22=0x57 +port_phy_addr_23=0x58 +port_phy_addr_24=0x59 +phy_port_primary_and_offset_17=0x1100 +phy_port_primary_and_offset_18=0x1101 +phy_port_primary_and_offset_19=0x1102 +phy_port_primary_and_offset_20=0x1103 +phy_port_primary_and_offset_21=0x1104 +phy_port_primary_and_offset_22=0x1105 +phy_port_primary_and_offset_23=0x1106 +phy_port_primary_and_offset_24=0x1107 +dport_map_port_17=42 +dport_map_port_18=41 +dport_map_port_19=44 +dport_map_port_20=43 +dport_map_port_21=46 +dport_map_port_22=45 +dport_map_port_23=48 +dport_map_port_24=47 +portmap_17=17:1 +portmap_18=18:1 +portmap_19=19:1 +portmap_20=20:1 +portmap_21=21:1 +portmap_22=22:1 +portmap_23=23:1 +portmap_24=24:1 +phy_chain_rx_lane_map_physical{17.0}=0x3210 +phy_chain_rx_lane_map_physical{18.0}=0x3210 +phy_chain_rx_lane_map_physical{19.0}=0x3210 +phy_chain_rx_lane_map_physical{20.0}=0x3210 +phy_chain_rx_lane_map_physical{21.0}=0x3210 +phy_chain_rx_lane_map_physical{22.0}=0x3210 +phy_chain_rx_lane_map_physical{23.0}=0x3210 +phy_chain_rx_lane_map_physical{24.0}=0x3210 +phy_chain_tx_lane_map_physical{17.0}=0x3210 +phy_chain_tx_lane_map_physical{18.0}=0x3210 +phy_chain_tx_lane_map_physical{19.0}=0x3210 +phy_chain_tx_lane_map_physical{20.0}=0x3210 +phy_chain_tx_lane_map_physical{21.0}=0x3210 +phy_chain_tx_lane_map_physical{22.0}=0x3210 +phy_chain_tx_lane_map_physical{23.0}=0x3210 +phy_chain_tx_lane_map_physical{24.0}=0x3210 +phy_chain_rx_polarity_flip_physical{17.0}=0x0 +phy_chain_rx_polarity_flip_physical{18.0}=0x0 +phy_chain_rx_polarity_flip_physical{19.0}=0x0 +phy_chain_rx_polarity_flip_physical{20.0}=0x0 +phy_chain_rx_polarity_flip_physical{21.0}=0x0 +phy_chain_rx_polarity_flip_physical{22.0}=0x0 +phy_chain_rx_polarity_flip_physical{23.0}=0x0 +phy_chain_rx_polarity_flip_physical{24.0}=0x0 +phy_chain_tx_polarity_flip_physical{17.0}=0x0 +phy_chain_tx_polarity_flip_physical{18.0}=0x0 +phy_chain_tx_polarity_flip_physical{19.0}=0x0 +phy_chain_tx_polarity_flip_physical{20.0}=0x0 +phy_chain_tx_polarity_flip_physical{21.0}=0x0 +phy_chain_tx_polarity_flip_physical{22.0}=0x0 +phy_chain_tx_polarity_flip_physical{23.0}=0x0 +phy_chain_tx_polarity_flip_physical{24.0}=0x0 + +#PHY1 U53 xx1, MDC/MDIO0, PHYADDR:0x00-0x07, 0x08 +port_phy_addr_25=0x00 +port_phy_addr_26=0x01 +port_phy_addr_27=0x02 +port_phy_addr_28=0x03 +port_phy_addr_29=0x04 +port_phy_addr_30=0x05 +port_phy_addr_31=0x06 +port_phy_addr_32=0x07 +phy_port_primary_and_offset_25=0x1900 +phy_port_primary_and_offset_26=0x1901 +phy_port_primary_and_offset_27=0x1902 +phy_port_primary_and_offset_28=0x1903 +phy_port_primary_and_offset_29=0x1904 +phy_port_primary_and_offset_30=0x1905 +phy_port_primary_and_offset_31=0x1906 +phy_port_primary_and_offset_32=0x1907 +dport_map_port_25=2 +dport_map_port_26=1 +dport_map_port_27=4 +dport_map_port_28=3 +dport_map_port_29=6 +dport_map_port_30=5 +dport_map_port_31=8 +dport_map_port_32=7 +portmap_25=25:1 +portmap_26=26:1 +portmap_27=27:1 +portmap_28=28:1 +portmap_29=29:1 +portmap_30=30:1 +portmap_31=31:1 +portmap_32=32:1 +phy_chain_rx_lane_map_physical{25.0}=0x3210 +phy_chain_rx_lane_map_physical{26.0}=0x3210 +phy_chain_rx_lane_map_physical{27.0}=0x3210 +phy_chain_rx_lane_map_physical{28.0}=0x3210 +phy_chain_rx_lane_map_physical{29.0}=0x3210 +phy_chain_rx_lane_map_physical{30.0}=0x3210 +phy_chain_rx_lane_map_physical{31.0}=0x3210 +phy_chain_rx_lane_map_physical{32.0}=0x3210 +phy_chain_tx_lane_map_physical{25.0}=0x3210 +phy_chain_tx_lane_map_physical{26.0}=0x3210 +phy_chain_tx_lane_map_physical{27.0}=0x3210 +phy_chain_tx_lane_map_physical{28.0}=0x3210 +phy_chain_tx_lane_map_physical{29.0}=0x3210 +phy_chain_tx_lane_map_physical{30.0}=0x3210 +phy_chain_tx_lane_map_physical{31.0}=0x3210 +phy_chain_tx_lane_map_physical{32.0}=0x3210 +phy_chain_rx_polarity_flip_physical{25.0}=0x0 +phy_chain_rx_polarity_flip_physical{26.0}=0x0 +phy_chain_rx_polarity_flip_physical{27.0}=0x0 +phy_chain_rx_polarity_flip_physical{28.0}=0x0 +phy_chain_rx_polarity_flip_physical{29.0}=0x0 +phy_chain_rx_polarity_flip_physical{30.0}=0x0 +phy_chain_rx_polarity_flip_physical{31.0}=0x0 +phy_chain_rx_polarity_flip_physical{32.0}=0x0 +phy_chain_tx_polarity_flip_physical{25.0}=0x0 +phy_chain_tx_polarity_flip_physical{26.0}=0x0 +phy_chain_tx_polarity_flip_physical{27.0}=0x0 +phy_chain_tx_polarity_flip_physical{28.0}=0x0 +phy_chain_tx_polarity_flip_physical{29.0}=0x0 +phy_chain_tx_polarity_flip_physical{30.0}=0x0 +phy_chain_tx_polarity_flip_physical{31.0}=0x0 +phy_chain_tx_polarity_flip_physical{32.0}=0x0 + +#MCQ2 +port_gmii_mode_33=1 #Q mode + +#PHY2 U54 x1x, MDC/MDIO0, PHYADDR:0x09-0x10, 0x11 +port_phy_addr_33=0x0D +port_phy_addr_34=0x0E +port_phy_addr_35=0x0F +port_phy_addr_36=0x10 +port_phy_addr_37=0x09 +port_phy_addr_38=0x0A +port_phy_addr_39=0x0B +port_phy_addr_40=0x0C +phy_port_primary_and_offset_33=0x2504 +phy_port_primary_and_offset_34=0x2505 +phy_port_primary_and_offset_35=0x2506 +phy_port_primary_and_offset_36=0x2507 +phy_port_primary_and_offset_37=0x2500 +phy_port_primary_and_offset_38=0x2501 +phy_port_primary_and_offset_39=0x2502 +phy_port_primary_and_offset_40=0x2503 +dport_map_port_33=14 +dport_map_port_34=13 +dport_map_port_35=16 +dport_map_port_36=15 +dport_map_port_37=10 +dport_map_port_38=9 +dport_map_port_39=12 +dport_map_port_40=11 +portmap_33=33:1 +portmap_34=34:1 +portmap_35=35:1 +portmap_36=36:1 +portmap_37=37:1 +portmap_38=38:1 +portmap_39=39:1 +portmap_40=40:1 +phy_chain_rx_lane_map_physical{33.0}=0x3210 +phy_chain_rx_lane_map_physical{34.0}=0x3210 +phy_chain_rx_lane_map_physical{35.0}=0x3210 +phy_chain_rx_lane_map_physical{36.0}=0x3210 +phy_chain_rx_lane_map_physical{37.0}=0x3210 +phy_chain_rx_lane_map_physical{38.0}=0x3210 +phy_chain_rx_lane_map_physical{39.0}=0x3210 +phy_chain_rx_lane_map_physical{40.0}=0x3210 +phy_chain_tx_lane_map_physical{33.0}=0x3210 +phy_chain_tx_lane_map_physical{34.0}=0x3210 +phy_chain_tx_lane_map_physical{35.0}=0x3210 +phy_chain_tx_lane_map_physical{36.0}=0x3210 +phy_chain_tx_lane_map_physical{37.0}=0x3210 +phy_chain_tx_lane_map_physical{38.0}=0x3210 +phy_chain_tx_lane_map_physical{39.0}=0x3210 +phy_chain_tx_lane_map_physical{40.0}=0x3210 +phy_chain_rx_polarity_flip_physical{33.0}=0x1 +phy_chain_rx_polarity_flip_physical{34.0}=0x1 +phy_chain_rx_polarity_flip_physical{35.0}=0x1 +phy_chain_rx_polarity_flip_physical{36.0}=0x1 +phy_chain_rx_polarity_flip_physical{37.0}=0x1 +phy_chain_rx_polarity_flip_physical{38.0}=0x1 +phy_chain_rx_polarity_flip_physical{39.0}=0x1 +phy_chain_rx_polarity_flip_physical{40.0}=0x1 +phy_chain_tx_polarity_flip_physical{33.0}=0x1 +phy_chain_tx_polarity_flip_physical{34.0}=0x1 +phy_chain_tx_polarity_flip_physical{35.0}=0x1 +phy_chain_tx_polarity_flip_physical{36.0}=0x1 +phy_chain_tx_polarity_flip_physical{37.0}=0x1 +phy_chain_tx_polarity_flip_physical{38.0}=0x1 +phy_chain_tx_polarity_flip_physical{39.0}=0x1 +phy_chain_tx_polarity_flip_physical{40.0}=0x1 + +#PHY3 U55 11x, MDC/MDIO0, PHYADDR:0x12-0x19, 0x1A +port_phy_addr_41=0x16 +port_phy_addr_42=0x17 +port_phy_addr_43=0x18 +port_phy_addr_44=0x19 +port_phy_addr_45=0x12 +port_phy_addr_46=0x13 +port_phy_addr_47=0x14 +port_phy_addr_48=0x15 +phy_port_primary_and_offset_41=0x2D00 +phy_port_primary_and_offset_42=0x2D01 +phy_port_primary_and_offset_43=0x2D02 +phy_port_primary_and_offset_44=0x2D03 +phy_port_primary_and_offset_45=0x2D04 +phy_port_primary_and_offset_46=0x2D05 +phy_port_primary_and_offset_47=0x2D06 +phy_port_primary_and_offset_48=0x2D07 +dport_map_port_41=22 +dport_map_port_42=21 +dport_map_port_43=24 +dport_map_port_44=23 +dport_map_port_45=18 +dport_map_port_46=17 +dport_map_port_47=20 +dport_map_port_48=19 +portmap_41=41:1 +portmap_42=42:1 +portmap_43=43:1 +portmap_44=44:1 +portmap_45=45:1 +portmap_46=46:1 +portmap_47=47:1 +portmap_48=48:1 +phy_chain_rx_lane_map_physical{41.0}=0x3210 +phy_chain_rx_lane_map_physical{42.0}=0x3210 +phy_chain_rx_lane_map_physical{43.0}=0x3210 +phy_chain_rx_lane_map_physical{44.0}=0x3210 +phy_chain_rx_lane_map_physical{45.0}=0x3210 +phy_chain_rx_lane_map_physical{46.0}=0x3210 +phy_chain_rx_lane_map_physical{47.0}=0x3210 +phy_chain_rx_lane_map_physical{48.0}=0x3210 +phy_chain_tx_lane_map_physical{41.0}=0x3210 +phy_chain_tx_lane_map_physical{42.0}=0x3210 +phy_chain_tx_lane_map_physical{43.0}=0x3210 +phy_chain_tx_lane_map_physical{44.0}=0x3210 +phy_chain_tx_lane_map_physical{45.0}=0x3210 +phy_chain_tx_lane_map_physical{46.0}=0x3210 +phy_chain_tx_lane_map_physical{47.0}=0x3210 +phy_chain_tx_lane_map_physical{48.0}=0x3210 +phy_chain_rx_polarity_flip_physical{41.0}=0x1 +phy_chain_rx_polarity_flip_physical{42.0}=0x1 +phy_chain_rx_polarity_flip_physical{43.0}=0x1 +phy_chain_rx_polarity_flip_physical{44.0}=0x1 +phy_chain_rx_polarity_flip_physical{45.0}=0x1 +phy_chain_rx_polarity_flip_physical{46.0}=0x1 +phy_chain_rx_polarity_flip_physical{47.0}=0x1 +phy_chain_rx_polarity_flip_physical{48.0}=0x1 +phy_chain_tx_polarity_flip_physical{41.0}=0x1 +phy_chain_tx_polarity_flip_physical{42.0}=0x1 +phy_chain_tx_polarity_flip_physical{43.0}=0x1 +phy_chain_tx_polarity_flip_physical{44.0}=0x1 +phy_chain_tx_polarity_flip_physical{45.0}=0x1 +phy_chain_tx_polarity_flip_physical{46.0}=0x1 +phy_chain_tx_polarity_flip_physical{47.0}=0x1 +phy_chain_tx_polarity_flip_physical{48.0}=0x1 + +#3x PM4x25 (3 * 4 = 12 physical ports) +#FC0 +dport_map_port_49=51 +dport_map_port_50=50 +dport_map_port_51=49 +dport_map_port_52=52 +portmap_49=65:25 +portmap_50=66:25 +portmap_51=67:25 +portmap_52=68:25 +#FC1 +dport_map_port_53=57 +dport_map_port_54=58 +dport_map_port_55=59 +dport_map_port_56=60 +portmap_53=69:100:4 +#portmap_55=71:50 +#portmap_54=70:25 +#portmap_55=71:25 +#portmap_56=72:25 +#FC2 +dport_map_port_57=53 +dport_map_port_58=54 +dport_map_port_59=55 +dport_map_port_60=56 +portmap_57=73:100:4 +#portmap_59=75:50 +#portmap_58=74:25 +#portmap_59=75:25 +#portmap_60=76:25 + +#4x PM4x10 (4 * 4 = 16 physical ports) +#MC0 No connection +#MC1 No connection +#MC2 No connection +#MC3 No connection +#portmap_=49:10 +#portmap_=50:10 +#portmap_=51:10 +#portmap_=52:10 + +#portmap_=53:10 +#portmap_=54:10 +#portmap_=55:10 +#portmap_=56:10 + +#portmap_=57:10 +#portmap_=58:10 +#portmap_=59:10 +#portmap_=60:10 + +#portmap_=61:10 +#portmap_=62:10 +#portmap_=63:10 +#portmap_=64:10 diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/port_config.ini b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/port_config.ini new file mode 100755 index 0000000000..d008d016ef --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/port_config.ini @@ -0,0 +1,55 @@ +# name lanes alias index +Ethernet0 26 thousandE1 0 +Ethernet1 25 thousandE2 1 +Ethernet2 28 thousandE3 2 +Ethernet3 27 thousandE4 3 +Ethernet4 30 thousandE5 4 +Ethernet5 29 thousandE6 5 +Ethernet6 32 thousandE7 6 +Ethernet7 31 thousandE8 7 +Ethernet8 38 thousandE9 8 +Ethernet9 37 thousandE10 9 +Ethernet10 40 thousandE11 10 +Ethernet11 39 thousandE12 11 +Ethernet12 34 thousandE13 12 +Ethernet13 33 thousandE14 13 +Ethernet14 36 thousandE15 14 +Ethernet15 35 thousandE16 15 +Ethernet16 46 thousandE17 16 +Ethernet17 45 thousandE18 17 +Ethernet18 48 thousandE19 18 +Ethernet19 47 thousandE20 19 +Ethernet20 42 thousandE21 20 +Ethernet21 41 thousandE22 21 +Ethernet22 44 thousandE23 22 +Ethernet23 43 thousandE24 23 +Ethernet24 2 thousandE25 24 +Ethernet25 1 thousandE26 25 +Ethernet26 4 thousandE27 26 +Ethernet27 3 thousandE28 27 +Ethernet28 6 thousandE29 28 +Ethernet29 5 thousandE30 29 +Ethernet30 8 thousandE31 30 +Ethernet31 7 thousandE32 31 +Ethernet32 10 thousandE33 32 +Ethernet33 9 thousandE34 33 +Ethernet34 12 thousandE35 34 +Ethernet35 11 thousandE36 35 +Ethernet36 14 thousandE37 36 +Ethernet37 13 thousandE38 37 +Ethernet38 16 thousandE39 38 +Ethernet39 15 thousandE40 39 +Ethernet40 18 thousandE41 40 +Ethernet41 17 thousandE42 41 +Ethernet42 20 thousandE43 42 +Ethernet43 19 thousandE44 43 +Ethernet44 22 thousandE45 44 +Ethernet45 21 thousandE46 45 +Ethernet46 24 thousandE47 46 +Ethernet47 23 thousandE48 47 +Ethernet48 67 twentyfiveGigE49 48 +Ethernet49 66 twentyfiveGigE50 49 +Ethernet50 65 twentyfiveGigE51 50 +Ethernet51 68 twentyfiveGigE52 51 +Ethernet52 73,74,75,76 hundredGigE53 52 +Ethernet56 69,70,71,72 hundredGigE54 56 diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/sai.profile b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/sai.profile new file mode 100755 index 0000000000..5329410fe8 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/hx5-as4630-48x1G+4x25G+2x100G.bcm diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/default_sku b/device/accton/x86_64-accton_as4630_54pe-r0/default_sku new file mode 100755 index 0000000000..64e4213bdc --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/default_sku @@ -0,0 +1 @@ +Accton-AS4630-54PE t1 diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/installer.conf b/device/accton/x86_64-accton_as4630_54pe-r0/installer.conf new file mode 100755 index 0000000000..925a32fc0c --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/installer.conf @@ -0,0 +1,3 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/led_proc_init.soc b/device/accton/x86_64-accton_as4630_54pe-r0/led_proc_init.soc new file mode 100755 index 0000000000..4fa004f5d1 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/led_proc_init.soc @@ -0,0 +1,2 @@ +led start +led auto on diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as4630_54pe-r0/plugins/eeprom.py new file mode 100755 index 0000000000..0d7def70fd --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/plugins/eeprom.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +try: + import exceptions + import binascii + import time + import optparse + import warnings + import os + import sys + from sonic_eeprom import eeprom_base + from sonic_eeprom import eeprom_tlvinfo + import subprocess +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + +class board(eeprom_tlvinfo.TlvInfoDecoder): + _TLV_INFO_MAX_LEN = 256 + def __init__(self, name, path, cpld_root, ro): + self.eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/plugins/psuutil.py b/device/accton/x86_64-accton_as4630_54pe-r0/plugins/psuutil.py new file mode 100755 index 0000000000..a646981334 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/plugins/psuutil.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +############################################################################# +# Accton +# +# Module contains an implementation of SONiC PSU Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +import os.path + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + PsuBase.__init__(self) + + self.psu_path = "/sys/bus/i2c/devices/" + self.psu_presence = "/psu_present" + self.psu_oper_status = "/psu_power_good" + self.psu_mapping = { + 1: "10-0050", + 2: "11-0051", + } + + def get_num_psus(self): + return len(self.psu_mapping) + + def get_psu_status(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index]+self.psu_oper_status + try: + with open(node, 'r') as power_status: + status = int(power_status.read()) + except IOError: + return False + + return status == 1 + + def get_psu_presence(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index] + self.psu_presence + try: + with open(node, 'r') as presence_status: + status = int(presence_status.read()) + except IOError: + return False + + return status == 1 diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as4630_54pe-r0/plugins/sfputil.py new file mode 100755 index 0000000000..69c2870669 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/plugins/sfputil.py @@ -0,0 +1,103 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + + PORT_START = 48 + PORT_END = 53 + PORTS_IN_BLOCK = 54 + + BASE_OOM_PATH = "/sys/bus/i2c/devices/{0}-0050/" + BASE_CPLD_PATH = "/sys/bus/i2c/devices/3-0060/" + + _port_to_is_present = {} + _port_to_lp_mode = {} + + _port_to_eeprom_mapping = {} + _port_to_i2c_mapping = { + 48: [18], + 49: [19], + 50: [20], + 51: [21], + 52: [22], + 53: [23], + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(self.PORT_START, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = self.BASE_OOM_PATH + "eeprom" + + for x in range(0, self.port_end+1): + if x < 48: + self.port_to_eeprom_mapping[x] = eeprom_path.format(0) + else: + self.port_to_eeprom_mapping[x] = eeprom_path.format( + self._port_to_i2c_mapping[x][0]) + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + present_path = self.BASE_CPLD_PATH + "module_present_" + str(port_num+1) + self.__port_to_is_present = present_path + + try: + val_file = open(self.__port_to_is_present) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + + # content is a string, either "0" or "1" + if content == "1": + return True + + return False + + def get_low_power_mode(self, port_num): + raise NotImplementedError + + def set_low_power_mode(self, port_num, lpmode): + raise NotImplementedError + + def reset(self, port_num): + raise NotImplementedError + + def get_transceiver_change_event(self): + """ + TODO: This function need to be implemented + when decide to support monitoring SFP(Xcvrd) + on this platform. + """ + raise NotImplementedError diff --git a/device/accton/x86_64-accton_as5812_54x-r0/Accton-AS5812-54X/port_config.ini b/device/accton/x86_64-accton_as5812_54x-r0/Accton-AS5812-54X/port_config.ini new file mode 100755 index 0000000000..315fd86981 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/Accton-AS5812-54X/port_config.ini @@ -0,0 +1,73 @@ +# name lanes alias index +Ethernet0 13 tenGigE0 1 +Ethernet1 14 tenGigE1 2 +Ethernet2 15 tenGigE2 3 +Ethernet3 16 tenGigE3 4 +Ethernet4 21 tenGigE4 5 +Ethernet5 22 tenGigE5 6 +Ethernet6 23 tenGigE6 7 +Ethernet7 24 tenGigE7 8 +Ethernet8 25 tenGigE8 9 +Ethernet9 26 tenGigE9 10 +Ethernet10 27 tenGigE10 11 +Ethernet11 28 tenGigE11 12 +Ethernet12 29 tenGigE12 13 +Ethernet13 30 tenGigE13 14 +Ethernet14 31 tenGigE14 15 +Ethernet15 32 tenGigE15 16 +Ethernet16 45 tenGigE16 17 +Ethernet17 46 tenGigE17 18 +Ethernet18 47 tenGigE18 19 +Ethernet19 48 tenGigE19 20 +Ethernet20 49 tenGigE20 21 +Ethernet21 50 tenGigE21 22 +Ethernet22 51 tenGigE22 23 +Ethernet23 52 tenGigE23 24 +Ethernet24 53 tenGigE24 25 +Ethernet25 54 tenGigE25 26 +Ethernet26 55 tenGigE26 27 +Ethernet27 56 tenGigE27 28 +Ethernet28 57 tenGigE28 29 +Ethernet29 58 tenGigE29 30 +Ethernet30 59 tenGigE30 31 +Ethernet31 60 tenGigE31 32 +Ethernet32 61 tenGigE32 33 +Ethernet33 62 tenGigE33 34 +Ethernet34 63 tenGigE34 35 +Ethernet35 64 tenGigE35 36 +Ethernet36 65 tenGigE36 37 +Ethernet37 66 tenGigE37 38 +Ethernet38 67 tenGigE38 39 +Ethernet39 68 tenGigE39 40 +Ethernet40 69 tenGigE40 41 +Ethernet41 70 tenGigE41 42 +Ethernet42 71 tenGigE42 43 +Ethernet43 72 tenGigE43 44 +Ethernet44 73 tenGigE44 45 +Ethernet45 74 tenGigE45 46 +Ethernet46 75 tenGigE46 47 +Ethernet47 76 tenGigE47 48 +Ethernet48 97 tenGigE48 49 +Ethernet49 98 tenGigE49 50 +Ethernet50 99 tenGigE50 51 +Ethernet51 100 tenGigE51 52 +Ethernet52 101 tenGigE52 53 +Ethernet53 102 tenGigE53 54 +Ethernet54 103 tenGigE54 55 +Ethernet55 104 tenGigE55 56 +Ethernet56 81 tenGigE56 57 +Ethernet57 82 tenGigE57 58 +Ethernet58 83 tenGigE58 59 +Ethernet59 84 tenGigE59 60 +Ethernet60 105 tenGigE60 61 +Ethernet61 106 tenGigE61 62 +Ethernet62 107 tenGigE62 63 +Ethernet63 108 tenGigE63 64 +Ethernet64 109 tenGigE64 65 +Ethernet65 110 tenGigE65 66 +Ethernet66 111 tenGigE66 67 +Ethernet67 112 tenGigE67 68 +Ethernet68 77 tenGigE68 69 +Ethernet69 78 tenGigE69 70 +Ethernet70 79 tenGigE70 71 +EthernEt71 80 tenGigE71 72 diff --git a/device/accton/x86_64-accton_as5812_54x-r0/Accton-AS5812-54X/sai.profile b/device/accton/x86_64-accton_as5812_54x-r0/Accton-AS5812-54X/sai.profile new file mode 100755 index 0000000000..063814c1fc --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/Accton-AS5812-54X/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td2-as5812-72x10G.config.bcm diff --git a/device/accton/x86_64-accton_as5812_54x-r0/Accton-AS5812-54X/td2-as5812-72x10G.config.bcm b/device/accton/x86_64-accton_as5812_54x-r0/Accton-AS5812-54X/td2-as5812-72x10G.config.bcm new file mode 100644 index 0000000000..4844616d03 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/Accton-AS5812-54X/td2-as5812-72x10G.config.bcm @@ -0,0 +1,148 @@ +os=unix +bcm_stat_flags=0 +parity_enable=0 +parity_correction=0 + +bcm_num_cos=8 +l2_mem_entries=32768 +l3_mem_entries=16384 +l3_alpm_enable=2 +ipv6_lpm_128b_enable=1 + +mmu_lossless=0 +lls_num_l2uc=12 +module_64ports=0 + +#SFI +serdes_if_type=9 + +port_init_cl72=0 +phy_an_c73=5 # TSCMOD_CL73_CL37 + +#sdk6.5.5 only supports 156(default) or 125 +#xgxs_lcpll_xtal_refclk=1 +tslam_dma_enable=1 +table_dma_enable=1 + +#for 72 ports with 48 10G ports and 6 40G ports for breakout mode +pbmp_oversubscribe=0x1fffffffffffffffffe +pbmp_xport_xe=0x1fffffffffffffffffe + +rate_ext_mdio_divisor=96 + +#SFP+ 1-4 from WC3 +portmap_1=13:10 +portmap_2=14:10 +portmap_3=15:10 +portmap_4=16:10 + +#SFP+ 5-8 from WC5 +portmap_5=21:10 +portmap_6=22:10 +portmap_7=23:10 +portmap_8=24:10 + +#SFP+ 9-12 from WC6 +portmap_9=25:10 +portmap_10=26:10 +portmap_11=27:10 +portmap_12=28:10 + +#SFP+ 13-16 from WC7 +portmap_13=29:10 +portmap_14=30:10 +portmap_15=31:10 +portmap_16=32:10 + +#SFP+ 17-20 from WC11 +portmap_17=45:10 +portmap_18=46:10 +portmap_19=47:10 +portmap_20=48:10 + +#SFP+ 21-24 from WC12 +portmap_21=49:10 +portmap_22=50:10 +portmap_23=51:10 +portmap_24=52:10 + +#SFP+ 25-28 from WC13 +portmap_25=53:10 +portmap_26=54:10 +portmap_27=55:10 +portmap_28=56:10 + +#SFP+ 29-32 from WC14 +portmap_29=57:10 +portmap_30=58:10 +portmap_31=59:10 +portmap_32=60:10 + +#SFP+ 33-36 from WC15 +portmap_33=61:10 +portmap_34=62:10 +portmap_35=63:10 +portmap_36=64:10 + +#SFP+ 37-40 from WC16 +portmap_37=65:10 +portmap_38=66:10 +portmap_39=67:10 +portmap_40=68:10 + +#SFP+ 41-44 from WC17 +portmap_41=69:10 +portmap_42=70:10 +portmap_43=71:10 +portmap_44=72:10 + +#SFP+ 45-48 from WC18 +portmap_45=73:10 +portmap_46=74:10 +portmap_47=75:10 +portmap_48=76:10 + +# QSFP+ 49/WC24/port 49 +portmap_49=97:10 +portmap_50=98:10 +portmap_51=99:10 +portmap_52=100:10 + +# QSFP+ 51/WC25/port 50 +portmap_53=101:10 +portmap_54=102:10 +portmap_55=103:10 +portmap_56=104:10 + +# QSFP+ 53/WC20/port 51 +portmap_57=81:10 +portmap_58=82:10 +portmap_59=83:10 +portmap_60=84:10 + +# QSFP+ 50/WC26/port 52 +portmap_61=105:10 +portmap_62=106:10 +portmap_63=107:10 +portmap_64=108:10 + +# QSFP+ 52/WC27/port 53 +portmap_65=109:10 +portmap_66=110:10 +portmap_67=111:10 +portmap_68=112:10 + +# QSFP+ 54/WC19/port 54 +portmap_69=77:10 +portmap_70=78:10 +portmap_71=79:10 +portmap_72=80:10 + +# L3 ECMP +# - In Trident2, VP LAGs share the same table as ECMP group table. +# The first N entries are reserved for VP LAGs, where N is the value of the +# config property "max_vp_lags". By default this was set to 256 +l3_max_ecmp_mode=1 +max_vp_lags=0 + +stable_size=0x2000000 diff --git a/device/accton/x86_64-accton_as5812_54x-r0/default_sku b/device/accton/x86_64-accton_as5812_54x-r0/default_sku new file mode 100644 index 0000000000..b52f975041 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/default_sku @@ -0,0 +1 @@ +Accton-AS5812-54X t1 diff --git a/device/accton/x86_64-accton_as5812_54x-r0/installer.conf b/device/accton/x86_64-accton_as5812_54x-r0/installer.conf new file mode 100644 index 0000000000..14404194ef --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/installer.conf @@ -0,0 +1,3 @@ +CONSOLE_PORT=0x2f8 +CONSOLE_DEV=1 +CONSOLE_SPEED=115200 diff --git a/device/accton/x86_64-accton_as5812_54x-r0/led_proc_init.soc b/device/accton/x86_64-accton_as5812_54x-r0/led_proc_init.soc new file mode 100644 index 0000000000..d93e373d05 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/led_proc_init.soc @@ -0,0 +1,162 @@ +# LED setting for active +# ----------------------------------------------------------------------------- +# for as5812_54x (48xg+6qxg) +# +# on green - if link up +# off - if link down +# blink - if active +# ----------------------------------------------------------------------------- +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0 +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1 +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2 +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48 +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49 +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50 +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_63=0 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_62=1 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_61=2 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_59=4 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_58=5 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_57=6 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_55=8 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_54=9 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_53=10 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_51=12 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_50=13 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_49=14 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_35=16 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_34=17 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_33=18 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=19 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_39=20 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_38=21 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_37=22 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=23 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_43=24 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_42=25 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_41=26 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=27 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_47=28 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_46=29 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_45=30 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=31 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_31=32 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_30=33 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_29=34 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_27=36 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_26=37 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_25=38 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_23=40 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_22=41 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_21=42 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_19=44 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_18=45 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_17=46 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_3=48 +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_2=49 +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_1=50 +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=51 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_7=52 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_6=53 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_5=54 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=55 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_11=56 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_10=57 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_9=58 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=59 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_15=60 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_14=61 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_13=62 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=63 + +led 0 stop +led 0 prog \ + 06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \ + 61 FD 02 3F 60 FF 28 32 0F 87 67 4A 96 FF 06 FF \ + D2 2B 74 16 02 1F 60 FF 28 32 0F 87 67 4A 96 FF \ + 06 FF D2 13 74 28 02 0F 60 FF 28 32 0F 87 67 4A \ + 96 FF 06 FF D2 0B 74 3A 3A 48 32 07 32 08 C7 32 \ + 04 C7 97 71 57 77 69 32 00 32 01 B7 97 71 63 32 \ + 0E 77 6B 26 FD 97 27 77 6B 32 0F 87 57 00 00 00 +led 0 start + +led 1 stop +led 1 prog \ + 06 FE 80 D2 19 71 08 E0 60 FE E9 D2 0F 75 10 81 \ + 61 FD 02 20 67 89 02 24 67 89 02 10 67 89 02 28 \ + 67 89 02 2C 67 89 02 0C 67 89 02 2C 67 79 02 28 \ + 67 79 02 24 67 79 02 20 67 79 02 10 67 79 02 0C \ + 67 79 02 0B 60 FF 28 32 0F 87 67 56 96 FF 06 FF \ + D2 FF 74 46 3A 36 32 07 32 08 C7 32 04 C7 97 71 \ + 63 77 75 32 00 32 01 B7 97 71 6F 32 0E 77 77 26 \ + FD 97 27 77 77 32 0F 87 57 12 A0 F8 15 1A 01 75 \ + 85 28 67 56 57 32 0F 87 57 12 A0 F8 15 1A 01 71 \ + A1 28 67 56 80 28 67 56 80 28 67 56 80 28 67 56 \ + 57 32 0F 87 32 0F 87 32 0F 87 32 0F 87 57 00 00 +led 1 start diff --git a/device/accton/x86_64-accton_as5812_54x-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as5812_54x-r0/plugins/eeprom.py new file mode 100644 index 0000000000..7681caafee --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/plugins/eeprom.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +try: + import exceptions + import binascii + import time + import optparse + import warnings + import os + import sys + from sonic_eeprom import eeprom_base + from sonic_eeprom import eeprom_tlvinfo + import subprocess +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + +class board(eeprom_tlvinfo.TlvInfoDecoder): + _TLV_INFO_MAX_LEN = 256 + def __init__(self, name, path, cpld_root, ro): + self.eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom" + #Two i2c buses might get flipped order, check them both. + if not os.path.exists(self.eeprom_path): + self.eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/accton/x86_64-accton_as5812_54x-r0/plugins/psuutil.py b/device/accton/x86_64-accton_as5812_54x-r0/plugins/psuutil.py new file mode 100755 index 0000000000..841070637b --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/plugins/psuutil.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +############################################################################# +# Accton +# +# Module contains an implementation of SONiC PSU Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +import os.path + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + PsuBase.__init__(self) + + self.psu_path = "/sys/bus/i2c/devices/" + self.psu_presence = "/psu_present" + self.psu_oper_status = "/psu_power_good" + self.psu_mapping = { + 1: "57-0038", + 2: "58-003b", + } + + def get_num_psus(self): + return len(self.psu_mapping) + + def get_psu_status(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index]+self.psu_oper_status + try: + with open(node, 'r') as power_status: + status = int(power_status.read()) + except IOError: + return False + + return status == 1 + + def get_psu_presence(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index] + self.psu_presence + try: + with open(node, 'r') as presence_status: + status = int(presence_status.read()) + except IOError: + return False + + return status == 1 diff --git a/device/accton/x86_64-accton_as5812_54x-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as5812_54x-r0/plugins/sfputil.py new file mode 100755 index 0000000000..0200aa1449 --- /dev/null +++ b/device/accton/x86_64-accton_as5812_54x-r0/plugins/sfputil.py @@ -0,0 +1,311 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# +try: + import time + import os + import pickle + from ctypes import create_string_buffer + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 72 + PORTS_IN_BLOCK = 72 + QSFP_PORT_START = 48 + QSFP_PORT_END = 72 + + BASE_VAL_PATH = "/sys/class/i2c-adapter/i2c-{0}/{1}-0050/" + BASE_OOM_PATH = "/sys/bus/i2c/devices/{0}-0050/" + BASE_CPLD2_PATH = "/sys/bus/i2c/devices/{0}-0061/" + BASE_CPLD3_PATH = "/sys/bus/i2c/devices/{0}-0062/" + I2C_BUS_ORDER = -1 + + #The sidebands of QSFP is different. + #present is in-order. + #But lp_mode and reset are not. + qsfp_sb_map = [1, 3, 5, 2, 4, 6] + + _port_to_is_present = {} + _port_to_lp_mode = {} + + _port_to_eeprom_mapping = {} + _port_to_i2c_mapping = { + 1: [1, 2], + 2: [2, 3], + 3: [3, 4], + 4: [4, 5], + 5: [5, 6], + 6: [6, 7], + 7: [7, 8], + 8: [8, 9], + 9: [9, 10], + 10: [10, 11], + 11: [11, 12], + 12: [12, 13], + 13: [13, 14], + 14: [14, 15], + 15: [15, 16], + 16: [16, 17], + 17: [17, 18], + 18: [18, 19], + 19: [19, 20], + 20: [20, 21], + 21: [21, 22], + 22: [22, 23], + 23: [23, 24], + 24: [24, 25], + 25: [25, 26], + 26: [26, 27], + 27: [27, 28], + 28: [28, 29], + 29: [29, 30], + 30: [30, 31], + 31: [31, 32], + 32: [32, 33], + 33: [33, 34], + 34: [34, 35], + 35: [35, 36], + 36: [36, 37], + 37: [37, 38], + 38: [38, 39], + 39: [39, 40], + 40: [40, 41], + 41: [41, 42], + 42: [42, 43], + 43: [43, 44], + 44: [44, 45], + 45: [45, 46], + 46: [46, 47], + 47: [47, 48], + 48: [48, 49], + 49: [49, 50],#QSFP49 + 50: [49, 50], + 51: [49, 50], + 52: [49, 50], + 53: [50, 52],#QSFP50 + 54: [50, 52], + 55: [50, 52], + 56: [50, 52], + 57: [51, 54],#QSFP51 + 58: [51, 54], + 59: [51, 54], + 60: [51, 54], + 61: [52, 51],#QSFP52 + 62: [52, 51], + 63: [52, 51], + 64: [52, 51], + 65: [53, 53],#QSFP53 + 66: [53, 53], + 67: [53, 53], + 68: [53, 53], + 69: [54, 55],#QSFP54 + 70: [54, 55], + 71: [54, 55], + 72: [54, 55], + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_port_start(self): + return self.QSFP_PORT_START + + @property + def qsfp_port_end(self): + return self.QSFP_PORT_END + + @property + def qsfp_ports(self): + return range(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = self.BASE_OOM_PATH + "eeprom" + + for x in range(self.port_start, self.port_end+1): + self.port_to_eeprom_mapping[x] = eeprom_path.format( + self._port_to_i2c_mapping[x][1] + ) + + SfpUtilBase.__init__(self) + + #Two i2c buses might get flipped order, check them both. + def update_i2c_order(self): + if os.path.exists("/tmp/accton_util.p"): + self.I2C_BUS_ORDER = pickle.load(open("/tmp/accton_util.p", "rb")) + else: + if self.I2C_BUS_ORDER < 0: + eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom" + if os.path.exists(eeprom_path): + self.I2C_BUS_ORDER = 0 + eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom" + if os.path.exists(eeprom_path): + self.I2C_BUS_ORDER = 1 + return self.I2C_BUS_ORDER + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + order = self.update_i2c_order() + if port_num <= 24: + present_path = self.BASE_CPLD2_PATH.format(order) + else: + present_path = self.BASE_CPLD3_PATH.format(order) + + present_path = present_path + "module_present_" + str(self._port_to_i2c_mapping[port_num][0]) + self.__port_to_is_present = present_path + + try: + val_file = open(self.__port_to_is_present) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + + # content is a string, either "0" or "1" + if content == "1": + return True + + return False + + def qsfp_sb_remap(self, port_num): + qsfp_start = self.qsfp_port_start + qsfp_index = self._port_to_i2c_mapping[port_num][0] - qsfp_start + qsfp_index = self.qsfp_sb_map[qsfp_index-1] + return qsfp_start+qsfp_index + + def get_low_power_mode_cpld(self, port_num): + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + order = self.update_i2c_order() + lp_mode_path = self.BASE_CPLD3_PATH.format(order) + lp_mode_path = lp_mode_path + "module_lp_mode_" + q = self.qsfp_sb_remap(port_num) + lp_mode_path = lp_mode_path + str(q) + + try: + val_file = open(lp_mode_path) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + + # content is a string, either "0" or "1" + if content == "1": + return True + + return False + + def get_low_power_mode(self, port_num): + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + if not self.get_presence(port_num): + return self.get_low_power_mode_cpld(port_num) + + try: + eeprom = None + + eeprom = open(self.port_to_eeprom_mapping[port_num], "rb") + eeprom.seek(93) + lpmode = ord(eeprom.read(1)) + + if not (lpmode & 0x1): # 'Power override' bit is 0 + return self.get_low_power_mode_cpld(port_num) + else: + if ((lpmode & 0x2) == 0x2): + return True # Low Power Mode if "Power set" bit is 1 + else: + return False # High Power Mode if "Power set" bit is 0 + except IOError as err: + print "Error: unable to open file: %s" % str(err) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + + def set_low_power_mode(self, port_num, lpmode): + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + try: + eeprom = None + + if not self.get_presence(port_num): + return False # Port is not present, unable to set the eeprom + + # Fill in write buffer + regval = 0x3 if lpmode else 0x1 # 0x3:Low Power Mode, 0x1:High Power Mode + buffer = create_string_buffer(1) + buffer[0] = chr(regval) + + # Write to eeprom + eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b") + eeprom.seek(93) + eeprom.write(buffer[0]) + return True + except IOError as err: + print "Error: unable to open file: %s" % str(err) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + + def reset(self, port_num): + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + order = self.update_i2c_order() + lp_mode_path = self.BASE_CPLD3_PATH.format(order) + mod_rst_path = lp_mode_path + "module_reset_" + q = self.qsfp_sb_remap(port_num) + mod_rst_path = mod_rst_path + str(q) + + try: + reg_file = open(mod_rst_path, 'r+') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + #toggle reset + reg_file.seek(0) + reg_file.write('0') + time.sleep(1) + reg_file.seek(0) + reg_file.write('1') + reg_file.close() + return True + + def get_transceiver_change_event(self): + """ + TODO: This function need to be implemented + when decide to support monitoring SFP(Xcvrd) + on this platform. + """ + raise NotImplementedError + diff --git a/device/accton/x86_64-accton_as7326_56x-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as7326_56x-r0/plugins/sfputil.py index 4844d22015..eca0abc39e 100644 --- a/device/accton/x86_64-accton_as7326_56x-r0/plugins/sfputil.py +++ b/device/accton/x86_64-accton_as7326_56x-r0/plugins/sfputil.py @@ -5,6 +5,8 @@ try: import time + import string + from ctypes import create_string_buffer from sonic_sfp.sfputilbase import SfpUtilBase except ImportError as e: raise ImportError("%s - required module not found" % str(e)) @@ -193,11 +195,63 @@ class SfpUtil(SfpUtilBase): return False - def get_low_power_mode(self, port_num): - raise NotImplementedError + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False - def set_low_power_mode(self, port_num, lpmode): - raise NotImplementedError + try: + eeprom = None + + if not self.get_presence(port_num): + return False + + eeprom = open(self.port_to_eeprom_mapping[port_num], "rb") + eeprom.seek(93) + lpmode = ord(eeprom.read(1)) + + if ((lpmode & 0x3) == 0x1): + return False # High Power Mode if "Power override" bit is 1 and "Power set" bit is 0 + else: + return True # Low Power Mode if one of the following conditions is matched: + # 1. Power override" bit is 0 + # 2. Power override" bit is 1 and "Power set" bit is 1 + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + try: + eeprom = None + + if not self.get_presence(port_num): + return False # Port is not present, unable to set the eeprom + + # Fill in write buffer + regval = 0x3 if lpmode else 0x1 # 0x3:Low Power Mode, 0x1:High Power Mode + buffer = create_string_buffer(1) + buffer[0] = chr(regval) + + # Write to eeprom + eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b") + eeprom.seek(93) + eeprom.write(buffer[0]) + return True + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) def reset(self, port_num): raise NotImplementedError diff --git a/device/accton/x86_64-accton_as7712_32x-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as7712_32x-r0/plugins/sfputil.py index 5d1346e9b9..f70916ca43 100644 --- a/device/accton/x86_64-accton_as7712_32x-r0/plugins/sfputil.py +++ b/device/accton/x86_64-accton_as7712_32x-r0/plugins/sfputil.py @@ -2,6 +2,8 @@ try: import time + import string + from ctypes import create_string_buffer from sonic_sfp.sfputilbase import SfpUtilBase except ImportError, e: raise ImportError (str(e) + "- required module not found") @@ -81,12 +83,6 @@ class SfpUtil(SfpUtilBase): reg_file.write('0') reg_file.close() return True - - def set_low_power_mode(self, port_nuM, lpmode): - raise NotImplementedError - - def get_low_power_mode(self, port_num): - raise NotImplementedError def get_presence(self, port_num): # Check for invalid port_num @@ -132,3 +128,61 @@ class SfpUtil(SfpUtilBase): on this platform. """ raise NotImplementedError + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self._port_start or port_num > self._port_end: + return False + + try: + eeprom = None + + if not self.get_presence(port_num): + return False + + eeprom = open(self.port_to_eeprom_mapping[port_num], "rb") + eeprom.seek(93) + lpmode = ord(eeprom.read(1)) + + if ((lpmode & 0x3) == 0x3): + return True # Low Power Mode if "Power override" bit is 1 and "Power set" bit is 1 + else: + return False # High Power Mode if one of the following conditions is matched: + # 1. "Power override" bit is 0 + # 2. "Power override" bit is 1 and "Power set" bit is 0 + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self._port_start or port_num > self._port_end: + return False + + try: + eeprom = None + + if not self.get_presence(port_num): + return False # Port is not present, unable to set the eeprom + + # Fill in write buffer + regval = 0x3 if lpmode else 0x1 # 0x3:Low Power Mode, 0x1:High Power Mode + buffer = create_string_buffer(1) + buffer[0] = chr(regval) + + # Write to eeprom + eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b") + eeprom.seek(93) + eeprom.write(buffer[0]) + return True + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) \ No newline at end of file diff --git a/device/arista/x86_64-arista_7050_qx32/platform_reboot b/device/arista/x86_64-arista_7050_qx32/platform_reboot deleted file mode 100755 index da438b8fe5..0000000000 --- a/device/arista/x86_64-arista_7050_qx32/platform_reboot +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2018 Arista Networks, Inc. All rights reserved. -# Arista Networks, Inc. Confidential and Proprietary. - -# Reboot script for 7050QX-32 - -from __future__ import print_function -import sys -import mmap, os -import subprocess -from struct import pack, unpack - -class MmapResource( object ): - """Resource implementation for a directly-mapped memory region.""" - - def __init__( self, path ): - try: - fd = os.open( path, os.O_RDWR ) - except EnvironmentError: - print( "FAIL can not open scd memory-map resource file" ) - print( "FAIL are you running on the proper platform?" ) - sys.exit( 1 ) - try: - size = os.fstat( fd ).st_size - except EnvironmentError: - print( "FAIL can not fstat scd memory-map resource file" ) - print( "FAIL are you running on the proper platform?" ) - sys.exit( 1 ) - try: - self.mmap_ = mmap.mmap( fd, size, mmap.MAP_SHARED, - mmap.PROT_READ | mmap.PROT_WRITE ) - except EnvironmentError: - print( "FAIL can not map scd memory-map file" ) - print( "FAIL are you running on the proper platform?" ) - sys.exit( 1 ) - finally: - try: - # Note that closing the file descriptor has no effect on the memory map - os.close( fd ) - except EnvironmentError: - print( "FAIL failed to close scd memory-map file" ) - sys.exit( 1 ) - - def read32( self, addr ): - return unpack( ' self.port_end: return False - # Port offset starts with 0x4000 - port_offset = 16384 + ((port_num) * 16) + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) - status = self.pci_get_value(self.BASE_RES_PATH, port_offset) - reg_value = int(status) + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) # Absence of status throws error - if (reg_value == "" ): + if (reg_value == ""): return False # Mask off 4th bit for presence @@ -149,44 +152,44 @@ class SfpUtil(SfpUtilBase): if port_num < self.port_start or port_num > self.port_end: return False - # Port offset starts with 0x4000 - port_offset = 16384 + ((port_num) * 16) + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) - status = self.pci_get_value(self.BASE_RES_PATH, port_offset) - reg_value = int(status) + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) # Absence of status throws error - if (reg_value == "" ): + if (reg_value == ""): return False # Mask off 4th bit for presence mask = (1 << 6) - - # LPMode is active high; set or clear the bit accordingly + + # LPMode is active high; set or clear the bit accordingly if lpmode is True: reg_value = reg_value | mask else: reg_value = reg_value & ~mask # Convert our register value back to a hex string and write back - status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) return True def reset(self, port_num): - # Check for invalid port_num + # Check for invalid port_num if port_num < self.port_start or port_num > self.port_end: return False - # Port offset starts with 0x4000 - port_offset = 16384 + ((port_num) * 16) + # Port offset starts with 0x4000 + port_offset = 16384 + ((port_num-1) * 16) - status = self.pci_get_value(self.BASE_RES_PATH, port_offset) - reg_value = int(status) + status = self.pci_get_value(self.BASE_RES_PATH, port_offset) + reg_value = int(status) # Absence of status throws error - if (reg_value == "" ): + if (reg_value == ""): return False # Mask off 4th bit for presence @@ -195,33 +198,106 @@ class SfpUtil(SfpUtilBase): # ResetL is active low reg_value = reg_value & ~mask - # Convert our register value back to a hex string and write back - status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) # Sleep 1 second to allow it to settle time.sleep(1) reg_value = reg_value | mask - # Convert our register value back to a hex string and write back - status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + # Convert our register value back to a hex string and write back + status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) return True - def get_transceiver_change_event(self): - port_dict = {} - while True: + def get_register(self, reg_file): + retval = 'ERR' + if (not path.isfile(reg_file)): + print reg_file, 'not found !' + return retval + + try: + with fdopen(open(reg_file, O_RDONLY)) as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", reg_file, "file !") + + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + return retval + + def check_interrupts(self, port_dict): + retval = 0 + is_port_dict_updated = False for port_num in range(self.port_start, (self.port_end + 1)): presence = self.get_presence(port_num) if(presence and self._global_port_pres_dict[port_num] == '0'): + is_port_dict_updated = True self._global_port_pres_dict[port_num] = '1' port_dict[port_num] = '1' elif(not presence and self._global_port_pres_dict[port_num] == '1'): + is_port_dict_updated = True self._global_port_pres_dict[port_num] = '0' port_dict[port_num] = '0' + return retval, is_port_dict_updated - if(len(port_dict) > 0): - return True, port_dict + def get_transceiver_change_event(self, timeout=0): + port_dict = {} + try: + # We get notified when there is a MSI interrupt (vector 4/5)CVR + # Open the sysfs file and register the epoll object + self.oir_fd = fdopen(open(self.OIR_FD_PATH, O_RDONLY)) + if self.oir_fd != -1: + # Do a dummy read before epoll register + self.oir_fd.read() + self.epoll = select.epoll() + self.epoll.register( + self.oir_fd.fileno(), select.EPOLLIN & select.EPOLLET) + else: + print("get_transceiver_change_event : unable to create fd") + return False, {} - time.sleep(0.5) + # Check for missed interrupts by invoking self.check_interrupts + # which will update the port_dict. + while True: + interrupt_count_start = self.get_register(self.OIR_FD_PATH) + retval, is_port_dict_updated = \ + self.check_interrupts(port_dict) + if ((retval == 0) and (is_port_dict_updated is True)): + return True, port_dict + interrupt_count_end = self.get_register(self.OIR_FD_PATH) + if (interrupt_count_start == 'ERR' or + interrupt_count_end == 'ERR'): + print("get_transceiver_change_event : \ + unable to retrive interrupt count") + break + + # check_interrupts() itself may take upto 100s of msecs. + # We detect a missed interrupt based on the count + if interrupt_count_start == interrupt_count_end: + break + + # Block until an xcvr is inserted or removed with timeout = -1 + events = self.epoll.poll( + timeout=timeout if timeout != 0 else -1) + if events: + # check interrupts and return the port_dict + retval, is_port_dict_updated = \ + self.check_interrupts(port_dict) + if (retval != 0): + return False, {} + + return True, port_dict + except: + return False, {} + finally: + if self.oir_fd != -1: + self.epoll.unregister(self.oir_fd.fileno()) + self.epoll.close() + self.oir_fd.close() + self.oir_fd = -1 + self.epoll = -1 + + return False, {} \ No newline at end of file diff --git a/device/mellanox/x86_64-mlnx_msn2410-r0/ACS-MSN2410/sai_2410.xml b/device/mellanox/x86_64-mlnx_msn2410-r0/ACS-MSN2410/sai_2410.xml index 1f97994f88..4884cd754a 100644 --- a/device/mellanox/x86_64-mlnx_msn2410-r0/ACS-MSN2410/sai_2410.xml +++ b/device/mellanox/x86_64-mlnx_msn2410-r0/ACS-MSN2410/sai_2410.xml @@ -5,6 +5,9 @@ 00:02:03:04:05:00 + + 1 + 56 diff --git a/dockers/docker-fpm-frr/Dockerfile.j2 b/dockers/docker-fpm-frr/Dockerfile.j2 index fc57b7c0ef..748c9b29a5 100644 --- a/dockers/docker-fpm-frr/Dockerfile.j2 +++ b/dockers/docker-fpm-frr/Dockerfile.j2 @@ -13,7 +13,7 @@ ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update # Install required packages -RUN apt-get install -y libdbus-1-3 libdaemon0 libjansson4 libc-ares2 iproute2 libpython2.7 libjson-c3 logrotate +RUN apt-get install -y libdbus-1-3 libdaemon0 libjansson4 libc-ares2 iproute2 libpython2.7 libjson-c3 logrotate libunwind8 {% if docker_fpm_frr_debs.strip() -%} # Copy locally-built Debian package dependencies @@ -30,6 +30,8 @@ RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return {%- endfor %} {%- endif %} +RUN chown -R ${frr_user_uid}:${frr_user_gid} /etc/frr/ + # Clean up RUN apt-get clean -y RUN apt-get autoclean -y diff --git a/dockers/docker-fpm-frr/start.sh b/dockers/docker-fpm-frr/start.sh index 03bb71d4fc..238d26783a 100755 --- a/dockers/docker-fpm-frr/start.sh +++ b/dockers/docker-fpm-frr/start.sh @@ -32,6 +32,7 @@ supervisorctl start bgpcfgd # Start Quagga processes supervisorctl start zebra +supervisorctl start staticd supervisorctl start bgpd if [ "$CONFIG_TYPE" == "unified" ]; then diff --git a/dockers/docker-fpm-frr/supervisord.conf b/dockers/docker-fpm-frr/supervisord.conf index f8aa329719..0b1c813847 100644 --- a/dockers/docker-fpm-frr/supervisord.conf +++ b/dockers/docker-fpm-frr/supervisord.conf @@ -39,6 +39,15 @@ startsecs=0 stdout_logfile=syslog stderr_logfile=syslog +[program:staticd] +command=/usr/lib/frr/staticd -A 127.0.0.1 +priority=4 +autostart=false +autorestart=false +startsecs=0 +stdout_logfile=syslog +stderr_logfile=syslog + [program:bgpd] command=/usr/lib/frr/bgpd -A 127.0.0.1 priority=5 diff --git a/dockers/docker-lldp-sv2/lldpmgrd b/dockers/docker-lldp-sv2/lldpmgrd index 7d2528a9d3..62ed6904fb 100755 --- a/dockers/docker-lldp-sv2/lldpmgrd +++ b/dockers/docker-lldp-sv2/lldpmgrd @@ -74,11 +74,14 @@ def signal_handler(sig, frame): # ========================== Helpers ================================== def is_port_exist(port_name): - filename = "/sys/class/net/%s/ifindex" % port_name - if not os.path.exists(filename): - return False - - return True + filename = "/sys/class/net/%s/operstate" % port_name + if os.path.exists(filename): + with open(filename) as fp: + state = fp.read() + return "up" in state + else: + filename = "/sys/class/net/%s/ifindex" % port_name + return os.path.exists(filename) # ============================== Classes ============================== diff --git a/dockers/docker-platform-monitor/Dockerfile.j2 b/dockers/docker-platform-monitor/Dockerfile.j2 index bc91e28f4a..2244828c21 100755 --- a/dockers/docker-platform-monitor/Dockerfile.j2 +++ b/dockers/docker-platform-monitor/Dockerfile.j2 @@ -7,7 +7,7 @@ RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%s ENV DEBIAN_FRONTEND=noninteractive # Install required packages -RUN apt-get update && apt-get install -y python-pip libpython2.7 ipmitool librrd8 librrd-dev rrdtool +RUN apt-get update && apt-get install -y python-pip libpython2.7 ipmitool librrd8 librrd-dev rrdtool python-smbus ethtool {% if docker_platform_monitor_debs.strip() -%} # Copy locally-built Debian package dependencies diff --git a/files/Aboot/boot0.j2 b/files/Aboot/boot0.j2 index f64a2286bc..64b1414fc1 100644 --- a/files/Aboot/boot0.j2 +++ b/files/Aboot/boot0.j2 @@ -68,6 +68,8 @@ cmdline_base="$target_path/kernel-params-base" cmdline_image="$image_path/kernel-cmdline" boot_config="$target_path/boot-config" +swi_tmpfs="/tmp/tmp-swi" + bootconfigvars="KERNEL INITRD CONSOLESPEED PASSWORD NETDEV NETAUTO NETIP NETMASK NETGW NETDOMAIN NETDNS NETHW memtest" flash_re=" /mnt/flash| /host" @@ -126,9 +128,34 @@ update_next_boot() { fi } +move_swi_to_tmpfs() { + local oldswi="$1" + local newswi="$swi_tmpfs/$(basename $oldswi)" + + mkdir -p "$swi_tmpfs" + if ! $in_aboot && ! mount | grep -q ' /tmp type tmpfs'; then + # mount a real tmpfs on /tmp/tmp-swi if /tmp is not one already. + mount -t tmpfs tmp-swi "$swi_tmpfs" + fi + + mv "$oldswi" "$newswi" + echo "$newswi" +} + +cleanup_swi_tmpfs() { + rm -f "$swipath" + if mount | grep -q "$swi_tmpfs"; then + umount "$swi_tmpfs" || : + fi +} + extract_image() { mkdir -p "$image_path" + info "Moving swi to a tmpfs" + ## Avoid problematic flash usage spike on older systems, also improves I/O + swipath="$(move_swi_to_tmpfs $swipath)" + info "Extracting swi content" ## Unzip the image except boot0 and dockerfs archive unzip -oq "$swipath" -x boot0 "$dockerfs" -d "$image_path" @@ -146,7 +173,6 @@ extract_image() { fi ## extract docker archive - info "Unpacking $dockerfs" unzip -oqp "$swipath" "$dockerfs" | tar xzf - -C "$image_path/{{ DOCKERFS_DIR }}" $TAR_EXTRA_OPTION else ## save dockerfs archive in the image directory @@ -154,14 +180,15 @@ extract_image() { info "Unpacking $dockerfs delayed to initrd because $target_path is $rootfs_type" fi + ## remove installer since it's not needed anymore + info "Remove installer" + cleanup_swi_tmpfs + ## use new reduced-size boot swi local swi_boot_path="flash:$image_name/{{ ABOOT_BOOT_IMAGE }}" update_boot_config SWI "$swi_boot_path" update_boot_config SWI_DEFAULT "$swi_boot_path" - ## Remove installer swi as it has lots of redundunt contents - rm -f "$swipath" - ## sync disk operations sync } @@ -205,7 +232,8 @@ platform_specific() { flash_size=3700 echo "modprobe.blacklist=radeon,sp5100_tco" >>/tmp/append fi - if [ "$sid" = "Upperlake" ] || [ "$sid" = "UpperlakeES" ]; then + if [ "$sid" = "Upperlake" ] || [ "$sid" = "UpperlakeES" ] || + [ "$sid" = "UpperlakeSsd" ]; then aboot_machine=arista_7060_cx32s flash_size=3700 echo "amd_iommu=off" >> /tmp/append @@ -227,8 +255,13 @@ platform_specific() { aboot_machine=arista_7060dx4_32 flash_size=28000 fi - if [ "$platform" = "rook" ]; then - echo "iommu=on intel_iommu=on tsc=reliable pcie_ports=native" >>/tmp/append + if [ "$sid" = "Smartsville" ]; then + aboot_machine=arista_7280cr3_32p4 + flash_size=7382 + fi + if [ "$platform" = "rook" ] || [ "$platform" = "magpie" ] || + [ "$platform" = "woodpecker" ]; then + echo "tsc=reliable pcie_ports=native" >>/tmp/append echo "rhash_entries=1 usb-storage.delay_use=0" >>/tmp/append if [ -x /bin/readprefdl ]; then readprefdl -f /tmp/.system-prefdl -d > /mnt/flash/.system-prefdl @@ -238,6 +271,12 @@ platform_specific() { fi echo "reassign_prefmem" >> /tmp/append fi + if [ "$platform" = "rook" ] || [ "$platform" = "magpie" ]; then + echo "iommu=on intel_iommu=on" >>/tmp/append + fi + if [ "$platform" = "woodpecker" ]; then + echo "amd_iommu=off modprobe.blacklist=snd_hda_intel,hdaudio" >> /tmp/append + fi if [ $flash_size -ge 28000 ]; then varlog_size=4096 @@ -304,7 +343,7 @@ write_boot_configs() { fi fi - mv /tmp/append $cmdline_image + cat /tmp/append > $cmdline_image [ -e ${target_path}/machine.conf ] || write_machine_config } @@ -313,7 +352,10 @@ run_kexec() { local kernel="${KERNEL:-$(find $image_path/boot -name 'vmlinuz-*' -type f | head -n 1)}" local initrd="${INITRD:-$(find $image_path/boot -name 'initrd.img-*' -type f | head -n 1)}" - if ! $verbose; then + if $verbose; then + # show systemd showdown sequence when verbose is set + cmdline="$cmdline systemd.show_status=true" + else # Start showing systemd information from the first failing unit if any. # systemd.show_status=false or quiet can be used to silence systemd entierly cmdline="$cmdline systemd.show_status=auto" diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index 2aa8e5da60..03ae5f317d 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -111,6 +111,8 @@ sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/python-click*_all.deb || \ # Install python pexpect used by sonic-utilities consutil # using pip install instead to get a more recent version than is available through debian sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install pexpect +# Install python click-default-group by sonic-utilities +sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install click-default-group==1.2 # Install tabulate >= 0.8.1 via pip in order to support multi-line row output for sonic-utilities sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install tabulate==0.8.2 @@ -325,10 +327,10 @@ sudo cp {{src}} $FILESYSTEM_ROOT/{{dst}} {% if sonic_asic_platform == "mellanox" %} sudo mkdir -p $FILESYSTEM_ROOT/etc/mlnx/ -sudo cp target/files/$MLNX_SPC_FW_FILE $FILESYSTEM_ROOT/etc/mlnx/fw-SPC.mfa -sudo cp target/files/$MLNX_SPC2_FW_FILE $FILESYSTEM_ROOT/etc/mlnx/fw-SPC2.mfa -sudo cp target/files/$ISSU_VERSION_FILE $FILESYSTEM_ROOT/etc/mlnx/issu-version -sudo cp target/files/$MLNX_FFB_SCRIPT $FILESYSTEM_ROOT/usr/bin/mlnx-ffb.sh +sudo cp $files_path/$MLNX_SPC_FW_FILE $FILESYSTEM_ROOT/etc/mlnx/fw-SPC.mfa +sudo cp $files_path/$MLNX_SPC2_FW_FILE $FILESYSTEM_ROOT/etc/mlnx/fw-SPC2.mfa +sudo cp $files_path/$ISSU_VERSION_FILE $FILESYSTEM_ROOT/etc/mlnx/issu-version +sudo cp $files_path/$MLNX_FFB_SCRIPT $FILESYSTEM_ROOT/usr/bin/mlnx-ffb.sh j2 platform/mellanox/mlnx-fw-upgrade.j2 | sudo tee $FILESYSTEM_ROOT/usr/bin/mlnx-fw-upgrade.sh sudo chmod 755 $FILESYSTEM_ROOT/usr/bin/mlnx-fw-upgrade.sh {% endif %} diff --git a/files/image_config/cron.d/logrotate b/files/image_config/cron.d/logrotate index d0c2e0829b..173a2abe2b 100644 --- a/files/image_config/cron.d/logrotate +++ b/files/image_config/cron.d/logrotate @@ -1,2 +1,3 @@ -# Attempt to rotate system logs once per minute -* * * * * root /usr/sbin/logrotate /etc/logrotate.conf > /dev/null 2>&1 +# Attempt to rotate system logs once every 10 minutes. +# First kill any logrotate process(es) if they are still running, as they're most likely hung +*/10 * * * * root /usr/bin/pkill -9 logrotate > /dev/null 2>&1; /usr/sbin/logrotate /etc/logrotate.conf > /dev/null 2>&1 diff --git a/files/image_config/ebtables/ebtables.filter b/files/image_config/ebtables/ebtables.filter new file mode 100644 index 0000000000..4faad1f5f4 Binary files /dev/null and b/files/image_config/ebtables/ebtables.filter differ diff --git a/files/image_config/hostcfgd/tacplus_nss.conf.j2 b/files/image_config/hostcfgd/tacplus_nss.conf.j2 index 347a9ec3d8..7f737888f5 100644 --- a/files/image_config/hostcfgd/tacplus_nss.conf.j2 +++ b/files/image_config/hostcfgd/tacplus_nss.conf.j2 @@ -1,4 +1,4 @@ -onfiguration for libnss-tacplus +# Configuration for libnss-tacplus # debug - If you want to open debug log, set it on # Default: off diff --git a/files/image_config/logrotate/logrotate.d/rsyslog b/files/image_config/logrotate/logrotate.d/rsyslog index 6788762d76..76737ba144 100644 --- a/files/image_config/logrotate/logrotate.d/rsyslog +++ b/files/image_config/logrotate/logrotate.d/rsyslog @@ -19,11 +19,7 @@ delaycompress sharedscripts postrotate - # calling kill directly instead of 'service rsyslog rotate >/dev/null' due - # to bug in init-system-helpers. bug has apparently been fixed in v1.47. - # however, debian jessie is still using v1.22. - # see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=672218 - kill -hup $(cat /var/run/rsyslogd.pid) + /bin/kill -HUP $(cat /var/run/rsyslogd.pid) endscript } @@ -44,7 +40,7 @@ compress delaycompress nosharedscripts - prerotate + firstaction # Adjust NUM_LOGS_TO_ROTATE to reflect number of log files that trigger this block specified above NUM_LOGS_TO_ROTATE=8 @@ -65,6 +61,10 @@ # of caution, giving us a bit of a cushion if a log grows quickly and passes its rotation size THRESHOLD_KB=$((USABLE_SPACE_KB - (NUM_LOGS_TO_ROTATE * LOG_FILE_ROTATE_SIZE_KB * 2))) + # First, delete any *.1.gz files that might be left around from a prior incomplete + # logrotate execution, otherwise logrotate will fail to do its job + find /var/log/ -name '*.1.gz' -type f -exec rm -f {} + + while true; do USED_KB=$(du -s /var/log | awk '{ print $1; }') @@ -87,11 +87,7 @@ if [ $(echo $1 | grep -c "/var/log/swss/") -gt 0 ]; then pgrep -x orchagent | xargs /bin/kill -HUP 2>/dev/null || true else - # Calling kill directly instead of 'service rsyslog rotate >/dev/null' due - # to bug in init-system-helpers. Bug has apparently been fixed in v1.47. - # However, Debian Jessie is still using v1.22. - # See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=672218 - kill -HUP $(cat /var/run/rsyslogd.pid) + /bin/kill -HUP $(cat /var/run/rsyslogd.pid) fi endscript } diff --git a/files/image_config/updategraph/updategraph b/files/image_config/updategraph/updategraph index 686108727b..b14f75f858 100755 --- a/files/image_config/updategraph/updategraph +++ b/files/image_config/updategraph/updategraph @@ -16,6 +16,11 @@ reload_minigraph() fi config qos reload pfcwd start_default + + if [[ -x /usr/bin/db_migrator.py ]]; then + # Set latest version number + /usr/bin/db_migrator.py -o set_version + fi } function copy_config_files_and_directories() diff --git a/files/scripts/swss.sh b/files/scripts/swss.sh index 780051def9..5093e4c7f9 100755 --- a/files/scripts/swss.sh +++ b/files/scripts/swss.sh @@ -104,7 +104,7 @@ start() { /usr/bin/docker exec database redis-cli -n 1 FLUSHDB /usr/bin/docker exec database redis-cli -n 2 FLUSHDB /usr/bin/docker exec database redis-cli -n 5 FLUSHDB - clean_up_tables 6 "'PORT_TABLE*', 'MGMT_PORT_TABLE*', 'VLAN_TABLE*', 'VLAN_MEMBER_TABLE*', 'INTERFACE_TABLE*', 'MIRROR_SESSION*', 'VRF_TABLE*'" + clean_up_tables 6 "'PORT_TABLE*', 'MGMT_PORT_TABLE*', 'VLAN_TABLE*', 'VLAN_MEMBER_TABLE*', 'INTERFACE_TABLE*', 'MIRROR_SESSION*', 'VRF_TABLE*', 'FDB_TABLE*'" fi # start service docker diff --git a/files/scripts/syncd.sh b/files/scripts/syncd.sh index 0aa33add16..04f407ebbc 100755 --- a/files/scripts/syncd.sh +++ b/files/scripts/syncd.sh @@ -101,8 +101,13 @@ start() { fi if [[ x"$WARM_BOOT" != x"true" ]]; then - /bin/systemctl stop pmon - /usr/bin/hw-management.sh chipdown + if [[ x"$(/bin/systemctl is-active pmon)" == x"active" ]]; then + /bin/systemctl stop pmon + /usr/bin/hw-management.sh chipdown + /bin/systemctl restart pmon + else + /usr/bin/hw-management.sh chipdown + fi fi if [[ x"$BOOT_TYPE" == x"fast" ]]; then @@ -112,10 +117,6 @@ start() { /usr/bin/mst start /usr/bin/mlnx-fw-upgrade.sh /etc/init.d/sxdkernel start - - if [[ x"$WARM_BOOT" != x"true" ]]; then - /bin/systemctl start pmon - fi fi if [[ x"$WARM_BOOT" != x"true" ]]; then @@ -128,10 +129,6 @@ start() { /usr/bin/${SERVICE}.sh start debug "Started ${SERVICE} service..." - if [[ x"$sonic_asic_platform" == x"mellanox" && x"$BOOT_TYPE" == x"fast" ]]; then - /usr/bin/hw-management.sh chipupen - fi - unlock_service_state_change } diff --git a/platform/barefoot/sonic-platform-modules-arista b/platform/barefoot/sonic-platform-modules-arista index 7e2d714ae7..0ed1df5a7d 160000 --- a/platform/barefoot/sonic-platform-modules-arista +++ b/platform/barefoot/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit 7e2d714ae7c072ee587d1cf0356cf548ac4be4a9 +Subproject commit 0ed1df5a7d6c88319ce41b10ce604c2727afab69 diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index a277c6f592..24cdd64c57 100755 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -22,7 +22,9 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(ACCTON_AS7716_32XB_PLATFORM_MODULE) \ $(ACCTON_AS6712_32X_PLATFORM_MODULE) \ $(ACCTON_AS7726_32X_PLATFORM_MODULE) \ + $(ACCTON_AS4630_54PE_PLATFORM_MODULE) \ $(ACCTON_MINIPACK_PLATFORM_MODULE) \ + $(ACCTON_AS5812_54X_PLATFORM_MODULE) \ $(INVENTEC_D7032Q28B_PLATFORM_MODULE) \ $(INVENTEC_D7054Q28B_PLATFORM_MODULE) \ $(INVENTEC_D7264Q28B_PLATFORM_MODULE) \ diff --git a/platform/broadcom/platform-modules-accton.mk b/platform/broadcom/platform-modules-accton.mk index 76ef6ae3cc..397b38cb0c 100755 --- a/platform/broadcom/platform-modules-accton.mk +++ b/platform/broadcom/platform-modules-accton.mk @@ -9,7 +9,9 @@ ACCTON_AS7326_56X_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS7716_32XB_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS7726_32X_PLATFORM_MODULE_VERSION = 1.1 +ACCTON_AS4630_54PE_PLATFORM_MODULE_VERSION = 1.1 ACCTON_MINIPACK_PLATFORM_MODULE_VERSION = 1.1 +ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION = 1.1 export ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION export ACCTON_AS5712_54X_PLATFORM_MODULE_VERSION @@ -20,7 +22,9 @@ export ACCTON_AS7326_56X_PLATFORM_MODULE_VERSION export ACCTON_AS7716_32XB_PLATFORM_MODULE_VERSION export ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION export ACCTON_AS7726_32X_PLATFORM_MODULE_VERSION +export ACCTON_AS4630_54PE_PLATFORM_MODULE_VERSION export ACCTON_MINIPACK_PLATFORM_MODULE_VERSION +export ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION ACCTON_AS7712_32X_PLATFORM_MODULE = sonic-platform-accton-as7712-32x_$(ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION)_amd64.deb $(ACCTON_AS7712_32X_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-accton @@ -60,8 +64,17 @@ ACCTON_AS7726_32X_PLATFORM_MODULE = sonic-platform-accton-as7726-32x_$(ACCTON_AS $(ACCTON_AS7726_32X_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as7726_32x-r0 $(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS7726_32X_PLATFORM_MODULE))) +ACCTON_AS4630_54PE_PLATFORM_MODULE = sonic-platform-accton-as4630-54pe_$(ACCTON_AS4630_54PE_PLATFORM_MODULE_VERSION)_amd64.deb +$(ACCTON_AS4630_54PE_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as4630_54pe-r0 +$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS4630_54PE_PLATFORM_MODULE))) + + ACCTON_MINIPACK_PLATFORM_MODULE = sonic-platform-accton-minipack_$(ACCTON_MINIPACK_PLATFORM_MODULE_VERSION)_amd64.deb $(ACCTON_MINIPACK_PLATFORM_MODULE)_PLATFORM = x86_64-accton_minipack-r0 $(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_MINIPACK_PLATFORM_MODULE))) +ACCTON_AS5812_54X_PLATFORM_MODULE = sonic-platform-accton-as5812-54x_$(ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION)_amd64.deb +$(ACCTON_AS5812_54X_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as5812_54x-r0 +$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS5812_54X_PLATFORM_MODULE))) + SONIC_STRETCH_DEBS += $(ACCTON_AS7712_32X_PLATFORM_MODULE) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/__init__.py new file mode 100755 index 0000000000..e69de29bb2 diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/fanutil.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/fanutil.py new file mode 100755 index 0000000000..ca0f3f9da1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/fanutil.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 Accton Technology Corporation +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 11/13/2017: Polly Hsu, Create +# 1/10/2018: Jostar modify for as7716_32 +# 12/03/2018: Jostar modify for as7726_32 +# ------------------------------------------------------------------ + +try: + import time + import logging + from collections import namedtuple +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + + +class FanUtil(object): + """Platform-specific FanUtil class""" + + FAN_NUM_ON_MAIN_BROAD = 6 + FAN_NUM_1_IDX = 1 + FAN_NUM_2_IDX = 2 + FAN_NUM_3_IDX = 3 + FAN_NUM_4_IDX = 4 + FAN_NUM_5_IDX = 5 + FAN_NUM_6_IDX = 6 + + FAN_NODE_NUM_OF_MAP = 2 + FAN_NODE_FAULT_IDX_OF_MAP = 1 + FAN_NODE_DIR_IDX_OF_MAP = 2 + + BASE_VAL_PATH = '/sys/bus/i2c/devices/54-0066/{0}' + FAN_DUTY_PATH = '/sys/bus/i2c/devices/54-0066/fan_duty_cycle_percentage' + + #logfile = '' + #loglevel = logging.INFO + + """ Dictionary where + key1 = fan id index (integer) starting from 1 + key2 = fan node index (interger) starting from 1 + value = path to fan device file (string) """ + _fan_to_device_path_mapping = {} + +#fan1_direction +#fan1_fault +#fan1_present + + #(FAN_NUM_2_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan2_duty_cycle_percentage', + _fan_to_device_node_mapping = { + (FAN_NUM_1_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan1_fault', + (FAN_NUM_1_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan1_direction', + + (FAN_NUM_2_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan2_fault', + (FAN_NUM_2_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan2_direction', + + (FAN_NUM_3_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan3_fault', + (FAN_NUM_3_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan3_direction', + + (FAN_NUM_4_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan4_fault', + (FAN_NUM_4_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan4_direction', + + (FAN_NUM_5_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan5_fault', + (FAN_NUM_5_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan5_direction', + + (FAN_NUM_6_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan6_fault', + (FAN_NUM_6_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan6_direction', + } + + def _get_fan_to_device_node(self, fan_num, node_num): + return self._fan_to_device_node_mapping[(fan_num, node_num)] + + def _get_fan_node_val(self, fan_num, node_num): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: + logging.debug('GET. Parameter error. fan_num:%d', fan_num) + return None + + if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP: + logging.debug('GET. Parameter error. node_num:%d', node_num) + return None + + device_path = self.get_fan_to_device_path(fan_num, node_num) + + try: + val_file = open(device_path, 'r') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + + content = val_file.readline().rstrip() + + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + + try: + val_file.close() + except: + logging.debug('GET. unable to close file. device_path:%s', device_path) + return None + + return int(content) + + def _set_fan_node_val(self, fan_num, node_num, val): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: + logging.debug('GET. Parameter error. fan_num:%d', fan_num) + return None + + if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP: + logging.debug('GET. Parameter error. node_num:%d', node_num) + return None + + content = str(val) + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + + device_path = self.get_fan_to_device_path(fan_num, node_num) + try: + val_file = open(device_path, 'w') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + + val_file.write(content) + + try: + val_file.close() + except: + logging.debug('GET. unable to close file. device_path:%s', device_path) + return None + + return True + + def __init__(self): + fan_path = self.BASE_VAL_PATH + + for fan_num in range(self.FAN_NUM_1_IDX, self.FAN_NUM_ON_MAIN_BROAD+1): + for node_num in range(self.FAN_NODE_FAULT_IDX_OF_MAP, self.FAN_NODE_NUM_OF_MAP+1): + self._fan_to_device_path_mapping[(fan_num, node_num)] = fan_path.format( + self._fan_to_device_node_mapping[(fan_num, node_num)]) + + def get_num_fans(self): + return self.FAN_NUM_ON_MAIN_BROAD + + def get_idx_fan_start(self): + return self.FAN_NUM_1_IDX + + def get_num_nodes(self): + return self.FAN_NODE_NUM_OF_MAP + + def get_idx_node_start(self): + return self.FAN_NODE_FAULT_IDX_OF_MAP + + def get_size_node_map(self): + return len(self._fan_to_device_node_mapping) + + def get_size_path_map(self): + return len(self._fan_to_device_path_mapping) + + def get_fan_to_device_path(self, fan_num, node_num): + return self._fan_to_device_path_mapping[(fan_num, node_num)] + + def get_fan_fault(self, fan_num): + return self._get_fan_node_val(fan_num, self.FAN_NODE_FAULT_IDX_OF_MAP) + + #def get_fan_speed(self, fan_num): + # return self._get_fan_node_val(fan_num, self.FAN_NODE_SPEED_IDX_OF_MAP) + + def get_fan_dir(self, fan_num): + return self._get_fan_node_val(fan_num, self.FAN_NODE_DIR_IDX_OF_MAP) + + def get_fan_duty_cycle(self): + #duty_path = self.FAN_DUTY_PATH + try: + val_file = open(self.FAN_DUTY_PATH) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + + return int(content) + #self._get_fan_node_val(fan_num, self.FAN_NODE_DUTY_IDX_OF_MAP) +#static u32 reg_val_to_duty_cycle(u8 reg_val) +#{ +# reg_val &= FAN_DUTY_CYCLE_REG_MASK; +# return ((u32)(reg_val+1) * 625 + 75)/ 100; +#} +# + def set_fan_duty_cycle(self, val): + + try: + fan_file = open(self.FAN_DUTY_PATH, 'r+') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + #val = ((val + 1 ) * 625 +75 ) / 100 + fan_file.write(str(val)) + fan_file.close() + return True + + #def get_fanr_fault(self, fan_num): + # return self._get_fan_node_val(fan_num, self.FANR_NODE_FAULT_IDX_OF_MAP) + + def get_fanr_speed(self, fan_num): + return self._get_fan_node_val(fan_num, self.FANR_NODE_SPEED_IDX_OF_MAP) + + def get_fan_status(self, fan_num): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: + logging.debug('GET. Parameter error. fan_num, %d', fan_num) + return None + + if self.get_fan_fault(fan_num) is not None and self.get_fan_fault(fan_num) > 0: + logging.debug('GET. FAN fault. fan_num, %d', fan_num) + return False + + #if self.get_fanr_fault(fan_num) is not None and self.get_fanr_fault(fan_num) > 0: + # logging.debug('GET. FANR fault. fan_num, %d', fan_num) + # return False + + return True + +#def main(): +# fan = FanUtil() +# +# print 'get_size_node_map : %d' % fan.get_size_node_map() +# print 'get_size_path_map : %d' % fan.get_size_path_map() +# for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1): +# for y in range(fan.get_idx_node_start(), fan.get_num_nodes()+1): +# print fan.get_fan_to_device_path(x, y) +# +#if __name__ == '__main__': +# main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/thermalutil.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/thermalutil.py new file mode 100755 index 0000000000..96163f1d63 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/classes/thermalutil.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 Accton Technology Corporation +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 11/13/2017: Polly Hsu, Create +# 1/10/2018:Jostar modify for as7716_32x +# 12/03/2018:Jostar modify for as7726_32x thermal plan +# ------------------------------------------------------------------ + +try: + import os + import time + import logging + import glob + import commands + from collections import namedtuple +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +class ThermalUtil(object): + """Platform-specific ThermalUtil class""" + THERMAL_NUM_MAX = 5 + THERMAL_NUM_1_IDX = 1 # 1_ON_MAIN_BROAD. LM75 + THERMAL_NUM_2_IDX = 2 # 2_ON_MAIN_BROAD. LM75 + THERMAL_NUM_3_IDX = 3 # 3_ON_MAIN_BROAD. LM75 + THERMAL_NUM_4_IDX = 4 # 4_ON_MAIN_BROAD. LM75 + THERMAL_NUM_5_IDX = 5 # 5_ON_MAIN_BROAD. LM75 + + """ Dictionary where + key1 = thermal id index (integer) starting from 1 + value = path to fan device file (string) """ + #_thermal_to_device_path_mapping = {} + + _thermal_to_device_node_mapping = { + THERMAL_NUM_1_IDX: ['55', '48'], + THERMAL_NUM_2_IDX: ['55', '49'], + THERMAL_NUM_3_IDX: ['55', '4a'], + THERMAL_NUM_4_IDX: ['55', '4b'], + THERMAL_NUM_5_IDX: ['54', '4c'], + } + thermal_sysfspath ={ + THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/55-0048/hwmon/hwmon4/temp1_input"], + THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/55-0049/hwmon/hwmon5/temp1_input"], + THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/55-004a/hwmon/hwmon6/temp1_input"], + THERMAL_NUM_4_IDX: ["/sys/bus/i2c/devices/55-004b/hwmon/hwmon7/temp1_input"], + THERMAL_NUM_5_IDX: ["/sys/bus/i2c/devices/54-004c/hwmon/hwmon3/temp1_input"], + } + + #def __init__(self): + def _get_thermal_val(self, thermal_num): + if thermal_num < self.THERMAL_NUM_1_IDX or thermal_num > self.THERMAL_NUM_MAX: + logging.debug('GET. Parameter error. thermal_num, %d', thermal_num) + return None + + device_path = self.get_thermal_to_device_path(thermal_num) + if(os.path.isfile(device_path)): + for filename in glob.glob(device_path): + try: + val_file = open(filename, 'r') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + content = val_file.readline().rstrip() + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + try: + val_file.close() + except: + logging.debug('GET. unable to close file. device_path:%s', device_path) + return None + return int(content) + + else: + print "No such device_path=%s"%device_path + return 0 + + def get_num_thermals(self): + return self.THERMAL_NUM_MAX + + def get_idx_thermal_start(self): + return self.THERMAL_NUM_1_IDX + + def get_size_node_map(self): + return len(self._thermal_to_device_node_mapping) + + def get_size_path_map(self): + return len(self.thermal_sysfspath) + + def get_thermal_to_device_path(self, thermal_num): + return self.thermal_sysfspath[thermal_num][0] + + def get_thermal_1_val(self): + return self._get_thermal_node_val(self.THERMAL_NUM_1_IDX) + + def get_thermal_2_val(self): + return self._get_thermal_node_val(self.THERMAL_NUM_2_IDX) + def get_thermal_temp(self): + return (self._get_thermal_node_val(self.THERMAL_NUM_1_IDX) + self._get_thermal_node_val(self.THERMAL_NUM_2_IDX) +self._get_thermal_node_val(self.THERMAL_NUM_3_IDX)) + +def main(): + thermal = ThermalUtil() + print "termal1=%d" %thermal._get_thermal_val(1) + print "termal2=%d" %thermal._get_thermal_val(2) + print "termal3=%d" %thermal._get_thermal_val(3) + print "termal4=%d" %thermal._get_thermal_val(4) + print "termal5=%d" %thermal._get_thermal_val(5) +# +# print 'get_size_node_map : %d' % thermal.get_size_node_map() +# print 'get_size_path_map : %d' % thermal.get_size_path_map() +# for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1): +# print thermal.get_thermal_to_device_path(x) +# +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/Makefile new file mode 100755 index 0000000000..f845f2e17d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/Makefile @@ -0,0 +1,19 @@ +ifneq ($(KERNELRELEASE),) +obj-m:= x86-64-accton-as4630-54pe-cpld.o x86-64-accton-as4630-54pe-psu.o \ + x86-64-accton-as4630-54pe-leds.o ym2651y.o + +else +ifeq (,$(KERNEL_SRC)) +#$(error KERNEL_SRC is not defined) +KVERSION=3.16.0-8-amd64 +KERNEL_DIR = /usr/src/linux-headers-$(KVERSION)/ +KERNELDIR:=$(KERNEL_DIR) +else +KERNELDIR:=$(KERNEL_SRC) +endif +PWD:=$(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +clean: + rm -rf *.o *.mod.o *.mod.o *.mod.c *.ko .*cmd .tmp_versions Module.markers Module.symvers modules.order +endif diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-cpld.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-cpld.c new file mode 100755 index 0000000000..5e25e824d4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-cpld.c @@ -0,0 +1,1105 @@ +/* + * Copyright (C) Jostar yang + * + * This module supports the accton cpld that hold the channel select + * mechanism for other i2c slave devices, such as SFP. + * This includes the: + * Accton as4630_54pe CPLD + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ +#define FAN_DUTY_CYCLE_REG_MASK 0x1F +#define FAN_MAX_DUTY_CYCLE 100 +#define FAN_REG_VAL_TO_SPEED_RPM_STEP 114 // R.P.M value = read value x3.79*60/2 + +#define NUM_THERMAL_SENSORS (3) /* Get sum of this number of sensors.*/ +#define THERMAL_SENSORS_DRIVER "lm75" +#define THERMAL_SENSORS_ADDRS {0x48, 0x4a, 0x4b} + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +enum cpld_type { + as4630_54pe_cpld, +}; +enum fan_id { + FAN1_ID, + FAN2_ID, + FAN3_ID, +}; + +static const u8 fan_reg[] = { + 0x87, /* fan status, fan direction */ + 0x1A, /* fan PWM(for fan1 ,fan2) */ + 0x1B, /* fan PWM(for fan1 ,fan2) */ + 0x88, /* front fan1 speed(rpm) */ + 0x89, /* front fan2 speed(rpm) */ + 0x8A, /* front fan3 speed(rpm) */ + 0x20, /*fan fault*/ +}; + +struct as4630_54pe_cpld_data { + enum cpld_type type; + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_fan_val[ARRAY_SIZE(fan_reg)]; /* Register value */ + int system_temp; /*In unit of mini-Celsius*/ + int sensors_found; +}; + + + +static const struct i2c_device_id as4630_54pe_cpld_id[] = { + { "as4630_54pe_cpld", as4630_54pe_cpld}, + { } +}; +MODULE_DEVICE_TABLE(i2c, as4630_54pe_cpld_id); + +#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index +#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index +#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index +#define FAN_SPEED_RPM_ATTR_ID(index) FAN_SPEED_RPM_##index +#define FAN_DIRECTION_ID(index) FAN_DIRECTION_##index +#define FAN_PRESENT_ATTR_ID(index) FAN_PRESENT_##index +#define FAN_FAULT_ATTR_ID(index) FAN_FAULT_##index + +enum as4630_54pe_cpld_sysfs_attributes { + CPLD_VERSION, + ACCESS, + /* transceiver attributes */ + TRANSCEIVER_RXLOS_ATTR_ID(49), + TRANSCEIVER_RXLOS_ATTR_ID(50), + TRANSCEIVER_RXLOS_ATTR_ID(51), + TRANSCEIVER_RXLOS_ATTR_ID(52), + TRANSCEIVER_TXFAULT_ATTR_ID(49), + TRANSCEIVER_TXFAULT_ATTR_ID(50), + TRANSCEIVER_TXFAULT_ATTR_ID(51), + TRANSCEIVER_TXFAULT_ATTR_ID(52), + TRANSCEIVER_PRESENT_ATTR_ID(49), + TRANSCEIVER_PRESENT_ATTR_ID(50), + TRANSCEIVER_PRESENT_ATTR_ID(51), + TRANSCEIVER_PRESENT_ATTR_ID(52), + TRANSCEIVER_PRESENT_ATTR_ID(53), + TRANSCEIVER_PRESENT_ATTR_ID(54), + TRANSCEIVER_TXDISABLE_ATTR_ID(49), + TRANSCEIVER_TXDISABLE_ATTR_ID(50), + TRANSCEIVER_TXDISABLE_ATTR_ID(51), + TRANSCEIVER_TXDISABLE_ATTR_ID(52), + FAN_PRESENT_ATTR_ID(1), + FAN_PRESENT_ATTR_ID(2), + FAN_PRESENT_ATTR_ID(3), + FAN_SPEED_RPM_ATTR_ID(1), + FAN_SPEED_RPM_ATTR_ID(2), + FAN_SPEED_RPM_ATTR_ID(3), + FAN_DIRECTION_ID(1), + FAN_DIRECTION_ID(2), + FAN_DIRECTION_ID(3), + FAN_FAULT_ATTR_ID(1), + FAN_FAULT_ATTR_ID(2), + FAN_FAULT_ATTR_ID(3), + FAN_DUTY_CYCLE_PERCENTAGE, +}; + +/* sysfs attributes for hwmon + */ +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); +static int as4630_54pe_cpld_read_internal(struct i2c_client *client, u8 reg); +static int as4630_54pe_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value); + +/*fan sysfs*/ +static struct as4630_54pe_cpld_data *as4630_54pe_fan_update_device(struct device *dev); +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t get_sys_temp(struct device *dev, struct device_attribute *da, char *buf); +//static ssize_t show_power(struct device *dev, struct device_attribute *da, + // char *buf); + + + +/* transceiver attributes */ +#define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_tx_disable, MODULE_TXDISABLE_##index); \ + static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_TXFAULT_##index); + +#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \ + &sensor_dev_attr_module_rx_los_##index.dev_attr.attr, \ + &sensor_dev_attr_module_tx_fault_##index.dev_attr.attr + +#define DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index); + +#define DECLARE_QSFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr + + +#define DECLARE_FAN_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan_present_##index, S_IRUGO, fan_show_value, NULL, FAN_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(fan_fault_##index, S_IRUGO, fan_show_value, NULL, FAN_FAULT_##index); \ + static SENSOR_DEVICE_ATTR(fan_speed_rpm_##index, S_IRUGO, fan_show_value, NULL, FAN_SPEED_RPM_##index); \ + static SENSOR_DEVICE_ATTR(fan##index##_input, S_IRUGO, fan_show_value, NULL, FAN_SPEED_RPM_##index);\ + static SENSOR_DEVICE_ATTR(fan_direction_##index, S_IRUGO, fan_show_value, NULL, FAN_DIRECTION_##index); + +#define DECLARE_FAN_ATTR(index) \ + &sensor_dev_attr_fan_present_##index.dev_attr.attr, \ + &sensor_dev_attr_fan_fault_##index.dev_attr.attr, \ + &sensor_dev_attr_fan_speed_rpm_##index.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_input.dev_attr.attr, \ + &sensor_dev_attr_fan_direction_##index.dev_attr.attr + +#define DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN_DUTY_CYCLE_PERCENTAGE); +#define DECLARE_FAN_DUTY_CYCLE_ATTR(index) &sensor_dev_attr_fan_duty_cycle_percentage.dev_attr.attr + +#define DECLARE_FAN_SYSTEM_TEMP_SENSOR_DEV_ATTR() \ + static SENSOR_DEVICE_ATTR(sys_temp, S_IRUGO, get_sys_temp, NULL, FAN_DUTY_CYCLE_PERCENTAGE) + +#define DECLARE_FAN_SYSTEM_TEMP_ATTR() &sensor_dev_attr_sys_temp.dev_attr.attr + +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); +static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); + + + +/* transceiver attributes */ +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(49); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(50); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(51); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(52); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(53); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(54); +/* fan attributes */ +DECLARE_FAN_SENSOR_DEV_ATTR(1); +DECLARE_FAN_SENSOR_DEV_ATTR(2); +DECLARE_FAN_SENSOR_DEV_ATTR(3); +DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(1); + +static struct attribute *as4630_54pe_cpld_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + DECLARE_SFP_TRANSCEIVER_ATTR(49), + DECLARE_SFP_TRANSCEIVER_ATTR(50), + DECLARE_SFP_TRANSCEIVER_ATTR(51), + DECLARE_SFP_TRANSCEIVER_ATTR(52), + DECLARE_QSFP_TRANSCEIVER_ATTR(53), + DECLARE_QSFP_TRANSCEIVER_ATTR(54), + DECLARE_FAN_ATTR(1), + DECLARE_FAN_ATTR(2), + DECLARE_FAN_ATTR(3), + DECLARE_FAN_DUTY_CYCLE_ATTR(1), + NULL +}; + +static const struct attribute_group as4630_54pe_cpld_group = { + .attrs = as4630_54pe_cpld_attributes, +}; + + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as4630_54pe_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0, revert = 0; + + switch (attr->index) + { + case MODULE_RXLOS_49 ... MODULE_RXLOS_50: + reg=0x5; + mask = 0x1<< (attr->index==MODULE_RXLOS_49?4:0); + break; + case MODULE_TXFAULT_49 ... MODULE_TXFAULT_50: + reg=0x5; + mask=0x1 << (attr->index==MODULE_TXFAULT_49?5:1); + break; + case MODULE_PRESENT_49 ... MODULE_PRESENT_50: + reg=0x5; + mask=0x1 << (attr->index==MODULE_PRESENT_49?6:2); + break; + case MODULE_TXDISABLE_49 ... MODULE_TXDISABLE_50: + reg=0x5; + mask=0x1 << (attr->index==MODULE_TXFAULT_49?7:3); + break; + + case MODULE_RXLOS_51 ... MODULE_RXLOS_52: + reg=0x6; + mask = 0x1<< (attr->index==MODULE_RXLOS_51?4:0); + break; + case MODULE_TXFAULT_51 ... MODULE_TXFAULT_52: + reg=0x6; + mask=0x1 << (attr->index==MODULE_TXFAULT_51?5:1); + break; + case MODULE_PRESENT_51 ... MODULE_PRESENT_52: + reg=0x6; + mask=0x1 << (attr->index==MODULE_PRESENT_51?6:2); + break; + case MODULE_TXDISABLE_51 ... MODULE_TXDISABLE_52: + reg=0x6; + mask=0x1 << (attr->index==MODULE_TXFAULT_51?7:3); + break; + case MODULE_PRESENT_53 ... MODULE_PRESENT_54: + reg=0x21; + mask=0x1 << (attr->index==MODULE_PRESENT_53?0:4); + break; + default: + return 0; + } + + if( attr->index >= MODULE_PRESENT_49 && attr->index <= MODULE_PRESENT_54 ) + { + revert = 1; + } + + mutex_lock(&data->update_lock); + status = as4630_54pe_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", revert ? !(status & mask) : !!(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as4630_54pe_cpld_data *data = i2c_get_clientdata(client); + long disable; + int status; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &disable); + if (status) { + return status; + } + reg = 0x9; + switch (attr->index) + { + case MODULE_TXDISABLE_49 ... MODULE_TXDISABLE_50: + reg=0x5; + mask=0x1 << (attr->index==MODULE_TXFAULT_49?7:3); + break; + case MODULE_TXDISABLE_51 ... MODULE_TXDISABLE_52: + reg=0x6; + mask=0x1 << (attr->index==MODULE_TXFAULT_51?7:3); + break; + + default: + return 0; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as4630_54pe_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + /* Update tx_disable status */ + if (disable) { + status &= ~mask; + } + else { + status |= mask; + } + status = as4630_54pe_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + u32 addr, val; + struct i2c_client *client = to_i2c_client(dev); + struct as4630_54pe_cpld_data *data = i2c_get_clientdata(client); + + if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) { + return -EINVAL; + } + + if (addr > 0xFF || val > 0xFF) { + return -EINVAL; + } + + mutex_lock(&data->update_lock); + status = as4630_54pe_cpld_write_internal(client, addr, val); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static void as4630_54pe_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); + return; + } + + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &cpld_client_list); + mutex_unlock(&list_lock); +} + +static void as4630_54pe_cpld_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(cpld_node); + } + + mutex_unlock(&list_lock); +} + +static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + int val = 0; + struct i2c_client *client = to_i2c_client(dev); + + val = i2c_smbus_read_byte_data(client, 0x1); + + if (val < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val); + } + + return sprintf(buf, "%d\n", val); +} + +/* fan utility functions + */ +static u32 reg_val_to_duty_cycle(u8 reg_val) +{ + reg_val &= FAN_DUTY_CYCLE_REG_MASK; + return ((u32)(reg_val) * 625)/ 100; +} + +static u8 duty_cycle_to_reg_val(u8 duty_cycle) +{ + return ((u32)duty_cycle * 100 / 625); +} + +static u32 reg_val_to_speed_rpm(u8 reg_val) +{ + return (u32)reg_val * FAN_REG_VAL_TO_SPEED_RPM_STEP; +} + +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value; + struct i2c_client *client = to_i2c_client(dev); + + error = kstrtoint(buf, 10, &value); + if (error) + return error; + + if (value < 0 || value > FAN_MAX_DUTY_CYCLE) + return -EINVAL; + + as4630_54pe_cpld_write_internal(client, fan_reg[1], duty_cycle_to_reg_val(value)); + as4630_54pe_cpld_write_internal(client, fan_reg[2], duty_cycle_to_reg_val(value)); + return count; +} + +static u8 reg_val_to_direction(u8 reg_val, enum fan_id id) +{ + u8 mask = (1 << id); + + reg_val &= mask; + + return reg_val ? 1 : 0; +} + +static u8 reg_val_to_is_present(u8 reg_val, enum fan_id id) +{ + u8 mask = (1 << id); + + reg_val &= mask; + + return reg_val ? 0 : 1; +} + +static u8 is_fan_fault(struct as4630_54pe_cpld_data *data, enum fan_id id) +{ + u8 ret = 1; + + if(id > FAN3_ID) + return 1; + /* Check if the speed of front or rear fan is ZERO, + */ + if (reg_val_to_speed_rpm(data->reg_fan_val[id+3])) + { + + ret = 0; + } + + return ret; +} + +/* Due to this struct is declared at lm75.c, it cannot be include + * under Sonic environment. I duplicate it from lm75.c. + */ +struct lm75_data { + struct i2c_client *client; + struct device *hwmon_dev; + struct thermal_zone_device *tz; + struct mutex update_lock; + u8 orig_conf; + u8 resolution; /* In bits, between 9 and 12 */ + u8 resolution_limits; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + unsigned long sample_time; /* In jiffies */ + s16 temp[3]; /* Register values, + 0 = input + 1 = max + 2 = hyst */ +}; + +/*Copied from lm75.c*/ +static inline long lm75_reg_to_mc(s16 temp, u8 resolution) +{ + return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8); +} + +/*Get hwmon_dev from i2c_client, set hwmon_dev = NULL is failed.*/ +static struct device * get_hwmon_dev( + struct i2c_client *client) +{ + struct lm75_data *data = NULL; + + data = i2c_get_clientdata(client); + if(data) + { + if( data->valid == 1 && data->hwmon_dev) + { + return data->hwmon_dev; + } + + } + return NULL; +} + +/* To find hwmon index by opening hwmon under that i2c address. + */ +static int find_hwmon_index_by_FileOpen( + int bus_nr, + unsigned short addr, + int *index) +{ +#define MAX_HWMON_DEVICE (10) /* Find hwmon device in 0~10*/ + struct file *sfd; + char client_name[96]; + int i=0; + + do { + snprintf(client_name, sizeof(client_name), + "/sys/bus/i2c/devices/%d-%04x/hwmon/hwmon%d/temp1_input", + bus_nr, addr, i); + + sfd = filp_open(client_name, O_RDONLY, 0); + i++; + } while( IS_ERR(sfd) && i < MAX_HWMON_DEVICE); + + if (IS_ERR(sfd)) { + pr_err("Failed to open file(%s)#%d\r\n", client_name, __LINE__); + return -ENOENT; + } + filp_close(sfd, 0); + *index = i - 1; + return 0; + +#undef MAX_HWMON_DEVICE +} + +static int get_temp_file_path( + int bus_nr, unsigned short addr, + struct device *hwmon_dev + ,char *path, int max_len) +{ + + if(hwmon_dev && strlen(dev_name(hwmon_dev))) + { + snprintf(path, max_len, + "/sys/bus/i2c/devices/%d-%04x/hwmon/%s/temp1_input", + bus_nr, addr, dev_name(hwmon_dev)); + } + else + { + int i=0; + if(find_hwmon_index_by_FileOpen( bus_nr, addr, &i)) + { + return -EIO; + } + snprintf(path, max_len, + "/sys/bus/i2c/devices/%d-%04x/hwmon/hwmon%d/temp1_input", + bus_nr, addr, i); + } + + return 0; +} + +/*File read the dev file at user space.*/ +static int read_devfile_temp1_input( + struct device *dev, + int bus_nr, + unsigned short addr, + struct device *hwmon_dev, + int *miniCelsius) +{ + struct file *sfd; + char buffer[96]; + char devfile[96]; + int rc, status; + int rdlen, value; + mm_segment_t old_fs; + + rc = 0; + get_temp_file_path(bus_nr, addr, hwmon_dev, devfile, sizeof(devfile)); + sfd = filp_open(devfile, O_RDONLY, 0); + if (IS_ERR(sfd)) { + pr_err("Failed to open file(%s)#%d\r\n", devfile, __LINE__); + return -ENOENT; + } + dev_dbg(dev, "Found device:%s\n",devfile); + + if(!(sfd->f_op) || !(sfd->f_op->read) ) { + pr_err("file %s cann't readable ?\n",devfile); + return -ENOENT; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + rdlen = sfd->f_op->read(sfd, buffer, sizeof(buffer), &sfd->f_pos); + if (rdlen == 0) { + pr_err( "File(%s) empty!\n", devfile); + rc = -EIO; + goto exit; + } + status = sscanf(buffer, "%d", &value); + if (status != 1) { + rc = -EIO; + goto exit; + } + *miniCelsius = value; + dev_dbg(dev,"found sensors: %d @i2c %d-%04x\n", value, bus_nr, addr); + +exit: + set_fs(old_fs); + filp_close(sfd, 0); + return rc; +} + +static u8 is_lm75_data_due(struct i2c_client *client) +{ + struct lm75_data *data = NULL; + + data = i2c_get_clientdata(client); + if (time_after(jiffies, data->last_updated + data->sample_time)) + { + return 1; + } + return 0; +} +static int get_lm75_temp(struct i2c_client *client, int *miniCelsius) +{ + struct lm75_data *data = NULL; + + data = i2c_get_clientdata(client); + *miniCelsius = lm75_reg_to_mc(data->temp[0], data->resolution); + + return 0; +} + +static bool lm75_addr_mached(unsigned short addr) +{ + int i; + unsigned short addrs[] = THERMAL_SENSORS_ADDRS; + + for (i = 0; i < ARRAY_SIZE(addrs); i++) + { + if( addr == addrs[i]) + return 1; + } + return 0; +} + +static int _find_lm75_device(struct device *dev, void *data) +{ + struct device_driver *driver; + struct as4630_54pe_cpld_data *prv = data; + char *driver_name = THERMAL_SENSORS_DRIVER; + + driver = dev->driver; + if (driver && driver->name && + strcmp(driver->name, driver_name) == 0) + { + struct i2c_client *client; + client = to_i2c_client(dev); + if (client) + { + /*cannot use "struct i2c_adapter *adap = to_i2c_adapter(dev);"*/ + struct i2c_adapter *adap = client->adapter; + int miniCelsius = 0; + + if (! lm75_addr_mached(client->addr)) + { + return 0; + } + + if (!adap) { + return -ENXIO; + } + + /* If the data is not updated, read them from devfile + to drive them updateing data from chip.*/ + if (is_lm75_data_due(client)) + { + struct device *hwmon_dev; + + hwmon_dev = get_hwmon_dev(client); + if(0 == read_devfile_temp1_input(dev, adap->nr, + client->addr, hwmon_dev, &miniCelsius)) + { + prv->system_temp += miniCelsius; + prv->sensors_found++; + } + + } + else + { + get_lm75_temp(client, &miniCelsius); + prv->system_temp += miniCelsius; + prv->sensors_found++; + + } + } + } + return 0; +} + +/*Find all lm75 devices and return sum of temperatures.*/ +static ssize_t get_sys_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + ssize_t ret = 0; + struct as4630_54pe_cpld_data *data = as4630_54pe_fan_update_device(dev); + + data->system_temp=0; + data->sensors_found=0; + i2c_for_each_dev(data, _find_lm75_device); + if (NUM_THERMAL_SENSORS != data->sensors_found) + { + dev_dbg(dev,"only %d of %d temps are found\n", + data->sensors_found, NUM_THERMAL_SENSORS); + data->system_temp = INT_MAX; + } + ret = sprintf(buf, "%d\n",data->system_temp); + return ret; +} + +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, + char *buf) +{ + u32 duty_cycle; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as4630_54pe_cpld_data *data = as4630_54pe_fan_update_device(dev); + ssize_t ret = 0; + + if (data->valid) { + switch (attr->index) + { + case FAN_PRESENT_1: + case FAN_PRESENT_2: + case FAN_PRESENT_3: + ret = sprintf(buf, "%d\n", + reg_val_to_is_present(data->reg_fan_val[0], + attr->index - FAN_PRESENT_1)); + break; + case FAN_DUTY_CYCLE_PERCENTAGE: + duty_cycle = reg_val_to_duty_cycle(data->reg_fan_val[1]); + ret = sprintf(buf, "%u\n", duty_cycle); + break; + case FAN_SPEED_RPM_1: + case FAN_SPEED_RPM_2: + case FAN_SPEED_RPM_3: + ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_fan_val[attr->index-FAN_SPEED_RPM_1+3])); + break; + case FAN_FAULT_1: + case FAN_FAULT_2: + case FAN_FAULT_3: + ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN_FAULT_1)); + break; + case FAN_DIRECTION_1: + case FAN_DIRECTION_2: + case FAN_DIRECTION_3: + ret = sprintf(buf, "%d\n", + reg_val_to_direction(data->reg_fan_val[0], + attr->index - FAN_DIRECTION_1)); + break; + default: + break; + } + } + + return ret; +} + +static struct as4630_54pe_cpld_data *as4630_54pe_fan_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as4630_54pe_cpld_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || + !data->valid) { + int i; + + dev_dbg(&client->dev, "Starting as4630_54pe_fan update\n"); + data->valid = 0; + + /* Update fan data + */ + for (i = 0; i < ARRAY_SIZE(data->reg_fan_val); i++) { + int status = as4630_54pe_cpld_read_internal(client, fan_reg[i]); + if (status < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + dev_dbg(&client->dev, "reg 0x%x, err %d\n", fan_reg[i], status); + return data; + } + else { + data->reg_fan_val[i] = status & 0xff; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +/* +static ssize_t show_power(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as4630_54pe_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0; + + reg=0xc; + mask=0x2; + mutex_lock(&data->update_lock); + status = as4630_54pe_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", !(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; +} +*/ +/* + * I2C init/probing/exit functions + */ +static int as4630_54pe_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + struct as4630_54pe_cpld_data *data; + int ret = -ENODEV; +// int status; + const struct attribute_group *group = NULL; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) + goto exit; + + data = kzalloc(sizeof(struct as4630_54pe_cpld_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->type = id->driver_data; + + /* Register sysfs hooks */ + switch (data->type) + { + case as4630_54pe_cpld: + group = &as4630_54pe_cpld_group; + break; + default: + break; + } + + if (group) + { + ret = sysfs_create_group(&client->dev.kobj, group); + if (ret) { + goto exit_free; + } + } + + as4630_54pe_cpld_add_client(client); + + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + ret = PTR_ERR(data->hwmon_dev); + goto exit_free; + } + + + return 0; + +exit_free: + kfree(data); +exit: + return ret; +} + +static int as4630_54pe_cpld_remove(struct i2c_client *client) +{ + struct as4630_54pe_cpld_data *data = i2c_get_clientdata(client); + const struct attribute_group *group = NULL; + + as4630_54pe_cpld_remove_client(client); + + /* Remove sysfs hooks */ + switch (data->type) + { + case as4630_54pe_cpld: + group = &as4630_54pe_cpld_group; + break; + default: + break; + } + + if (group) { + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, group); + } + + + kfree(data); + + return 0; +} + +static int as4630_54pe_cpld_read_internal(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int as4630_54pe_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +int as4630_54pe_cpld_read(unsigned short cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as4630_54pe_cpld_read_internal(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as4630_54pe_cpld_read); + +int as4630_54pe_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EIO; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as4630_54pe_cpld_write_internal(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as4630_54pe_cpld_write); + +static struct i2c_driver as4630_54pe_cpld_driver = { + .driver = { + .name = "as4630_54pe_cpld", + .owner = THIS_MODULE, + }, + .probe = as4630_54pe_cpld_probe, + .remove = as4630_54pe_cpld_remove, + .id_table = as4630_54pe_cpld_id, +}; + +static int __init as4630_54pe_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&as4630_54pe_cpld_driver); +} + +static void __exit as4630_54pe_cpld_exit(void) +{ + i2c_del_driver(&as4630_54pe_cpld_driver); +} + +MODULE_AUTHOR("Jostar Yang "); +MODULE_DESCRIPTION("Accton I2C CPLD driver"); +MODULE_LICENSE("GPL"); + +module_init(as4630_54pe_cpld_init); +module_exit(as4630_54pe_cpld_exit); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-leds.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-leds.c new file mode 100755 index 0000000000..34c22fd82a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-leds.c @@ -0,0 +1,579 @@ +/* + * A LED driver for the accton_as4630_54pe_led + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*#define DEBUG*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +extern int as4630_54pe_cpld_read (unsigned short cpld_addr, u8 reg); +extern int as4630_54pe_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +#define DRVNAME "accton_as4630_54pe_led" + +struct accton_as4630_54pe_led_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_val[2]; /* only 1 register*/ +}; + +static struct accton_as4630_54pe_led_data *ledctl = NULL; + +/* LED related data + */ + +#define LED_CNTRLER_I2C_ADDRESS (0x60) + +#define LED_TYPE_DIAG_REG_MASK (0x20|0x40|0x80) +#define LED_MODE_DIAG_GREEN_VALUE (0x20) +#define LED_MODE_DIAG_GREEN_BLINK_VALUE (0x60) +#define LED_MODE_DIAG_AMBER_VALUE (0x80) /*It's yellow actually. Green+Red=Yellow*/ +#define LED_MODE_DIAG_OFF_VALUE (0x0) + +#define LED_TYPE_PRI_REG_MASK (0x8|0x4) +#define LED_MODE_PRI_GREEN_VALUE 0x4 +#define LED_MODE_PRI_AMBER_VALUE 0x8 +#define LED_MODE_PRI_OFF_VALUE 0x0 + +#define LED_TYPE_POE_REG_MASK (0x2|0x1) +#define LED_MODE_POE_GREEN_VALUE 0x1 +#define LED_MODE_POE_AMBER_VALUE 0x2 +#define LED_MODE_POE_OFF_VALUE 0x0 + +#define LED_TYPE_STK1_REG_MASK 0x20 +#define LED_MODE_STK1_GREEN_VALUE 0x0 +#define LED_MODE_STK1_OFF_VALUE 0x20 + +#define LED_TYPE_STK2_REG_MASK 0x10 +#define LED_MODE_STK2_GREEN_VALUE 0x0 +#define LED_MODE_STK2_OFF_VALUE 0x10 + +#define LED_TYPE_FAN_REG_MASK (0x20|0x10) +#define LED_MODE_FAN_AMBER_VALUE 0x20 +#define LED_MODE_FAN_GREEN_VALUE 0x10 +#define LED_MODE_FAN_OFF_VALUE (0x0) + +#define LED_TYPE_PSU2_REG_MASK (0x8|0x4) +#define LED_MODE_PSU2_AMBER_VALUE 0x8 +#define LED_MODE_PSU2_GREEN_VALUE 0x4 +#define LED_MODE_PSU2_OFF_VALUE (0x0) + +#define LED_TYPE_PSU1_REG_MASK (0x2|0x1) +#define LED_MODE_PSU1_AMBER_VALUE 0x2 +#define LED_MODE_PSU1_GREEN_VALUE 0x1 +#define LED_MODE_PSU1_OFF_VALUE (0x0) + +enum led_type { + LED_TYPE_DIAG, + LED_TYPE_PRI, + LED_TYPE_POE, + LED_TYPE_STK1, + LED_TYPE_STK2, + LED_TYPE_FAN, + LED_TYPE_PSU1, + LED_TYPE_PSU2 +}; + +struct led_reg { + u32 types; + u8 reg_addr; +}; + +static const struct led_reg led_reg_map[] = { + {(1<update_lock); + + if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2) + || !ledctl->valid) { + int i; + + dev_dbg(&ledctl->pdev->dev, "Starting accton_as4630_54pe_led update\n"); + + /* Update LED data + */ + for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) { + int status = accton_as4630_54pe_led_read_value(led_reg_map[i].reg_addr); + + if (status < 0) { + ledctl->valid = 0; + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", led_reg_map[i].reg_addr, status); + goto exit; + } + else + { + ledctl->reg_val[i] = status; + } + } + + ledctl->last_updated = jiffies; + ledctl->valid = 1; + } + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void accton_as4630_54pe_led_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode, + enum led_type type) +{ + int reg_val; + u8 reg ; + mutex_lock(&ledctl->update_lock); + + if( !accton_getLedReg(type, ®)) + { + dev_dbg(&ledctl->pdev->dev, "Not match item for %d.\n", type); + } + + + reg_val = accton_as4630_54pe_led_read_value(reg); + if (reg_val < 0) { + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", reg, reg_val); + goto exit; + } + reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val); + + accton_as4630_54pe_led_write_value(reg, reg_val); + + /* to prevent the slow-update issue */ + ledctl->valid = 0; + +exit: + mutex_unlock(&ledctl->update_lock); +} + + +static void accton_as4630_54pe_led_diag_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54pe_led_set(led_cdev, led_light_mode, LED_TYPE_DIAG); +} + +static enum led_brightness accton_as4630_54pe_led_diag_get(struct led_classdev *cdev) +{ + accton_as4630_54pe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_DIAG, ledctl->reg_val[0]); +} + +static void accton_as4630_54pe_led_pri_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54pe_led_set(led_cdev, led_light_mode, LED_TYPE_PRI); +} + +static enum led_brightness accton_as4630_54pe_led_pri_get(struct led_classdev *cdev) +{ + accton_as4630_54pe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PRI, ledctl->reg_val[0]); +} + +static void accton_as4630_54pe_led_poe_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54pe_led_set(led_cdev, led_light_mode, LED_TYPE_POE); +} + +static enum led_brightness accton_as4630_54pe_led_poe_get(struct led_classdev *cdev) +{ + accton_as4630_54pe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_POE, ledctl->reg_val[1]); +} + + +static void accton_as4630_54pe_led_stk1_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54pe_led_set(led_cdev, led_light_mode, LED_TYPE_STK1); +} + +static enum led_brightness accton_as4630_54pe_led_stk1_get(struct led_classdev *cdev) +{ + accton_as4630_54pe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_STK1, ledctl->reg_val[1]); +} + +static void accton_as4630_54pe_led_stk2_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54pe_led_set(led_cdev, led_light_mode, LED_TYPE_STK2); +} + +static enum led_brightness accton_as4630_54pe_led_stk2_get(struct led_classdev *cdev) +{ + accton_as4630_54pe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_STK2, ledctl->reg_val[1]); +} + +static void accton_as4630_54pe_led_fan_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54pe_led_set(led_cdev, led_light_mode, LED_TYPE_FAN); +} + +static enum led_brightness accton_as4630_54pe_led_fan_get(struct led_classdev *cdev) +{ + accton_as4630_54pe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[0]); +} + +static void accton_as4630_54pe_led_psu1_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54pe_led_set(led_cdev, led_light_mode, LED_TYPE_PSU1); +} + +static enum led_brightness accton_as4630_54pe_led_psu1_get(struct led_classdev *cdev) +{ + accton_as4630_54pe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU1, ledctl->reg_val[0]); +} + +static void accton_as4630_54pe_led_psu2_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as4630_54pe_led_set(led_cdev, led_light_mode, LED_TYPE_PSU2); +} + +static enum led_brightness accton_as4630_54pe_led_psu2_get(struct led_classdev *cdev) +{ + accton_as4630_54pe_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[0]); +} + +static struct led_classdev accton_as4630_54pe_leds[] = { + [LED_TYPE_DIAG] = { + .name = "diag", + .default_trigger = "unused", + .brightness_set = accton_as4630_54pe_led_diag_set, + .brightness_get = accton_as4630_54pe_led_diag_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_GREEN, + }, + [LED_TYPE_PRI] = { + .name = "pri", + .default_trigger = "unused", + .brightness_set = accton_as4630_54pe_led_pri_set, + .brightness_get = accton_as4630_54pe_led_pri_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AMBER, + }, + [LED_TYPE_POE] = { + .name = "poe", + .default_trigger = "unused", + .brightness_set = accton_as4630_54pe_led_poe_set, + .brightness_get = accton_as4630_54pe_led_poe_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AMBER, + }, + [LED_TYPE_STK1] = { + .name = "stk1", + .default_trigger = "unused", + .brightness_set = accton_as4630_54pe_led_stk1_set, + .brightness_get = accton_as4630_54pe_led_stk1_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_GREEN, + }, + [LED_TYPE_STK2] = { + .name = "stk2", + .default_trigger = "unused", + .brightness_set = accton_as4630_54pe_led_stk2_set, + .brightness_get = accton_as4630_54pe_led_stk2_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_GREEN, + }, + [LED_TYPE_FAN] = { + .name = "fan", + .default_trigger = "unused", + .brightness_set = accton_as4630_54pe_led_fan_set, + .brightness_get = accton_as4630_54pe_led_fan_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_PSU1] = { + .name = "psu1", + .default_trigger = "unused", + .brightness_set = accton_as4630_54pe_led_psu1_set, + .brightness_get = accton_as4630_54pe_led_psu1_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_PSU2] = { + .name = "psu2", + .default_trigger = "unused", + .brightness_set = accton_as4630_54pe_led_psu2_set, + .brightness_get = accton_as4630_54pe_led_psu2_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, +}; + +static int accton_as4630_54pe_led_suspend(struct platform_device *dev, + pm_message_t state) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(accton_as4630_54pe_leds); i++) { + led_classdev_suspend(&accton_as4630_54pe_leds[i]); + } + + return 0; +} + +static int accton_as4630_54pe_led_resume(struct platform_device *dev) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(accton_as4630_54pe_leds); i++) { + led_classdev_resume(&accton_as4630_54pe_leds[i]); + } + + return 0; +} + +static int accton_as4630_54pe_led_probe(struct platform_device *pdev) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(accton_as4630_54pe_leds); i++) { + ret = led_classdev_register(&pdev->dev, &accton_as4630_54pe_leds[i]); + + if (ret < 0) + break; + } + + /* Check if all LEDs were successfully registered */ + if (i != ARRAY_SIZE(accton_as4630_54pe_leds)) { + int j; + + /* only unregister the LEDs that were successfully registered */ + for (j = 0; j < i; j++) { + led_classdev_unregister(&accton_as4630_54pe_leds[i]); + } + } + + return ret; +} + +static int accton_as4630_54pe_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(accton_as4630_54pe_leds); i++) { + led_classdev_unregister(&accton_as4630_54pe_leds[i]); + } + + return 0; +} + +static struct platform_driver accton_as4630_54pe_led_driver = { + .probe = accton_as4630_54pe_led_probe, + .remove = accton_as4630_54pe_led_remove, + .suspend = accton_as4630_54pe_led_suspend, + .resume = accton_as4630_54pe_led_resume, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init accton_as4630_54pe_led_init(void) +{ + int ret; + + ret = platform_driver_register(&accton_as4630_54pe_led_driver); + if (ret < 0) { + goto exit; + } + + ledctl = kzalloc(sizeof(struct accton_as4630_54pe_led_data), GFP_KERNEL); + if (!ledctl) { + ret = -ENOMEM; + platform_driver_unregister(&accton_as4630_54pe_led_driver); + goto exit; + } + + mutex_init(&ledctl->update_lock); + + ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(ledctl->pdev)) { + ret = PTR_ERR(ledctl->pdev); + platform_driver_unregister(&accton_as4630_54pe_led_driver); + kfree(ledctl); + goto exit; + } + +exit: + return ret; +} + +static void __exit accton_as4630_54pe_led_exit(void) +{ + platform_device_unregister(ledctl->pdev); + platform_driver_unregister(&accton_as4630_54pe_led_driver); + kfree(ledctl); +} + +module_init(accton_as4630_54pe_led_init); +module_exit(accton_as4630_54pe_led_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("accton_as4630_54pe_led driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-psu.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-psu.c new file mode 100755 index 0000000000..798a565641 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-psu.c @@ -0,0 +1,320 @@ +/* + * An hwmon driver for accton as4630_54pe Power Module + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_MODEL_NAME 20 +#define MAX_SERIAL_NUMBER 18 + +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf); +static int as4630_54pe_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len); +extern int as4630_54pe_cpld_read(unsigned short cpld_addr, u8 reg); + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { 0x50, 0x51, I2C_CLIENT_END }; + +/* Each client has this additional data + */ +struct as4630_54pe_psu_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 index; /* PSU index */ + u8 status; /* Status(present/power_good) register read from CPLD */ + char model_name[MAX_MODEL_NAME]; /* Model name, read from eeprom */ + char serial_number[MAX_SERIAL_NUMBER]; +}; + +static struct as4630_54pe_psu_data *as4630_54pe_psu_update_device(struct device *dev); + +enum as4630_54pe_psu_sysfs_attributes { + PSU_PRESENT, + PSU_MODEL_NAME, + PSU_POWER_GOOD, + PSU_SERIAL_NUMBER +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); +static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); +static SENSOR_DEVICE_ATTR(psu_serial_number, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER); + + +static struct attribute *as4630_54pe_psu_attributes[] = { + &sensor_dev_attr_psu_present.dev_attr.attr, + &sensor_dev_attr_psu_model_name.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + &sensor_dev_attr_psu_serial_number.dev_attr.attr, + NULL +}; + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as4630_54pe_psu_data *data = as4630_54pe_psu_update_device(dev); + u8 status = 0; + + //printk("data->status=0x%x, attr->index=%d,data->index=%d \n", data->status, attr->index, data->index); + if (attr->index == PSU_PRESENT) { + if(data->index==0) + status = !( (data->status >> 5) & 0x1); + else + status = !( (data->status >> 1) & 0x1); + } + else { /* PSU_POWER_GOOD */ + if(data->index==0) + status = ( (data->status >> 6) & 0x1); + else + status = ( (data->status >> 2) & 0x1); + } + + return sprintf(buf, "%d\n", status); +} + +static ssize_t show_string(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as4630_54pe_psu_data *data = as4630_54pe_psu_update_device(dev); + char *ptr = NULL; + + if (!data->valid) { + return -EIO; + } + + switch (attr->index) { + case PSU_MODEL_NAME: + ptr = data->model_name; + break; + case PSU_SERIAL_NUMBER: + ptr = data->serial_number; + break; + default: + return -EINVAL; + } + + return sprintf(buf, "%s\n", ptr); +} + +static const struct attribute_group as4630_54pe_psu_group = { + .attrs = as4630_54pe_psu_attributes, +}; + +static int as4630_54pe_psu_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct as4630_54pe_psu_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as4630_54pe_psu_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + data->index = dev_id->driver_data; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &as4630_54pe_psu_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &as4630_54pe_psu_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int as4630_54pe_psu_remove(struct i2c_client *client) +{ + struct as4630_54pe_psu_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &as4630_54pe_psu_group); + kfree(data); + + return 0; +} + +enum psu_index +{ + as4630_54pe_psu1, + as4630_54pe_psu2 +}; + +static const struct i2c_device_id as4630_54pe_psu_id[] = { + { "as4630_54pe_psu1", as4630_54pe_psu1 }, + { "as4630_54pe_psu2", as4630_54pe_psu2 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as4630_54pe_psu_id); + +static struct i2c_driver as4630_54pe_psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "as4630_54pe_psu", + }, + .probe = as4630_54pe_psu_probe, + .remove = as4630_54pe_psu_remove, + .id_table = as4630_54pe_psu_id, + .address_list = normal_i2c, +}; + +static int as4630_54pe_psu_read_block(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int result = 0; + int retry_count = 5; + + while (retry_count) { + retry_count--; + + result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + + if (unlikely(result < 0)) { + msleep(10); + continue; + } + + if (unlikely(result != data_len)) { + result = -EIO; + msleep(10); + continue; + } + + result = 0; + break; + } + + return result; +} + +static struct as4630_54pe_psu_data *as4630_54pe_psu_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as4630_54pe_psu_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int status; + int power_good = 0; + + dev_dbg(&client->dev, "Starting as4630_54pe update\n"); + + /* Read psu status */ + status = as4630_54pe_cpld_read(0x60, 0x22); + //printk("status=0x%x in %s\n", status, __FUNCTION__); + if (status < 0) { + dev_dbg(&client->dev, "cpld reg 0x60 err %d\n", status); + } + else { + data->status = status; + } + + /* Read model name */ + memset(data->model_name, 0, sizeof(data->model_name)); + memset(data->serial_number, 0, sizeof(data->serial_number)); + power_good = (data->status >> (3-data->index) & 0x1); + + if (power_good) { + status = as4630_54pe_psu_read_block(client, 0x20, data->model_name, + ARRAY_SIZE(data->model_name)-1); + if (status < 0) { + data->model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); + printk("unable to read model name from (0x%x)\n", client->addr); + } + else { + data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; + + } + /* Read from offset 0x2e ~ 0x3d (16 bytes) */ + status = as4630_54pe_psu_read_block(client, 0x35,data->serial_number, MAX_SERIAL_NUMBER); + if (status < 0) + { + data->serial_number[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x2e)\n", client->addr); + printk("unable to read model name from (0x%x) offset(0x2e)\n", client->addr); + } + data->serial_number[MAX_SERIAL_NUMBER-1]='\0'; + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +module_i2c_driver(as4630_54pe_psu_driver); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as4630_54pe_psu driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/ym2651y.c new file mode 120000 index 0000000000..f4d67640cc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/ym2651y.c @@ -0,0 +1 @@ +../../common/modules/ym2651y.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-platform-monitor-fan.service b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-platform-monitor-fan.service new file mode 100755 index 0000000000..9f562d2a05 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-platform-monitor-fan.service @@ -0,0 +1,16 @@ +[Unit] +Description=Accton AS4630-54PE Platform Monitoring FAN service +Before=pmon.service +After=as4630-54pe-platform-monitor.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/accton_as4630_54pe_monitor_fan.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-platform-monitor-psu.service b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-platform-monitor-psu.service new file mode 100755 index 0000000000..28d6013aa1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-platform-monitor-psu.service @@ -0,0 +1,16 @@ +[Unit] +Description=Accton AS4630-54PE Platform Monitoring PSU service +Before=pmon.service +After=as4630-54pe-platform-monitor.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/accton_as4630_54pe_monitor_psu.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-platform-monitor.service new file mode 100755 index 0000000000..47bf4e81d8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-platform-monitor.service @@ -0,0 +1,18 @@ +[Unit] +Description=Accton AS4630-54PE Platform Monitoring service +Before=pmon.service +After=sysinit.target +DefaultDependencies=no + +[Service] +ExecStartPre=/usr/local/bin/accton_as4630_54pe_util.py install +ExecStart=/usr/local/bin/accton_as4630_54pe_monitor.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL +#StandardOutput=tty + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/setup.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/setup.py new file mode 100755 index 0000000000..34e6bb59de --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/setup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +import os +import sys +from setuptools import setup +os.listdir + +setup( + name='as4630_54pe', + version='1.0', + description='Module to initialize Accton AS4630-54PE platforms', + + packages=['as4630_54pe'], + package_dir={'as4630_54pe': 'as4630-54pe/classes'}, +) + diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/README b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/README new file mode 100755 index 0000000000..44e03cab5f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/README @@ -0,0 +1,117 @@ +Copyright (C) 2016 Accton Networks, Inc. + +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 3 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. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Contents of this package: + patch - files under patch/ is for kernel and ONIE installer + for the kernel: + config-accton-as5712_54x.patch + for kernel configuration. + driver-i2c-muxes-pca954x-always-deselect.patch + for i2c_mux deselects after transaction. + driver-patches-for-accton-as5712-fan-psu-cpld.patch + for as5712's fan/psu/cpld/led/sfp drivers. + for ONIE: + onie_installer-accton-AS5712-54X.patch + for console port setting and copy util script o rootfs. + module - Contains source code of as5712 kernel driver modules. + +The late Sonic building scripts, pushed @Dec 5 2016, will automatically +create a docker container and run building process under it. +User is not necessary to handle docker environment creation. + +1. Download sonic-buildimage environment. + - Run "git clone https://github.com/Azure/sonic-buildimage". + - cd to sonic-buildimage and run "git submodule update --init --recursive". +2. Build kernel + - cd ./src/sonic-linux-kernel + - Copy patches and series from patch/kernel of this release to + sonic-linux-kernel/patch. + - Build kernel by "make". + - The built kernel package, linux-image-3.16.0-5-amd64_3.16.51-3+deb8u1_amd64.deb + , is generated. +3. Build installer + - Change directory back to sonic-buildimage/. + - Get onie_installer-accton-AS5712-54X.patch" from patch/installer. + - Change setting for AS5712-54X by patching build_image.sh. + "patch -p1 < onie_installer-accton-AS5712-54X.patch" + !!NOTICE, patching onie_installer-accton-AS5712-54X.patch comments out the + "git status" checking at build_image.sh. + - The account and password of installed OS can be given at rules/config. + The default user and password are "admin" & "YourPaSsWoRd" respectively. + - Run "make configure PLATFORM=broadcom" + - Copy the built kernel debian package to target/debs/. + The file is linux-image-3.16.0-5-amd64_*_amd64.deb under directory + src/sonic-linux-kernel/. + - Run "make target/sonic-generic.bin" + - Get the installer, target/sonic-generic.bin, to target machine and install. + +All Linux kernel code is licensed under the GPLv1. All other code is +licensed under the GPLv3. Please see the LICENSE file for copies of +both licenses. + +The code for integacting with Accton AS5712-54X has 2 parts, +kernel drivers and operational script. +The kernel drivers of peripherals are under module/ directory. +1. These drivers are patched into kernel by + driver-patches-for-accton-as5712-fan-psu-cpld.patch + Or you can build the driver under module/ by setting environment variable, + KERNEL_SRC, to proper linux built directory and run make. + It may be sonic-linux-kernel/linux-3.*/debian/build/build_amd64_none_amd64/. +2. A operational script, accton_as5712_util.py, for device initializatian and + peripheral accessing should be installed at /usr/bin. + This script is generated by onie_installer-accton-AS5712-54X.patch. + It's done by patching onie_installer-accton-AS5712-54X.patch at build-image. + Run "accton_as5712_util.py install" to install drivers. + +To initialize the system, run "accton_as5712_util.py install". +To clean up the drivers & devices, run "accton_as5712_util.py clean". +To dump information of sensors, run "accton_as5712_util.py show". +To dump SFP EEPROM, run "accton_as5712_util.py sff". +To set fan speed, run "accton_as5712_util.py set fan". +To enable/disable SFP emission, run "accton_as5712_util.py set sfp". +To set system LEDs' color, run "accton_as5712_util.py set led" +For more information, run "accton_as5712_util.py --help". + +==================================================================== +Besides applying accton_as5712_util.py to access peripherals, you can +access peripherals by sysfs nodes directly after the installation is run. + +System LED: + There are 5 system LEDs at the lower-left corner of front panel. + They are loc, diag, fan, ps1, and ps2. + The sysfs interface color mappings are as follows: + Brightness: + 0 => off + 1 => green + 2 => amber + 3 => red + 4 => blue + But not all colors are available for each LED. + +Fan Control: + There are 10 fans inside 5 fan modules. + All fans share 1 duty setting, ranged from 0~100. + +Thermal sensers: + 3 temperature sensors are controlled by the lm75 kernel modules. + +PSUs: + There 2 power supplies slot at the left/right side of the back. + Once if a PSU is not plugged, the status of it is shown failed. + +There are 48 SFP+ and 6 QSFP modules are equipped. +Before operating on PSU and QSFP+, please make sure it is well plugged. +Otherwise, operation is going to fail. + diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_monitor.py new file mode 100755 index 0000000000..eca1eac6b2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_monitor.py @@ -0,0 +1,345 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 Accton Technology Corporation +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.)# +# 4/20/2018: Jostar modify for as7726_32x +# 12/03/2018:Jostar modify for as7726_32x thermal plan +# ------------------------------------------------------------------ + +try: + import os + import sys, getopt + import subprocess + import click + import imp + import logging + import logging.config + import logging.handlers + import types + import time # this is only being used as part of the example + import traceback + from tabulate import tabulate + from as7726_32x.fanutil import FanUtil + from as7726_32x.thermalutil import ThermalUtil +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = '/usr/local/bin/accton_as4630_54pe_monitor' + +global log_file +global log_level + + +# Air Flow Front to Back : +# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 <=38C : Keep 37.5%(0x04) Fan speed +# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 38C : Change Fan speed from 37.5%(0x04) to 62.5%(0x08) +# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 46C : Change Fan speed from 62.5%(0x08) to 100%(0x0E) +# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 58C : Send alarm message +# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 66C : Shut down system +# One Fan fail : Change Fan speed to 100%(0x0E) + + +# Air Flow Back to Front : +# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 <=34C : Keep 37.5%(0x04) Fan speed +# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 34C : Change Fan speed from 37.5%(0x04) to 62.5%(0x08) +# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 44C : Change Fan speed from 62.5%(0x08) to 100%(0x0E) +# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 59C : Send alarm message +# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 67C : Shut down system +# One Fan fail: Change Fan speed to 100%(0x0E) +# sensor_LM75_CPU == sensor_LM75_4B + + +class switch(object): + def __init__(self, value): + self.value = value + self.fall = False + + def __iter__(self): + """Return the match method once, then stop""" + yield self.match + raise StopIteration + + def match(self, *args): + """Indicate whether or not to enter a case suite""" + if self.fall or not args: + return True + elif self.value in args: # changed for v1.5, see below + self.fall = True + return True + else: + return False + + +fan_policy_state=1 +fan_fail=0 +alarm_state = 0 #0->default or clear, 1-->alarm detect +test_temp = 0 +test_temp_list = [0, 0, 0, 0, 0, 0] +temp_test_data=0 +# Make a class we can use to capture stdout and sterr in the log +class device_monitor(object): + # static temp var + temp = 0 + new_pwm = 0 + pwm=0 + ori_pwm = 0 + default_pwm=0x4 + + def __init__(self, log_file, log_level): + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + sys_handler = handler = logging.handlers.SysLogHandler(address = '/dev/log') + sys_handler.setLevel(logging.WARNING) + logging.getLogger('').addHandler(sys_handler) + + #logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) + + def get_state_from_fan_policy(self, temp, policy): + state=0 + + logging.debug('temp=%d', temp) + for i in range(0, len(policy)): + #logging.debug('policy[%d][0]=%d, policy[%d][1]=%d, policy[%d][2]=%d', i,policy[i][0],i, policy[i][1], i, policy[i][2]) + if temp > policy[i][2]: + if temp <= policy[i][3]: + state =i + logging.debug ('temp=%d >= policy[%d][2]=%d, temp=%d < policy[%d][3]=%d' , temp, i, policy[i][2], temp, i, policy[i][3]) + logging.debug ('fan_state=%d', state) + break + + return state + + + def manage_fans(self): + + global fan_policy_state + global fan_fail + global test_temp + global test_temp_list + global alarm_state + global temp_test_data + + LEVEL_FAN_DEF=0 + LEVEL_FAN_MID=1 + LEVEL_FAN_MAX=2 + LEVEL_TEMP_HIGH=3 + LEVEL_TEMP_CRITICAL=4 + + + fan_policy_f2b = { + LEVEL_FAN_DEF: [38, 0x4, 0, 38000], + LEVEL_FAN_MID: [63, 0x6, 38000, 46000], + LEVEL_FAN_MAX: [100, 0xE, 46000, 58000], + LEVEL_TEMP_HIGH: [100, 0xE, 58000, 66000], + LEVEL_TEMP_CRITICAL: [100, 0xE, 58000, 200000], + } + fan_policy_b2f = { + LEVEL_FAN_DEF: [38, 0x4, 0, 34000], + LEVEL_FAN_MID: [63, 0x8, 34000, 44000], + LEVEL_FAN_MAX: [100, 0xE, 44000, 59000], + LEVEL_TEMP_HIGH: [100, 0xE, 59000, 67000], + LEVEL_TEMP_CRITICAL: [100, 0xE, 59000, 200000], + } + + fan_policy = fan_policy_f2b + + thermal = ThermalUtil() + fan = FanUtil() + fan_dir=fan.get_fan_dir(1) + if fan_dir == 1: + fan_dri=1 #something wrong, set fan_dir to default val + else: + fan_policy = fan_policy_b2f + + ori_pwm=fan.get_fan_duty_cycle() + new_pwm=0 + logging.debug('fan_dir=%d, ori_pwm=%d', fan_dir, ori_pwm) + logging.debug('test_temp=%d', test_temp) + if test_temp==0: + temp1 = thermal._get_thermal_val(1) + temp2 = thermal._get_thermal_val(2) + temp3 = thermal._get_thermal_val(3) + temp4 = thermal._get_thermal_val(4) + temp5 = thermal._get_thermal_val(5) + else: + temp1 = test_temp_list[0] + temp2 = test_temp_list[1] + temp3 = test_temp_list[2] + temp4 = test_temp_list[3] + temp5 = test_temp_list[4] + fan_fail=0 + + if temp3==0: + temp_get=50000 # if one detect sensor is fail or zero, assign temp=50000, let fan to 75% + logging.debug('lm75_49 detect fail, so set temp_get=50000, let fan to 75%') + elif temp4==0: + temp_get=50000 # if one detect sensor is fail or zero, assign temp=50000, let fan to 75% + logging.debug('lm75_4b detect fail, so set temp_get=50000, let fan to 75%') + else: + temp_get= (temp3 + temp4)/2 # Use (sensor_LM75_4a + sensor_LM75_4b) /2 + ori_state=fan_policy_state + + #temp_test_data=temp_test_data+1000 + #temp_get = temp_get + temp_test_data + #print "Unit test:temp_get=%d"%temp_get + + fan_policy_state=self.get_state_from_fan_policy(temp_get, fan_policy) + #print "temp3=%d"%temp3 + #print "temp4=%d"%temp4 + #print "temp_get=%d"%temp_get + + logging.debug('lm75_48=%d, lm75_49=%d, lm75_4a=%d, lm_4b=%d, lm_4b=%d', temp1,temp2,temp3,temp4,temp5) + logging.debug('ori_state=%d, fan_policy_state=%d', ori_state, fan_policy_state) + new_pwm = fan_policy[fan_policy_state][0] + if fan_fail==0: + logging.debug('new_fan_cycle=%d', new_pwm) + + if fan_fail==0: + if new_pwm!=ori_pwm: + fan.set_fan_duty_cycle(new_pwm) + logging.info('Set fan speed from %d to %d', ori_pwm, new_pwm) + + #Check Fan status + for i in range (fan.FAN_NUM_1_IDX, fan.FAN_NUM_ON_MAIN_BROAD+1): + if fan.get_fan_status(i)==0: + new_pwm=100 + logging.debug('fan_%d fail, set pwm to 100',i) + if test_temp==0: + fan_fail=1 + fan.set_fan_duty_cycle(new_pwm) + break + else: + fan_fail=0 + + #if fan_policy_state == ori_state: + # return True + #else: + new_state = fan_policy_state + + #logging.warning('Temperature high alarm testing') + if ori_state==LEVEL_FAN_DEF: + if new_state==LEVEL_TEMP_HIGH: + if alarm_state==0: + logging.warning('Alarm for temperature high is detected') + alarm_state=1 + if new_state==LEVEL_TEMP_CRITICAL: + logging.critical('Alarm for temperature critical is detected, reboot DUT') + time.sleep(2) + os.system('reboot') + if ori_state==LEVEL_FAN_MID: + if new_state==LEVEL_TEMP_HIGH: + if alarm_state==0: + logging.warning('Alarm for temperature high is detected') + alarm_state=1 + if new_state==LEVEL_TEMP_CRITICAL: + logging.critical('Alarm for temperature critical is detected') + time.sleep(2) + os.system('reboot') + if ori_state==LEVEL_FAN_MAX: + if new_state==LEVEL_TEMP_HIGH: + if alarm_state==0: + logging.warning('Alarm for temperature high is detected') + alarm_state=1 + if new_state==LEVEL_TEMP_CRITICAL: + logging.critical('Alarm for temperature critical is detected') + time.sleep(2) + os.system('reboot') + if alarm_state==1: + if temp_get < (fan_policy[3][0] - 5000): #below 65 C, clear alarm + logging.warning('Alarm for temperature high is cleared') + alarm_state=0 + if ori_state==LEVEL_TEMP_HIGH: + if new_state==LEVEL_TEMP_CRITICAL: + logging.critical('Alarm for temperature critical is detected') + time.sleep(2) + os.system('reboot') + if new_state <= LEVEL_FAN_MID: + logging.warning('Alarm for temperature high is cleared') + alarm_state=0 + if new_state <= LEVEL_FAN_MAX: + if temp_get < (fan_policy[3][0] - 5000): #below 65 C, clear alarm + logging.warning('Alarm for temperature high is cleared') + alarm_state=0 + if ori_state==LEVEL_TEMP_CRITICAL: + if new_state <= LEVEL_FAN_MAX: + logging.warning('Alarm for temperature critical is cleared') + + return True + +def main(argv): + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + global test_temp + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv,'hdlt:',['lfile=']) + except getopt.GetoptError: + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + for opt, arg in opts: + if opt == '-h': + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + elif opt in ('-d', '--debug'): + log_level = logging.DEBUG + elif opt in ('-l', '--lfile'): + log_file = arg + + if sys.argv[1]== '-t': + if len(sys.argv)!=7: + print "temp test, need input six temp" + return 0 + + i=0 + for x in range(2, 7): + test_temp_list[i]= int(sys.argv[x])*1000 + i=i+1 + test_temp = 1 + log_level = logging.DEBUG + print test_temp_list + + fan = FanUtil() + fan.set_fan_duty_cycle(38) + print "set default fan speed to 37.5%" + monitor = device_monitor(log_file, log_level) + # Loop forever, doing something useful hopefully: + while True: + #monitor.manage_fans() + time.sleep(5) + +if __name__ == '__main__': + main(sys.argv[1:]) + diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_monitor_fan.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_monitor_fan.py new file mode 100755 index 0000000000..11453818b0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_monitor_fan.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python +# +# Copyright (C) 2018 Accton Technology Corporation +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 5/15/2019: Jostar create for as4630-54pe +# ------------------------------------------------------------------ + +try: + import os + import sys, getopt + import subprocess + import click + import imp + import logging + import logging.config + import logging.handlers + import types + import time # this is only being used as part of the example + import traceback + from tabulate import tabulate + +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = '/usr/local/bin/accton_as4630_54pe_monitor_fan' + +global log_file +global log_level + + +class switch(object): + def __init__(self, value): + self.value = value + self.fall = False + + def __iter__(self): + """Return the match method once, then stop""" + yield self.match + raise StopIteration + + def match(self, *args): + """Indicate whether or not to enter a case suite""" + if self.fall or not args: + return True + elif self.value in args: # changed for v1.5, see below + self.fall = True + return True + else: + return False + + +fan_state=[2, 2, 2, 2] #init state=2, insert=1, remove=0 +fan_status_state=[2, 2, 2, 2] #init state=2, fault=1, normal=0 +# Make a class we can use to capture stdout and sterr in the log +class device_monitor(object): + + def __init__(self, log_file, log_level): + + self.fan_num = 3 + self.fan_path = "/sys/bus/i2c/devices/3-0060/" + self.present = { + 0: "fan_present_1", + 1: "fan_present_2", + 2: "fan_present_3", + } + + self.fault = { + 0: "fan_fault_1", + 1: "fan_fault_2", + 2: "fan_fault_3", + } + + + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(logging.DEBUG) + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + sys_handler = logging.handlers.SysLogHandler(address = '/dev/log') + #sys_handler.setLevel(logging.WARNING) + sys_handler.setLevel(logging.INFO) + logging.getLogger('').addHandler(sys_handler) + + + #logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) + + def manage_fan(self): + + FAN_STATE_REMOVE = 0 + FAN_STATE_INSERT = 1 + + FAN_STATUS_FAULT = 1 + FAN_STATUS_NORMAL = 0 + + global fan_state + global fan_status_state + + for idx in range (0, self.fan_num): + node = self.fan_path + self.present[idx] + try: + val_file = open(node) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + content = val_file.readline().rstrip() + val_file.close() + # content is a string, either "0" or "1" + if content == "1": + if fan_state[idx]!=1: + fan_state[idx]=FAN_STATE_INSERT + logging.info("FAN-%d present is detected", idx+1); + else: + if fan_state[idx]!=0: + fan_state[idx]=FAN_STATE_REMOVE + logging.warning("Alarm for FAN-%d absent is detected", idx+1) + + for idx in range (0, self.fan_num): + node = self.fan_path + self.fault[idx] + try: + val_file = open(node) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + content = val_file.readline().rstrip() + val_file.close() + # content is a string, either "0" or "1" + if content == "1": + if fan_status_state[idx]!=FAN_STATUS_FAULT: + if fan_state[idx] == FAN_STATE_INSERT: + logging.warning("Alarm for FAN-%d failed is detected", idx+1); + fan_status_state[idx]=FAN_STATUS_FAULT + else: + fan_status_state[idx]=FAN_STATUS_NORMAL + + return True + +def main(argv): + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv,'hdl:',['lfile=']) + except getopt.GetoptError: + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + for opt, arg in opts: + if opt == '-h': + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + elif opt in ('-d', '--debug'): + log_level = logging.DEBUG + elif opt in ('-l', '--lfile'): + log_file = arg + monitor = device_monitor(log_file, log_level) + while True: + monitor.manage_fan() + time.sleep(3) + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_monitor_psu.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_monitor_psu.py new file mode 100755 index 0000000000..8ef700f33c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_monitor_psu.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python +# +# Copyright (C) 2018 Accton Technology Corporation +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 5/15/2019: Jostar create for as4630-54pe +# ------------------------------------------------------------------ + +try: + import os + import sys, getopt + import subprocess + import click + import imp + import logging + import logging.config + import logging.handlers + import types + import time # this is only being used as part of the example + import traceback + from tabulate import tabulate +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = '/usr/local/bin/accton_as4630_54pe_monitor_psu' + +global log_file +global log_level + + +psu_state=[2, 2] +psu_status_state=[2, 2] +# Make a class we can use to capture stdout and sterr in the log +class device_monitor(object): + + def __init__(self, log_file, log_level): + + self.psu_num = 2 + self.psu_path = "/sys/bus/i2c/devices/" + self.presence = "/psu_present" + self.oper_status = "/psu_power_good" + self.mapping = { + 0: "10-0050", + 1: "11-0051", + } + + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + # set up logging to console + + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + sys_handler = logging.handlers.SysLogHandler(address = '/dev/log') + #sys_handler.setLevel(logging.WARNING) + sys_handler.setLevel(logging.INFO) + logging.getLogger('').addHandler(sys_handler) + + #logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) + + def manage_psu(self): + + PSU_STATE_REMOVE = 0 + PSU_STATE_INSERT = 1 + + PSU_STATUS_NO_POWER = 0 + PSU_STATUS_POWER_GOOD = 1 + PSU_STATUS_IDLE =2 + + global psu_state + + for idx in range (0, self.psu_num): + node = self.psu_path + self.mapping[idx] + self.presence + try: + val_file = open(node) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + content = val_file.readline().rstrip() + val_file.close() + # content is a string, either "0" or "1" + if content == "1": + if psu_state[idx]!=1: + psu_state[idx]=PSU_STATE_INSERT + logging.info("PSU-%d present is detected", idx+1); + #psu_status_state[idx]=PSU_STATUS_POWER_GOOD #when insert, assume power is good. If no_power, next code will find it. + else: + if psu_state[idx]!=0: + psu_state[idx]=PSU_STATE_REMOVE + logging.warning("Alarm for PSU-%d absent is detected", idx+1); + psu_status_state[idx]=PSU_STATUS_IDLE + + for idx in range (0, self.psu_num): + node = self.psu_path + self.mapping[idx] + self.oper_status + try: + val_file = open(node) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + content = val_file.readline().rstrip() + val_file.close() + # content is a string, either "0" or "1" + if content == "0": + if psu_status_state[idx]!=PSU_STATUS_NO_POWER: + if psu_state[idx]==PSU_STATE_INSERT: + logging.warning("Alarm for PSU-%d failed is detected", idx+1); + psu_status_state[idx]=PSU_STATUS_NO_POWER + else: + if psu_state[idx]==PSU_STATE_INSERT: + if psu_status_state[idx]!=PSU_STATUS_POWER_GOOD: + logging.info("PSU-%d power_good is detected", idx+1); + psu_status_state[idx]=PSU_STATUS_POWER_GOOD + + + return True + +def main(argv): + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv,'hdl:',['lfile=']) + except getopt.GetoptError: + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + for opt, arg in opts: + if opt == '-h': + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + elif opt in ('-d', '--debug'): + log_level = logging.DEBUG + elif opt in ('-l', '--lfile'): + log_file = arg + monitor = device_monitor(log_file, log_level) + # Loop forever, doing something useful hopefully: + while True: + monitor.manage_psu() + time.sleep(3) + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_util.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_util.py new file mode 100755 index 0000000000..2f73726f84 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_util.py @@ -0,0 +1,563 @@ +#!/usr/bin/env python +# +# Copyright (C) 2016 Accton Networks, Inc. +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes + show : show all systen status + sff : dump SFP eeprom + set : change board setting with fan|led|sfp +""" + +import os +import commands +import sys, getopt +import logging +import re +import time +from collections import namedtuple + +PROJECT_NAME = 'as4630_54pe' +version = '0.0.1' +verbose = False +DEBUG = False +args = [] +ALL_DEVICE = {} +DEVICE_NO = {'led':5, 'fan1':1, 'fan2':1,'fan3':1,'fan4':1,'fan5':1,'thermal':3, 'psu':2, 'sfp':54} + + +led_prefix ='/sys/devices/platform/as4630_54pe_led/leds/accton_'+PROJECT_NAME+'_led::' +fan_prefix ='/sys/devices/platform/as4630_54pe_' +hwmon_types = {'led': ['diag','fan','loc','psu1','psu2'], + 'fan1': ['fan'], + 'fan2': ['fan'], + 'fan3': ['fan'], + 'fan4': ['fan'], + 'fan5': ['fan'], + 'fan5': ['fan'], + } +hwmon_nodes = {'led': ['brightness'] , + 'fan1': ['fan_duty_cycle_percentage', 'fan1_fault', 'fan1_speed_rpm', 'fan1_direction', 'fanr1_fault', 'fanr1_speed_rpm'], + 'fan2': ['fan_duty_cycle_percentage','fan2_fault', 'fan2_speed_rpm', 'fan2_direction', 'fanr2_fault', 'fanr2_speed_rpm'], + 'fan3': ['fan_duty_cycle_percentage','fan3_fault', 'fan3_speed_rpm', 'fan3_direction', 'fanr3_fault', 'fanr3_speed_rpm'], + 'fan4': ['fan4_duty_cycle_percentage','fan4_fault', 'fan4_speed_rpm', 'fan4_direction', 'fanr4_fault', 'fanr4_speed_rpm'], + 'fan5': ['fan_duty_cycle_percentage','fan5_fault', 'fan5_speed_rpm', 'fan5_direction', 'fanr5_fault', 'fanr5_speed_rpm'], + } +hwmon_prefix ={'led': led_prefix, + 'fan1': fan_prefix, + 'fan2': fan_prefix, + 'fan3': fan_prefix, + 'fan4': fan_prefix, + 'fan5': fan_prefix, + } + +i2c_prefix = '/sys/bus/i2c/devices/' +i2c_bus = {'fan': ['54-0066'], + 'thermal': ['54-004c', '55-0048','55-0049', '55-004a', '55-004b'] , + 'psu': ['49-0050','50-0053'], + 'sfp': ['-0050']} +i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'], + 'thermal': ['hwmon/hwmon*/temp1_input'] , + 'psu': ['psu_present ', 'psu_power_good'] , + 'sfp': ['module_present_ ', 'module_tx_disable_']} + +sfp_map = [18, 19, 20, 21, 22, 23] + +mknod =[ +'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-2/new_device', +'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-3/new_device', + +'echo as4630_54pe_cpld 0x60 > /sys/bus/i2c/devices/i2c-3/new_device', + +'echo lm77 0x48 > /sys/bus/i2c/devices/i2c-14/new_device', +'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-25/new_device', +'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-24/new_device', + + +# PSU-1 +'echo as4630_54pe_psu1 0x50 > /sys/bus/i2c/devices/i2c-10/new_device', +'echo ype1200am 0x58 > /sys/bus/i2c/devices/i2c-10/new_device', + +# PSU-2 +'echo as4630_54pe_psu2 0x51> /sys/bus/i2c/devices/i2c-11/new_device', +'echo ype1200am 0x59 > /sys/bus/i2c/devices/i2c-11/new_device', + +#EERPOM +'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-1/new_device', +] + + + +FORCE = 0 +logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG) +logging.basicConfig(level=logging.INFO) + + +if DEBUG == True: + print sys.argv[0] + print 'ARGV :', sys.argv[1:] + + +def main(): + global DEBUG + global args + global FORCE + + if len(sys.argv)<2: + show_help() + + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', + 'debug', + 'force', + ]) + if DEBUG == True: + print options + print args + print len(sys.argv) + + for opt, arg in options: + if opt in ('-h', '--help'): + show_help() + elif opt in ('-d', '--debug'): + DEBUG = True + logging.basicConfig(level=logging.INFO) + elif opt in ('-f', '--force'): + FORCE = 1 + else: + print "TEST" + logging.info('no option') + for arg in args: + if arg == 'install': + do_install() + elif arg == 'clean': + do_uninstall() + elif arg == 'show': + device_traversal() + elif arg == 'sff': + if len(args)!=2: + show_eeprom_help() + elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']: + show_eeprom_help() + else: + show_eeprom(args[1]) + return + elif arg == 'set': + if len(args)<3: + show_set_help() + else: + set_device(args[1:]) + return + else: + show_help() + + + return 0 + +def show_help(): + print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} + sys.exit(0) + +def show_set_help(): + cmd = sys.argv[0].split("/")[-1]+ " " + args[0] + print cmd +" [led|sfp|fan]" + print " use \""+ cmd + " led 0-4 \" to set led color" + print " use \""+ cmd + " fan 0-100\" to set fan duty percetage" + print " use \""+ cmd + " sfp 1-32 {0|1}\" to set sfp# tx_disable" + sys.exit(0) + +def show_eeprom_help(): + cmd = sys.argv[0].split("/")[-1]+ " " + args[0] + print " use \""+ cmd + " 1-32 \" to dump sfp# eeprom" + sys.exit(0) + +def my_log(txt): + if DEBUG == True: + print "[ACCTON DBG]: "+txt + return + +def log_os_system(cmd, show): + logging.info('Run :'+cmd) + status = 1 + output = "" + status, output = commands.getstatusoutput(cmd) + my_log (cmd +"with result:" + str(status)) + my_log ("cmd:" + cmd) + my_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + +def driver_inserted(): + ret, lsmod = log_os_system("lsmod| grep accton", 0) + logging.info('mods:'+lsmod) + if len(lsmod) ==0: + return False + +#'modprobe cpr_4011_4mxx', + +kos = [ +'depmod -ae', +'modprobe i2c_dev', +'modprobe i2c_mux_pca954x force_deselect_on_exit=1', +'modprobe ym2651y', +'modprobe x86_64_accton_as4630_54pe_cpld', +'modprobe x86_64_accton_as4630_54pe_leds', +'modprobe x86_64_accton_as4630_54pe_psu', +'modprobe optoe'] + +def driver_install(): + global FORCE + + ret=log_os_system("lsmod|grep i2c_ismt",1) + my_log("rmmond i2cismt") + log_os_system("rmmod i2c_ismt", 1) + log_os_system("rmmod i2c_i801", 1) + log_os_system("modprobe i2c-i801", 1) + time.sleep(1) + log_os_system("modprobe i2c-ismt", 1) + + + + for i in range(0,len(kos)): + status, output = log_os_system(kos[i], 1) + if status: + if FORCE == 0: + return status + + return 0 + +def driver_uninstall(): + global FORCE + for i in range(0,len(kos)): + rm = kos[-(i+1)].replace("modprobe", "modprobe -rq") + lst = rm.split(" ") + print "lst=%s"%lst + if len(lst) > 3: + del(lst[3]) + rm = " ".join(lst) + status, output = log_os_system(rm, 1) + if status: + if FORCE == 0: + return status + return 0 + +def device_install(): + global FORCE + + for i in range(0,len(mknod)): + #for pca954x need times to built new i2c buses + if mknod[i].find('pca954') != -1: + time.sleep(2) + + status, output = log_os_system(mknod[i], 1) + if status: + print output + if FORCE == 0: + return status + print("Check SFP") + for i in range(0,len(sfp_map)): + if(i < 4): + opt='optoe2' + else: + opt='optoe1' + status, output =log_os_system("echo " + str(opt) + " 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + + status, output =log_os_system("echo port"+str(i+49) + " > /sys/bus/i2c/devices/"+str(sfp_map[i])+"-0050/port_name", 1) + if status: + print output + if FORCE == 0: + return status + + return + +def device_uninstall(): + global FORCE + + status, output =log_os_system("ls /sys/bus/i2c/devices/0-0070", 0) + if status==0: + I2C_ORDER=1 + else: + I2C_ORDER=0 + + for i in range(0,len(sfp_map)): + target = "/sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/delete_device" + status, output =log_os_system("echo 0x50 > "+ target, 1) + if status: + print output + if FORCE == 0: + return status + + nodelist = mknod + + for i in range(len(nodelist)): + target = nodelist[-(i+1)] + temp = target.split() + del temp[1] + temp[-1] = temp[-1].replace('new_device', 'delete_device') + status, output = log_os_system(" ".join(temp), 1) + if status: + print output + if FORCE == 0: + return status + + return + +def system_ready(): + if driver_inserted() == False: + return False + if not device_exist(): + print "not device_exist()" + return False + return True + +def do_install(): + if driver_inserted() == False: + status = driver_install() + if status: + if FORCE == 0: + return status + else: + print PROJECT_NAME.upper()+" drivers detected...." + if not device_exist(): + status = device_install() + if status: + if FORCE == 0: + return status + else: + print PROJECT_NAME.upper()+" devices detected...." + return + +def do_uninstall(): + if not device_exist(): + print PROJECT_NAME.upper() +" has no device installed...." + else: + print "Removing device...." + status = device_uninstall() + if status: + if FORCE == 0: + return status + + if driver_inserted()== False : + print PROJECT_NAME.upper() +" has no driver installed...." + else: + print "Removing installed driver...." + status = driver_uninstall() + if status: + if FORCE == 0: + return status + + return + +def devices_info(): + global DEVICE_NO + global ALL_DEVICE + global i2c_bus, hwmon_types + for key in DEVICE_NO: + ALL_DEVICE[key]= {} + for i in range(0,DEVICE_NO[key]): + ALL_DEVICE[key][key+str(i+1)] = [] + + for key in i2c_bus: + buses = i2c_bus[key] + nodes = i2c_nodes[key] + for i in range(0,len(buses)): + for j in range(0,len(nodes)): + if 'fan' == key: + for k in range(0,DEVICE_NO[key]): + node = key+str(k+1) + path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + elif 'sfp' == key: + for k in range(0,DEVICE_NO[key]): + node = key+str(k+1) + path = i2c_prefix+ str(sfp_map[k])+ buses[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + else: + node = key+str(i+1) + path = i2c_prefix+ buses[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + + for key in hwmon_types: + itypes = hwmon_types[key] + nodes = hwmon_nodes[key] + for i in range(0,len(itypes)): + for j in range(0,len(nodes)): + node = key+"_"+itypes[i] + path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][ key+str(i+1)].append(path) + + #show dict all in the order + if DEBUG == True: + for i in sorted(ALL_DEVICE.keys()): + print(i+": ") + for j in sorted(ALL_DEVICE[i].keys()): + print(" "+j) + for k in (ALL_DEVICE[i][j]): + print(" "+" "+k) + return + +def show_eeprom(index): + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0] + node = node.replace(node.split("/")[-1], 'eeprom') + # check if got hexdump command in current environment + ret, log = log_os_system("which hexdump", 0) + ret, log2 = log_os_system("which busybox hexdump", 0) + if len(log): + hex_cmd = 'hexdump' + elif len(log2): + hex_cmd = ' busybox hexdump' + else: + log = 'Failed : no hexdump cmd!!' + logging.info(log) + print log + return 1 + print "node=%s"%node + print node + ":" + ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1) + if ret==0: + print log + else: + print "**********device no found**********" + return + +def set_device(args): + global DEVICE_NO + global ALL_DEVICE + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + + if args[0]=='led': + if int(args[1])>4: + show_set_help() + return + #print ALL_DEVICE['led'] + for i in range(0,len(ALL_DEVICE['led'])): + for k in (ALL_DEVICE['led']['led'+str(i+1)]): + ret, log = log_os_system("echo "+args[1]+" >"+k, 1) + if ret: + return ret + elif args[0]=='fan': + if int(args[1])>100: + show_set_help() + return + #print ALL_DEVICE['fan'] + #fan1~6 is all fine, all fan share same setting + node = ALL_DEVICE['fan1'] ['fan11'][0] + node = node.replace(node.split("/")[-1], 'fan1_duty_cycle_percentage') + ret, log = log_os_system("cat "+ node, 1) + if ret==0: + print ("Previous fan duty: " + log.strip() +"%") + ret, log = log_os_system("echo "+args[1]+" >"+node, 1) + if ret==0: + print ("Current fan duty: " + args[1] +"%") + return ret + elif args[0]=='sfp': + if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0: + show_set_help() + return + if len(args)<2: + show_set_help() + return + + if int(args[2])>1: + show_set_help() + return + + #print ALL_DEVICE[args[0]] + for i in range(0,len(ALL_DEVICE[args[0]])): + for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]: + if j.find('tx_disable')!= -1: + ret, log = log_os_system("echo "+args[2]+" >"+ j, 1) + if ret: + return ret + + return + +#get digits inside a string. +#Ex: 31 for "sfp31" +def get_value(input): + digit = re.findall('\d+', input) + return int(digit[0]) + +def device_traversal(): + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + for i in sorted(ALL_DEVICE.keys()): + print("============================================") + print(i.upper()+": ") + print("============================================") + + for j in sorted(ALL_DEVICE[i].keys(), key=get_value): + print " "+j+":", + for k in (ALL_DEVICE[i][j]): + ret, log = log_os_system("cat "+k, 0) + func = k.split("/")[-1].strip() + func = re.sub(j+'_','',func,1) + func = re.sub(i.lower()+'_','',func,1) + if ret==0: + print func+"="+log+" ", + else: + print func+"="+"X"+" ", + print + print("----------------------------------------------------------------") + + + print + return + +def device_exist(): + ret1, log = log_os_system("ls "+i2c_prefix+"*0077", 0) + ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0) + return not(ret1 or ret2) + +if __name__ == "__main__": + main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as5712-54x/modules/i2c-mux-accton_as5712_54x_cpld.c b/platform/broadcom/sonic-platform-modules-accton/as5712-54x/modules/i2c-mux-accton_as5712_54x_cpld.c index ed097e6b30..9dbac9ca33 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as5712-54x/modules/i2c-mux-accton_as5712_54x_cpld.c +++ b/platform/broadcom/sonic-platform-modules-accton/as5712-54x/modules/i2c-mux-accton_as5712_54x_cpld.c @@ -37,6 +37,7 @@ #include #include #include +#include #define I2C_RW_RETRY_COUNT 10 #define I2C_RW_RETRY_INTERVAL 60 /* ms */ @@ -78,16 +79,16 @@ struct chip_desc { /* Provide specs for the PCA954x types we know about */ static const struct chip_desc chips[] = { [as5712_54x_cpld1] = { - .nchans = NUM_OF_CPLD1_CHANS, - .deselectChan = CPLD_DESELECT_CHANNEL, + .nchans = NUM_OF_CPLD1_CHANS, + .deselectChan = CPLD_DESELECT_CHANNEL, }, [as5712_54x_cpld2] = { - .nchans = NUM_OF_CPLD2_CHANS, - .deselectChan = CPLD_DESELECT_CHANNEL, + .nchans = NUM_OF_CPLD2_CHANS, + .deselectChan = CPLD_DESELECT_CHANNEL, }, [as5712_54x_cpld3] = { - .nchans = NUM_OF_CPLD3_CHANS, - .deselectChan = CPLD_DESELECT_CHANNEL, + .nchans = NUM_OF_CPLD3_CHANS, + .deselectChan = CPLD_DESELECT_CHANNEL, } }; @@ -103,6 +104,8 @@ MODULE_DEVICE_TABLE(i2c, as5712_54x_cpld_mux_id); #define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index #define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index #define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index +#define TRANSCEIVER_LPMODE_ATTR_ID(index) MODULE_LPMODE_##index +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index enum as5712_54x_cpld1_sysfs_attributes { CPLD_VERSION, @@ -308,22 +311,38 @@ enum as5712_54x_cpld1_sysfs_attributes { TRANSCEIVER_TXFAULT_ATTR_ID(46), TRANSCEIVER_TXFAULT_ATTR_ID(47), TRANSCEIVER_TXFAULT_ATTR_ID(48), + TRANSCEIVER_LPMODE_ATTR_ID(49), + TRANSCEIVER_LPMODE_ATTR_ID(50), + TRANSCEIVER_LPMODE_ATTR_ID(51), + TRANSCEIVER_LPMODE_ATTR_ID(52), + TRANSCEIVER_LPMODE_ATTR_ID(53), + TRANSCEIVER_LPMODE_ATTR_ID(54), + TRANSCEIVER_RESET_ATTR_ID(49), + TRANSCEIVER_RESET_ATTR_ID(50), + TRANSCEIVER_RESET_ATTR_ID(51), + TRANSCEIVER_RESET_ATTR_ID(52), + TRANSCEIVER_RESET_ATTR_ID(53), + TRANSCEIVER_RESET_ATTR_ID(54), }; -/* sysfs attributes for hwmon +/* sysfs attributes for hwmon */ static ssize_t show_status(struct device *dev, struct device_attribute *da, - char *buf); + char *buf); static ssize_t show_present_all(struct device *dev, struct device_attribute *da, - char *buf); + char *buf); static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, - char *buf); + char *buf); static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, - const char *buf, size_t count); + const char *buf, size_t count); +static ssize_t set_lp_mode(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_mode_reset(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); static ssize_t access(struct device *dev, struct device_attribute *da, - const char *buf, size_t count); + const char *buf, size_t count); static ssize_t show_version(struct device *dev, struct device_attribute *da, - char *buf); + char *buf); static int as5712_54x_cpld_read_internal(struct i2c_client *client, u8 reg); static int as5712_54x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value); @@ -336,11 +355,21 @@ static int as5712_54x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_tx_disable, MODULE_TXDISABLE_##index); \ static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \ static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_TXFAULT_##index) + #define DECLARE_SFP_TRANSCEIVER_ATTR(index) \ &sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \ &sensor_dev_attr_module_rx_los_##index.dev_attr.attr, \ &sensor_dev_attr_module_tx_fault_##index.dev_attr.attr +#define DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_lp_mode_##index, S_IRUGO | S_IWUSR, show_status, set_lp_mode, MODULE_LPMODE_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IWUSR | S_IRUGO, show_status, set_mode_reset, MODULE_RESET_##index) + +#define DECLARE_QSFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_lp_mode_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr + + static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); /* transceiver attributes */ @@ -449,6 +478,12 @@ DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(45); DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(46); DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(47); DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(48); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(49); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(50); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(51); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(52); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(53); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(54); static struct attribute *as5712_54x_cpld1_attributes[] = { &sensor_dev_attr_version.dev_attr.attr, @@ -581,6 +616,12 @@ static struct attribute *as5712_54x_cpld3_attributes[] = { DECLARE_SFP_TRANSCEIVER_ATTR(46), DECLARE_SFP_TRANSCEIVER_ATTR(47), DECLARE_SFP_TRANSCEIVER_ATTR(48), + DECLARE_QSFP_TRANSCEIVER_ATTR(49), + DECLARE_QSFP_TRANSCEIVER_ATTR(50), + DECLARE_QSFP_TRANSCEIVER_ATTR(51), + DECLARE_QSFP_TRANSCEIVER_ATTR(52), + DECLARE_QSFP_TRANSCEIVER_ATTR(53), + DECLARE_QSFP_TRANSCEIVER_ATTR(54), NULL }; @@ -589,7 +630,7 @@ static const struct attribute_group as5712_54x_cpld3_group = { }; static ssize_t show_present_all(struct device *dev, struct device_attribute *da, - char *buf) + char *buf) { int i, status, num_regs = 0; u8 values[4] = {0}; @@ -604,7 +645,7 @@ static ssize_t show_present_all(struct device *dev, struct device_attribute *da, for (i = 0; i < num_regs; i++) { status = as5712_54x_cpld_read_internal(client, regs[i]); - + if (status < 0) { goto exit; } @@ -617,12 +658,12 @@ static ssize_t show_present_all(struct device *dev, struct device_attribute *da, /* Return values 1 -> 54 in order */ if (data->type == as5712_54x_cpld2) { status = sprintf(buf, "%.2x %.2x %.2x\n", - values[0], values[1], values[2]); + values[0], values[1], values[2]); } else { /* as5712_54x_cpld3 */ values[3] &= 0x3F; status = sprintf(buf, "%.2x %.2x %.2x %.2x\n", - values[0], values[1], values[2], values[3]); + values[0], values[1], values[2], values[3]); } return status; @@ -633,7 +674,7 @@ exit: } static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, - char *buf) + char *buf) { int i, status; u8 values[3] = {0}; @@ -646,7 +687,7 @@ static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, for (i = 0; i < ARRAY_SIZE(regs); i++) { status = as5712_54x_cpld_read_internal(client, regs[i]); - + if (status < 0) { goto exit; } @@ -665,7 +706,7 @@ exit: } static ssize_t show_status(struct device *dev, struct device_attribute *da, - char *buf) + char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); @@ -795,6 +836,14 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, reg = 0x11; mask = 0x1 << (attr->index - MODULE_RXLOS_41); break; + case MODULE_LPMODE_49 ... MODULE_LPMODE_54: + reg = 0x16; + mask = 0x1 << (attr->index - MODULE_LPMODE_49); + break; + case MODULE_RESET_49 ... MODULE_RESET_54: + reg = 0x15; + mask = 0x1 << (attr->index - MODULE_RESET_49); + break; default: return 0; } @@ -818,7 +867,7 @@ exit: } static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) + const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); @@ -881,7 +930,7 @@ static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, if (unlikely(status < 0)) { goto exit; } - + mutex_unlock(&data->update_lock); return count; @@ -890,8 +939,110 @@ exit: return status; } +static ssize_t set_lp_mode(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc); + + long on; + int status= -ENOENT; + u8 reg = 0x16, mask = 0; + + if(attr->index < MODULE_LPMODE_49 || attr->index > MODULE_LPMODE_54) + return status; + + status = kstrtol(buf, 10, &on); + if (status) { + return status; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as5712_54x_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + mask = 0x1 << (attr->index - MODULE_LPMODE_49); + + /* Update lp_mode status */ + if (on) { + status |= mask; + } + else { + status &= ~mask; + } + + status = as5712_54x_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; + +} + +static ssize_t set_mode_reset(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc); + + long on; + int status= -ENOENT; + u8 reg = 0x15, mask = 0; + + if(attr->index < MODULE_RESET_49 || attr->index > MODULE_RESET_54) + return status; + + status = kstrtol(buf, 10, &on); + if (status) { + return status; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as5712_54x_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + mask = 0x1 << (attr->index - MODULE_RESET_49); + + /* Update tx_disable status */ + if (on) { + status |= mask; + } + else { + status &= ~mask; + } + + status = as5712_54x_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; + +} + static ssize_t access(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct i2c_mux_core *muxc = i2c_get_clientdata(client); @@ -923,7 +1074,7 @@ exit: /* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer() for this as they will try to lock adapter a second time */ static int as5712_54x_cpld_mux_reg_write(struct i2c_adapter *adap, - struct i2c_client *client, u8 val) + struct i2c_client *client, u8 val) { unsigned long orig_jiffies; unsigned short flags; @@ -939,22 +1090,22 @@ static int as5712_54x_cpld_mux_reg_write(struct i2c_adapter *adap, /* Retry automatically on arbitration loss */ orig_jiffies = jiffies; for (res = 0, try = 0; try <= adap->retries; try++) { - res = adap->algo->smbus_xfer(adap, client->addr, flags, - I2C_SMBUS_WRITE, CPLD_CHANNEL_SELECT_REG, - I2C_SMBUS_BYTE_DATA, &data); - if (res != -EAGAIN) - break; - if (time_after(jiffies, - orig_jiffies + adap->timeout)) - break; - } + res = adap->algo->smbus_xfer(adap, client->addr, flags, + I2C_SMBUS_WRITE, CPLD_CHANNEL_SELECT_REG, + I2C_SMBUS_BYTE_DATA, &data); + if (res != -EAGAIN) + break; + if (time_after(jiffies, + orig_jiffies + adap->timeout)) + break; + } } return res; } -static int as5712_54x_cpld_mux_select_chan(struct i2c_mux_core *muxc, - u32 chan) +static int as5712_54x_cpld_mux_select_chan(struct i2c_mux_core *muxc, + u32 chan) { struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc); struct i2c_client *client = data->client; @@ -972,7 +1123,7 @@ static int as5712_54x_cpld_mux_select_chan(struct i2c_mux_core *muxc, } static int as5712_54x_cpld_mux_deselect_mux(struct i2c_mux_core *muxc, - u32 chan) + u32 chan) { struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc); struct i2c_client *client = data->client; @@ -1028,13 +1179,13 @@ static ssize_t show_version(struct device *dev, struct device_attribute *attr, c { int val = 0; struct i2c_client *client = to_i2c_client(dev); - + val = i2c_smbus_read_byte_data(client, 0x1); if (val < 0) { dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val); } - + return sprintf(buf, "%d", val); } @@ -1042,7 +1193,7 @@ static ssize_t show_version(struct device *dev, struct device_attribute *attr, c * I2C init/probing/exit functions */ static int as5712_54x_cpld_mux_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); int num, force, class; @@ -1055,8 +1206,8 @@ static int as5712_54x_cpld_mux_probe(struct i2c_client *client, return -ENODEV; muxc = i2c_mux_alloc(adap, &client->dev, - chips[id->driver_data].nchans, sizeof(*data), 0, - as5712_54x_cpld_mux_select_chan, as5712_54x_cpld_mux_deselect_mux); + chips[id->driver_data].nchans, sizeof(*data), 0, + as5712_54x_cpld_mux_select_chan, as5712_54x_cpld_mux_deselect_mux); if (!muxc) return -ENOMEM; @@ -1076,8 +1227,8 @@ static int as5712_54x_cpld_mux_probe(struct i2c_client *client, if (ret) { dev_err(&client->dev, - "failed to register multiplexed adapter" - " %d as bus %d\n", num, force); + "failed to register multiplexed adapter" + " %d as bus %d\n", num, force); goto add_mux_failed; } } @@ -1099,7 +1250,7 @@ static int as5712_54x_cpld_mux_probe(struct i2c_client *client, default: break; } - + if (group) { ret = sysfs_create_group(&client->dev.kobj, group); if (ret) { @@ -1109,12 +1260,12 @@ static int as5712_54x_cpld_mux_probe(struct i2c_client *client, if (chips[data->type].nchans) { dev_info(&client->dev, - "registered %d multiplexed busses for I2C %s\n", - num, client->name); + "registered %d multiplexed busses for I2C %s\n", + num, client->name); } else { dev_info(&client->dev, - "device %s registered\n", client->name); + "device %s registered\n", client->name); } as5712_54x_cpld_add_client(client); diff --git a/platform/broadcom/sonic-platform-modules-accton/as5712-54x/utils/accton_as5712_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as5712-54x/utils/accton_as5712_monitor.py index d7b3721458..09b2b9ea96 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as5712-54x/utils/accton_as5712_monitor.py +++ b/platform/broadcom/sonic-platform-modules-accton/as5712-54x/utils/accton_as5712_monitor.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (C) 2017 Accton Technology Corporation +# Copyright (C) 2019 Accton Technology Corporation # # 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 @@ -19,7 +19,7 @@ # HISTORY: # mm/dd/yyyy (A.D.) # 11/13/2017: Polly Hsu, Create -# +# 05/08/2019: Roy Lee, changed for as5712-54x. # ------------------------------------------------------------------ try: @@ -53,7 +53,6 @@ class accton_as5712_monitor(object): # static temp var _ori_temp = 0 _new_perc = 0 - _ori_perc = 0 def __init__(self, log_file, log_level): """Needs a logger and a logger level.""" @@ -77,9 +76,9 @@ class accton_as5712_monitor(object): logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) def manage_fans(self): - FAN_LEV1_UP_TEMP = 57500 # temperature + FAN_LEV1_UP_TEMP = 57700 # temperature FAN_LEV1_DOWN_TEMP = 0 # unused - FAN_LEV1_SPEED_PERC = 100 # percentage*/ + FAN_LEV1_SPEED_PERC = DUTY_MAX # percentage*/ FAN_LEV2_UP_TEMP = 53000 FAN_LEV2_DOWN_TEMP = 52700 @@ -151,8 +150,9 @@ class accton_as5712_monitor(object): self._new_perc = FAN_LEV1_SPEED_PERC logging.debug('INFO. SET. FAN_SPEED as %d (new THERMAL temp:%d)', self._new_perc, new_temp) - if self._ori_perc == self._new_perc: - logging.debug('INFO. RETURN. FAN speed not changed. %d / %d (new_perc / ori_perc)', self._new_perc, self._ori_perc) + cur_perc = fan.get_fan_duty_cycle(fan.get_idx_fan_start()) + if cur_perc == self._new_perc: + logging.debug('INFO. RETURN. FAN speed not changed. %d / %d (new_perc / ori_perc)', self._new_perc, cur_perc) return True set_stat = fan.set_fan_duty_cycle(fan.get_idx_fan_start(), self._new_perc) @@ -161,10 +161,9 @@ class accton_as5712_monitor(object): else: logging.debug('INFO: FAIL. set_fan_duty_cycle (%d)', self._new_perc) - logging.debug('INFO: GET. ori_perc is %d. ori_temp is %d', self._ori_perc, self._ori_temp) - self._ori_perc = self._new_perc + logging.debug('INFO: GET. ori_perc is %d. ori_temp is %d', cur_perc, self._ori_temp) self._ori_temp = new_temp - logging.debug('INFO: UPDATE. ori_perc to %d. ori_temp to %d', self._ori_perc, self._ori_temp) + logging.debug('INFO: UPDATE. ori_perc to %d. ori_temp to %d', cur_perc, self._ori_temp) return True @@ -199,7 +198,7 @@ def main(argv): # Loop forever, doing something useful hopefully: while True: monitor.manage_fans() - time.sleep(1) + time.sleep(10) if __name__ == '__main__': main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/__init__.py new file mode 100755 index 0000000000..e69de29bb2 diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/fanutil.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/fanutil.py new file mode 100755 index 0000000000..efb21b9a45 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/fanutil.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 Accton Technology Corporation +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 11/13/2017: Polly Hsu, Create +# +# ------------------------------------------------------------------ + +try: + import time + import logging + from collections import namedtuple +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + + +class FanUtil(object): + """Platform-specific FanUtil class""" + + FAN_NUM_ON_MAIN_BROAD = 5 + FAN_NUM_1_IDX = 1 + FAN_NUM_2_IDX = 2 + FAN_NUM_3_IDX = 3 + FAN_NUM_4_IDX = 4 + FAN_NUM_5_IDX = 5 + + FAN_NODE_NUM_OF_MAP = 6 + FAN_NODE_FAULT_IDX_OF_MAP = 1 + FAN_NODE_SPEED_IDX_OF_MAP = 2 + FAN_NODE_DIR_IDX_OF_MAP = 3 + FAN_NODE_DUTY_IDX_OF_MAP = 4 + FANR_NODE_FAULT_IDX_OF_MAP = 5 + FANR_NODE_SPEED_IDX_OF_MAP = 6 + + BASE_VAL_PATH = '/sys/devices/platform/as5812_54x_fan/{0}' + + #logfile = '' + #loglevel = logging.INFO + + """ Dictionary where + key1 = fan id index (integer) starting from 1 + key2 = fan node index (interger) starting from 1 + value = path to fan device file (string) """ + _fan_to_device_path_mapping = {} + + _fan_to_device_node_mapping = { + (FAN_NUM_1_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan1_fault', + (FAN_NUM_1_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan1_speed_rpm', + (FAN_NUM_1_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan1_direction', + (FAN_NUM_1_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan1_duty_cycle_percentage', + (FAN_NUM_1_IDX, FANR_NODE_FAULT_IDX_OF_MAP): 'fanr1_fault', + (FAN_NUM_1_IDX, FANR_NODE_SPEED_IDX_OF_MAP): 'fanr1_speed_rpm', + + (FAN_NUM_2_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan2_fault', + (FAN_NUM_2_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan2_speed_rpm', + (FAN_NUM_2_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan2_direction', + (FAN_NUM_2_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan2_duty_cycle_percentage', + (FAN_NUM_2_IDX, FANR_NODE_FAULT_IDX_OF_MAP): 'fanr2_fault', + (FAN_NUM_2_IDX, FANR_NODE_SPEED_IDX_OF_MAP): 'fanr2_speed_rpm', + + (FAN_NUM_3_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan3_fault', + (FAN_NUM_3_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan3_speed_rpm', + (FAN_NUM_3_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan3_direction', + (FAN_NUM_3_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan3_duty_cycle_percentage', + (FAN_NUM_3_IDX, FANR_NODE_FAULT_IDX_OF_MAP): 'fanr3_fault', + (FAN_NUM_3_IDX, FANR_NODE_SPEED_IDX_OF_MAP): 'fanr3_speed_rpm', + + (FAN_NUM_4_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan4_fault', + (FAN_NUM_4_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan4_speed_rpm', + (FAN_NUM_4_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan4_direction', + (FAN_NUM_4_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan4_duty_cycle_percentage', + (FAN_NUM_4_IDX, FANR_NODE_FAULT_IDX_OF_MAP): 'fanr4_fault', + (FAN_NUM_4_IDX, FANR_NODE_SPEED_IDX_OF_MAP): 'fanr4_speed_rpm', + + (FAN_NUM_5_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan5_fault', + (FAN_NUM_5_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan5_speed_rpm', + (FAN_NUM_5_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan5_direction', + (FAN_NUM_5_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan5_duty_cycle_percentage', + (FAN_NUM_5_IDX, FANR_NODE_FAULT_IDX_OF_MAP): 'fanr5_fault', + (FAN_NUM_5_IDX, FANR_NODE_SPEED_IDX_OF_MAP): 'fanr5_speed_rpm', + } + + def _get_fan_to_device_node(self, fan_num, node_num): + return self._fan_to_device_node_mapping[(fan_num, node_num)] + + def _get_fan_node_val(self, fan_num, node_num): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: + logging.debug('GET. Parameter error. fan_num:%d', fan_num) + return None + + if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP: + logging.debug('GET. Parameter error. node_num:%d', node_num) + return None + + device_path = self.get_fan_to_device_path(fan_num, node_num) + try: + val_file = open(device_path, 'r') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + + content = val_file.readline().rstrip() + + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + + try: + val_file.close() + except: + logging.debug('GET. unable to close file. device_path:%s', device_path) + return None + + return int(content) + + def _set_fan_node_val(self, fan_num, node_num, val): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: + logging.debug('GET. Parameter error. fan_num:%d', fan_num) + return None + + if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP: + logging.debug('GET. Parameter error. node_num:%d', node_num) + return None + + content = str(val) + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + + device_path = self.get_fan_to_device_path(fan_num, node_num) + try: + val_file = open(device_path, 'w') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + + val_file.write(content) + + try: + val_file.close() + except: + logging.debug('GET. unable to close file. device_path:%s', device_path) + return None + + return True + + def __init__(self): + fan_path = self.BASE_VAL_PATH + + for fan_num in range(self.FAN_NUM_1_IDX, self.FAN_NUM_ON_MAIN_BROAD+1): + for node_num in range(self.FAN_NODE_FAULT_IDX_OF_MAP, self.FAN_NODE_NUM_OF_MAP+1): + self._fan_to_device_path_mapping[(fan_num, node_num)] = fan_path.format( + self._fan_to_device_node_mapping[(fan_num, node_num)]) + + def get_num_fans(self): + return self.FAN_NUM_ON_MAIN_BROAD + + def get_idx_fan_start(self): + return self.FAN_NUM_1_IDX + + def get_num_nodes(self): + return self.FAN_NODE_NUM_OF_MAP + + def get_idx_node_start(self): + return self.FAN_NODE_FAULT_IDX_OF_MAP + + def get_size_node_map(self): + return len(self._fan_to_device_node_mapping) + + def get_size_path_map(self): + return len(self._fan_to_device_path_mapping) + + def get_fan_to_device_path(self, fan_num, node_num): + return self._fan_to_device_path_mapping[(fan_num, node_num)] + + def get_fan_fault(self, fan_num): + return self._get_fan_node_val(fan_num, self.FAN_NODE_FAULT_IDX_OF_MAP) + + def get_fan_speed(self, fan_num): + return self._get_fan_node_val(fan_num, self.FAN_NODE_SPEED_IDX_OF_MAP) + + def get_fan_dir(self, fan_num): + return self._get_fan_node_val(fan_num, self.FAN_NODE_DIR_IDX_OF_MAP) + + def get_fan_duty_cycle(self, fan_num): + return self._get_fan_node_val(fan_num, self.FAN_NODE_DUTY_IDX_OF_MAP) + + def set_fan_duty_cycle(self, fan_num, val): + return self._set_fan_node_val(fan_num, self.FAN_NODE_DUTY_IDX_OF_MAP, val) + + def get_fanr_fault(self, fan_num): + return self._get_fan_node_val(fan_num, self.FANR_NODE_FAULT_IDX_OF_MAP) + + def get_fanr_speed(self, fan_num): + return self._get_fan_node_val(fan_num, self.FANR_NODE_SPEED_IDX_OF_MAP) + + def get_fan_status(self, fan_num): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: + logging.debug('GET. Parameter error. fan_num, %d', fan_num) + return None + + if self.get_fan_fault(fan_num) is not None and self.get_fan_fault(fan_num) > 0: + logging.debug('GET. FAN fault. fan_num, %d', fan_num) + return False + + if self.get_fanr_fault(fan_num) is not None and self.get_fanr_fault(fan_num) > 0: + logging.debug('GET. FANR fault. fan_num, %d', fan_num) + return False + + return True + +#def main(): +# fan = FanUtil() +# +# print 'get_size_node_map : %d' % fan.get_size_node_map() +# print 'get_size_path_map : %d' % fan.get_size_path_map() +# for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1): +# for y in range(fan.get_idx_node_start(), fan.get_num_nodes()+1): +# print fan.get_fan_to_device_path(x, y) +# +#if __name__ == '__main__': +# main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/thermalutil.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/thermalutil.py new file mode 100755 index 0000000000..5b8f890e88 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/classes/thermalutil.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 Accton Technology Corporation +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 11/13/2017: Polly Hsu, Create +# +# ------------------------------------------------------------------ + +try: + import time + import logging + import glob + from collections import namedtuple +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + + +class ThermalUtil(object): + """Platform-specific ThermalUtil class""" + + THERMAL_NUM_ON_MAIN_BROAD = 3 + THERMAL_NUM_1_IDX = 1 # 1_ON_MAIN_BROAD + THERMAL_NUM_2_IDX = 2 # 2_ON_MAIN_BROAD + THERMAL_NUM_3_IDX = 3 # 3_ON_MAIN_BROAD + + BASE_VAL_PATH = '/sys/bus/i2c/devices/{0}-00{1}/hwmon/hwmon*/temp1_input' + + """ Dictionary where + key1 = thermal id index (integer) starting from 1 + value = path to fan device file (string) """ + _thermal_to_device_path_mapping = {} + + _thermal_to_device_node_mapping = { + THERMAL_NUM_1_IDX: ['61', '48'], + THERMAL_NUM_2_IDX: ['62', '49'], + THERMAL_NUM_3_IDX: ['63', '4a'], + } + + def __init__(self): + thermal_path = self.BASE_VAL_PATH + + for x in range(self.THERMAL_NUM_1_IDX, self.THERMAL_NUM_ON_MAIN_BROAD+1): + self._thermal_to_device_path_mapping[x] = thermal_path.format( + self._thermal_to_device_node_mapping[x][0], + self._thermal_to_device_node_mapping[x][1]) + + def _get_thermal_node_val(self, thermal_num): + if thermal_num < self.THERMAL_NUM_1_IDX or thermal_num > self.THERMAL_NUM_ON_MAIN_BROAD: + logging.debug('GET. Parameter error. thermal_num, %d', thermal_num) + return None + + device_path = self.get_thermal_to_device_path(thermal_num) + for filename in glob.glob(device_path): + try: + val_file = open(filename, 'r') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + + content = val_file.readline().rstrip() + + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + + try: + val_file.close() + except: + logging.debug('GET. unable to close file. device_path:%s', device_path) + return None + + return int(content) + + + def get_num_thermals(self): + return self.THERMAL_NUM_ON_MAIN_BROAD + + def get_idx_thermal_start(self): + return self.THERMAL_NUM_1_IDX + + def get_size_node_map(self): + return len(self._thermal_to_device_node_mapping) + + def get_size_path_map(self): + return len(self._thermal_to_device_path_mapping) + + def get_thermal_to_device_path(self, thermal_num): + return self._thermal_to_device_path_mapping[thermal_num] + + def get_thermal_1_val(self): + return self._get_thermal_node_val(self.THERMAL_NUM_1_IDX) + + def get_thermal_2_val(self): + return self._get_thermal_node_val(self.THERMAL_NUM_2_IDX) + +#def main(): +# thermal = ThermalUtil() +# +# print 'get_size_node_map : %d' % thermal.get_size_node_map() +# print 'get_size_path_map : %d' % thermal.get_size_path_map() +# for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1): +# print thermal.get_thermal_to_device_path(x) +# +#if __name__ == '__main__': +# main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/Makefile new file mode 100755 index 0000000000..ba91f25f24 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/Makefile @@ -0,0 +1,17 @@ +ifneq ($(KERNELRELEASE),) +obj-m:= i2c-mux-accton_as5812_54x_cpld.o \ + accton_as5812_54x_fan.o leds-accton_as5812_54x.o accton_as5812_54x_psu.o \ + cpr_4011_4mxx.o ym2651y.o + +else +ifeq (,$(KERNEL_SRC)) +$(error KERNEL_SRC is not defined) +else +KERNELDIR:=$(KERNEL_SRC) +endif +PWD:=$(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +clean: + rm -rf *.o *.mod.o *.mod.o *.ko .*cmd .tmp_versions Module.markers Module.symvers modules.order +endif diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_fan.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_fan.c new file mode 100644 index 0000000000..deeabde23b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_fan.c @@ -0,0 +1,457 @@ +/* + * A hwmon driver for the Accton as5710 54x fan contrl + * + * Copyright (C) 2013 Accton Technology Corporation. + * Brandon Chuang + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as5812_54x_fan" + +#define FAN_MAX_NUMBER 5 +#define FAN_SPEED_CPLD_TO_RPM_STEP 150 +#define FAN_SPEED_PRECENT_TO_CPLD_STEP 5 +#define FAN_DUTY_CYCLE_MIN 0 /* 10% ??*/ +#define FAN_DUTY_CYCLE_MAX 100 /* 100% */ + +#define CPLD_REG_FAN_STATUS_OFFSET 0xC +#define CPLD_REG_FANR_STATUS_OFFSET 0x1F +#define CPLD_REG_FAN_DIRECTION_OFFSET 0x1E + +#define CPLD_FAN1_REG_SPEED_OFFSET 0x10 +#define CPLD_FAN2_REG_SPEED_OFFSET 0x11 +#define CPLD_FAN3_REG_SPEED_OFFSET 0x12 +#define CPLD_FAN4_REG_SPEED_OFFSET 0x13 +#define CPLD_FAN5_REG_SPEED_OFFSET 0x14 + +#define CPLD_FANR1_REG_SPEED_OFFSET 0x18 +#define CPLD_FANR2_REG_SPEED_OFFSET 0x19 +#define CPLD_FANR3_REG_SPEED_OFFSET 0x1A +#define CPLD_FANR4_REG_SPEED_OFFSET 0x1B +#define CPLD_FANR5_REG_SPEED_OFFSET 0x1C + +#define CPLD_REG_FAN_PWM_CYCLE_OFFSET 0xD + +#define CPLD_FAN1_INFO_BIT_MASK 0x1 +#define CPLD_FAN2_INFO_BIT_MASK 0x2 +#define CPLD_FAN3_INFO_BIT_MASK 0x4 +#define CPLD_FAN4_INFO_BIT_MASK 0x8 +#define CPLD_FAN5_INFO_BIT_MASK 0x10 + +#define PROJECT_NAME + +#define LOCAL_DEBUG 0 + +static struct accton_as5812_54x_fan *fan_data = NULL; + +struct accton_as5812_54x_fan { + struct platform_device *pdev; + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 status[FAN_MAX_NUMBER]; /* inner first fan status */ + u32 speed[FAN_MAX_NUMBER]; /* inner first fan speed */ + u8 direction[FAN_MAX_NUMBER]; /* reconrd the direction of inner first and second fans */ + u32 duty_cycle[FAN_MAX_NUMBER]; /* control the speed of inner first and second fans */ + u8 r_status[FAN_MAX_NUMBER]; /* inner second fan status */ + u32 r_speed[FAN_MAX_NUMBER]; /* inner second fan speed */ +}; + +/*******************/ +#define MAKE_FAN_MASK_OR_REG(name,type) \ + CPLD_FAN##type##1_##name, \ + CPLD_FAN##type##2_##name, \ + CPLD_FAN##type##3_##name, \ + CPLD_FAN##type##4_##name, \ + CPLD_FAN##type##5_##name, + +/* fan related data + */ +static const u8 fan_info_mask[] = { + MAKE_FAN_MASK_OR_REG(INFO_BIT_MASK,) +}; + +static const u8 fan_speed_reg[] = { + MAKE_FAN_MASK_OR_REG(REG_SPEED_OFFSET,) +}; + +static const u8 fanr_speed_reg[] = { + MAKE_FAN_MASK_OR_REG(REG_SPEED_OFFSET,R) +}; + +/*******************/ +#define DEF_FAN_SET(id) \ + FAN##id##_FAULT, \ + FAN##id##_SPEED, \ + FAN##id##_DUTY_CYCLE, \ + FAN##id##_DIRECTION, \ + FANR##id##_FAULT, \ + FANR##id##_SPEED, + +enum sysfs_fan_attributes { + DEF_FAN_SET(1) + DEF_FAN_SET(2) + DEF_FAN_SET(3) + DEF_FAN_SET(4) + DEF_FAN_SET(5) +}; +/*******************/ +static void accton_as5812_54x_fan_update_device(struct device *dev); +static int accton_as5812_54x_fan_read_value(u8 reg); +static int accton_as5812_54x_fan_write_value(u8 reg, u8 value); + +static ssize_t fan_set_duty_cycle(struct device *dev, + struct device_attribute *da,const char *buf, size_t count); +static ssize_t fan_show_value(struct device *dev, + struct device_attribute *da, char *buf); +static ssize_t show_name(struct device *dev, + struct device_attribute *da, char *buf); + +extern int as5812_54x_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as5812_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + + +/*******************/ +#define _MAKE_SENSOR_DEVICE_ATTR(prj, id, id2) \ + static SENSOR_DEVICE_ATTR(prj##fan##id##_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##id##_SPEED); \ + static SENSOR_DEVICE_ATTR(prj##fan##id##_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, \ + fan_set_duty_cycle, FAN##id##_DUTY_CYCLE); \ + static SENSOR_DEVICE_ATTR(prj##fan##id##_direction, S_IRUGO, fan_show_value, NULL, FAN##id##_DIRECTION); \ + static SENSOR_DEVICE_ATTR(prj##fanr##id##_fault, S_IRUGO, fan_show_value, NULL, FANR##id##_FAULT); \ + static SENSOR_DEVICE_ATTR(prj##fanr##id##_speed_rpm, S_IRUGO, fan_show_value, NULL, FANR##id##_SPEED); \ + static SENSOR_DEVICE_ATTR(prj##fan##id##_input, S_IRUGO, fan_show_value, NULL, FAN##id##_SPEED); \ + static SENSOR_DEVICE_ATTR(prj##fan##id2##_input, S_IRUGO, fan_show_value, NULL, FANR##id##_SPEED); \ + static SENSOR_DEVICE_ATTR(prj##fan##id##_fault, S_IRUGO, fan_show_value, NULL, FAN##id##_FAULT); \ + static SENSOR_DEVICE_ATTR(prj##fan##id2##_fault, S_IRUGO, fan_show_value, NULL, FAN##id##_FAULT); + +#define MAKE_SENSOR_DEVICE_ATTR(prj,id, id2) _MAKE_SENSOR_DEVICE_ATTR(prj,id, id2) + +MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME,1,11) +MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME,2,12) +MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME,3,13) +MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME,4,14) +MAKE_SENSOR_DEVICE_ATTR(PROJECT_NAME,5,15) + +static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); +/*******************/ + +#define _MAKE_FAN_ATTR(prj, id, id2) \ + &sensor_dev_attr_##prj##fan##id##_speed_rpm.dev_attr.attr, \ + &sensor_dev_attr_##prj##fan##id##_duty_cycle_percentage.dev_attr.attr,\ + &sensor_dev_attr_##prj##fan##id##_direction.dev_attr.attr, \ + &sensor_dev_attr_##prj##fanr##id##_fault.dev_attr.attr, \ + &sensor_dev_attr_##prj##fanr##id##_speed_rpm.dev_attr.attr, \ + &sensor_dev_attr_##prj##fan##id##_input.dev_attr.attr, \ + &sensor_dev_attr_##prj##fan##id2##_input.dev_attr.attr, \ + &sensor_dev_attr_##prj##fan##id##_fault.dev_attr.attr, \ + &sensor_dev_attr_##prj##fan##id2##_fault.dev_attr.attr, + + +#define MAKE_FAN_ATTR(prj, id, id2) _MAKE_FAN_ATTR(prj, id, id2) + +static struct attribute *accton_as5812_54x_fan_attributes[] = { + /* fan related attributes */ + MAKE_FAN_ATTR(PROJECT_NAME,1,11) + MAKE_FAN_ATTR(PROJECT_NAME,2,12) + MAKE_FAN_ATTR(PROJECT_NAME,3,13) + MAKE_FAN_ATTR(PROJECT_NAME,4,14) + MAKE_FAN_ATTR(PROJECT_NAME,5,15) + &sensor_dev_attr_name.dev_attr.attr, + NULL +}; +/*******************/ + +/* fan related functions + */ +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + ssize_t ret = 0; + int data_index, type_index; + + accton_as5812_54x_fan_update_device(dev); + + if (fan_data->valid == 0) { + return ret; + } + + type_index = attr->index%FAN2_FAULT; + data_index = attr->index/FAN2_FAULT; + + switch (type_index) { + case FAN1_FAULT: + ret = sprintf(buf, "%d\n", fan_data->status[data_index]); + if (LOCAL_DEBUG) + printk ("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index); + break; + case FAN1_SPEED: + ret = sprintf(buf, "%d\n", fan_data->speed[data_index]); + if (LOCAL_DEBUG) + printk ("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index); + break; + case FAN1_DUTY_CYCLE: + ret = sprintf(buf, "%d\n", fan_data->duty_cycle[data_index]); + if (LOCAL_DEBUG) + printk ("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index); + break; + case FAN1_DIRECTION: + ret = sprintf(buf, "%d\n", fan_data->direction[data_index]); /* presnet, need to modify*/ + if (LOCAL_DEBUG) + printk ("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index); + break; + case FANR1_FAULT: + ret = sprintf(buf, "%d\n", fan_data->r_status[data_index]); + if (LOCAL_DEBUG) + printk ("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index); + break; + case FANR1_SPEED: + ret = sprintf(buf, "%d\n", fan_data->r_speed[data_index]); + if (LOCAL_DEBUG) + printk ("[Check !!][%s][%d][type->index=%d][data->index=%d]\n", __FUNCTION__, __LINE__, type_index, data_index); + break; + default: + if (LOCAL_DEBUG) + printk ("[Check !!][%s][%d] \n", __FUNCTION__, __LINE__); + break; + } + + return ret; +} + +static ssize_t show_name(struct device *dev, struct device_attribute *da, + char *buf) +{ + return sprintf(buf, "%s\n", DRVNAME); +} +/*******************/ +static ssize_t fan_set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { + + int error, value; + + error = kstrtoint(buf, 10, &value); + if (error) + return error; + + if (value < FAN_DUTY_CYCLE_MIN || value > FAN_DUTY_CYCLE_MAX) + return -EINVAL; + + accton_as5812_54x_fan_write_value(CPLD_REG_FAN_PWM_CYCLE_OFFSET, value/FAN_SPEED_PRECENT_TO_CPLD_STEP); + + fan_data->valid = 0; + + return count; +} + +static const struct attribute_group accton_as5812_54x_fan_group = { + .attrs = accton_as5812_54x_fan_attributes, +}; + +static int accton_as5812_54x_fan_read_value(u8 reg) +{ + return as5812_54x_cpld_read(0x60, reg); +} + +static int accton_as5812_54x_fan_write_value(u8 reg, u8 value) +{ + return as5812_54x_cpld_write(0x60, reg, value); +} + +static void accton_as5812_54x_fan_update_device(struct device *dev) +{ + int speed, r_speed, fault, r_fault, ctrl_speed, direction; + int i; + + mutex_lock(&fan_data->update_lock); + + if (LOCAL_DEBUG) + printk ("Starting accton_as5812_54x_fan update \n"); + + if (!(time_after(jiffies, fan_data->last_updated + HZ + HZ / 2) || !fan_data->valid)) { + /* do nothing */ + goto _exit; + } + + fan_data->valid = 0; + + if (LOCAL_DEBUG) + printk ("Starting accton_as5812_54x_fan update 2 \n"); + + fault = accton_as5812_54x_fan_read_value(CPLD_REG_FAN_STATUS_OFFSET); + r_fault = accton_as5812_54x_fan_read_value(CPLD_REG_FANR_STATUS_OFFSET); + direction = accton_as5812_54x_fan_read_value(CPLD_REG_FAN_DIRECTION_OFFSET); + ctrl_speed = accton_as5812_54x_fan_read_value(CPLD_REG_FAN_PWM_CYCLE_OFFSET); + + if ( (fault < 0) || (r_fault < 0) || (direction < 0) || (ctrl_speed < 0) ) + { + if (LOCAL_DEBUG) + printk ("[Error!!][%s][%d] \n", __FUNCTION__, __LINE__); + goto _exit; /* error */ + } + + if (LOCAL_DEBUG) + printk ("[fan:] fault:%d, r_fault=%d, direction=%d, ctrl_speed=%d \n",fault, r_fault, direction, ctrl_speed); + + for (i=0; istatus[i] = (fault & fan_info_mask[i]) >> i; + if (LOCAL_DEBUG) + printk ("[fan%d:] fail=%d \n",i, fan_data->status[i]); + + fan_data->r_status[i] = (r_fault & fan_info_mask[i]) >> i; + fan_data->direction[i] = (direction & fan_info_mask[i]) >> i; + fan_data->duty_cycle[i] = ctrl_speed * FAN_SPEED_PRECENT_TO_CPLD_STEP; + + /* fan speed + */ + speed = accton_as5812_54x_fan_read_value(fan_speed_reg[i]); + r_speed = accton_as5812_54x_fan_read_value(fanr_speed_reg[i]); + if ( (speed < 0) || (r_speed < 0) ) + { + if (LOCAL_DEBUG) + printk ("[Error!!][%s][%d] \n", __FUNCTION__, __LINE__); + goto _exit; /* error */ + } + + if (LOCAL_DEBUG) + printk ("[fan%d:] speed:%d, r_speed=%d \n", i, speed, r_speed); + + fan_data->speed[i] = speed * FAN_SPEED_CPLD_TO_RPM_STEP; + fan_data->r_speed[i] = r_speed * FAN_SPEED_CPLD_TO_RPM_STEP; + } + + /* finish to update */ + fan_data->last_updated = jiffies; + fan_data->valid = 1; + +_exit: + mutex_unlock(&fan_data->update_lock); +} + +static int accton_as5812_54x_fan_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &accton_as5812_54x_fan_group); + if (status) { + goto exit; + + } + + fan_data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(fan_data->hwmon_dev)) { + status = PTR_ERR(fan_data->hwmon_dev); + goto exit_remove; + } + + dev_info(&pdev->dev, "accton_as5812_54x_fan\n"); + + return 0; + +exit_remove: + sysfs_remove_group(&pdev->dev.kobj, &accton_as5812_54x_fan_group); +exit: + return status; +} + +static int accton_as5812_54x_fan_remove(struct platform_device *pdev) +{ + hwmon_device_unregister(fan_data->hwmon_dev); + sysfs_remove_group(&fan_data->pdev->dev.kobj, &accton_as5812_54x_fan_group); + + return 0; +} + + + +static struct platform_driver accton_as5812_54x_fan_driver = { + .probe = accton_as5812_54x_fan_probe, + .remove = accton_as5812_54x_fan_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init accton_as5812_54x_fan_init(void) +{ + int ret; + + ret = platform_driver_register(&accton_as5812_54x_fan_driver); + if (ret < 0) { + goto exit; + } + + fan_data = kzalloc(sizeof(struct accton_as5812_54x_fan), GFP_KERNEL); + if (!fan_data) { + ret = -ENOMEM; + platform_driver_unregister(&accton_as5812_54x_fan_driver); + goto exit; + } + + mutex_init(&fan_data->update_lock); + fan_data->valid = 0; + + fan_data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(fan_data->pdev)) { + ret = PTR_ERR(fan_data->pdev); + platform_driver_unregister(&accton_as5812_54x_fan_driver); + kfree(fan_data); + goto exit; + } + +exit: + return ret; +} + +static void __exit accton_as5812_54x_fan_exit(void) +{ + platform_device_unregister(fan_data->pdev); + platform_driver_unregister(&accton_as5812_54x_fan_driver); + kfree(fan_data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("accton_as5812_54x_fan driver"); +MODULE_LICENSE("GPL"); + +module_init(accton_as5812_54x_fan_init); +module_exit(accton_as5812_54x_fan_exit); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_psu.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_psu.c new file mode 100755 index 0000000000..2c6b5f492a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_psu.c @@ -0,0 +1,371 @@ +/* + * An hwmon driver for accton as5812_54x Power Module + * + * Copyright (C) 2015 Accton Technology Corporation. + * Copyright (C) Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#if 0 +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define PSU_STATUS_I2C_ADDR 0x60 +#define PSU_STATUS_I2C_REG_OFFSET 0x2 + +#define IS_POWER_GOOD(id, value) (!!(value & BIT(id*4 + 1))) +#define IS_PRESENT(id, value) (!(value & BIT(id*4))) + +static ssize_t show_index(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf); +static int as5812_54x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len); +extern int as5812_54x_cpld_read(unsigned short cpld_addr, u8 reg); +static int as5812_54x_psu_model_name_get(struct device *dev); + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +/* Each client has this additional data + */ +struct as5812_54x_psu_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 index; /* PSU index */ + u8 status; /* Status(present/power_good) register read from CPLD */ + char model_name[14]; /* Model name, read from eeprom */ +}; + +static struct as5812_54x_psu_data *as5812_54x_psu_update_device(struct device *dev); + +enum as5812_54x_psu_sysfs_attributes { + PSU_INDEX, + PSU_PRESENT, + PSU_MODEL_NAME, + PSU_POWER_GOOD +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_index, S_IRUGO, show_index, NULL, PSU_INDEX); +static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); +static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_model_name,NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); + +static struct attribute *as5812_54x_psu_attributes[] = { + &sensor_dev_attr_psu_index.dev_attr.attr, + &sensor_dev_attr_psu_present.dev_attr.attr, + &sensor_dev_attr_psu_model_name.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + NULL +}; + +static ssize_t show_index(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5812_54x_psu_data *data = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", data->index); +} + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as5812_54x_psu_data *data = as5812_54x_psu_update_device(dev); + u8 status = 0; + + if (!data->valid) { + return sprintf(buf, "0\n"); + } + + if (attr->index == PSU_PRESENT) { + status = IS_PRESENT(data->index, data->status); + } + else { /* PSU_POWER_GOOD */ + status = IS_POWER_GOOD(data->index, data->status); + } + + return sprintf(buf, "%d\n", status); +} + +static ssize_t show_model_name(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct as5812_54x_psu_data *data = as5812_54x_psu_update_device(dev); + + if (!data->valid) { + return 0; + } + + if (!IS_PRESENT(data->index, data->status)) { + return 0; + } + + if (as5812_54x_psu_model_name_get(dev) < 0) { + return -ENXIO; + } + + return sprintf(buf, "%s\n", data->model_name); +} + +static const struct attribute_group as5812_54x_psu_group = { + .attrs = as5812_54x_psu_attributes, +}; + +static int as5812_54x_psu_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct as5812_54x_psu_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as5812_54x_psu_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + data->index = dev_id->driver_data; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &as5812_54x_psu_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &as5812_54x_psu_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int as5812_54x_psu_remove(struct i2c_client *client) +{ + struct as5812_54x_psu_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &as5812_54x_psu_group); + kfree(data); + + return 0; +} + +enum psu_index +{ + as5812_54x_psu1, + as5812_54x_psu2 +}; + +static const struct i2c_device_id as5812_54x_psu_id[] = { + { "as5812_54x_psu1", as5812_54x_psu1 }, + { "as5812_54x_psu2", as5812_54x_psu2 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as5812_54x_psu_id); + +static struct i2c_driver as5812_54x_psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "as5812_54x_psu", + }, + .probe = as5812_54x_psu_probe, + .remove = as5812_54x_psu_remove, + .id_table = as5812_54x_psu_id, + .address_list = normal_i2c, +}; + +static int as5812_54x_psu_read_block(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + + if (unlikely(result < 0)) + goto abort; + if (unlikely(result != data_len)) { + result = -EIO; + goto abort; + } + + result = 0; + +abort: + return result; +} + +enum psu_type { + PSU_YM_2401_JCR, /* AC110V - F2B */ + PSU_YM_2401_JDR, /* AC110V - B2F */ + PSU_CPR_4011_4M11, /* AC110V - F2B */ + PSU_CPR_4011_4M21, /* AC110V - B2F */ + PSU_CPR_6011_2M11, /* AC110V - F2B */ + PSU_CPR_6011_2M21, /* AC110V - B2F */ + PSU_UM400D_01G, /* DC48V - F2B */ + PSU_UM400D01_01G /* DC48V - B2F */ +}; + +struct model_name_info { + enum psu_type type; + u8 offset; + u8 length; + char* model_name; +}; + +struct model_name_info models[] = { +{PSU_YM_2401_JCR, 0x20, 11, "YM-2401JCR"}, +{PSU_YM_2401_JDR, 0x20, 11, "YM-2401JDR"}, +{PSU_CPR_4011_4M11, 0x26, 13, "CPR-4011-4M11"}, +{PSU_CPR_4011_4M21, 0x26, 13, "CPR-4011-4M21"}, +{PSU_CPR_6011_2M11, 0x26, 13, "CPR-6011-2M11"}, +{PSU_CPR_6011_2M21, 0x26, 13, "CPR-6011-2M21"}, +{PSU_UM400D_01G, 0x50, 9, "um400d01G"}, +{PSU_UM400D01_01G, 0x50, 12, "um400d01-01G"}, +}; + +static int as5812_54x_psu_model_name_get(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5812_54x_psu_data *data = i2c_get_clientdata(client); + int i, status; + + for (i = 0; i < ARRAY_SIZE(models); i++) { + memset(data->model_name, 0, sizeof(data->model_name)); + + status = as5812_54x_psu_read_block(client, models[i].offset, + data->model_name, models[i].length); + if (status < 0) { + data->model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x%x)\n", + client->addr, models[i].offset); + return status; + } + else { + data->model_name[models[i].length] = '\0'; + } + + if (i == PSU_YM_2401_JCR || i == PSU_YM_2401_JDR) { + /* Skip the meaningless data byte 8*/ + data->model_name[8] = data->model_name[9]; + data->model_name[9] = data->model_name[10]; + data->model_name[10] = '\0'; + } + + /* Determine if the model name is known, if not, read next index + */ + if (strncmp(data->model_name, models[i].model_name, models[i].length) == 0) { + return 0; + } + else { + data->model_name[0] = '\0'; + } + } + + return -ENODATA; +} + +static struct as5812_54x_psu_data *as5812_54x_psu_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5812_54x_psu_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int status = -1; + + dev_dbg(&client->dev, "Starting as5812_54x update\n"); + data->valid = 0; + + + /* Read psu status */ + status = as5812_54x_cpld_read(PSU_STATUS_I2C_ADDR, PSU_STATUS_I2C_REG_OFFSET); + + if (status < 0) { + dev_dbg(&client->dev, "cpld reg (0x%x) err %d\n", PSU_STATUS_I2C_ADDR, status); + goto exit; + } + else { + data->status = status; + } + + data->last_updated = jiffies; + data->valid = 1; + } + +exit: + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init as5812_54x_psu_init(void) +{ + return i2c_add_driver(&as5812_54x_psu_driver); +} + +static void __exit as5812_54x_psu_exit(void) +{ + i2c_del_driver(&as5812_54x_psu_driver); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("accton as5812_54x_psu driver"); +MODULE_LICENSE("GPL"); + +module_init(as5812_54x_psu_init); +module_exit(as5812_54x_psu_exit); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_sfp.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_sfp.c new file mode 100755 index 0000000000..10841c1d22 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/accton_as5812_54x_sfp.c @@ -0,0 +1,825 @@ +/* + * An hwmon driver for accton as5812_54x sfp + * + * Copyright (C) Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#if 0 +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NUM_OF_SFF_PORT 54 +#define SFP_PORT_MAX 48 +#define I2C_ADDR_CPLD1 0x60 +#define I2C_ADDR_CPLD2 0x61 +#define I2C_ADDR_CPLD3 0x62 +#define CPLD3_OFFSET_QSFP_MOD_RST 0x15 +#define CPLD3_OFFSET_QSFP_LPMODE 0x16 + + +#define BIT_INDEX(i) (1ULL << (i)) + +#if 0 +static ssize_t show_status(struct device *dev, struct device_attribute *da,char *buf); +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_port_number(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_eeprom(struct device *dev, struct device_attribute *da, char *buf); +static int as5812_54x_sfp_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len); +extern int as5812_54x_i2c_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as5812_54x_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); +#endif + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END }; + +/* Each client has this additional data + */ +struct as5812_54x_sfp_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + int port; /* Front port index */ + char eeprom[256]; /* eeprom data */ + u64 status[4]; /* bit0:port0, bit1:port1 and so on */ + /* index 0 => is_present + 1 => tx_fail + 2 => tx_disable + 3 => rx_loss */ +}; + +/* The table maps active port to cpld port. + * Array index 0 is for active port 1, + * index 1 for active port 2, and so on. + * The array content implies cpld port index. + */ +static const u8 cpld_to_front_port_table[] = +{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 52, 50, 53, 51, 54}; + +#define CPLD_PORT_TO_FRONT_PORT(port) (cpld_to_front_port_table[port]) + +static struct as5812_54x_sfp_data *as5812_54x_sfp_update_device(struct device *dev, int update_eeprom); +static ssize_t show_port_number(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_eeprom(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t get_lp_mode(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_lp_mode(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t get_mode_reset(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_mode_reset(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +extern int as5812_54x_i2c_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as5812_54x_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +enum as5812_54x_sfp_sysfs_attributes { + SFP_IS_PRESENT, + SFP_TX_FAULT, + SFP_TX_DISABLE, + SFP_RX_LOSS, + SFP_PORT_NUMBER, + SFP_EEPROM, + SFP_RX_LOS_ALL, + SFP_IS_PRESENT_ALL, + SFP_LP_MODE, + SFP_MOD_RST, +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(sfp_is_present, S_IRUGO, show_status, NULL, SFP_IS_PRESENT); +static SENSOR_DEVICE_ATTR(sfp_tx_fault, S_IRUGO, show_status, NULL, SFP_TX_FAULT); +static SENSOR_DEVICE_ATTR(sfp_tx_disable, S_IWUSR | S_IRUGO, show_status, set_tx_disable, SFP_TX_DISABLE); +static SENSOR_DEVICE_ATTR(sfp_rx_loss, S_IRUGO, show_status,NULL, SFP_RX_LOSS); +static SENSOR_DEVICE_ATTR(sfp_port_number, S_IRUGO, show_port_number, NULL, SFP_PORT_NUMBER); +static SENSOR_DEVICE_ATTR(sfp_eeprom, S_IRUGO, show_eeprom, NULL, SFP_EEPROM); +static SENSOR_DEVICE_ATTR(sfp_rx_los_all, S_IRUGO, show_status,NULL, SFP_RX_LOS_ALL); +static SENSOR_DEVICE_ATTR(sfp_is_present_all, S_IRUGO, show_status,NULL, SFP_IS_PRESENT_ALL); +static SENSOR_DEVICE_ATTR(sfp_lp_mode, S_IWUSR | S_IRUGO, get_lp_mode, set_lp_mode, SFP_LP_MODE); +static SENSOR_DEVICE_ATTR(sfp_mod_rst, S_IWUSR | S_IRUGO, get_mode_reset, set_mode_reset, SFP_MOD_RST); + +static struct attribute *as5812_54x_sfp_attributes[] = { + &sensor_dev_attr_sfp_is_present.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault.dev_attr.attr, + &sensor_dev_attr_sfp_rx_loss.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable.dev_attr.attr, + &sensor_dev_attr_sfp_eeprom.dev_attr.attr, + &sensor_dev_attr_sfp_port_number.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los_all.dev_attr.attr, + &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, + &sensor_dev_attr_sfp_lp_mode.dev_attr.attr, + &sensor_dev_attr_sfp_mod_rst.dev_attr.attr, + NULL +}; + +static ssize_t show_port_number(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5812_54x_sfp_data *data = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", CPLD_PORT_TO_FRONT_PORT(data->port)); +} + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as5812_54x_sfp_data *data; + u8 val; + int values[7]; + + /* Error-check the CPLD read results. */ +#define VALIDATED_READ(_buf, _rv, _read_expr, _invert) \ + do { \ + _rv = (_read_expr); \ + if(_rv < 0) { \ + return sprintf(_buf, "READ ERROR\n"); \ + } \ + if(_invert) { \ + _rv = ~_rv; \ + } \ + _rv &= 0xFF; \ + } while(0) + + if(attr->index == SFP_RX_LOS_ALL) { + /* + * Report the RX_LOS status for all ports. + * This does not depend on the currently active SFP selector. + */ + + /* RX_LOS Ports 1-8 */ + VALIDATED_READ(buf, values[0], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2, 0x0F), 0); + /* RX_LOS Ports 9-16 */ + VALIDATED_READ(buf, values[1], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2, 0x10), 0); + /* RX_LOS Ports 17-24 */ + VALIDATED_READ(buf, values[2], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2, 0x11), 0); + /* RX_LOS Ports 25-32 */ + VALIDATED_READ(buf, values[3], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x0F), 0); + /* RX_LOS Ports 33-40 */ + VALIDATED_READ(buf, values[4], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x10), 0); + /* RX_LOS Ports 41-48 */ + VALIDATED_READ(buf, values[5], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x11), 0); + + /** Return values 1 -> 48 in order */ + return sprintf(buf, "%.2x %.2x %.2x %.2x %.2x %.2x\n", + values[0], values[1], values[2], + values[3], values[4], values[5]); + } + + if(attr->index == SFP_IS_PRESENT_ALL) { + /* + * Report the SFP_PRESENCE status for all ports. + * This does not depend on the currently active SFP selector. + */ + + /* SFP_PRESENT Ports 1-8 */ + VALIDATED_READ(buf, values[0], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2, 0x6), 1); + /* SFP_PRESENT Ports 9-16 */ + VALIDATED_READ(buf, values[1], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2, 0x7), 1); + /* SFP_PRESENT Ports 17-24 */ + VALIDATED_READ(buf, values[2], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2, 0x8), 1); + /* SFP_PRESENT Ports 25-32 */ + VALIDATED_READ(buf, values[3], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x6), 1); + /* SFP_PRESENT Ports 33-40 */ + VALIDATED_READ(buf, values[4], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x7), 1); + /* SFP_PRESENT Ports 41-48 */ + VALIDATED_READ(buf, values[5], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x8), 1); + /* QSFP_PRESENT Ports 49-54 */ + VALIDATED_READ(buf, values[6], as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x14), 1); + + /* Return values 1 -> 54 in order */ + return sprintf(buf, "%.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", + values[0], values[1], values[2], + values[3], values[4], values[5], + values[6] & 0x3F); + } + /* + * The remaining attributes are gathered on a per-selected-sfp basis. + */ + data = as5812_54x_sfp_update_device(dev, 0); + if (attr->index == SFP_IS_PRESENT) { + val = (data->status[attr->index] & BIT_INDEX(data->port)) ? 0 : 1; + } + else { + val = (data->status[attr->index] & BIT_INDEX(data->port)) ? 1 : 0; + } + + return sprintf(buf, "%d", val); +} + +static ssize_t get_lp_mode(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5812_54x_sfp_data *data = i2c_get_clientdata(client); + u8 cpld_val = 0; + int port_bit; + int status = -EINVAL; + + /* Low power mode is not supported for SFP ports(1-48) */ + if (data->port < SFP_PORT_MAX) { + return -EINVAL; + } + mutex_lock(&data->update_lock); + + port_bit = data->port - SFP_PORT_MAX; + cpld_val = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, CPLD3_OFFSET_QSFP_LPMODE); + cpld_val = cpld_val & 0x3F; + cpld_val = cpld_val & BIT_INDEX(port_bit); + status = snprintf(buf, PAGE_SIZE - 1, "%d\r\n", cpld_val>>port_bit); + + mutex_unlock(&data->update_lock); + + return status; +} + +static ssize_t set_lp_mode(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5812_54x_sfp_data *data = i2c_get_clientdata(client); + u8 cpld_val = 0; + long mode; + int error, port_bit; + + /* Tx disable is not supported for QSFP ports(49-54) */ + if (data->port < SFP_PORT_MAX) { + return -EINVAL; + } + port_bit = data->port - SFP_PORT_MAX; + error = kstrtol(buf, 10, &mode); + if (error) { + return error; + } + mutex_lock(&data->update_lock); + + cpld_val = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, CPLD3_OFFSET_QSFP_LPMODE); + /* Update lp_mode status */ + if (mode) + { + cpld_val |= BIT_INDEX(port_bit); + } + else + { + cpld_val &=~BIT_INDEX(port_bit); + } + as5812_54x_i2c_cpld_write(I2C_ADDR_CPLD3, CPLD3_OFFSET_QSFP_LPMODE, cpld_val); + + mutex_unlock(&data->update_lock); + + return count; +} + + +static ssize_t get_mode_reset(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5812_54x_sfp_data *data = i2c_get_clientdata(client); + u8 cpld_val = 0; + int port_bit; + int status = -EINVAL; + + /* Low power mode is not supported for SFP ports(1-48) */ + if (data->port < SFP_PORT_MAX) { + return -EINVAL; + } + mutex_lock(&data->update_lock); + + port_bit = data->port - SFP_PORT_MAX; + cpld_val = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, CPLD3_OFFSET_QSFP_MOD_RST); + cpld_val = cpld_val & 0x3F; + cpld_val = cpld_val & BIT_INDEX(port_bit); + status = snprintf(buf, PAGE_SIZE - 1, "%d\r\n", cpld_val>>port_bit); + + mutex_unlock(&data->update_lock); + + return status; +} + +static ssize_t set_mode_reset(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5812_54x_sfp_data *data = i2c_get_clientdata(client); + u8 cpld_val = 0; + long reset; + int error, port_bit; + + /* Tx disable is not supported for QSFP ports(49-54) */ + if (data->port < SFP_PORT_MAX) { + return -EINVAL; + } + port_bit = data->port - SFP_PORT_MAX; + error = kstrtol(buf, 10, &reset); + if (error) { + return error; + } + mutex_lock(&data->update_lock); + + cpld_val = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, CPLD3_OFFSET_QSFP_MOD_RST); + /* Update lp_mode status */ + if (reset) + { + cpld_val |= BIT_INDEX(port_bit); + } + else + { + cpld_val &=~BIT_INDEX(port_bit); + } + as5812_54x_i2c_cpld_write(I2C_ADDR_CPLD3, CPLD3_OFFSET_QSFP_MOD_RST, cpld_val); + + mutex_unlock(&data->update_lock); + + return count; +} + + +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5812_54x_sfp_data *data = i2c_get_clientdata(client); + unsigned short cpld_addr = 0; + u8 cpld_reg = 0, cpld_val = 0, cpld_bit = 0; + long disable; + int error; + + /* Tx disable is not supported for QSFP ports(49-54) */ + if (data->port >= SFP_PORT_MAX) { + return -EINVAL; + } + + error = kstrtol(buf, 10, &disable); + if (error) { + return error; + } + + mutex_lock(&data->update_lock); + + if(data->port < 24) { + cpld_addr = I2C_ADDR_CPLD2; + cpld_reg = 0xC + data->port / 8; + cpld_bit = 1 << (data->port % 8); + } + else { + cpld_addr = I2C_ADDR_CPLD3; + cpld_reg = 0xC + (data->port - 24) / 8; + cpld_bit = 1 << (data->port % 8); + } + + cpld_val = as5812_54x_i2c_cpld_read(cpld_addr, cpld_reg); + + /* Update tx_disable status */ + if (disable) { + data->status[SFP_TX_DISABLE] |= BIT_INDEX(data->port); + cpld_val |= cpld_bit; + } + else { + data->status[SFP_TX_DISABLE] &= ~BIT_INDEX(data->port); + cpld_val &= ~cpld_bit; + } + + as5812_54x_i2c_cpld_write(cpld_addr, cpld_reg, cpld_val); + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_eeprom(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct as5812_54x_sfp_data *data = as5812_54x_sfp_update_device(dev, 1); + + if (!data->valid) { + return 0; + } + + if ((data->status[SFP_IS_PRESENT] & BIT_INDEX(data->port)) != 0) { + return 0; + } + + memcpy(buf, data->eeprom, sizeof(data->eeprom)); + + return sizeof(data->eeprom); +} + +static const struct attribute_group as5812_54x_sfp_group = { + .attrs = as5812_54x_sfp_attributes, +}; + +static int as5812_54x_sfp_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct as5812_54x_sfp_data *data; + int status; + + extern int platform_accton_as5812_54x(void); + if(!platform_accton_as5812_54x()) { + return -ENODEV; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as5812_54x_sfp_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + mutex_init(&data->update_lock); + data->port = dev_id->driver_data; + i2c_set_clientdata(client, data); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &as5812_54x_sfp_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: sfp '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &as5812_54x_sfp_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int as5812_54x_sfp_remove(struct i2c_client *client) +{ + struct as5812_54x_sfp_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &as5812_54x_sfp_group); + kfree(data); + + return 0; +} + +enum port_numbers { +as5812_54x_sfp1, as5812_54x_sfp2, as5812_54x_sfp3, as5812_54x_sfp4, +as5812_54x_sfp5, as5812_54x_sfp6, as5812_54x_sfp7, as5812_54x_sfp8, +as5812_54x_sfp9, as5812_54x_sfp10, as5812_54x_sfp11,as5812_54x_sfp12, +as5812_54x_sfp13, as5812_54x_sfp14, as5812_54x_sfp15,as5812_54x_sfp16, +as5812_54x_sfp17, as5812_54x_sfp18, as5812_54x_sfp19,as5812_54x_sfp20, +as5812_54x_sfp21, as5812_54x_sfp22, as5812_54x_sfp23,as5812_54x_sfp24, +as5812_54x_sfp25, as5812_54x_sfp26, as5812_54x_sfp27,as5812_54x_sfp28, +as5812_54x_sfp29, as5812_54x_sfp30, as5812_54x_sfp31,as5812_54x_sfp32, +as5812_54x_sfp33, as5812_54x_sfp34, as5812_54x_sfp35,as5812_54x_sfp36, +as5812_54x_sfp37, as5812_54x_sfp38, as5812_54x_sfp39,as5812_54x_sfp40, +as5812_54x_sfp41, as5812_54x_sfp42, as5812_54x_sfp43,as5812_54x_sfp44, +as5812_54x_sfp45, as5812_54x_sfp46, as5812_54x_sfp47,as5812_54x_sfp48, +as5812_54x_sfp49, as5812_54x_sfp52, as5812_54x_sfp50,as5812_54x_sfp53, +as5812_54x_sfp51, as5812_54x_sfp54 +}; + +static const struct i2c_device_id as5812_54x_sfp_id[] = { +{ "as5812_54x_sfp1", as5812_54x_sfp1 }, { "as5812_54x_sfp2", as5812_54x_sfp2 }, +{ "as5812_54x_sfp3", as5812_54x_sfp3 }, { "as5812_54x_sfp4", as5812_54x_sfp4 }, +{ "as5812_54x_sfp5", as5812_54x_sfp5 }, { "as5812_54x_sfp6", as5812_54x_sfp6 }, +{ "as5812_54x_sfp7", as5812_54x_sfp7 }, { "as5812_54x_sfp8", as5812_54x_sfp8 }, +{ "as5812_54x_sfp9", as5812_54x_sfp9 }, { "as5812_54x_sfp10", as5812_54x_sfp10 }, +{ "as5812_54x_sfp11", as5812_54x_sfp11 }, { "as5812_54x_sfp12", as5812_54x_sfp12 }, +{ "as5812_54x_sfp13", as5812_54x_sfp13 }, { "as5812_54x_sfp14", as5812_54x_sfp14 }, +{ "as5812_54x_sfp15", as5812_54x_sfp15 }, { "as5812_54x_sfp16", as5812_54x_sfp16 }, +{ "as5812_54x_sfp17", as5812_54x_sfp17 }, { "as5812_54x_sfp18", as5812_54x_sfp18 }, +{ "as5812_54x_sfp19", as5812_54x_sfp19 }, { "as5812_54x_sfp20", as5812_54x_sfp20 }, +{ "as5812_54x_sfp21", as5812_54x_sfp21 }, { "as5812_54x_sfp22", as5812_54x_sfp22 }, +{ "as5812_54x_sfp23", as5812_54x_sfp23 }, { "as5812_54x_sfp24", as5812_54x_sfp24 }, +{ "as5812_54x_sfp25", as5812_54x_sfp25 }, { "as5812_54x_sfp26", as5812_54x_sfp26 }, +{ "as5812_54x_sfp27", as5812_54x_sfp27 }, { "as5812_54x_sfp28", as5812_54x_sfp28 }, +{ "as5812_54x_sfp29", as5812_54x_sfp29 }, { "as5812_54x_sfp30", as5812_54x_sfp30 }, +{ "as5812_54x_sfp31", as5812_54x_sfp31 }, { "as5812_54x_sfp32", as5812_54x_sfp32 }, +{ "as5812_54x_sfp33", as5812_54x_sfp33 }, { "as5812_54x_sfp34", as5812_54x_sfp34 }, +{ "as5812_54x_sfp35", as5812_54x_sfp35 }, { "as5812_54x_sfp36", as5812_54x_sfp36 }, +{ "as5812_54x_sfp37", as5812_54x_sfp37 }, { "as5812_54x_sfp38", as5812_54x_sfp38 }, +{ "as5812_54x_sfp39", as5812_54x_sfp39 }, { "as5812_54x_sfp40", as5812_54x_sfp40 }, +{ "as5812_54x_sfp41", as5812_54x_sfp41 }, { "as5812_54x_sfp42", as5812_54x_sfp42 }, +{ "as5812_54x_sfp43", as5812_54x_sfp43 }, { "as5812_54x_sfp44", as5812_54x_sfp44 }, +{ "as5812_54x_sfp45", as5812_54x_sfp45 }, { "as5812_54x_sfp46", as5812_54x_sfp46 }, +{ "as5812_54x_sfp47", as5812_54x_sfp47 }, { "as5812_54x_sfp48", as5812_54x_sfp48 }, +{ "as5812_54x_sfp49", as5812_54x_sfp49 }, { "as5812_54x_sfp50", as5812_54x_sfp50 }, +{ "as5812_54x_sfp51", as5812_54x_sfp51 }, { "as5812_54x_sfp52", as5812_54x_sfp52 }, +{ "as5812_54x_sfp53", as5812_54x_sfp53 }, { "as5812_54x_sfp54", as5812_54x_sfp54 }, + +{} +}; +MODULE_DEVICE_TABLE(i2c, as5812_54x_sfp_id); + +static struct i2c_driver as5812_54x_sfp_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "as5812_54x_sfp", + }, + .probe = as5812_54x_sfp_probe, + .remove = as5812_54x_sfp_remove, + .id_table = as5812_54x_sfp_id, + .address_list = normal_i2c, +}; + +static int as5812_54x_sfp_read_byte(struct i2c_client *client, u8 command, u8 *data) +{ + int result = i2c_smbus_read_byte_data(client, command); + + if (unlikely(result < 0)) { + dev_dbg(&client->dev, "sfp read byte data failed, command(0x%2x), data(0x%2x)\r\n", command, result); + goto abort; + } + + *data = (u8)result; + result = 0; + +abort: + return result; +} + +#define ALWAYS_UPDATE_DEVICE 1 + +static struct as5812_54x_sfp_data *as5812_54x_sfp_update_device(struct device *dev, int update_eeprom) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5812_54x_sfp_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (ALWAYS_UPDATE_DEVICE || time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int status = -1; + int i = 0, j = 0; + + data->valid = 0; + //dev_dbg(&client->dev, "Starting as5812_54x sfp status update\n"); + memset(data->status, 0, sizeof(data->status)); + + /* Read status of port 1~48(SFP port) */ + for (i = 0; i < 2; i++) { + for (j = 0; j < 12; j++) { + status = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2+i, 0x6+j); + + if (status < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", I2C_ADDR_CPLD2+i, 0x6+j, status); + goto exit; + } + + data->status[j/3] |= (u64)status << ((i*24) + (j%3)*8); + } + } + + /* + * Bring QSFPs out of reset, + * This is a temporary fix until the QSFP+_MOD_RST register + * can be exposed through the driver. + */ + as5812_54x_i2c_cpld_write(I2C_ADDR_CPLD3, 0x15, 0x3F); + + /* Read present status of port 49-54(QSFP port) */ + status = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x14); + + if (status < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", I2C_ADDR_CPLD2+i, 0x6+j, status); + } + else { + data->status[SFP_IS_PRESENT] |= (u64)status << 48; + } + + if (update_eeprom) { + /* Read eeprom data based on port number */ + memset(data->eeprom, 0, sizeof(data->eeprom)); + + /* Check if the port is present */ + if ((data->status[SFP_IS_PRESENT] & BIT_INDEX(data->port)) == 0) { + /* read eeprom */ + for (i = 0; i < sizeof(data->eeprom); i++) { + status = as5812_54x_sfp_read_byte(client, i, data->eeprom + i); + + if (status < 0) { + dev_dbg(&client->dev, "unable to read eeprom from port(%d)\n", + CPLD_PORT_TO_FRONT_PORT(data->port)); + goto exit; + } + } + } + } + + data->valid = 1; + data->last_updated = jiffies; + } + +exit: + mutex_unlock(&data->update_lock); + + return data; +} + +module_i2c_driver(as5812_54x_sfp_driver); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("accton as5812_54x_sfp driver"); +MODULE_LICENSE("GPL"); + +#if 0 + int i = 0, j = 0; + + data->valid = 0; + //dev_dbg(&client->dev, "Starting as5812_54x sfp update\n"); + memset(data->status, 0, sizeof(data->status)); + + /* Read status of port 1~48(SFP port) */ + for (i = 0; i < 2; i++) { + for (j = 0; j < 12; j++) { + status = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2+i, 0x6+j); + + if (status < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", I2C_ADDR_CPLD2+i, 0x6+j, status); + continue; + } + + data->status[j/3] |= (u64)status << ((i*24) + (j%3)*8); + } + } + + /* Read present status of port 49-54(QSFP port) */ + status = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x14); + + if (status < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", I2C_ADDR_CPLD2+i, 0x6+j, status); + } + else { + data->status[SFP_IS_PRESENT] |= (u64)status << 48; + } +#endif + +/* Reserver to prevent from CPLD port mapping is changed + */ +#if 0 +BIT_INDEX(port_present_index[data->port]) +/* The bit index of is_present field read from CPLD + * Array index 0 is for as5812_54x_sfp1, + * index 1 is for as5812_54x_sfp2, and so on. + */ +static const int port_present_index[] = { + 4, 5, 6, 7, 9, 8, 11, 10, + 0, 1, 2, 3, 12, 13, 14, 15, +16, 17, 18, 19, 28, 29, 30, 31, +20, 21, 22, 23, 24, 25, 26, 27 +}; +#endif + +#if 0 +static struct as5812_54x_sfp_data *as5812_54x_sfp_update_status(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5812_54x_sfp_data *data = i2c_get_clientdata(client); + int status = -1; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->status_last_updated + HZ + HZ / 2) + || !data->status_valid) { + int status = -1; + int i = 0, j = 0; + + data->status_valid = 0; + //dev_dbg(&client->dev, "Starting as5812_54x sfp status update\n"); + memset(data->status, 0, sizeof(data->status)); + + /* Read status of port 1~48(SFP port) */ + for (i = 0; i < 2; i++) { + for (j = 0; j < 12; j++) { + status = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD2+i, 0x6+j); + + if (status < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", I2C_ADDR_CPLD2+i, 0x6+j, status); + goto exit; + } + + data->status[j/3] |= (u64)status << ((i*24) + (j%3)*8); + } + } + + /* + * Bring QSFPs out of reset, + * This is a temporary fix until the QSFP+_MOD_RST register + * can be exposed through the driver. + */ + as5812_54x_i2c_cpld_write(I2C_ADDR_CPLD3, 0x15, 0x3F); + + /* Read present status of port 49-54(QSFP port) */ + status = as5812_54x_i2c_cpld_read(I2C_ADDR_CPLD3, 0x14); + + if (status < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", I2C_ADDR_CPLD2+i, 0x6+j, status); + } + else { + data->status[SFP_IS_PRESENT] |= (u64)status << 48; + } + + data->status_valid = 1; + data->status_last_updated = jiffies; + } + +exit: + mutex_unlock(&data->update_lock); + + return data; +} + +static struct as5812_54x_sfp_data *as5812_54x_sfp_update_eeprom(struct device *dev) +{ + struct as5812_54x_sfp_data *data = NULL; + + data = as5812_54x_sfp_update_status(dev); + + if (data == NULL || data->status_valid == 0) { + data->eeprom_valid = 0; + return data; + } + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->eeprom_last_updated + HZ + HZ / 2) + || !data->eeprom_valid) { + int status = -1; + int i = 0; + + /* Read eeprom data based on port number */ + memset(data->eeprom, 0, sizeof(data->eeprom)); + + /* Check if the port is present */ + if ((data->status[SFP_IS_PRESENT] & BIT_INDEX(data->port)) == 0) { + /* read eeprom */ + for (i = 0; i < sizeof(data->eeprom)/I2C_SMBUS_BLOCK_MAX; i++) { + status = as5812_54x_sfp_read_block(client, i*I2C_SMBUS_BLOCK_MAX, + data->eeprom+(i*I2C_SMBUS_BLOCK_MAX), + I2C_SMBUS_BLOCK_MAX); + if (status < 0) { + dev_dbg(&client->dev, "unable to read eeprom from port(%d)\n", + CPLD_PORT_TO_FRONT_PORT(data->port)); + goto exit; + } + } + } + + data->eeprom_last_updated = jiffies; + data->eeprom_valid = 1; + } + +exit: + mutex_unlock(&data->update_lock); + + return data; +} +#endif diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/cpr_4011_4mxx.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/cpr_4011_4mxx.c new file mode 100755 index 0000000000..30bea914d5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/cpr_4011_4mxx.c @@ -0,0 +1,400 @@ +/* + * An hwmon driver for the CPR-4011-4Mxx Redundant Power Module + * + * Copyright (C) Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#if 0 +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_FAN_DUTY_CYCLE 100 + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { 0x3c, 0x3d, 0x3e, 0x3f, I2C_CLIENT_END }; + +/* Each client has this additional data + */ +struct cpr_4011_4mxx_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 vout_mode; /* Register value */ + u16 v_in; /* Register value */ + u16 v_out; /* Register value */ + u16 i_in; /* Register value */ + u16 i_out; /* Register value */ + u16 p_in; /* Register value */ + u16 p_out; /* Register value */ + u16 temp_input[2]; /* Register value */ + u8 fan_fault; /* Register value */ + u16 fan_duty_cycle[2]; /* Register value */ + u16 fan_speed[2]; /* Register value */ +}; + +static ssize_t show_linear(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_vout(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static int cpr_4011_4mxx_write_word(struct i2c_client *client, u8 reg, u16 value); +static struct cpr_4011_4mxx_data *cpr_4011_4mxx_update_device(struct device *dev); + +enum cpr_4011_4mxx_sysfs_attributes { + PSU_V_IN, + PSU_V_OUT, + PSU_I_IN, + PSU_I_OUT, + PSU_P_IN, + PSU_P_OUT, + PSU_TEMP1_INPUT, + PSU_FAN1_FAULT, + PSU_FAN1_DUTY_CYCLE, + PSU_FAN1_SPEED, +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_v_in, S_IRUGO, show_linear, NULL, PSU_V_IN); +static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_vout, NULL, PSU_V_OUT); +static SENSOR_DEVICE_ATTR(psu_i_in, S_IRUGO, show_linear, NULL, PSU_I_IN); +static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT); +static SENSOR_DEVICE_ATTR(psu_p_in, S_IRUGO, show_linear, NULL, PSU_P_IN); +static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT); +static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT); +static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE); +static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); + +static struct attribute *cpr_4011_4mxx_attributes[] = { + &sensor_dev_attr_psu_v_in.dev_attr.attr, + &sensor_dev_attr_psu_v_out.dev_attr.attr, + &sensor_dev_attr_psu_i_in.dev_attr.attr, + &sensor_dev_attr_psu_i_out.dev_attr.attr, + &sensor_dev_attr_psu_p_in.dev_attr.attr, + &sensor_dev_attr_psu_p_out.dev_attr.attr, + &sensor_dev_attr_psu_temp1_input.dev_attr.attr, + &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, + &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, + &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr, + NULL +}; + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask) +{ + u16 valid_data = data & mask; + bool is_negative = valid_data >> (valid_bit - 1); + + return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data; +} + +static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct cpr_4011_4mxx_data *data = i2c_get_clientdata(client); + int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1; + long speed; + int error; + + error = kstrtol(buf, 10, &speed); + if (error) + return error; + + if (speed < 0 || speed > MAX_FAN_DUTY_CYCLE) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->fan_duty_cycle[nr] = speed; + cpr_4011_4mxx_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_linear(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct cpr_4011_4mxx_data *data = cpr_4011_4mxx_update_device(dev); + + u16 value = 0; + int exponent, mantissa; + int multiplier = 1000; + + switch (attr->index) { + case PSU_V_IN: + value = data->v_in; + break; + case PSU_I_IN: + value = data->i_in; + break; + case PSU_I_OUT: + value = data->i_out; + break; + case PSU_P_IN: + value = data->p_in; + break; + case PSU_P_OUT: + value = data->p_out; + break; + case PSU_TEMP1_INPUT: + value = data->temp_input[0]; + break; + case PSU_FAN1_DUTY_CYCLE: + multiplier = 1; + value = data->fan_duty_cycle[0]; + break; + case PSU_FAN1_SPEED: + multiplier = 1; + value = data->fan_speed[0]; + break; + default: + break; + } + + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + + return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); +} + +static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct cpr_4011_4mxx_data *data = cpr_4011_4mxx_update_device(dev); + + u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; + + return sprintf(buf, "%d\n", data->fan_fault >> shift); +} + +static ssize_t show_vout(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct cpr_4011_4mxx_data *data = cpr_4011_4mxx_update_device(dev); + int exponent, mantissa; + int multiplier = 1000; + + exponent = two_complement_to_int(data->vout_mode, 5, 0x1f); + mantissa = data->v_out; + + return (exponent > 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); +} + +static const struct attribute_group cpr_4011_4mxx_group = { + .attrs = cpr_4011_4mxx_attributes, +}; + +static int cpr_4011_4mxx_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct cpr_4011_4mxx_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct cpr_4011_4mxx_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &cpr_4011_4mxx_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &cpr_4011_4mxx_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int cpr_4011_4mxx_remove(struct i2c_client *client) +{ + struct cpr_4011_4mxx_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &cpr_4011_4mxx_group); + kfree(data); + + return 0; +} + +static const struct i2c_device_id cpr_4011_4mxx_id[] = { + { "cpr_4011_4mxx", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, cpr_4011_4mxx_id); + +static struct i2c_driver cpr_4011_4mxx_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "cpr_4011_4mxx", + }, + .probe = cpr_4011_4mxx_probe, + .remove = cpr_4011_4mxx_remove, + .id_table = cpr_4011_4mxx_id, + .address_list = normal_i2c, +}; + +static int cpr_4011_4mxx_read_byte(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int cpr_4011_4mxx_read_word(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_word_data(client, reg); +} + +static int cpr_4011_4mxx_write_word(struct i2c_client *client, u8 reg, u16 value) +{ + return i2c_smbus_write_word_data(client, reg, value); +} + +struct reg_data_byte { + u8 reg; + u8 *value; +}; + +struct reg_data_word { + u8 reg; + u16 *value; +}; + +static struct cpr_4011_4mxx_data *cpr_4011_4mxx_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cpr_4011_4mxx_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int i, status; + struct reg_data_byte regs_byte[] = { {0x20, &data->vout_mode}, + {0x81, &data->fan_fault}}; + struct reg_data_word regs_word[] = { {0x88, &data->v_in}, + {0x8b, &data->v_out}, + {0x89, &data->i_in}, + {0x8c, &data->i_out}, + {0x96, &data->p_out}, + {0x97, &data->p_in}, + {0x8d, &(data->temp_input[0])}, + {0x8e, &(data->temp_input[1])}, + {0x3b, &(data->fan_duty_cycle[0])}, + {0x3c, &(data->fan_duty_cycle[1])}, + {0x90, &(data->fan_speed[0])}, + {0x91, &(data->fan_speed[1])}}; + + dev_dbg(&client->dev, "Starting cpr_4011_4mxx update\n"); + + /* Read byte data */ + for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { + status = cpr_4011_4mxx_read_byte(client, regs_byte[i].reg); + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_byte[i].reg, status); + } + else { + *(regs_byte[i].value) = status; + } + } + + /* Read word data */ + for (i = 0; i < ARRAY_SIZE(regs_word); i++) { + status = cpr_4011_4mxx_read_word(client, regs_word[i].reg); + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_word[i].reg, status); + } + else { + *(regs_word[i].value) = status; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init cpr_4011_4mxx_init(void) +{ + return i2c_add_driver(&cpr_4011_4mxx_driver); +} + +static void __exit cpr_4011_4mxx_exit(void) +{ + i2c_del_driver(&cpr_4011_4mxx_driver); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("CPR_4011_4MXX driver"); +MODULE_LICENSE("GPL"); + +module_init(cpr_4011_4mxx_init); +module_exit(cpr_4011_4mxx_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/i2c-mux-accton_as5812_54x_cpld.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/i2c-mux-accton_as5812_54x_cpld.c new file mode 100644 index 0000000000..1578d75bdd --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/i2c-mux-accton_as5812_54x_cpld.c @@ -0,0 +1,1421 @@ +/* + * An I2C multiplexer dirver for accton as5812 CPLD + * + * Copyright (C) 2015 Accton Technology Corporation. + * Brandon Chuang + * + * This module supports the accton cpld that hold the channel select + * mechanism for other i2c slave devices, such as SFP. + * This includes the: + * Accton as5812_54x CPLD1/CPLD2/CPLD3 + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +#define NUM_OF_CPLD1_CHANS 0x0 +#define NUM_OF_CPLD2_CHANS 0x18 +#define NUM_OF_CPLD3_CHANS 0x1E +#define CPLD_CHANNEL_SELECT_REG 0x2 +#define CPLD_DESELECT_CHANNEL 0xFF + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +enum cpld_mux_type { + as5812_54x_cpld2, + as5812_54x_cpld3, + as5812_54x_cpld1 +}; + +struct as5812_54x_cpld_data { + enum cpld_mux_type type; + struct i2c_client *client; + u8 last_chan; /* last register value */ + + struct device *hwmon_dev; + struct mutex update_lock; +}; + +struct chip_desc { + u8 nchans; + u8 deselectChan; +}; + +/* Provide specs for the PCA954x types we know about */ +static const struct chip_desc chips[] = { + [as5812_54x_cpld1] = { + .nchans = NUM_OF_CPLD1_CHANS, + .deselectChan = CPLD_DESELECT_CHANNEL, + }, + [as5812_54x_cpld2] = { + .nchans = NUM_OF_CPLD2_CHANS, + .deselectChan = CPLD_DESELECT_CHANNEL, + }, + [as5812_54x_cpld3] = { + .nchans = NUM_OF_CPLD3_CHANS, + .deselectChan = CPLD_DESELECT_CHANNEL, + } +}; + +static const struct i2c_device_id as5812_54x_cpld_mux_id[] = { + { "as5812_54x_cpld1", as5812_54x_cpld1 }, + { "as5812_54x_cpld2", as5812_54x_cpld2 }, + { "as5812_54x_cpld3", as5812_54x_cpld3 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, as5812_54x_cpld_mux_id); + +#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index +#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index +#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index +#define TRANSCEIVER_LPMODE_ATTR_ID(index) MODULE_LPMODE_##index +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index + +enum as5812_54x_cpld1_sysfs_attributes { + CPLD_VERSION, + ACCESS, + MODULE_PRESENT_ALL, + MODULE_RXLOS_ALL, + /* transceiver attributes */ + TRANSCEIVER_PRESENT_ATTR_ID(1), + TRANSCEIVER_PRESENT_ATTR_ID(2), + TRANSCEIVER_PRESENT_ATTR_ID(3), + TRANSCEIVER_PRESENT_ATTR_ID(4), + TRANSCEIVER_PRESENT_ATTR_ID(5), + TRANSCEIVER_PRESENT_ATTR_ID(6), + TRANSCEIVER_PRESENT_ATTR_ID(7), + TRANSCEIVER_PRESENT_ATTR_ID(8), + TRANSCEIVER_PRESENT_ATTR_ID(9), + TRANSCEIVER_PRESENT_ATTR_ID(10), + TRANSCEIVER_PRESENT_ATTR_ID(11), + TRANSCEIVER_PRESENT_ATTR_ID(12), + TRANSCEIVER_PRESENT_ATTR_ID(13), + TRANSCEIVER_PRESENT_ATTR_ID(14), + TRANSCEIVER_PRESENT_ATTR_ID(15), + TRANSCEIVER_PRESENT_ATTR_ID(16), + TRANSCEIVER_PRESENT_ATTR_ID(17), + TRANSCEIVER_PRESENT_ATTR_ID(18), + TRANSCEIVER_PRESENT_ATTR_ID(19), + TRANSCEIVER_PRESENT_ATTR_ID(20), + TRANSCEIVER_PRESENT_ATTR_ID(21), + TRANSCEIVER_PRESENT_ATTR_ID(22), + TRANSCEIVER_PRESENT_ATTR_ID(23), + TRANSCEIVER_PRESENT_ATTR_ID(24), + TRANSCEIVER_PRESENT_ATTR_ID(25), + TRANSCEIVER_PRESENT_ATTR_ID(26), + TRANSCEIVER_PRESENT_ATTR_ID(27), + TRANSCEIVER_PRESENT_ATTR_ID(28), + TRANSCEIVER_PRESENT_ATTR_ID(29), + TRANSCEIVER_PRESENT_ATTR_ID(30), + TRANSCEIVER_PRESENT_ATTR_ID(31), + TRANSCEIVER_PRESENT_ATTR_ID(32), + TRANSCEIVER_PRESENT_ATTR_ID(33), + TRANSCEIVER_PRESENT_ATTR_ID(34), + TRANSCEIVER_PRESENT_ATTR_ID(35), + TRANSCEIVER_PRESENT_ATTR_ID(36), + TRANSCEIVER_PRESENT_ATTR_ID(37), + TRANSCEIVER_PRESENT_ATTR_ID(38), + TRANSCEIVER_PRESENT_ATTR_ID(39), + TRANSCEIVER_PRESENT_ATTR_ID(40), + TRANSCEIVER_PRESENT_ATTR_ID(41), + TRANSCEIVER_PRESENT_ATTR_ID(42), + TRANSCEIVER_PRESENT_ATTR_ID(43), + TRANSCEIVER_PRESENT_ATTR_ID(44), + TRANSCEIVER_PRESENT_ATTR_ID(45), + TRANSCEIVER_PRESENT_ATTR_ID(46), + TRANSCEIVER_PRESENT_ATTR_ID(47), + TRANSCEIVER_PRESENT_ATTR_ID(48), + TRANSCEIVER_PRESENT_ATTR_ID(49), + TRANSCEIVER_PRESENT_ATTR_ID(50), + TRANSCEIVER_PRESENT_ATTR_ID(51), + TRANSCEIVER_PRESENT_ATTR_ID(52), + TRANSCEIVER_PRESENT_ATTR_ID(53), + TRANSCEIVER_PRESENT_ATTR_ID(54), + TRANSCEIVER_TXDISABLE_ATTR_ID(1), + TRANSCEIVER_TXDISABLE_ATTR_ID(2), + TRANSCEIVER_TXDISABLE_ATTR_ID(3), + TRANSCEIVER_TXDISABLE_ATTR_ID(4), + TRANSCEIVER_TXDISABLE_ATTR_ID(5), + TRANSCEIVER_TXDISABLE_ATTR_ID(6), + TRANSCEIVER_TXDISABLE_ATTR_ID(7), + TRANSCEIVER_TXDISABLE_ATTR_ID(8), + TRANSCEIVER_TXDISABLE_ATTR_ID(9), + TRANSCEIVER_TXDISABLE_ATTR_ID(10), + TRANSCEIVER_TXDISABLE_ATTR_ID(11), + TRANSCEIVER_TXDISABLE_ATTR_ID(12), + TRANSCEIVER_TXDISABLE_ATTR_ID(13), + TRANSCEIVER_TXDISABLE_ATTR_ID(14), + TRANSCEIVER_TXDISABLE_ATTR_ID(15), + TRANSCEIVER_TXDISABLE_ATTR_ID(16), + TRANSCEIVER_TXDISABLE_ATTR_ID(17), + TRANSCEIVER_TXDISABLE_ATTR_ID(18), + TRANSCEIVER_TXDISABLE_ATTR_ID(19), + TRANSCEIVER_TXDISABLE_ATTR_ID(20), + TRANSCEIVER_TXDISABLE_ATTR_ID(21), + TRANSCEIVER_TXDISABLE_ATTR_ID(22), + TRANSCEIVER_TXDISABLE_ATTR_ID(23), + TRANSCEIVER_TXDISABLE_ATTR_ID(24), + TRANSCEIVER_TXDISABLE_ATTR_ID(25), + TRANSCEIVER_TXDISABLE_ATTR_ID(26), + TRANSCEIVER_TXDISABLE_ATTR_ID(27), + TRANSCEIVER_TXDISABLE_ATTR_ID(28), + TRANSCEIVER_TXDISABLE_ATTR_ID(29), + TRANSCEIVER_TXDISABLE_ATTR_ID(30), + TRANSCEIVER_TXDISABLE_ATTR_ID(31), + TRANSCEIVER_TXDISABLE_ATTR_ID(32), + TRANSCEIVER_TXDISABLE_ATTR_ID(33), + TRANSCEIVER_TXDISABLE_ATTR_ID(34), + TRANSCEIVER_TXDISABLE_ATTR_ID(35), + TRANSCEIVER_TXDISABLE_ATTR_ID(36), + TRANSCEIVER_TXDISABLE_ATTR_ID(37), + TRANSCEIVER_TXDISABLE_ATTR_ID(38), + TRANSCEIVER_TXDISABLE_ATTR_ID(39), + TRANSCEIVER_TXDISABLE_ATTR_ID(40), + TRANSCEIVER_TXDISABLE_ATTR_ID(41), + TRANSCEIVER_TXDISABLE_ATTR_ID(42), + TRANSCEIVER_TXDISABLE_ATTR_ID(43), + TRANSCEIVER_TXDISABLE_ATTR_ID(44), + TRANSCEIVER_TXDISABLE_ATTR_ID(45), + TRANSCEIVER_TXDISABLE_ATTR_ID(46), + TRANSCEIVER_TXDISABLE_ATTR_ID(47), + TRANSCEIVER_TXDISABLE_ATTR_ID(48), + TRANSCEIVER_RXLOS_ATTR_ID(1), + TRANSCEIVER_RXLOS_ATTR_ID(2), + TRANSCEIVER_RXLOS_ATTR_ID(3), + TRANSCEIVER_RXLOS_ATTR_ID(4), + TRANSCEIVER_RXLOS_ATTR_ID(5), + TRANSCEIVER_RXLOS_ATTR_ID(6), + TRANSCEIVER_RXLOS_ATTR_ID(7), + TRANSCEIVER_RXLOS_ATTR_ID(8), + TRANSCEIVER_RXLOS_ATTR_ID(9), + TRANSCEIVER_RXLOS_ATTR_ID(10), + TRANSCEIVER_RXLOS_ATTR_ID(11), + TRANSCEIVER_RXLOS_ATTR_ID(12), + TRANSCEIVER_RXLOS_ATTR_ID(13), + TRANSCEIVER_RXLOS_ATTR_ID(14), + TRANSCEIVER_RXLOS_ATTR_ID(15), + TRANSCEIVER_RXLOS_ATTR_ID(16), + TRANSCEIVER_RXLOS_ATTR_ID(17), + TRANSCEIVER_RXLOS_ATTR_ID(18), + TRANSCEIVER_RXLOS_ATTR_ID(19), + TRANSCEIVER_RXLOS_ATTR_ID(20), + TRANSCEIVER_RXLOS_ATTR_ID(21), + TRANSCEIVER_RXLOS_ATTR_ID(22), + TRANSCEIVER_RXLOS_ATTR_ID(23), + TRANSCEIVER_RXLOS_ATTR_ID(24), + TRANSCEIVER_RXLOS_ATTR_ID(25), + TRANSCEIVER_RXLOS_ATTR_ID(26), + TRANSCEIVER_RXLOS_ATTR_ID(27), + TRANSCEIVER_RXLOS_ATTR_ID(28), + TRANSCEIVER_RXLOS_ATTR_ID(29), + TRANSCEIVER_RXLOS_ATTR_ID(30), + TRANSCEIVER_RXLOS_ATTR_ID(31), + TRANSCEIVER_RXLOS_ATTR_ID(32), + TRANSCEIVER_RXLOS_ATTR_ID(33), + TRANSCEIVER_RXLOS_ATTR_ID(34), + TRANSCEIVER_RXLOS_ATTR_ID(35), + TRANSCEIVER_RXLOS_ATTR_ID(36), + TRANSCEIVER_RXLOS_ATTR_ID(37), + TRANSCEIVER_RXLOS_ATTR_ID(38), + TRANSCEIVER_RXLOS_ATTR_ID(39), + TRANSCEIVER_RXLOS_ATTR_ID(40), + TRANSCEIVER_RXLOS_ATTR_ID(41), + TRANSCEIVER_RXLOS_ATTR_ID(42), + TRANSCEIVER_RXLOS_ATTR_ID(43), + TRANSCEIVER_RXLOS_ATTR_ID(44), + TRANSCEIVER_RXLOS_ATTR_ID(45), + TRANSCEIVER_RXLOS_ATTR_ID(46), + TRANSCEIVER_RXLOS_ATTR_ID(47), + TRANSCEIVER_RXLOS_ATTR_ID(48), + TRANSCEIVER_TXFAULT_ATTR_ID(1), + TRANSCEIVER_TXFAULT_ATTR_ID(2), + TRANSCEIVER_TXFAULT_ATTR_ID(3), + TRANSCEIVER_TXFAULT_ATTR_ID(4), + TRANSCEIVER_TXFAULT_ATTR_ID(5), + TRANSCEIVER_TXFAULT_ATTR_ID(6), + TRANSCEIVER_TXFAULT_ATTR_ID(7), + TRANSCEIVER_TXFAULT_ATTR_ID(8), + TRANSCEIVER_TXFAULT_ATTR_ID(9), + TRANSCEIVER_TXFAULT_ATTR_ID(10), + TRANSCEIVER_TXFAULT_ATTR_ID(11), + TRANSCEIVER_TXFAULT_ATTR_ID(12), + TRANSCEIVER_TXFAULT_ATTR_ID(13), + TRANSCEIVER_TXFAULT_ATTR_ID(14), + TRANSCEIVER_TXFAULT_ATTR_ID(15), + TRANSCEIVER_TXFAULT_ATTR_ID(16), + TRANSCEIVER_TXFAULT_ATTR_ID(17), + TRANSCEIVER_TXFAULT_ATTR_ID(18), + TRANSCEIVER_TXFAULT_ATTR_ID(19), + TRANSCEIVER_TXFAULT_ATTR_ID(20), + TRANSCEIVER_TXFAULT_ATTR_ID(21), + TRANSCEIVER_TXFAULT_ATTR_ID(22), + TRANSCEIVER_TXFAULT_ATTR_ID(23), + TRANSCEIVER_TXFAULT_ATTR_ID(24), + TRANSCEIVER_TXFAULT_ATTR_ID(25), + TRANSCEIVER_TXFAULT_ATTR_ID(26), + TRANSCEIVER_TXFAULT_ATTR_ID(27), + TRANSCEIVER_TXFAULT_ATTR_ID(28), + TRANSCEIVER_TXFAULT_ATTR_ID(29), + TRANSCEIVER_TXFAULT_ATTR_ID(30), + TRANSCEIVER_TXFAULT_ATTR_ID(31), + TRANSCEIVER_TXFAULT_ATTR_ID(32), + TRANSCEIVER_TXFAULT_ATTR_ID(33), + TRANSCEIVER_TXFAULT_ATTR_ID(34), + TRANSCEIVER_TXFAULT_ATTR_ID(35), + TRANSCEIVER_TXFAULT_ATTR_ID(36), + TRANSCEIVER_TXFAULT_ATTR_ID(37), + TRANSCEIVER_TXFAULT_ATTR_ID(38), + TRANSCEIVER_TXFAULT_ATTR_ID(39), + TRANSCEIVER_TXFAULT_ATTR_ID(40), + TRANSCEIVER_TXFAULT_ATTR_ID(41), + TRANSCEIVER_TXFAULT_ATTR_ID(42), + TRANSCEIVER_TXFAULT_ATTR_ID(43), + TRANSCEIVER_TXFAULT_ATTR_ID(44), + TRANSCEIVER_TXFAULT_ATTR_ID(45), + TRANSCEIVER_TXFAULT_ATTR_ID(46), + TRANSCEIVER_TXFAULT_ATTR_ID(47), + TRANSCEIVER_TXFAULT_ATTR_ID(48), + TRANSCEIVER_LPMODE_ATTR_ID(49), + TRANSCEIVER_LPMODE_ATTR_ID(50), + TRANSCEIVER_LPMODE_ATTR_ID(51), + TRANSCEIVER_LPMODE_ATTR_ID(52), + TRANSCEIVER_LPMODE_ATTR_ID(53), + TRANSCEIVER_LPMODE_ATTR_ID(54), + TRANSCEIVER_RESET_ATTR_ID(49), + TRANSCEIVER_RESET_ATTR_ID(50), + TRANSCEIVER_RESET_ATTR_ID(51), + TRANSCEIVER_RESET_ATTR_ID(52), + TRANSCEIVER_RESET_ATTR_ID(53), + TRANSCEIVER_RESET_ATTR_ID(54), +}; + +/* sysfs attributes for hwmon + */ +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_lp_mode(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_mode_reset(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); +static int as5812_54x_cpld_read_internal(struct i2c_client *client, u8 reg); +static int as5812_54x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value); + +/* transceiver attributes */ +#define DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index) +#define DECLARE_TRANSCEIVER_PRESENT_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr + +#define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_tx_disable, MODULE_TXDISABLE_##index); \ + static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_TXFAULT_##index) + +#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \ + &sensor_dev_attr_module_rx_los_##index.dev_attr.attr, \ + &sensor_dev_attr_module_tx_fault_##index.dev_attr.attr + +#define DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_lp_mode_##index, S_IRUGO | S_IWUSR, show_status, set_lp_mode, MODULE_LPMODE_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IWUSR | S_IRUGO, show_status, set_mode_reset, MODULE_RESET_##index) + +#define DECLARE_QSFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_lp_mode_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr + + +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); +static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); +/* transceiver attributes */ +static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_present_all, NULL, MODULE_PRESENT_ALL); +static SENSOR_DEVICE_ATTR(module_rx_los_all, S_IRUGO, show_rxlos_all, NULL, MODULE_RXLOS_ALL); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(1); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(2); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(3); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(4); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(5); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(6); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(7); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(8); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(9); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(10); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(11); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(12); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(13); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(14); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(15); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(16); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(17); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(18); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(19); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(20); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(21); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(22); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(23); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(24); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(25); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(26); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(27); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(28); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(29); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(30); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(31); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(32); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(33); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(34); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(35); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(36); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(37); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(38); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(39); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(40); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(41); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(42); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(43); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(44); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(45); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(46); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(47); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(48); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(49); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(50); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(51); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(52); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(53); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(54); + +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(1); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(2); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(3); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(4); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(5); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(6); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(7); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(8); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(9); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(10); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(11); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(12); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(13); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(14); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(15); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(16); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(17); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(18); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(19); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(20); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(21); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(22); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(23); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(24); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(25); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(26); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(27); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(28); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(29); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(30); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(31); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(32); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(33); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(34); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(35); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(36); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(37); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(38); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(39); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(40); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(41); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(42); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(43); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(44); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(45); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(46); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(47); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(48); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(49); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(50); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(51); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(52); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(53); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(54); + +static struct attribute *as5812_54x_cpld1_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + NULL +}; + +static const struct attribute_group as5812_54x_cpld1_group = { + .attrs = as5812_54x_cpld1_attributes, +}; + +static struct attribute *as5812_54x_cpld2_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + /* transceiver attributes */ + &sensor_dev_attr_module_present_all.dev_attr.attr, + &sensor_dev_attr_module_rx_los_all.dev_attr.attr, + DECLARE_TRANSCEIVER_PRESENT_ATTR(1), + DECLARE_TRANSCEIVER_PRESENT_ATTR(2), + DECLARE_TRANSCEIVER_PRESENT_ATTR(3), + DECLARE_TRANSCEIVER_PRESENT_ATTR(4), + DECLARE_TRANSCEIVER_PRESENT_ATTR(5), + DECLARE_TRANSCEIVER_PRESENT_ATTR(6), + DECLARE_TRANSCEIVER_PRESENT_ATTR(7), + DECLARE_TRANSCEIVER_PRESENT_ATTR(8), + DECLARE_TRANSCEIVER_PRESENT_ATTR(9), + DECLARE_TRANSCEIVER_PRESENT_ATTR(10), + DECLARE_TRANSCEIVER_PRESENT_ATTR(11), + DECLARE_TRANSCEIVER_PRESENT_ATTR(12), + DECLARE_TRANSCEIVER_PRESENT_ATTR(13), + DECLARE_TRANSCEIVER_PRESENT_ATTR(14), + DECLARE_TRANSCEIVER_PRESENT_ATTR(15), + DECLARE_TRANSCEIVER_PRESENT_ATTR(16), + DECLARE_TRANSCEIVER_PRESENT_ATTR(17), + DECLARE_TRANSCEIVER_PRESENT_ATTR(18), + DECLARE_TRANSCEIVER_PRESENT_ATTR(19), + DECLARE_TRANSCEIVER_PRESENT_ATTR(20), + DECLARE_TRANSCEIVER_PRESENT_ATTR(21), + DECLARE_TRANSCEIVER_PRESENT_ATTR(22), + DECLARE_TRANSCEIVER_PRESENT_ATTR(23), + DECLARE_TRANSCEIVER_PRESENT_ATTR(24), + DECLARE_SFP_TRANSCEIVER_ATTR(1), + DECLARE_SFP_TRANSCEIVER_ATTR(2), + DECLARE_SFP_TRANSCEIVER_ATTR(3), + DECLARE_SFP_TRANSCEIVER_ATTR(4), + DECLARE_SFP_TRANSCEIVER_ATTR(5), + DECLARE_SFP_TRANSCEIVER_ATTR(6), + DECLARE_SFP_TRANSCEIVER_ATTR(7), + DECLARE_SFP_TRANSCEIVER_ATTR(8), + DECLARE_SFP_TRANSCEIVER_ATTR(9), + DECLARE_SFP_TRANSCEIVER_ATTR(10), + DECLARE_SFP_TRANSCEIVER_ATTR(11), + DECLARE_SFP_TRANSCEIVER_ATTR(12), + DECLARE_SFP_TRANSCEIVER_ATTR(13), + DECLARE_SFP_TRANSCEIVER_ATTR(14), + DECLARE_SFP_TRANSCEIVER_ATTR(15), + DECLARE_SFP_TRANSCEIVER_ATTR(16), + DECLARE_SFP_TRANSCEIVER_ATTR(17), + DECLARE_SFP_TRANSCEIVER_ATTR(18), + DECLARE_SFP_TRANSCEIVER_ATTR(19), + DECLARE_SFP_TRANSCEIVER_ATTR(20), + DECLARE_SFP_TRANSCEIVER_ATTR(21), + DECLARE_SFP_TRANSCEIVER_ATTR(22), + DECLARE_SFP_TRANSCEIVER_ATTR(23), + DECLARE_SFP_TRANSCEIVER_ATTR(24), + NULL +}; + +static const struct attribute_group as5812_54x_cpld2_group = { + .attrs = as5812_54x_cpld2_attributes, +}; + +static struct attribute *as5812_54x_cpld3_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + /* transceiver attributes */ + &sensor_dev_attr_module_present_all.dev_attr.attr, + &sensor_dev_attr_module_rx_los_all.dev_attr.attr, + DECLARE_TRANSCEIVER_PRESENT_ATTR(25), + DECLARE_TRANSCEIVER_PRESENT_ATTR(26), + DECLARE_TRANSCEIVER_PRESENT_ATTR(27), + DECLARE_TRANSCEIVER_PRESENT_ATTR(28), + DECLARE_TRANSCEIVER_PRESENT_ATTR(29), + DECLARE_TRANSCEIVER_PRESENT_ATTR(30), + DECLARE_TRANSCEIVER_PRESENT_ATTR(31), + DECLARE_TRANSCEIVER_PRESENT_ATTR(32), + DECLARE_TRANSCEIVER_PRESENT_ATTR(33), + DECLARE_TRANSCEIVER_PRESENT_ATTR(34), + DECLARE_TRANSCEIVER_PRESENT_ATTR(35), + DECLARE_TRANSCEIVER_PRESENT_ATTR(36), + DECLARE_TRANSCEIVER_PRESENT_ATTR(37), + DECLARE_TRANSCEIVER_PRESENT_ATTR(38), + DECLARE_TRANSCEIVER_PRESENT_ATTR(39), + DECLARE_TRANSCEIVER_PRESENT_ATTR(40), + DECLARE_TRANSCEIVER_PRESENT_ATTR(41), + DECLARE_TRANSCEIVER_PRESENT_ATTR(42), + DECLARE_TRANSCEIVER_PRESENT_ATTR(43), + DECLARE_TRANSCEIVER_PRESENT_ATTR(44), + DECLARE_TRANSCEIVER_PRESENT_ATTR(45), + DECLARE_TRANSCEIVER_PRESENT_ATTR(46), + DECLARE_TRANSCEIVER_PRESENT_ATTR(47), + DECLARE_TRANSCEIVER_PRESENT_ATTR(48), + DECLARE_TRANSCEIVER_PRESENT_ATTR(49), + DECLARE_TRANSCEIVER_PRESENT_ATTR(50), + DECLARE_TRANSCEIVER_PRESENT_ATTR(51), + DECLARE_TRANSCEIVER_PRESENT_ATTR(52), + DECLARE_TRANSCEIVER_PRESENT_ATTR(53), + DECLARE_TRANSCEIVER_PRESENT_ATTR(54), + DECLARE_SFP_TRANSCEIVER_ATTR(25), + DECLARE_SFP_TRANSCEIVER_ATTR(26), + DECLARE_SFP_TRANSCEIVER_ATTR(27), + DECLARE_SFP_TRANSCEIVER_ATTR(28), + DECLARE_SFP_TRANSCEIVER_ATTR(29), + DECLARE_SFP_TRANSCEIVER_ATTR(30), + DECLARE_SFP_TRANSCEIVER_ATTR(31), + DECLARE_SFP_TRANSCEIVER_ATTR(32), + DECLARE_SFP_TRANSCEIVER_ATTR(33), + DECLARE_SFP_TRANSCEIVER_ATTR(34), + DECLARE_SFP_TRANSCEIVER_ATTR(35), + DECLARE_SFP_TRANSCEIVER_ATTR(36), + DECLARE_SFP_TRANSCEIVER_ATTR(37), + DECLARE_SFP_TRANSCEIVER_ATTR(38), + DECLARE_SFP_TRANSCEIVER_ATTR(39), + DECLARE_SFP_TRANSCEIVER_ATTR(40), + DECLARE_SFP_TRANSCEIVER_ATTR(41), + DECLARE_SFP_TRANSCEIVER_ATTR(42), + DECLARE_SFP_TRANSCEIVER_ATTR(43), + DECLARE_SFP_TRANSCEIVER_ATTR(44), + DECLARE_SFP_TRANSCEIVER_ATTR(45), + DECLARE_SFP_TRANSCEIVER_ATTR(46), + DECLARE_SFP_TRANSCEIVER_ATTR(47), + DECLARE_SFP_TRANSCEIVER_ATTR(48), + DECLARE_QSFP_TRANSCEIVER_ATTR(49), + DECLARE_QSFP_TRANSCEIVER_ATTR(50), + DECLARE_QSFP_TRANSCEIVER_ATTR(51), + DECLARE_QSFP_TRANSCEIVER_ATTR(52), + DECLARE_QSFP_TRANSCEIVER_ATTR(53), + DECLARE_QSFP_TRANSCEIVER_ATTR(54), + NULL +}; + +static const struct attribute_group as5812_54x_cpld3_group = { + .attrs = as5812_54x_cpld3_attributes, +}; + +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf) +{ + int i, status, num_regs = 0; + u8 values[4] = {0}; + u8 regs[] = {0x6, 0x7, 0x8, 0x14}; + struct i2c_client *client = to_i2c_client(dev); + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc); + + mutex_lock(&data->update_lock); + + num_regs = (data->type == as5812_54x_cpld2) ? 3 : 4; + + for (i = 0; i < num_regs; i++) { + status = as5812_54x_cpld_read_internal(client, regs[i]); + + if (status < 0) { + goto exit; + } + + values[i] = ~(u8)status; + } + + mutex_unlock(&data->update_lock); + + /* Return values 1 -> 54 in order */ + if (data->type == as5812_54x_cpld2) { + status = sprintf(buf, "%.2x %.2x %.2x\n", + values[0], values[1], values[2]); + } + else { /* as5812_54x_cpld3 */ + values[3] &= 0x3F; + status = sprintf(buf, "%.2x %.2x %.2x %.2x\n", + values[0], values[1], values[2], values[3]); + } + + return status; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, + char *buf) +{ + int i, status; + u8 values[3] = {0}; + u8 regs[] = {0xF, 0x10, 0x11}; + struct i2c_client *client = to_i2c_client(dev); + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc); + + mutex_lock(&data->update_lock); + + for (i = 0; i < ARRAY_SIZE(regs); i++) { + status = as5812_54x_cpld_read_internal(client, regs[i]); + + if (status < 0) { + goto exit; + } + + values[i] = (u8)status; + } + + mutex_unlock(&data->update_lock); + + /* Return values 1 -> 24 in order */ + return sprintf(buf, "%.2x %.2x %.2x\n", values[0], values[1], values[2]); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc); + int status = 0; + u8 reg = 0, mask = 0, revert = 0; + + switch (attr->index) { + case MODULE_PRESENT_1 ... MODULE_PRESENT_8: + reg = 0x6; + mask = 0x1 << (attr->index - MODULE_PRESENT_1); + break; + case MODULE_PRESENT_9 ... MODULE_PRESENT_16: + reg = 0x7; + mask = 0x1 << (attr->index - MODULE_PRESENT_9); + break; + case MODULE_PRESENT_17 ... MODULE_PRESENT_24: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_PRESENT_17); + break; + case MODULE_PRESENT_25 ... MODULE_PRESENT_32: + reg = 0x6; + mask = 0x1 << (attr->index - MODULE_PRESENT_25); + break; + case MODULE_PRESENT_33 ... MODULE_PRESENT_40: + reg = 0x7; + mask = 0x1 << (attr->index - MODULE_PRESENT_33); + break; + case MODULE_PRESENT_41 ... MODULE_PRESENT_48: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_PRESENT_41); + break; + case MODULE_PRESENT_49: + reg = 0x14; + mask = 0x1; + break; + case MODULE_PRESENT_50: + reg = 0x14; + mask = 0x4; + break; + case MODULE_PRESENT_51: + reg = 0x14; + mask = 0x10; + break; + case MODULE_PRESENT_52: + reg = 0x14; + mask = 0x2; + break; + case MODULE_PRESENT_53: + reg = 0x14; + mask = 0x8; + break; + case MODULE_PRESENT_54: + reg = 0x14; + mask = 0x20; + break; + case MODULE_TXFAULT_1 ... MODULE_TXFAULT_8: + reg = 0x9; + mask = 0x1 << (attr->index - MODULE_TXFAULT_1); + break; + case MODULE_TXFAULT_9 ... MODULE_TXFAULT_16: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_TXFAULT_9); + break; + case MODULE_TXFAULT_17 ... MODULE_TXFAULT_24: + reg = 0xB; + mask = 0x1 << (attr->index - MODULE_TXFAULT_17); + break; + case MODULE_TXFAULT_25 ... MODULE_TXFAULT_32: + reg = 0x9; + mask = 0x1 << (attr->index - MODULE_TXFAULT_25); + break; + case MODULE_TXFAULT_33 ... MODULE_TXFAULT_40: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_TXFAULT_33); + break; + case MODULE_TXFAULT_41 ... MODULE_TXFAULT_48: + reg = 0xB; + mask = 0x1 << (attr->index - MODULE_TXFAULT_41); + break; + case MODULE_TXDISABLE_1 ... MODULE_TXDISABLE_8: + reg = 0xC; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_1); + break; + case MODULE_TXDISABLE_9 ... MODULE_TXDISABLE_16: + reg = 0xD; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_9); + break; + case MODULE_TXDISABLE_17 ... MODULE_TXDISABLE_24: + reg = 0xE; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_17); + break; + case MODULE_TXDISABLE_25 ... MODULE_TXDISABLE_32: + reg = 0xC; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_25); + break; + case MODULE_TXDISABLE_33 ... MODULE_TXDISABLE_40: + reg = 0xD; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_33); + break; + case MODULE_TXDISABLE_41 ... MODULE_TXDISABLE_48: + reg = 0xE; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_41); + break; + case MODULE_RXLOS_1 ... MODULE_RXLOS_8: + reg = 0xF; + mask = 0x1 << (attr->index - MODULE_RXLOS_1); + break; + case MODULE_RXLOS_9 ... MODULE_RXLOS_16: + reg = 0x10; + mask = 0x1 << (attr->index - MODULE_RXLOS_9); + break; + case MODULE_RXLOS_17 ... MODULE_RXLOS_24: + reg = 0x11; + mask = 0x1 << (attr->index - MODULE_RXLOS_17); + break; + case MODULE_RXLOS_25 ... MODULE_RXLOS_32: + reg = 0xF; + mask = 0x1 << (attr->index - MODULE_RXLOS_25); + break; + case MODULE_RXLOS_33 ... MODULE_RXLOS_40: + reg = 0x10; + mask = 0x1 << (attr->index - MODULE_RXLOS_33); + break; + case MODULE_RXLOS_41 ... MODULE_RXLOS_48: + reg = 0x11; + mask = 0x1 << (attr->index - MODULE_RXLOS_41); + break; + case MODULE_LPMODE_49 ... MODULE_LPMODE_54: + reg = 0x16; + mask = 0x1 << (attr->index - MODULE_LPMODE_49); + break; + case MODULE_RESET_49 ... MODULE_RESET_54: + reg = 0x15; + mask = 0x1 << (attr->index - MODULE_RESET_49); + break; + default: + return 0; + } + + if (attr->index >= MODULE_PRESENT_1 && attr->index <= MODULE_PRESENT_54) { + revert = 1; + } + + mutex_lock(&data->update_lock); + status = as5812_54x_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", revert ? !(status & mask) : !!(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc); + long disable; + int status; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &disable); + if (status) { + return status; + } + + switch (attr->index) { + case MODULE_TXDISABLE_1 ... MODULE_TXDISABLE_8: + reg = 0xC; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_1); + break; + case MODULE_TXDISABLE_9 ... MODULE_TXDISABLE_16: + reg = 0xD; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_9); + break; + case MODULE_TXDISABLE_17 ... MODULE_TXDISABLE_24: + reg = 0xE; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_17); + break; + case MODULE_TXDISABLE_25 ... MODULE_TXDISABLE_32: + reg = 0xC; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_25); + break; + case MODULE_TXDISABLE_33 ... MODULE_TXDISABLE_40: + reg = 0xD; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_33); + break; + case MODULE_TXDISABLE_41 ... MODULE_TXDISABLE_48: + reg = 0xE; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_41); + break; + default: + return 0; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as5812_54x_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + /* Update tx_disable status */ + if (disable) { + status |= mask; + } + else { + status &= ~mask; + } + + status = as5812_54x_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_lp_mode(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc); + + long on; + int status= -ENOENT; + u8 reg = 0x16, mask = 0; + + if(attr->index < MODULE_LPMODE_49 || attr->index > MODULE_LPMODE_54) + return status; + + status = kstrtol(buf, 10, &on); + if (status) { + return status; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as5812_54x_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + mask = 0x1 << (attr->index - MODULE_LPMODE_49); + + /* Update lp_mode status */ + if (on) { + status |= mask; + } + else { + status &= ~mask; + } + + status = as5812_54x_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; + +} + +static ssize_t set_mode_reset(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc); + + long on; + int status= -ENOENT; + u8 reg = 0x15, mask = 0; + + if(attr->index < MODULE_RESET_49 || attr->index > MODULE_RESET_54) + return status; + + status = kstrtol(buf, 10, &on); + if (status) { + return status; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as5812_54x_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + mask = 0x1 << (attr->index - MODULE_RESET_49); + + /* Update tx_disable status */ + if (on) { + status |= mask; + } + else { + status &= ~mask; + } + + status = as5812_54x_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; + +} + +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc); + int status; + u32 addr, val; + + if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) { + return -EINVAL; + } + + if (addr > 0xFF || val > 0xFF) { + return -EINVAL; + } + + mutex_lock(&data->update_lock); + status = as5812_54x_cpld_write_internal(client, addr, val); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer() + for this as they will try to lock adapter a second time */ +static int as5812_54x_cpld_mux_reg_write(struct i2c_adapter *adap, + struct i2c_client *client, u8 val) +{ + unsigned long orig_jiffies; + unsigned short flags; + union i2c_smbus_data data; + int try; + s32 res = -EIO; + + data.byte = val; + flags = client->flags; + flags &= I2C_M_TEN | I2C_CLIENT_PEC; + + if (adap->algo->smbus_xfer) { + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (res = 0, try = 0; try <= adap->retries; try++) { + res = adap->algo->smbus_xfer(adap, client->addr, flags, + I2C_SMBUS_WRITE, CPLD_CHANNEL_SELECT_REG, + I2C_SMBUS_BYTE_DATA, &data); + if (res != -EAGAIN) + break; + if (time_after(jiffies, + orig_jiffies + adap->timeout)) + break; + } + } + + return res; +} + +static int as5812_54x_cpld_mux_select_chan(struct i2c_mux_core *muxc, + u32 chan) +{ + struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + u8 regval; + int ret = 0; + + regval = chan; + /* Only select the channel if its different from the last channel */ + if (data->last_chan != regval) { + ret = as5812_54x_cpld_mux_reg_write(muxc->parent, client, regval); + data->last_chan = regval; + } + + return ret; +} + +static int as5812_54x_cpld_mux_deselect_mux(struct i2c_mux_core *muxc, + u32 chan) +{ + struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + + /* Deselect active channel */ + data->last_chan = chips[data->type].deselectChan; + + return as5812_54x_cpld_mux_reg_write(muxc->parent, client, data->last_chan); +} + +static void as5812_54x_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); + return; + } + + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &cpld_client_list); + mutex_unlock(&list_lock); +} + +static void as5812_54x_cpld_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(cpld_node); + } + + mutex_unlock(&list_lock); +} + +static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + int val = 0; + struct i2c_client *client = to_i2c_client(dev); + + val = i2c_smbus_read_byte_data(client, 0x1); + + if (val < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val); + } + + return sprintf(buf, "%d", val); +} + +/* + * I2C init/probing/exit functions + */ +static int as5812_54x_cpld_mux_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + int num, force, class; + struct i2c_mux_core *muxc; + struct as5812_54x_cpld_data *data; + int ret = 0; + const struct attribute_group *group = NULL; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) + return -ENODEV; + + muxc = i2c_mux_alloc(adap, &client->dev, + chips[id->driver_data].nchans, sizeof(*data), 0, + as5812_54x_cpld_mux_select_chan, as5812_54x_cpld_mux_deselect_mux); + if (!muxc) + return -ENOMEM; + + i2c_set_clientdata(client, muxc); + data = i2c_mux_priv(muxc); + data->client = client; + data->type = id->driver_data; + data->last_chan = chips[data->type].deselectChan; /* force the first selection */ + mutex_init(&data->update_lock); + + /* Now create an adapter for each channel */ + for (num = 0; num < chips[data->type].nchans; num++) { + force = 0; /* dynamic adap number */ + class = 0; /* no class by default */ + + ret = i2c_mux_add_adapter(muxc, force, num, class); + + if (ret) { + dev_err(&client->dev, + "failed to register multiplexed adapter" + " %d as bus %d\n", num, force); + goto add_mux_failed; + } + } + + /* Register sysfs hooks */ + switch (data->type) { + case as5812_54x_cpld1: + group = &as5812_54x_cpld1_group; + break; + case as5812_54x_cpld2: + group = &as5812_54x_cpld2_group; + break; + case as5812_54x_cpld3: + group = &as5812_54x_cpld3_group; + + /* Bring QSFPs out of reset */ + as5812_54x_cpld_write_internal(client, 0x15, 0x3F); + break; + default: + break; + } + + if (group) { + ret = sysfs_create_group(&client->dev.kobj, group); + if (ret) { + goto add_mux_failed; + } + } + + if (chips[data->type].nchans) { + dev_info(&client->dev, + "registered %d multiplexed busses for I2C %s\n", + num, client->name); + } + else { + dev_info(&client->dev, + "device %s registered\n", client->name); + } + + as5812_54x_cpld_add_client(client); + + return 0; + +add_mux_failed: + i2c_mux_del_adapters(muxc); + return ret; +} + +static int as5812_54x_cpld_mux_remove(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc); + const struct attribute_group *group = NULL; + + as5812_54x_cpld_remove_client(client); + + /* Remove sysfs hooks */ + switch (data->type) { + case as5812_54x_cpld1: + group = &as5812_54x_cpld1_group; + break; + case as5812_54x_cpld2: + group = &as5812_54x_cpld2_group; + break; + case as5812_54x_cpld3: + group = &as5812_54x_cpld3_group; + break; + default: + break; + } + + if (group) { + sysfs_remove_group(&client->dev.kobj, group); + } + + i2c_mux_del_adapters(muxc); + + return 0; +} + +static int as5812_54x_cpld_read_internal(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int as5812_54x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +int as5812_54x_cpld_read(unsigned short cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as5812_54x_cpld_read_internal(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as5812_54x_cpld_read); + +int as5812_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EIO; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as5812_54x_cpld_write_internal(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as5812_54x_cpld_write); + +static struct i2c_driver as5812_54x_cpld_mux_driver = { + .driver = { + .name = "as5812_54x_cpld", + .owner = THIS_MODULE, + }, + .probe = as5812_54x_cpld_mux_probe, + .remove = as5812_54x_cpld_mux_remove, + .id_table = as5812_54x_cpld_mux_id, +}; + +static int __init as5812_54x_cpld_mux_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&as5812_54x_cpld_mux_driver); +} + +static void __exit as5812_54x_cpld_mux_exit(void) +{ + i2c_del_driver(&as5812_54x_cpld_mux_driver); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("Accton as5812-54x CPLD driver"); +MODULE_LICENSE("GPL"); + +module_init(as5812_54x_cpld_mux_init); +module_exit(as5812_54x_cpld_mux_exit); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/leds-accton_as5812_54x.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/leds-accton_as5812_54x.c new file mode 100755 index 0000000000..2ebe948612 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/leds-accton_as5812_54x.c @@ -0,0 +1,594 @@ +/* + * A LED driver for the accton_as5812_54x_led + * + * Copyright (C) 2013 Accton Technology Corporation. + * Brandon Chuang + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#if 0 +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include + +extern int as5812_54x_cpld_read (unsigned short cpld_addr, u8 reg); +extern int as5812_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +extern void led_classdev_unregister(struct led_classdev *led_cdev); +extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev); +extern void led_classdev_resume(struct led_classdev *led_cdev); +extern void led_classdev_suspend(struct led_classdev *led_cdev); + +#define DRVNAME "as5812_54x_led" + +struct accton_as5812_54x_led_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_val[4]; /* Register value, 0 = LOC/DIAG/FAN LED + 1 = PSU1/PSU2 LED + 2 = FAN1-4 LED + 3 = FAN5-6 LED */ +}; + +static struct accton_as5812_54x_led_data *ledctl = NULL; + +/* LED related data + */ +#define LED_TYPE_PSU1_REG_MASK 0x03 +#define LED_MODE_PSU1_GREEN_MASK 0x02 +#define LED_MODE_PSU1_AMBER_MASK 0x01 +#define LED_MODE_PSU1_OFF_MASK 0x03 +#define LED_MODE_PSU1_AUTO_MASK 0x00 + +#define LED_TYPE_PSU2_REG_MASK 0x0C +#define LED_MODE_PSU2_GREEN_MASK 0x08 +#define LED_MODE_PSU2_AMBER_MASK 0x04 +#define LED_MODE_PSU2_OFF_MASK 0x0C +#define LED_MODE_PSU2_AUTO_MASK 0x00 + +#define LED_TYPE_DIAG_REG_MASK 0x0C +#define LED_MODE_DIAG_GREEN_MASK 0x08 +#define LED_MODE_DIAG_AMBER_MASK 0x04 +#define LED_MODE_DIAG_OFF_MASK 0x0C + +#define LED_TYPE_FAN_REG_MASK 0x03 +#define LED_MODE_FAN_GREEN_MASK 0x02 +#define LED_MODE_FAN_AMBER_MASK 0x01 +#define LED_MODE_FAN_OFF_MASK 0x03 +#define LED_MODE_FAN_AUTO_MASK 0x00 + +#define LED_TYPE_FAN1_REG_MASK 0x03 +#define LED_TYPE_FAN2_REG_MASK 0x0C +#define LED_TYPE_FAN3_REG_MASK 0x30 +#define LED_TYPE_FAN4_REG_MASK 0xC0 +#define LED_TYPE_FAN5_REG_MASK 0x03 +#define LED_TYPE_FAN6_REG_MASK 0x0C + +#define LED_MODE_FANX_GREEN_MASK 0x01 +#define LED_MODE_FANX_RED_MASK 0x02 +#define LED_MODE_FANX_OFF_MASK 0x00 + +#define LED_TYPE_LOC_REG_MASK 0x30 +#define LED_MODE_LOC_ON_MASK 0x00 +#define LED_MODE_LOC_OFF_MASK 0x10 +#define LED_MODE_LOC_BLINK_MASK 0x20 + +static const u8 led_reg[] = { + 0xA, /* LOC/DIAG/FAN LED*/ + 0xB, /* PSU1/PSU2 LED */ + 0x16, /* FAN1-4 LED */ + 0x17, /* FAN4-6 LED */ +}; + +enum led_type { + LED_TYPE_PSU1, + LED_TYPE_PSU2, + LED_TYPE_DIAG, + LED_TYPE_FAN, + LED_TYPE_FAN1, + LED_TYPE_FAN2, + LED_TYPE_FAN3, + LED_TYPE_FAN4, + LED_TYPE_FAN5, + LED_TYPE_LOC +}; + +enum led_light_mode { + LED_MODE_OFF = 0, + LED_MODE_GREEN, + LED_MODE_AMBER, + LED_MODE_RED, + LED_MODE_GREEN_BLINK, + LED_MODE_AMBER_BLINK, + LED_MODE_RED_BLINK, + LED_MODE_AUTO, +}; + +struct led_type_mode { + enum led_type type; + int type_mask; + enum led_light_mode mode; + int mode_mask; +}; + +static struct led_type_mode led_type_mode_data[] = { +{LED_TYPE_PSU1, LED_TYPE_PSU1_REG_MASK, LED_MODE_GREEN, LED_MODE_PSU1_GREEN_MASK}, +{LED_TYPE_PSU1, LED_TYPE_PSU1_REG_MASK, LED_MODE_AMBER, LED_MODE_PSU1_AMBER_MASK}, +{LED_TYPE_PSU1, LED_TYPE_PSU1_REG_MASK, LED_MODE_AUTO, LED_MODE_PSU1_AUTO_MASK}, +{LED_TYPE_PSU1, LED_TYPE_PSU1_REG_MASK, LED_MODE_OFF, LED_MODE_PSU1_OFF_MASK}, +{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_GREEN, LED_MODE_PSU2_GREEN_MASK}, +{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_AMBER, LED_MODE_PSU2_AMBER_MASK}, +{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_AUTO, LED_MODE_PSU2_AUTO_MASK}, +{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_OFF, LED_MODE_PSU2_OFF_MASK}, +{LED_TYPE_FAN, LED_TYPE_FAN_REG_MASK, LED_MODE_GREEN, LED_MODE_FAN_GREEN_MASK}, +{LED_TYPE_FAN, LED_TYPE_FAN_REG_MASK, LED_MODE_AMBER, LED_MODE_FAN_AMBER_MASK}, +{LED_TYPE_FAN, LED_TYPE_FAN_REG_MASK, LED_MODE_AUTO, LED_MODE_FAN_AUTO_MASK}, +{LED_TYPE_FAN, LED_TYPE_FAN_REG_MASK, LED_MODE_OFF, LED_MODE_FAN_OFF_MASK}, +{LED_TYPE_FAN1, LED_TYPE_FAN1_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 0}, +{LED_TYPE_FAN1, LED_TYPE_FAN1_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 0}, +{LED_TYPE_FAN1, LED_TYPE_FAN1_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 0}, +{LED_TYPE_FAN2, LED_TYPE_FAN2_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 2}, +{LED_TYPE_FAN2, LED_TYPE_FAN2_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 2}, +{LED_TYPE_FAN2, LED_TYPE_FAN2_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 2}, +{LED_TYPE_FAN3, LED_TYPE_FAN3_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 4}, +{LED_TYPE_FAN3, LED_TYPE_FAN3_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 4}, +{LED_TYPE_FAN3, LED_TYPE_FAN3_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 4}, +{LED_TYPE_FAN4, LED_TYPE_FAN4_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 6}, +{LED_TYPE_FAN4, LED_TYPE_FAN4_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 6}, +{LED_TYPE_FAN4, LED_TYPE_FAN4_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 6}, +{LED_TYPE_FAN5, LED_TYPE_FAN5_REG_MASK, LED_MODE_GREEN, LED_MODE_FANX_GREEN_MASK << 0}, +{LED_TYPE_FAN5, LED_TYPE_FAN5_REG_MASK, LED_MODE_RED, LED_MODE_FANX_RED_MASK << 0}, +{LED_TYPE_FAN5, LED_TYPE_FAN5_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 0}, +{LED_TYPE_DIAG, LED_TYPE_DIAG_REG_MASK, LED_MODE_GREEN, LED_MODE_DIAG_GREEN_MASK}, +{LED_TYPE_DIAG, LED_TYPE_DIAG_REG_MASK, LED_MODE_AMBER, LED_MODE_DIAG_AMBER_MASK}, +{LED_TYPE_DIAG, LED_TYPE_DIAG_REG_MASK, LED_MODE_OFF, LED_MODE_DIAG_OFF_MASK}, +{LED_TYPE_LOC, LED_TYPE_LOC_REG_MASK, LED_MODE_AMBER, LED_MODE_LOC_ON_MASK}, +{LED_TYPE_LOC, LED_TYPE_LOC_REG_MASK, LED_MODE_OFF, LED_MODE_LOC_OFF_MASK}, +{LED_TYPE_LOC, LED_TYPE_LOC_REG_MASK, LED_MODE_AMBER_BLINK, LED_MODE_LOC_BLINK_MASK} +}; + + +struct fanx_info_s { + u8 cname; /* device name */ + enum led_type type; + u8 reg_id; /* map to led_reg & reg_val */ +}; + +static struct fanx_info_s fanx_info[] = { + {'1', LED_TYPE_FAN1, 2}, + {'2', LED_TYPE_FAN2, 2}, + {'3', LED_TYPE_FAN3, 2}, + {'4', LED_TYPE_FAN4, 2}, + {'5', LED_TYPE_FAN5, 3} +}; + +static int led_reg_val_to_light_mode(enum led_type type, u8 reg_val) { + int i; + + for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) { + + if (type != led_type_mode_data[i].type) + continue; + + if ((led_type_mode_data[i].type_mask & reg_val) == + led_type_mode_data[i].mode_mask) + { + return led_type_mode_data[i].mode; + } + } + + return 0; +} + +static u8 led_light_mode_to_reg_val(enum led_type type, + enum led_light_mode mode, u8 reg_val) { + int i; + + for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) { + if (type != led_type_mode_data[i].type) + continue; + + if (mode != led_type_mode_data[i].mode) + continue; + + reg_val = led_type_mode_data[i].mode_mask | + (reg_val & (~led_type_mode_data[i].type_mask)); + } + + return reg_val; +} + +static int accton_as5812_54x_led_read_value(u8 reg) +{ + return as5812_54x_cpld_read(0x60, reg); +} + +static int accton_as5812_54x_led_write_value(u8 reg, u8 value) +{ + return as5812_54x_cpld_write(0x60, reg, value); +} + +static void accton_as5812_54x_led_update(void) +{ + mutex_lock(&ledctl->update_lock); + + if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2) + || !ledctl->valid) { + int i; + + dev_dbg(&ledctl->pdev->dev, "Starting accton_as5812_54x_led update\n"); + + /* Update LED data + */ + for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) { + int status = accton_as5812_54x_led_read_value(led_reg[i]); + + if (status < 0) { + ledctl->valid = 0; + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", led_reg[i], status); + goto exit; + } + else + { + ledctl->reg_val[i] = status; + } + } + + ledctl->last_updated = jiffies; + ledctl->valid = 1; + } + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void accton_as5812_54x_led_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode, + u8 reg, enum led_type type) +{ + int reg_val; + + mutex_lock(&ledctl->update_lock); + + reg_val = accton_as5812_54x_led_read_value(reg); + + if (reg_val < 0) { + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", reg, reg_val); + goto exit; + } + + reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val); + accton_as5812_54x_led_write_value(reg, reg_val); + + /* to prevent the slow-update issue */ + ledctl->valid = 0; + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void accton_as5812_54x_led_psu_1_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as5812_54x_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU1); +} + +static enum led_brightness accton_as5812_54x_led_psu_1_get(struct led_classdev *cdev) +{ + accton_as5812_54x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU1, ledctl->reg_val[1]); +} + +static void accton_as5812_54x_led_psu_2_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as5812_54x_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU2); +} + +static enum led_brightness accton_as5812_54x_led_psu_2_get(struct led_classdev *cdev) +{ + accton_as5812_54x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]); +} + +static void accton_as5812_54x_led_fan_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as5812_54x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_FAN); +} + +static enum led_brightness accton_as5812_54x_led_fan_get(struct led_classdev *cdev) +{ + accton_as5812_54x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[0]); +} + + +static void accton_as5812_54x_led_fanx_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + enum led_type led_type1; + int reg_id; + int i, nsize; + int ncount = sizeof(fanx_info)/sizeof(struct fanx_info_s); + + for(i=0;iname); + + if (led_cdev->name[nsize-1] == fanx_info[i].cname) + { + led_type1 = fanx_info[i].type; + reg_id = fanx_info[i].reg_id; + accton_as5812_54x_led_set(led_cdev, led_light_mode, led_reg[reg_id], led_type1); + return; + } + } +} + + +static enum led_brightness accton_as5812_54x_led_fanx_get(struct led_classdev *cdev) +{ + enum led_type led_type1; + int reg_id; + int i, nsize; + int ncount = sizeof(fanx_info)/sizeof(struct fanx_info_s); + + for(i=0;iname); + + if (cdev->name[nsize-1] == fanx_info[i].cname) + { + led_type1 = fanx_info[i].type; + reg_id = fanx_info[i].reg_id; + accton_as5812_54x_led_update(); + return led_reg_val_to_light_mode(led_type1, ledctl->reg_val[reg_id]); + } + } + + + return led_reg_val_to_light_mode(LED_TYPE_FAN1, ledctl->reg_val[2]); +} + + +static void accton_as5812_54x_led_diag_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as5812_54x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_DIAG); +} + +static enum led_brightness accton_as5812_54x_led_diag_get(struct led_classdev *cdev) +{ + accton_as5812_54x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_DIAG, ledctl->reg_val[0]); +} + +static void accton_as5812_54x_led_loc_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as5812_54x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_LOC); +} + +static enum led_brightness accton_as5812_54x_led_loc_get(struct led_classdev *cdev) +{ + accton_as5812_54x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_LOC, ledctl->reg_val[0]); +} + +static struct led_classdev accton_as5812_54x_leds[] = { + [LED_TYPE_PSU1] = { + .name = "accton_as5812_54x_led::psu1", + .default_trigger = "unused", + .brightness_set = accton_as5812_54x_led_psu_1_set, + .brightness_get = accton_as5812_54x_led_psu_1_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_PSU2] = { + .name = "accton_as5812_54x_led::psu2", + .default_trigger = "unused", + .brightness_set = accton_as5812_54x_led_psu_2_set, + .brightness_get = accton_as5812_54x_led_psu_2_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN] = { + .name = "accton_as5812_54x_led::fan", + .default_trigger = "unused", + .brightness_set = accton_as5812_54x_led_fan_set, + .brightness_get = accton_as5812_54x_led_fan_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN1] = { + .name = "accton_as5812_54x_led::fan1", + .default_trigger = "unused", + .brightness_set = accton_as5812_54x_led_fanx_set, + .brightness_get = accton_as5812_54x_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN2] = { + .name = "accton_as5812_54x_led::fan2", + .default_trigger = "unused", + .brightness_set = accton_as5812_54x_led_fanx_set, + .brightness_get = accton_as5812_54x_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN3] = { + .name = "accton_as5812_54x_led::fan3", + .default_trigger = "unused", + .brightness_set = accton_as5812_54x_led_fanx_set, + .brightness_get = accton_as5812_54x_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN4] = { + .name = "accton_as5812_54x_led::fan4", + .default_trigger = "unused", + .brightness_set = accton_as5812_54x_led_fanx_set, + .brightness_get = accton_as5812_54x_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN5] = { + .name = "accton_as5812_54x_led::fan5", + .default_trigger = "unused", + .brightness_set = accton_as5812_54x_led_fanx_set, + .brightness_get = accton_as5812_54x_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_DIAG] = { + .name = "accton_as5812_54x_led::diag", + .default_trigger = "unused", + .brightness_set = accton_as5812_54x_led_diag_set, + .brightness_get = accton_as5812_54x_led_diag_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_LOC] = { + .name = "accton_as5812_54x_led::loc", + .default_trigger = "unused", + .brightness_set = accton_as5812_54x_led_loc_set, + .brightness_get = accton_as5812_54x_led_loc_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, +}; + +static int accton_as5812_54x_led_suspend(struct platform_device *dev, + pm_message_t state) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(accton_as5812_54x_leds); i++) { + led_classdev_suspend(&accton_as5812_54x_leds[i]); + } + + return 0; +} + +static int accton_as5812_54x_led_resume(struct platform_device *dev) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(accton_as5812_54x_leds); i++) { + led_classdev_resume(&accton_as5812_54x_leds[i]); + } + + return 0; +} + +static int accton_as5812_54x_led_probe(struct platform_device *pdev) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(accton_as5812_54x_leds); i++) { + ret = led_classdev_register(&pdev->dev, &accton_as5812_54x_leds[i]); + + if (ret < 0) + break; + } + + /* Check if all LEDs were successfully registered */ + if (i != ARRAY_SIZE(accton_as5812_54x_leds)){ + int j; + + /* only unregister the LEDs that were successfully registered */ + for (j = 0; j < i; j++) { + led_classdev_unregister(&accton_as5812_54x_leds[i]); + } + } + + return ret; +} + +static int accton_as5812_54x_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(accton_as5812_54x_leds); i++) { + led_classdev_unregister(&accton_as5812_54x_leds[i]); + } + + return 0; +} + +static struct platform_driver accton_as5812_54x_led_driver = { + .probe = accton_as5812_54x_led_probe, + .remove = accton_as5812_54x_led_remove, + .suspend = accton_as5812_54x_led_suspend, + .resume = accton_as5812_54x_led_resume, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init accton_as5812_54x_led_init(void) +{ + int ret; + + ret = platform_driver_register(&accton_as5812_54x_led_driver); + if (ret < 0) { + goto exit; + } + + ledctl = kzalloc(sizeof(struct accton_as5812_54x_led_data), GFP_KERNEL); + if (!ledctl) { + ret = -ENOMEM; + platform_driver_unregister(&accton_as5812_54x_led_driver); + goto exit; + } + + mutex_init(&ledctl->update_lock); + + ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(ledctl->pdev)) { + ret = PTR_ERR(ledctl->pdev); + platform_driver_unregister(&accton_as5812_54x_led_driver); + kfree(ledctl); + goto exit; + } + +exit: + return ret; +} + +static void __exit accton_as5812_54x_led_exit(void) +{ + platform_device_unregister(ledctl->pdev); + platform_driver_unregister(&accton_as5812_54x_led_driver); + kfree(ledctl); +} + +module_init(accton_as5812_54x_led_init); +module_exit(accton_as5812_54x_led_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("accton_as5812_54x_led driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/ym2651y.c new file mode 100755 index 0000000000..519530387e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/modules/ym2651y.c @@ -0,0 +1,683 @@ +/* + * An hwmon driver for the 3Y Power YM-2651Y Power Module + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#if 0 +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_FAN_DUTY_CYCLE 100 + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +enum chips { + YM2651, + YM2401, +}; + +/* Each client has this additional data + */ +struct ym2651y_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 chip; /* chip id */ + u8 capability; /* Register value */ + u16 status_word; /* Register value */ + u8 fan_fault; /* Register value */ + u8 over_temp; /* Register value */ + u16 v_out; /* Register value */ + u16 i_out; /* Register value */ + u16 p_out; /* Register value */ + u8 vout_mode; /* Register value */ + u16 temp; /* Register value */ + u16 fan_speed; /* Register value */ + u16 fan_duty_cycle[2]; /* Register value */ + u8 fan_dir[5]; /* Register value */ + u8 pmbus_revision; /* Register value */ + u8 mfr_id[10]; /* Register value */ + u8 mfr_model[16]; /* Register value */ + u8 mfr_revsion[3]; /* Register value */ + u16 mfr_vin_min; /* Register value */ + u16 mfr_vin_max; /* Register value */ + u16 mfr_iin_max; /* Register value */ + u16 mfr_iout_max; /* Register value */ + u16 mfr_pin_max; /* Register value */ + u16 mfr_pout_max; /* Register value */ + u16 mfr_vout_min; /* Register value */ + u16 mfr_vout_max; /* Register value */ +}; + +static ssize_t show_byte(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_word(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_linear(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_vout(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_ascii(struct device *dev, struct device_attribute *da, + char *buf); +static struct ym2651y_data *ym2651y_update_device(struct device *dev); +static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value); + +enum ym2651y_sysfs_attributes { + PSU_POWER_ON = 0, + PSU_TEMP_FAULT, + PSU_POWER_GOOD, + PSU_FAN1_FAULT, + PSU_FAN_DIRECTION, + PSU_OVER_TEMP, + PSU_V_OUT, + PSU_I_OUT, + PSU_P_OUT, + PSU_TEMP1_INPUT, + PSU_FAN1_SPEED, + PSU_FAN1_DUTY_CYCLE, + PSU_PMBUS_REVISION, + PSU_MFR_ID, + PSU_MFR_MODEL, + PSU_MFR_REVISION, + PSU_MFR_VIN_MIN, + PSU_MFR_VIN_MAX, + PSU_MFR_VOUT_MIN, + PSU_MFR_VOUT_MAX, + PSU_MFR_IIN_MAX, + PSU_MFR_IOUT_MAX, + PSU_MFR_PIN_MAX, + PSU_MFR_POUT_MAX +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_power_on, S_IRUGO, show_word, NULL, PSU_POWER_ON); +static SENSOR_DEVICE_ATTR(psu_temp_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_word, NULL, PSU_POWER_GOOD); +static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT); +static SENSOR_DEVICE_ATTR(psu_over_temp, S_IRUGO, show_over_temp, NULL, PSU_OVER_TEMP); +static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_vout, NULL, PSU_V_OUT); +static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT); +static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT); +static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); +static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE); +static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_ascii, NULL, PSU_FAN_DIRECTION); +static SENSOR_DEVICE_ATTR(psu_pmbus_revision,S_IRUGO, show_byte, NULL, PSU_PMBUS_REVISION); +static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, show_ascii, NULL, PSU_MFR_ID); +static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL); +static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MFR_REVISION); +static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN); +static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN); +static SENSOR_DEVICE_ATTR(psu_mfr_vout_max, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_iin_max, S_IRUGO, show_linear, NULL, PSU_MFR_IIN_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_iout_max, S_IRUGO, show_linear, NULL, PSU_MFR_IOUT_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_pin_max, S_IRUGO, show_linear, NULL, PSU_MFR_PIN_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_pout_max, S_IRUGO, show_linear, NULL, PSU_MFR_POUT_MAX); + +static struct attribute *ym2651y_attributes[] = { + &sensor_dev_attr_psu_power_on.dev_attr.attr, + &sensor_dev_attr_psu_temp_fault.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, + &sensor_dev_attr_psu_over_temp.dev_attr.attr, + &sensor_dev_attr_psu_v_out.dev_attr.attr, + &sensor_dev_attr_psu_i_out.dev_attr.attr, + &sensor_dev_attr_psu_p_out.dev_attr.attr, + &sensor_dev_attr_psu_temp1_input.dev_attr.attr, + &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr, + &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, + &sensor_dev_attr_psu_fan_dir.dev_attr.attr, + &sensor_dev_attr_psu_pmbus_revision.dev_attr.attr, + &sensor_dev_attr_psu_mfr_id.dev_attr.attr, + &sensor_dev_attr_psu_mfr_model.dev_attr.attr, + &sensor_dev_attr_psu_mfr_revision.dev_attr.attr, + &sensor_dev_attr_psu_mfr_vin_min.dev_attr.attr, + &sensor_dev_attr_psu_mfr_vin_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_pout_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_iin_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_pin_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_vout_min.dev_attr.attr, + &sensor_dev_attr_psu_mfr_vout_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_iout_max.dev_attr.attr, + NULL +}; + +static ssize_t show_byte(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + + if (!data->valid) { + return 0; + } + + return (attr->index == PSU_PMBUS_REVISION) ? sprintf(buf, "%d\n", data->pmbus_revision) : + sprintf(buf, "0\n"); +} + +static ssize_t show_word(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + u16 status = 0; + + if (!data->valid) { + return 0; + } + + switch (attr->index) { + case PSU_POWER_ON: /* psu_power_on, low byte bit 6 of status_word, 0=>ON, 1=>OFF */ + status = (data->status_word & 0x40) ? 0 : 1; + break; + case PSU_TEMP_FAULT: /* psu_temp_fault, low byte bit 2 of status_word, 0=>Normal, 1=>temp fault */ + status = (data->status_word & 0x4) >> 2; + break; + case PSU_POWER_GOOD: /* psu_power_good, high byte bit 3 of status_word, 0=>OK, 1=>FAIL */ + status = (data->status_word & 0x800) ? 0 : 1; + break; + } + + return sprintf(buf, "%d\n", status); +} + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask) +{ + u16 valid_data = data & mask; + bool is_negative = valid_data >> (valid_bit - 1); + + return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data; +} + +static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1; + long speed; + int error; + + error = kstrtol(buf, 10, &speed); + if (error) + return error; + + if (speed < 0 || speed > MAX_FAN_DUTY_CYCLE) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->fan_duty_cycle[nr] = speed; + ym2651y_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_linear(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + + u16 value = 0; + int exponent, mantissa; + int multiplier = 1000; + + if (!data->valid) { + return 0; + } + + switch (attr->index) { + case PSU_V_OUT: + value = data->v_out; + break; + case PSU_I_OUT: + value = data->i_out; + break; + case PSU_P_OUT: + value = data->p_out; + break; + case PSU_TEMP1_INPUT: + value = data->temp; + break; + case PSU_FAN1_SPEED: + value = data->fan_speed; + multiplier = 1; + break; + case PSU_FAN1_DUTY_CYCLE: + value = data->fan_duty_cycle[0]; + multiplier = 1; + break; + case PSU_MFR_VIN_MIN: + value = data->mfr_vin_min; + break; + case PSU_MFR_VIN_MAX: + value = data->mfr_vin_max; + break; + case PSU_MFR_VOUT_MIN: + value = data->mfr_vout_min; + break; + case PSU_MFR_VOUT_MAX: + value = data->mfr_vout_max; + break; + case PSU_MFR_PIN_MAX: + value = data->mfr_pin_max; + break; + case PSU_MFR_POUT_MAX: + value = data->mfr_pout_max; + break; + case PSU_MFR_IOUT_MAX: + value = data->mfr_iout_max; + break; + case PSU_MFR_IIN_MAX: + value = data->mfr_iin_max; + break; + } + + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + + return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); +} + +static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + u8 shift; + + if (!data->valid) { + return 0; + } + + shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; + + return sprintf(buf, "%d\n", data->fan_fault >> shift); +} + +static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct ym2651y_data *data = ym2651y_update_device(dev); + + if (!data->valid) { + return 0; + } + + return sprintf(buf, "%d\n", data->over_temp >> 7); +} + +static ssize_t show_ascii(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + u8 *ptr = NULL; + + if (!data->valid) { + return 0; + } + + switch (attr->index) { + case PSU_FAN_DIRECTION: /* psu_fan_dir */ + ptr = data->fan_dir + 1; /* Skip the first byte since it is the length of string. */ + break; + case PSU_MFR_ID: /* psu_mfr_id */ + ptr = data->mfr_id + 1; /* The first byte is the count byte of string. */; + break; + case PSU_MFR_MODEL: /* psu_mfr_model */ + ptr = data->mfr_model + 1; /* The first byte is the count byte of string. */ + break; + case PSU_MFR_REVISION: /* psu_mfr_revision */ + ptr = data->mfr_revsion + 1; /* The first byte is the count byte of string. */ + break; + default: + return 0; + } + + return sprintf(buf, "%s\n", ptr); +} + +static ssize_t show_vout_by_mode(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct ym2651y_data *data = ym2651y_update_device(dev); + int exponent, mantissa; + int multiplier = 1000; + + if (!data->valid) { + return 0; + } + + exponent = two_complement_to_int(data->vout_mode, 5, 0x1f); + mantissa = data->v_out; + + return (exponent > 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); +} + +static ssize_t show_vout(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + + if (data->chip == YM2401) { + return show_vout_by_mode(dev, da, buf); + } + + return show_linear(dev, da, buf); +} + +static const struct attribute_group ym2651y_group = { + .attrs = ym2651y_attributes, +}; + +static int ym2651y_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct ym2651y_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct ym2651y_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->chip = dev_id->driver_data; + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &ym2651y_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &ym2651y_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int ym2651y_remove(struct i2c_client *client) +{ + struct ym2651y_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &ym2651y_group); + kfree(data); + + return 0; +} + +static const struct i2c_device_id ym2651y_id[] = { + { "ym2651", YM2651 }, + { "ym2401", YM2401 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ym2651y_id); + +static struct i2c_driver ym2651y_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "ym2651", + }, + .probe = ym2651y_probe, + .remove = ym2651y_remove, + .id_table = ym2651y_id, + .address_list = normal_i2c, +}; + +static int ym2651y_read_byte(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int ym2651y_read_word(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_word_data(client, reg); +} + +static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value) +{ + return i2c_smbus_write_word_data(client, reg, value); +} + +static int ym2651y_read_block(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + + if (unlikely(result < 0)) + goto abort; + if (unlikely(result != data_len)) { + result = -EIO; + goto abort; + } + + result = 0; + +abort: + return result; +} + +struct reg_data_byte { + u8 reg; + u8 *value; +}; + +struct reg_data_word { + u8 reg; + u16 *value; +}; + +static struct ym2651y_data *ym2651y_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int i, status, length; + u8 command, buf; + struct reg_data_byte regs_byte[] = { {0x19, &data->capability}, + {0x20, &data->vout_mode}, + {0x7d, &data->over_temp}, + {0x81, &data->fan_fault}, + {0x98, &data->pmbus_revision}}; + struct reg_data_word regs_word[] = { {0x79, &data->status_word}, + {0x8b, &data->v_out}, + {0x8c, &data->i_out}, + {0x96, &data->p_out}, + {0x8d, &data->temp}, + {0x3b, &(data->fan_duty_cycle[0])}, + {0x3c, &(data->fan_duty_cycle[1])}, + {0x90, &data->fan_speed}, + {0xa0, &data->mfr_vin_min}, + {0xa1, &data->mfr_vin_max}, + {0xa2, &data->mfr_iin_max}, + {0xa3, &data->mfr_pin_max}, + {0xa4, &data->mfr_vout_min}, + {0xa5, &data->mfr_vout_max}, + {0xa6, &data->mfr_iout_max}, + {0xa7, &data->mfr_pout_max}}; + + dev_dbg(&client->dev, "Starting ym2651 update\n"); + data->valid = 0; + + /* Read byte data */ + for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { + status = ym2651y_read_byte(client, regs_byte[i].reg); + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_byte[i].reg, status); + goto exit; + } + else { + *(regs_byte[i].value) = status; + } + } + + /* Read word data */ + for (i = 0; i < ARRAY_SIZE(regs_word); i++) { + status = ym2651y_read_word(client, regs_word[i].reg); + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_word[i].reg, status); + goto exit; + } + else { + *(regs_word[i].value) = status; + } + } + + /* Read fan_direction */ + command = 0xC3; + status = ym2651y_read_block(client, command, data->fan_dir, + ARRAY_SIZE(data->fan_dir)-1); + data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0'; + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } + + /* Read mfr_id */ + command = 0x99; + status = ym2651y_read_block(client, command, data->mfr_id, + ARRAY_SIZE(data->mfr_id)-1); + data->mfr_id[ARRAY_SIZE(data->mfr_id)-1] = '\0'; + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } + + /* Read mfr_model */ + command = 0x9a; + length = 1; + + /* Read first byte to determine the length of data */ + status = ym2651y_read_block(client, command, &buf, length); + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } + + status = ym2651y_read_block(client, command, data->mfr_model, buf+1); + data->mfr_model[buf+1] = '\0'; + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } + + /* Read mfr_revsion */ + command = 0x9b; + status = ym2651y_read_block(client, command, data->mfr_revsion, + ARRAY_SIZE(data->mfr_revsion)-1); + data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0'; + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + } + +exit: + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init ym2651y_init(void) +{ + return i2c_add_driver(&ym2651y_driver); +} + +static void __exit ym2651y_exit(void) +{ + i2c_del_driver(&ym2651y_driver); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("3Y Power YM-2651Y driver"); +MODULE_LICENSE("GPL"); + +module_init(ym2651y_init); +module_exit(ym2651y_exit); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/service/as5812-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/service/as5812-platform-monitor.service new file mode 100755 index 0000000000..e495bcba3a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/service/as5812-platform-monitor.service @@ -0,0 +1,17 @@ +[Unit] +Description=Accton AS5812-54X Platform Monitoring service +Before=pmon.service +After=sysinit.target +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStartPre=/usr/local/bin/accton_as5812_util.py install +ExecStart=/usr/local/bin/accton_as5812_monitor.py +RemainAfterExit=yes + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/setup.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/setup.py new file mode 100755 index 0000000000..aa8615fd8a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/setup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +import os +import sys +from setuptools import setup +os.listdir + +setup( + name='as5812_54x', + version='1.0', + description='Module to initialize Accton AS5812-54X platforms', + + packages=['as5812_54x'], + package_dir={'as5812_54x': 'as5812-54x/classes'}, +) + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/README b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/README new file mode 100755 index 0000000000..4ce43d9407 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/README @@ -0,0 +1,117 @@ +Copyright (C) 2016 Accton Networks, Inc. + +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 3 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. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Contents of this package: + patch - files under patch/ is for kernel and ONIE installer + for the kernel: + config-accton-as5812_54x.patch + for kernel configuration. + driver-i2c-muxes-pca954x-always-deselect.patch + for i2c_mux deselects after transaction. + driver-patches-for-accton-as5812-fan-psu-cpld.patch + for as5812's fan/psu/cpld/led/sfp drivers. + for ONIE: + onie_installer-accton-AS5812-54X.patch + for console port setting and copy util script o rootfs. + module - Contains source code of as5812 kernel driver modules. + +The late Sonic building scripts, pushed @Dec 5 2016, will automatically +create a docker container and run building process under it. +User is not necessary to handle docker environment creation. + +1. Download sonic-buildimage environment. + - Run "git clone https://github.com/Azure/sonic-buildimage". + - cd to sonic-buildimage and run "git submodule update --init --recursive". +2. Build kernel + - cd ./src/sonic-linux-kernel + - Copy patches and series from patch/kernel of this release to + sonic-linux-kernel/patch. + - Build kernel by "make". + - The built kernel package, linux-image-3.16.0-5-amd64_3.16.51-3+deb8u1_amd64.deb + , is generated. +3. Build installer + - Change directory back to sonic-buildimage/. + - Get onie_installer-accton-AS5812-54X.patch" from patch/installer. + - Change setting for AS5812-54X by patching build_image.sh. + "patch -p1 < onie_installer-accton-AS5812-54X.patch" + !!NOTICE, patching onie_installer-accton-AS5812-54X.patch comments out the + "git status" checking at build_image.sh. + - The account and password of installed OS can be given at rules/config. + The default user and password are "admin" & "YourPaSsWoRd" respectively. + - Run "make configure PLATFORM=broadcom" + - Copy the built kernel debian package to target/debs/. + The file is linux-image-3.16.0-5-amd64_*_amd64.deb under directory + src/sonic-linux-kernel/. + - Run "make target/sonic-generic.bin" + - Get the installer, target/sonic-generic.bin, to target machine and install. + +All Linux kernel code is licensed under the GPLv1. All other code is +licensed under the GPLv3. Please see the LICENSE file for copies of +both licenses. + +The code for integacting with Accton AS5812-54X has 2 parts, +kernel drivers and operational script. +The kernel drivers of peripherals are under module/ directory. +1. These drivers are patched into kernel by + driver-patches-for-accton-as5812-fan-psu-cpld.patch + Or you can build the driver under module/ by setting environment variable, + KERNEL_SRC, to proper linux built directory and run make. + It may be sonic-linux-kernel/linux-3.*/debian/build/build_amd64_none_amd64/. +2. A operational script, accton_as5812_util.py, for device initializatian and + peripheral accessing should be installed at /usr/bin. + This script is generated by onie_installer-accton-AS5812-54X.patch. + It's done by patching onie_installer-accton-AS5812-54X.patch at build-image. + Run "accton_as5812_util.py install" to install drivers. + +To initialize the system, run "accton_as5812_util.py install". +To clean up the drivers & devices, run "accton_as5812_util.py clean". +To dump information of sensors, run "accton_as5812_util.py show". +To dump SFP EEPROM, run "accton_as5812_util.py sff". +To set fan speed, run "accton_as5812_util.py set fan". +To enable/disable SFP emission, run "accton_as5812_util.py set sfp". +To set system LEDs' color, run "accton_as5812_util.py set led" +For more information, run "accton_as5812_util.py --help". + +==================================================================== +Besides applying accton_as5812_util.py to access peripherals, you can +access peripherals by sysfs nodes directly after the installation is run. + +System LED: + There are 5 system LEDs at the lower-left corner of front panel. + They are loc, diag, fan, ps1, and ps2. + The sysfs interface color mappings are as follows: + Brightness: + 0 => off + 1 => green + 2 => amber + 3 => red + 4 => blue + But not all colors are available for each LED. + +Fan Control: + There are 10 fans inside 5 fan modules. + All fans share 1 duty setting, ranged from 0~100. + +Thermal sensers: + 3 temperature sensors are controlled by the lm75 kernel modules. + +PSUs: + There 2 power supplies slot at the left/right side of the back. + Once if a PSU is not plugged, the status of it is shown failed. + +There are 48 SFP+ and 6 QSFP modules are equipped. +Before operating on PSU and QSFP+, please make sure it is well plugged. +Otherwise, operation is going to fail. + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_monitor.py new file mode 100755 index 0000000000..78c06f4656 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_monitor.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python +# +# Copyright (C) 2019 Accton Technology Corporation +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 11/13/2017: Polly Hsu, Create +# 05/08/2019: Roy Lee, changed for as5812-54x. +# ------------------------------------------------------------------ + +try: + import os + import sys, getopt + import subprocess + import click + import imp + import logging + import logging.config + import types + import time # this is only being used as part of the example + import traceback + import signal + from tabulate import tabulate + from as5812_54x.fanutil import FanUtil + from as5812_54x.thermalutil import ThermalUtil +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = 'accton_as5812_monitor' +DUTY_MAX = 100 + +global log_file +global log_level + +# Make a class we can use to capture stdout and sterr in the log +class accton_as5812_monitor(object): + # static temp var + _ori_temp = 0 + _new_perc = 0 + + def __init__(self, log_file, log_level): + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) + + def manage_fans(self): + FAN_LEV1_UP_TEMP = 57700 # temperature + FAN_LEV1_DOWN_TEMP = 0 # unused + FAN_LEV1_SPEED_PERC = DUTY_MAX # percentage*/ + + FAN_LEV2_UP_TEMP = 53000 + FAN_LEV2_DOWN_TEMP = 52700 + FAN_LEV2_SPEED_PERC = 80 + + FAN_LEV3_UP_TEMP = 49500 + FAN_LEV3_DOWN_TEMP = 47700 + FAN_LEV3_SPEED_PERC = 65 + + FAN_LEV4_UP_TEMP = 0 # unused + FAN_LEV4_DOWN_TEMP = 42700 + FAN_LEV4_SPEED_PERC = 40 + + + thermal = ThermalUtil() + fan = FanUtil() + + temp1 = thermal.get_thermal_1_val() + if temp1 is None: + return False + + temp2 = thermal.get_thermal_2_val() + if temp2 is None: + return False + + new_temp = (temp1 + temp2) / 2 + + for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1): + fan_stat = fan.get_fan_status(x) + if fan_stat is None: + return False + if fan_stat is False: + self._new_perc = FAN_LEV1_SPEED_PERC + logging.debug('INFO. SET new_perc to %d (FAN fault. fan_num:%d)', self._new_perc, x) + break + logging.debug('INFO. fan_stat is True (fan_num:%d)', x) + + if fan_stat is not None and fan_stat is not False: + diff = new_temp - self._ori_temp + if diff == 0: + logging.debug('INFO. RETURN. THERMAL temp not changed. %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp) + return True + else: + if diff >= 0: + is_up = True + logging.debug('INFO. THERMAL temp UP %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp) + else: + is_up = False + logging.debug('INFO. THERMAL temp DOWN %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp) + + if is_up is True: + if new_temp >= FAN_LEV1_UP_TEMP: + self._new_perc = FAN_LEV1_SPEED_PERC + elif new_temp >= FAN_LEV2_UP_TEMP: + self._new_perc = FAN_LEV2_SPEED_PERC + elif new_temp >= FAN_LEV3_UP_TEMP: + self._new_perc = FAN_LEV3_SPEED_PERC + else: + self._new_perc = FAN_LEV4_SPEED_PERC + logging.debug('INFO. SET. FAN_SPEED as %d (new THERMAL temp:%d)', self._new_perc, new_temp) + else: + if new_temp <= FAN_LEV4_DOWN_TEMP: + self._new_perc = FAN_LEV4_SPEED_PERC + elif new_temp <= FAN_LEV3_DOWN_TEMP: + self._new_perc = FAN_LEV3_SPEED_PERC + elif new_temp <= FAN_LEV2_DOWN_TEMP: + self._new_perc = FAN_LEV2_SPEED_PERC + else: + self._new_perc = FAN_LEV1_SPEED_PERC + logging.debug('INFO. SET. FAN_SPEED as %d (new THERMAL temp:%d)', self._new_perc, new_temp) + + cur_perc = fan.get_fan_duty_cycle(fan.get_idx_fan_start()) + if cur_perc == self._new_perc: + logging.debug('INFO. RETURN. FAN speed not changed. %d / %d (new_perc / ori_perc)', self._new_perc, cur_perc) + return True + + set_stat = fan.set_fan_duty_cycle(fan.get_idx_fan_start(), self._new_perc) + if set_stat is True: + logging.debug('INFO: PASS. set_fan_duty_cycle (%d)', self._new_perc) + else: + logging.debug('INFO: FAIL. set_fan_duty_cycle (%d)', self._new_perc) + + logging.debug('INFO: GET. ori_perc is %d. ori_temp is %d', cur_perc, self._ori_temp) + self._ori_temp = new_temp + logging.debug('INFO: UPDATE. ori_perc to %d. ori_temp to %d', cur_perc, self._ori_temp) + + return True + +def handler(signum, frame): + fan = FanUtil() + logging.debug('INFO:Cause signal %d, set fan speed max.', signum) + fan.set_fan_duty_cycle(fan.get_idx_fan_start(), DUTY_MAX) + sys.exit(0) + +def main(argv): + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv,'hdl:',['lfile=']) + except getopt.GetoptError: + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + for opt, arg in opts: + if opt == '-h': + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + elif opt in ('-d', '--debug'): + log_level = logging.DEBUG + elif opt in ('-l', '--lfile'): + log_file = arg + + signal.signal(signal.SIGINT, handler) + signal.signal(signal.SIGTERM, handler) + monitor = accton_as5812_monitor(log_file, log_level) + + # Loop forever, doing something useful hopefully: + while True: + monitor.manage_fans() + time.sleep(10) + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_util.py b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_util.py new file mode 100755 index 0000000000..37ca9f2875 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5812-54x/utils/accton_as5812_util.py @@ -0,0 +1,686 @@ +#!/usr/bin/env python +# +# Copyright (C) 2016 Accton Networks, Inc. +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes + show : show all systen status + sff : dump SFP eeprom + set : change board setting with fan|led|sfp +""" + +import os +import commands +import sys, getopt +import logging +import re +import time +import pickle +from collections import namedtuple + +PROJECT_NAME = 'as5812_54x' +version = '0.2.0' +verbose = False +DEBUG = False +args = [] +ALL_DEVICE = {} +DEVICE_NO = {'led':5, 'fan1':1, 'fan2':1,'fan3':1,'fan4':1,'fan5':1,'thermal':3, 'psu':2, 'sfp':54} + + +led_prefix ='/sys/devices/platform/as5812_54x_led/leds/accton_'+PROJECT_NAME+'_led::' +fan_prefix ='/sys/devices/platform/as5812_54x_' +hwmon_types = {'led': ['diag','fan','loc','psu1','psu2'], + 'fan1': ['fan'], + 'fan2': ['fan'], + 'fan3': ['fan'], + 'fan4': ['fan'], + 'fan5': ['fan'], + } +hwmon_nodes = {'led': ['brightness'] , + 'fan1': ['fan1_duty_cycle_percentage', 'fan1_fault', 'fan1_speed_rpm', 'fan1_direction', 'fanr1_fault', 'fanr1_speed_rpm'], + 'fan2': ['fan2_duty_cycle_percentage','fan2_fault', 'fan2_speed_rpm', 'fan2_direction', 'fanr2_fault', 'fanr2_speed_rpm'], + 'fan3': ['fan3_duty_cycle_percentage','fan3_fault', 'fan3_speed_rpm', 'fan3_direction', 'fanr3_fault', 'fanr3_speed_rpm'], + 'fan4': ['fan4_duty_cycle_percentage','fan4_fault', 'fan4_speed_rpm', 'fan4_direction', 'fanr4_fault', 'fanr4_speed_rpm'], + 'fan5': ['fan5_duty_cycle_percentage','fan5_fault', 'fan5_speed_rpm', 'fan5_direction', 'fanr5_fault', 'fanr5_speed_rpm'], + } +hwmon_prefix ={'led': led_prefix, + 'fan1': fan_prefix, + 'fan2': fan_prefix, + 'fan3': fan_prefix, + 'fan4': fan_prefix, + 'fan5': fan_prefix, + } + +i2c_prefix = '/sys/bus/i2c/devices/' +i2c_bus = {'thermal': ['61-0048','62-0049', '63-004a'] , + 'psu': ['57-0050','58-0053'], + 'sfp': ['-0050']} +i2c_nodes = { + 'thermal': ['hwmon/hwmon*/temp1_input'] , + 'psu': ['psu_present ', 'psu_power_good'] , + 'sfp': ['sfp_is_present ', 'sfp_tx_disable']} + +QSFP_START = 48 +I2C_BUS_ORDER = -1 + +sfp_map = [2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 52, 54, 51, 53, 55] + +port_cpld_path = [ "/sys/bus/i2c/devices/0-0061/" + ,'/sys/bus/i2c/devices/0-0062/'] + +mknod =[ +'echo as5812_54x_cpld1 0x60 > /sys/bus/i2c/devices/i2c-0/new_device', +'echo as5812_54x_cpld2 0x61 > /sys/bus/i2c/devices/i2c-0/new_device', +'echo as5812_54x_cpld3 0x62 > /sys/bus/i2c/devices/i2c-0/new_device', +'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device', + +# PSU-1 +'echo as5812_54x_psu1 0x38 > /sys/bus/i2c/devices/i2c-57/new_device', +'echo cpr_4011_4mxx 0x3c > /sys/bus/i2c/devices/i2c-57/new_device', +'echo as5812_54x_psu1 0x50 > /sys/bus/i2c/devices/i2c-57/new_device', + +# PSU-2 +'echo as5812_54x_psu2 0x3b > /sys/bus/i2c/devices/i2c-58/new_device', +'echo cpr_4011_4mxx 0x3f > /sys/bus/i2c/devices/i2c-58/new_device', +'echo as5812_54x_psu2 0x53 > /sys/bus/i2c/devices/i2c-58/new_device', + +'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-61/new_device', +'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-62/new_device', +'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-63/new_device', + +#EERPOM +'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-1/new_device', +] + +mknod2 =[ +'echo as5812_54x_cpld1 0x60 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo as5812_54x_cpld2 0x61 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo as5812_54x_cpld3 0x62 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-0/new_device', + +# PSU-1 +'echo as5812_54x_psu1 0x38 > /sys/bus/i2c/devices/i2c-57/new_device', +'echo cpr_4011_4mxx 0x3c > /sys/bus/i2c/devices/i2c-57/new_device', +'echo as5812_54x_psu1 0x50 > /sys/bus/i2c/devices/i2c-57/new_device', + +# PSU-2 +'echo as5812_54x_psu2 0x3b > /sys/bus/i2c/devices/i2c-58/new_device', +'echo cpr_4011_4mxx 0x3f > /sys/bus/i2c/devices/i2c-58/new_device', +'echo as5812_54x_psu2 0x53 > /sys/bus/i2c/devices/i2c-58/new_device', + +'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-61/new_device', +'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-62/new_device', +'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-63/new_device', + +#EERPOM +'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-0/new_device', +] + +FORCE = 0 +logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG) +logging.basicConfig(level=logging.INFO) + + +if DEBUG == True: + print sys.argv[0] + print 'ARGV :', sys.argv[1:] + + +def main(): + global DEBUG + global args + global FORCE + + if len(sys.argv)<2: + show_help() + + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', + 'debug', + 'force', + ]) + if DEBUG == True: + print options + print args + print len(sys.argv) + + for opt, arg in options: + if opt in ('-h', '--help'): + show_help() + elif opt in ('-d', '--debug'): + DEBUG = True + logging.basicConfig(level=logging.INFO) + elif opt in ('-f', '--force'): + FORCE = 1 + else: + logging.info('no option') + for arg in args: + if arg == 'install': + do_install() + elif arg == 'clean': + do_uninstall() + elif arg == 'show': + device_traversal() + elif arg == 'sff': + if len(args)!=2: + show_eeprom_help() + elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']: + show_eeprom_help() + else: + show_eeprom(args[1]) + return + elif arg == 'set': + if len(args)<3: + show_set_help() + else: + set_device(args[1:]) + return + else: + show_help() + + + return 0 + +def show_help(): + print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} + sys.exit(0) + +def show_set_help(): + cmd = sys.argv[0].split("/")[-1]+ " " + args[0] + print cmd +" [led|sfp|fan]" + print " use \""+ cmd + " led 0-4 \" to set led color" + print " use \""+ cmd + " fan 0-100\" to set fan duty percetage" + print " use \""+ cmd + " sfp 1-48 {0|1}\" to set sfp# tx_disable" + sys.exit(0) + +def show_eeprom_help(): + cmd = sys.argv[0].split("/")[-1]+ " " + args[0] + print " use \""+ cmd + " 1-54 \" to dump sfp# eeprom" + sys.exit(0) + +def my_log(txt): + if DEBUG == True: + print "[ACCTON DBG]: "+txt + return + +def log_os_system(cmd, show): + logging.info('Run :'+cmd) + status = 1 + output = "" + status, output = commands.getstatusoutput(cmd) + my_log (cmd +"with result:" + str(status)) + my_log ("cmd:" + cmd) + my_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + +def driver_inserted(): + ret, lsmod = log_os_system("lsmod| grep accton", 0) + logging.info('mods:'+lsmod) + if len(lsmod) ==0: + return False + + + +kos = [ +'depmod -ae', +'modprobe i2c_dev', +'modprobe i2c_mux_pca954x', +'modprobe optoe', +'modprobe i2c-mux-accton_as5812_54x_cpld', +'modprobe cpr_4011_4mxx', +'modprobe ym2651y', +'modprobe accton_as5812_54x_fan', +'modprobe leds-accton_as5812_54x', +'modprobe accton_as5812_54x_psu'] + +def driver_install(): + global FORCE + for i in range(0,len(kos)): + status, output = log_os_system(kos[i], 1) + if status: + if FORCE == 0: + return status + return 0 + +def driver_uninstall(): + global FORCE + for i in range(0,len(kos)): + rm = kos[-(i+1)].replace("modprobe", "modprobe -rq") + rm = rm.replace("insmod", "rmmod") + status, output = log_os_system(rm, 1) + if status: + if FORCE == 0: + return status + return 0 + + + +def i2c_order_check(): + # i2c bus 0 and 1 might be installed in different order. + # Here check if 0x70 is exist @ i2c-0 + tmp = "echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device" + status, output = log_os_system(tmp, 0) + if not device_exist(): + order = 1 + else: + order = 0 + tmp = "echo 0x70 > /sys/bus/i2c/devices/i2c-1/delete_device" + status, output = log_os_system(tmp, 0) + return order + +def update_i2c_order(): + global I2C_BUS_ORDER + + order = i2c_order_check() + pickle.dump(order, open("/tmp/accton_util.p", "wb")) # save it + I2C_BUS_ORDER = order + print "[%s]Detected I2C_BUS_ORDER:%d" % (os.path.basename(__file__), I2C_BUS_ORDER) + +def get_i2c_order(): + global I2C_BUS_ORDER + if I2C_BUS_ORDER < 0: + if os.path.exists("/tmp/accton_util.p"): + I2C_BUS_ORDER = pickle.load(open("/tmp/accton_util.p", "rb")) + else: + update_i2c_order() + +def device_install(): + global FORCE + global I2C_BUS_ORDER + + update_i2c_order() + order = I2C_BUS_ORDER + # if 0x76 is not exist @i2c-0, use reversed bus order + if order: + for i in range(0,len(mknod2)): + #for pca954x need times to built new i2c buses + if mknod2[i].find('pca954') != -1: + time.sleep(2) + + status, output = log_os_system(mknod2[i], 1) + if status: + print output + if FORCE == 0: + return status + else: + for i in range(0,len(mknod)): + #for pca954x need times to built new i2c buses + if mknod[i].find('pca954') != -1: + time.sleep(2) + + status, output = log_os_system(mknod[i], 1) + if status: + print output + if FORCE == 0: + return status + + for i in range(0,len(sfp_map)): + if i < QSFP_START: + status, output =log_os_system("echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) + else: + status, output =log_os_system("echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + status, output =log_os_system("echo port"+str(i)+" > /sys/bus/i2c/devices/"+str(sfp_map[i])+"-0050/port_name", 1) + if status: + print output + if FORCE == 0: + return status + + return + +def device_uninstall(): + global FORCE + global I2C_BUS_ORDER + + get_i2c_order() + order = I2C_BUS_ORDER + for i in range(0,len(sfp_map)): + target = "/sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/delete_device" + status, output =log_os_system("echo 0x50 > "+ target, 1) + if status: + print output + if FORCE == 0: + return status + + if order == 0: + nodelist = mknod + else: + nodelist = mknod2 + + for i in range(len(nodelist)): + target = nodelist[-(i+1)] + temp = target.split() + del temp[1] + temp[-1] = temp[-1].replace('new_device', 'delete_device') + status, output = log_os_system(" ".join(temp), 1) + if status: + print output + if FORCE == 0: + return status + + return + +def system_ready(): + if driver_inserted() == False: + return False + if not device_exist(): + return False + return True + +def do_install(): + print "Checking system...." + if driver_inserted() == False: + print "No driver, installing...." + status = driver_install() + if status: + if FORCE == 0: + return status + else: + print PROJECT_NAME.upper()+" drivers detected...." + if not device_exist(): + print "No device, installing...." + status = device_install() + if status: + if FORCE == 0: + return status + else: + print PROJECT_NAME.upper()+" devices detected...." + return + +def do_uninstall(): + print "Checking system...." + if not device_exist(): + print PROJECT_NAME.upper() +" has no device installed...." + else: + print "Removing device...." + status = device_uninstall() + if status: + if FORCE == 0: + return status + + if driver_inserted()== False : + print PROJECT_NAME.upper() +" has no driver installed...." + else: + print "Removing installed driver...." + status = driver_uninstall() + if status: + if FORCE == 0: + return status + + return + +def devices_info(): + global DEVICE_NO + global ALL_DEVICE + global i2c_bus, hwmon_types + for key in DEVICE_NO: + ALL_DEVICE[key]= {} + for i in range(0,DEVICE_NO[key]): + ALL_DEVICE[key][key+str(i+1)] = [] + + for key in i2c_bus: + buses = i2c_bus[key] + nodes = i2c_nodes[key] + for i in range(0,len(buses)): + for j in range(0,len(nodes)): + if 'fan' == key: + for k in range(0,DEVICE_NO[key]): + node = key+str(k+1) + path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + elif 'sfp' == key: + for k in range(0,DEVICE_NO[key]): + node = key+str(k+1) + path = i2c_prefix+ str(sfp_map[k])+ buses[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + else: + node = key+str(i+1) + path = i2c_prefix+ buses[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + + for key in hwmon_types: + itypes = hwmon_types[key] + nodes = hwmon_nodes[key] + for i in range(0,len(itypes)): + for j in range(0,len(nodes)): + node = key+"_"+itypes[i] + path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][ key+str(i+1)].append(path) + + #show dict all in the order + if DEBUG == True: + for i in sorted(ALL_DEVICE.keys()): + print(i+": ") + for j in sorted(ALL_DEVICE[i].keys()): + print(" "+j) + for k in (ALL_DEVICE[i][j]): + print(" "+" "+k) + return + +def show_eeprom(index): + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0] + node = node.replace(node.split("/")[-1], 'eeprom') + # check if got hexdump command in current environment + ret, log = log_os_system("which hexdump", 0) + ret, log2 = log_os_system("which busybox hexdump", 0) + if len(log): + hex_cmd = 'hexdump' + elif len(log2): + hex_cmd = ' busybox hexdump' + else: + log = 'Failed : no hexdump cmd!!' + logging.info(log) + print log + return 1 + + print node + ":" + ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1) + if ret==0: + print log + else: + print "**********device no found**********" + return + + +def get_cpld_path(index): + global I2C_BUS_ORDER + + if I2C_BUS_ORDER < 0: + get_i2c_order() + + if I2C_BUS_ORDER !=0 : + return port_cpld_path[index].replace("0-", "1-") + else: + return port_cpld_path[index] + +def cpld_path_of_port(port_index): + if port_index < 1 and port_index > DEVICE_NO['sfp']: + return None + if port_index < 25: + return get_cpld_path(0) + else: + return get_cpld_path(1) + +def get_path_sfp_tx_dis(port_index): + cpld_p = cpld_path_of_port(port_index) + if cpld_p == None: + return False, '' + else: + dev = cpld_p+"module_tx_disable_"+str(port_index) + return True, dev + +def get_path_sfp_presence(port_index): + cpld_p = cpld_path_of_port(port_index) + if cpld_p == None: + return False, '' + else: + dev = cpld_p+"module_present_"+str(port_index) + return True, dev + + +def set_device(args): + global DEVICE_NO + global ALL_DEVICE + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + + if args[0]=='led': + if int(args[1])>4: + show_set_help() + return + #print ALL_DEVICE['led'] + for i in range(0,len(ALL_DEVICE['led'])): + for k in (ALL_DEVICE['led']['led'+str(i+1)]): + ret, log = log_os_system("echo "+args[1]+" >"+k, 1) + if ret: + return ret + elif args[0]=='fan': + if int(args[1])>100: + show_set_help() + return + #print ALL_DEVICE['fan'] + #fan1~6 is all fine, all fan share same setting + node = ALL_DEVICE['fan1'] ['fan11'][0] + node = node.replace(node.split("/")[-1], 'fan1_duty_cycle_percentage') + ret, log = log_os_system("cat "+ node, 1) + if ret==0: + print ("Previous fan duty: " + log.strip() +"%") + ret, log = log_os_system("echo "+args[1]+" >"+node, 1) + if ret==0: + print ("Current fan duty: " + args[1] +"%") + return ret + elif args[0]=='sfp': + #if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0: + #There no tx_disable for QSFP port + if int(args[1]) > QSFP_START or int(args[1])==0: + show_set_help() + return + if len(args)<2: + show_set_help() + return + + if int(args[2])>1: + show_set_help() + return + + port_index = int(args[1]) + ret, dev = get_path_sfp_tx_dis(port_index) + if ret == False: + return False + else: + ret, log = log_os_system("echo "+args[2]+" >"+ dev, 1) + return ret + return + +#get digits inside a string. +#Ex: 31 for "sfp31" +def get_value(input): + digit = re.findall('\d+', input) + return int(digit[0]) + +def print_1_device_traversal(i, j, k): + ret, log = log_os_system("cat "+k, 0) + func = k.split("/")[-1].strip() + func = re.sub(j+'_','',func,1) + func = re.sub(i.lower()+'_','',func,1) + if ret==0: + return func+"="+log+" " + else: + return func+"="+"X"+" " + +def device_traversal(): + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + for i in sorted(ALL_DEVICE.keys()): + print("============================================") + print(i.upper()+": ") + print("============================================") + + for j in sorted(ALL_DEVICE[i].keys(), key=get_value): + print " "+j+":", + if i == 'sfp': + port_index = int(filter(str.isdigit, j)) + for k in (ALL_DEVICE[i][j]): + if k.find('tx_disable')!= -1: + ret, k = get_path_sfp_tx_dis(port_index) + if ret == False: + continue + log = print_1_device_traversal(i, j, k) + print log, + if k.find('present')!= -1: + ret, k = get_path_sfp_presence(port_index) + if ret == False: + continue + log = print_1_device_traversal(i, j, k) + print log, + + else: + for k in (ALL_DEVICE[i][j]): + log = print_1_device_traversal(i, j, k) + print log, + print + print("----------------------------------------------------------------") + + + print + return + +def device_exist(): + ret1, log = log_os_system("ls "+i2c_prefix+"*0070", 0) + ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0) + return not(ret1 or ret2) + +if __name__ == "__main__": + main() diff --git a/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c old mode 100644 new mode 100755 index 47e6a1d06b..dd4f6dd8c4 --- a/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c +++ b/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c @@ -42,6 +42,7 @@ enum chips { YM2651, YM2401, YM2851, + YPEB1200AM }; /* Each client has this additional data @@ -438,6 +439,7 @@ static const struct i2c_device_id ym2651y_id[] = { { "ym2651", YM2651 }, { "ym2401", YM2401 }, { "ym2851", YM2851 }, + { "ype1200am", YPEB1200AM }, {} }; MODULE_DEVICE_TABLE(i2c, ym2651y_id); diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/control b/platform/broadcom/sonic-platform-modules-accton/debian/control index 731c454568..8cc6b986c5 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/control +++ b/platform/broadcom/sonic-platform-modules-accton/debian/control @@ -41,7 +41,14 @@ Package: sonic-platform-accton-as7726-32x Architecture: amd64 Description: kernel modules for platform devices such as fan, led, sfp +Package: sonic-platform-accton-as4630-54pe +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp + Package: sonic-platform-accton-minipack Architecture: amd64 Description: kernel modules for platform devices such as fan, led, sfp +Package: sonic-platform-accton-as5812-54x +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/rules b/platform/broadcom/sonic-platform-modules-accton/debian/rules index ef761c01aa..2cd3d6d7b6 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/rules +++ b/platform/broadcom/sonic-platform-modules-accton/debian/rules @@ -19,7 +19,7 @@ PACKAGE_PRE_NAME := sonic-platform-accton KVERSION ?= $(shell uname -r) KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) -MODULE_DIRS:= as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x as7326-56x as6712-32x as7726-32x minipack +MODULE_DIRS:= as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x as7326-56x as6712-32x as7726-32x as4630-54pe minipack as5812-54x MODULE_DIR := modules UTILS_DIR := utils SERVICE_DIR := service diff --git a/platform/broadcom/sonic-platform-modules-arista b/platform/broadcom/sonic-platform-modules-arista index 7e2d714ae7..0ed1df5a7d 160000 --- a/platform/broadcom/sonic-platform-modules-arista +++ b/platform/broadcom/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit 7e2d714ae7c072ee587d1cf0356cf548ac4be4a9 +Subproject commit 0ed1df5a7d6c88319ce41b10ce604c2727afab69 diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.init index 2117ab22b4..aa13d572be 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.init @@ -12,7 +12,8 @@ ### END INIT INFO function export_gpio { -label=$2 +label=$3 +gpio_dir=$2 gpio_num=$1 gpio_base=`( cat /sys/class/gpio/gpiochip*/base | head -1 ) 2>/dev/null` gpio_label=`( cat /sys/class/gpio/gpiochip*/label | head -1 ) 2>/dev/null` @@ -27,6 +28,13 @@ if [ $? -ne 0 ]; then echo "Platform driver error: Cannot export gpio$ionum!" exit 1; fi +if [[ "X$gpio_dir" != "X" ]]; then + echo $gpio_dir > /sys/class/gpio/gpio${ionum}/direction + if [ $? -ne 0 ]; then + echo "Platform driver error: Cannot set direction of gpio$ionum!" + exit 1; + fi +fi } case "$1" in @@ -95,27 +103,33 @@ start) sleep 2 # Export platform gpio sysfs - export_gpio 10 # Fan 1 present - export_gpio 11 # Fan 2 present - export_gpio 12 # Fan 3 present - export_gpio 13 # Fan 4 present - export_gpio 14 # Fan 5 present + export_gpio 10 "in" # Fan 1 present + export_gpio 11 "in" # Fan 2 present + export_gpio 12 "in" # Fan 3 present + export_gpio 13 "in" # Fan 4 present + export_gpio 14 "in" # Fan 5 present - export_gpio 22 # PSU L PWOK - export_gpio 25 # PSU R PWOK - export_gpio 27 # PSU L ABS - export_gpio 28 # PSU R ABS + export_gpio 15 "in" # Fan 1 direction + export_gpio 16 "in" # Fan 2 direction + export_gpio 17 "in" # Fan 3 direction + export_gpio 18 "in" # Fan 4 direction + export_gpio 19 "in" # Fan 5 direction - export_gpio 29 # Fan 1 LED: Red - export_gpio 30 # Fan 1 LED: Yellow - export_gpio 31 # Fan 2 LED: Red - export_gpio 32 # Fan 2 LED: Yellow - export_gpio 33 # Fan 3 LED: Red - export_gpio 34 # Fan 3 LED: Yellow - export_gpio 35 # Fan 4 LED: Red - export_gpio 36 # Fan 4 LED: Yellow - export_gpio 37 # Fan 5 LED: Red - export_gpio 38 # Fan 5 LED: Yellow + export_gpio 22 "in" # PSU L PWOK + export_gpio 25 "in" # PSU R PWOK + export_gpio 27 "in" # PSU L ABS + export_gpio 28 "in" # PSU R ABS + + export_gpio 29 "out" # Fan 1 LED: Red + export_gpio 30 "out" # Fan 1 LED: Yellow + export_gpio 31 "out" # Fan 2 LED: Red + export_gpio 32 "out" # Fan 2 LED: Yellow + export_gpio 33 "out" # Fan 3 LED: Red + export_gpio 34 "out" # Fan 3 LED: Yellow + export_gpio 35 "out" # Fan 4 LED: Red + export_gpio 36 "out" # Fan 4 LED: Yellow + export_gpio 37 "out" # Fan 5 LED: Red + export_gpio 38 "out" # Fan 5 LED: Yellow # Turn off/down lpmod by defult (0 - Normal, 1 - Low Pow) echo 0x00000000 > /sys/devices/platform/dx010_cpld/qsfp_lpmode diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.init index db0e8cfdb8..af74da87d5 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.init @@ -17,6 +17,7 @@ start) modprobe smc modprobe hlx_gpio_ich + modprobe dps200 found=0 for devnum in 0 1; do @@ -51,6 +52,9 @@ start) echo max6697 0x1a > /sys/bus/i2c/devices/i2c-3/new_device echo max6697 0x1a > /sys/bus/i2c/devices/i2c-11/new_device + # Attach PSUs + echo dps200 0x5a > /sys/bus/i2c/devices/i2c-12/new_device + echo dps200 0x5b > /sys/bus/i2c/devices/i2c-13/new_device # Attach fans echo emc2305 0x4d > /sys/bus/i2c/devices/i2c-23/new_device diff --git a/platform/broadcom/sonic-platform-modules-cel/dx010/modules/dx010_cpld.c b/platform/broadcom/sonic-platform-modules-cel/dx010/modules/dx010_cpld.c index 397361a5ed..7893220ff6 100644 --- a/platform/broadcom/sonic-platform-modules-cel/dx010/modules/dx010_cpld.c +++ b/platform/broadcom/sonic-platform-modules-cel/dx010/modules/dx010_cpld.c @@ -30,6 +30,13 @@ #define DRIVER_NAME "dx010_cpld" +#define CPLD1_VERSION_ADDR 0x100 +#define CPLD2_VERSION_ADDR 0x200 +#define CPLD3_VERSION_ADDR 0x280 +#define CPLD4_VERSION_ADDR 0x300 +#define CPLD5_VERSION_ADDR 0x380 + + #define RESET0108 0x250 #define RESET0910 0x251 #define RESET1118 0x2d0 @@ -110,10 +117,36 @@ struct dx010_i2c_data { struct dx010_cpld_data { struct i2c_adapter *i2c_adapter[LENGTH_PORT_CPLD]; struct mutex cpld_lock; + uint16_t read_addr; }; struct dx010_cpld_data *cpld_data; +static ssize_t getreg_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + + uint16_t addr; + char *last; + + addr = (uint16_t)strtoul(buf,&last,16); + if(addr == 0 && buf == last){ + return -EINVAL; + } + cpld_data->read_addr = addr; + return count; +} + +static ssize_t getreg_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + + int len = 0; + mutex_lock(&cpld_data->cpld_lock); + len = sprintf(buf, "0x%2.2x\n",inb(cpld_data->read_addr)); + mutex_unlock(&cpld_data->cpld_lock); + return len; +} + static ssize_t get_reset(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -134,6 +167,47 @@ static ssize_t get_reset(struct device *dev, struct device_attribute *devattr, return sprintf(buf,"0x%8.8lx\n", reset & 0xffffffff); } +static ssize_t setreg_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + + uint16_t addr; + uint8_t value; + char *tok; + char clone[count]; + char *pclone = clone; + char *last; + + strcpy(clone, buf); + + mutex_lock(&cpld_data->cpld_lock); + tok = strsep((char**)&pclone, " "); + if(tok == NULL){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + addr = (uint16_t)strtoul(tok,&last,16); + if(addr == 0 && tok == last){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + + tok = strsep((char**)&pclone, " "); + if(tok == NULL){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + value = (uint8_t)strtoul(tok,&last,16); + if(value == 0 && tok == last){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + + outb(value,addr); + mutex_unlock(&cpld_data->cpld_lock); + return count; +} + static ssize_t set_reset(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { @@ -248,12 +322,16 @@ static ssize_t get_modirq(struct device *dev, struct device_attribute *devattr, return sprintf(buf,"0x%8.8lx\n", irq & 0xffffffff); } +static DEVICE_ATTR_RW(getreg); +static DEVICE_ATTR_WO(setreg); static DEVICE_ATTR(qsfp_reset, S_IRUGO | S_IWUSR, get_reset, set_reset); static DEVICE_ATTR(qsfp_lpmode, S_IRUGO | S_IWUSR, get_lpmode, set_lpmode); static DEVICE_ATTR(qsfp_modprs, S_IRUGO, get_modprs, NULL); static DEVICE_ATTR(qsfp_modirq, S_IRUGO, get_modirq, NULL); static struct attribute *dx010_lpc_attrs[] = { + &dev_attr_getreg.attr, + &dev_attr_setreg.attr, &dev_attr_qsfp_reset.attr, &dev_attr_qsfp_lpmode.attr, &dev_attr_qsfp_modprs.attr, @@ -499,6 +577,7 @@ static int cel_dx010_lpc_drv_probe(struct platform_device *pdev) return -ENOMEM; mutex_init(&cpld_data->cpld_lock); + cpld_data->read_addr = CPLD1_VERSION_ADDR; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (unlikely(!res)) { @@ -558,4 +637,4 @@ module_exit(cel_dx010_lpc_exit); MODULE_AUTHOR("Abhisit Sangjan "); MODULE_AUTHOR("Pariwat Leamsumran "); MODULE_DESCRIPTION("Celestica SeaStone DX010 LPC Driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/haliburton/modules/Makefile b/platform/broadcom/sonic-platform-modules-cel/haliburton/modules/Makefile index b34cf2cabe..415d1b5e62 100644 --- a/platform/broadcom/sonic-platform-modules-cel/haliburton/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-cel/haliburton/modules/Makefile @@ -1 +1 @@ -obj-m := mc24lc64t.o emc2305.o smc.o hlx_gpio_ich.o +obj-m := mc24lc64t.o emc2305.o smc.o hlx_gpio_ich.o dps200.o diff --git a/platform/broadcom/sonic-platform-modules-cel/haliburton/modules/dps200.c b/platform/broadcom/sonic-platform-modules-cel/haliburton/modules/dps200.c new file mode 100644 index 0000000000..6d5afdfb78 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/haliburton/modules/dps200.c @@ -0,0 +1,128 @@ +/* + * Hardware monitoring driver for Delta DPS200 + * + * (C) Copyright 2019, Celestica Inc. + * Author: Pradchaya Phucharoen + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pmbus.h" + + +static int dps200_read_word_data(struct i2c_client *client, int page, int reg) +{ + + if (reg >= PMBUS_VIRT_BASE || + reg == PMBUS_VOUT_OV_FAULT_LIMIT || + reg == PMBUS_VOUT_OV_WARN_LIMIT || + reg == PMBUS_VOUT_UV_WARN_LIMIT || + reg == PMBUS_VOUT_UV_FAULT_LIMIT || + reg == PMBUS_IOUT_OC_LV_FAULT_LIMIT || + reg == PMBUS_IOUT_UC_FAULT_LIMIT || + reg == PMBUS_UT_WARN_LIMIT || + reg == PMBUS_UT_FAULT_LIMIT || + reg == PMBUS_VIN_OV_FAULT_LIMIT || + reg == PMBUS_VIN_OV_WARN_LIMIT || + reg == PMBUS_IIN_OC_FAULT_LIMIT || + reg == PMBUS_POUT_MAX) + return -ENXIO; + + /* + * WARNING: The following feild have coinstant driver value. + * If the register are + * PMBUS_IOUT_OC_WARN_LIMIT or PMBUS_IOUT_OC_FAULT_LIMIT convert + * the constant value from linear to direct fomat. + */ + if (reg == PMBUS_IOUT_OC_WARN_LIMIT) + return 0xb4; + else if (reg == PMBUS_IOUT_OC_FAULT_LIMIT) + return 0xc8; + else + return pmbus_read_word_data(client, page, reg); +} + +/* + * Form DPS-200 datasheet the supported sensors format defined as: + * VOUT: direct mode with one decimal place. + * + * Other sensors: + * IOUT: direct mode with one decimal place. + * IOUT Limits: linear mode, which difference from IOUT. + * VIN, IIN, POWER, TEMP, & FAN: linear mode. + */ +static struct pmbus_driver_info dps200_info = { + .pages = 1, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT + | PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 + | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_STATUS_INPUT, + .format = { + [PSC_VOLTAGE_OUT] = direct, + [PSC_CURRENT_OUT] = direct, + }, + .m = { + [PSC_VOLTAGE_OUT] = 10, + [PSC_CURRENT_OUT] = 10, + }, + .b = { + [PSC_VOLTAGE_OUT] = 0, + [PSC_CURRENT_OUT] = 0, + }, + .R = { + [PSC_VOLTAGE_OUT] = 0, + [PSC_CURRENT_OUT] = 0, + }, + .read_word_data = &dps200_read_word_data, +}; + +static int pmbus_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return pmbus_do_probe(client, id, &dps200_info); +} +/* user driver datat to pass the grpup */ +static const struct i2c_device_id dps200_id[] = { + {"dps200", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, dps200_id); + +/* This is the driver that will be inserted */ +static struct i2c_driver dps200_driver = { + .driver = { + .name = "dps200", + }, + .probe = pmbus_probe, + .remove = pmbus_do_remove, + .id_table = dps200_id, +}; + +module_i2c_driver(dps200_driver); + +MODULE_AUTHOR("Pradchaya Phucharoen"); +MODULE_DESCRIPTION("PMBus driver for Delta DPS200"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-cel/haliburton/modules/pmbus.h b/platform/broadcom/sonic-platform-modules-cel/haliburton/modules/pmbus.h new file mode 100644 index 0000000000..521baf6da4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/haliburton/modules/pmbus.h @@ -0,0 +1,425 @@ +/* + * pmbus.h - Common defines and structures for PMBus devices + * + * Copyright (c) 2010, 2011 Ericsson AB. + * Copyright (c) 2012 Guenter Roeck + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef PMBUS_H +#define PMBUS_H + +#include +#include + +/* + * Registers + */ +enum pmbus_regs { + PMBUS_PAGE = 0x00, + PMBUS_OPERATION = 0x01, + PMBUS_ON_OFF_CONFIG = 0x02, + PMBUS_CLEAR_FAULTS = 0x03, + PMBUS_PHASE = 0x04, + + PMBUS_CAPABILITY = 0x19, + PMBUS_QUERY = 0x1A, + + PMBUS_VOUT_MODE = 0x20, + PMBUS_VOUT_COMMAND = 0x21, + PMBUS_VOUT_TRIM = 0x22, + PMBUS_VOUT_CAL_OFFSET = 0x23, + PMBUS_VOUT_MAX = 0x24, + PMBUS_VOUT_MARGIN_HIGH = 0x25, + PMBUS_VOUT_MARGIN_LOW = 0x26, + PMBUS_VOUT_TRANSITION_RATE = 0x27, + PMBUS_VOUT_DROOP = 0x28, + PMBUS_VOUT_SCALE_LOOP = 0x29, + PMBUS_VOUT_SCALE_MONITOR = 0x2A, + + PMBUS_COEFFICIENTS = 0x30, + PMBUS_POUT_MAX = 0x31, + + PMBUS_FAN_CONFIG_12 = 0x3A, + PMBUS_FAN_COMMAND_1 = 0x3B, + PMBUS_FAN_COMMAND_2 = 0x3C, + PMBUS_FAN_CONFIG_34 = 0x3D, + PMBUS_FAN_COMMAND_3 = 0x3E, + PMBUS_FAN_COMMAND_4 = 0x3F, + + PMBUS_VOUT_OV_FAULT_LIMIT = 0x40, + PMBUS_VOUT_OV_FAULT_RESPONSE = 0x41, + PMBUS_VOUT_OV_WARN_LIMIT = 0x42, + PMBUS_VOUT_UV_WARN_LIMIT = 0x43, + PMBUS_VOUT_UV_FAULT_LIMIT = 0x44, + PMBUS_VOUT_UV_FAULT_RESPONSE = 0x45, + PMBUS_IOUT_OC_FAULT_LIMIT = 0x46, + PMBUS_IOUT_OC_FAULT_RESPONSE = 0x47, + PMBUS_IOUT_OC_LV_FAULT_LIMIT = 0x48, + PMBUS_IOUT_OC_LV_FAULT_RESPONSE = 0x49, + PMBUS_IOUT_OC_WARN_LIMIT = 0x4A, + PMBUS_IOUT_UC_FAULT_LIMIT = 0x4B, + PMBUS_IOUT_UC_FAULT_RESPONSE = 0x4C, + + PMBUS_OT_FAULT_LIMIT = 0x4F, + PMBUS_OT_FAULT_RESPONSE = 0x50, + PMBUS_OT_WARN_LIMIT = 0x51, + PMBUS_UT_WARN_LIMIT = 0x52, + PMBUS_UT_FAULT_LIMIT = 0x53, + PMBUS_UT_FAULT_RESPONSE = 0x54, + PMBUS_VIN_OV_FAULT_LIMIT = 0x55, + PMBUS_VIN_OV_FAULT_RESPONSE = 0x56, + PMBUS_VIN_OV_WARN_LIMIT = 0x57, + PMBUS_VIN_UV_WARN_LIMIT = 0x58, + PMBUS_VIN_UV_FAULT_LIMIT = 0x59, + + PMBUS_IIN_OC_FAULT_LIMIT = 0x5B, + PMBUS_IIN_OC_WARN_LIMIT = 0x5D, + + PMBUS_POUT_OP_FAULT_LIMIT = 0x68, + PMBUS_POUT_OP_WARN_LIMIT = 0x6A, + PMBUS_PIN_OP_WARN_LIMIT = 0x6B, + + PMBUS_STATUS_BYTE = 0x78, + PMBUS_STATUS_WORD = 0x79, + PMBUS_STATUS_VOUT = 0x7A, + PMBUS_STATUS_IOUT = 0x7B, + PMBUS_STATUS_INPUT = 0x7C, + PMBUS_STATUS_TEMPERATURE = 0x7D, + PMBUS_STATUS_CML = 0x7E, + PMBUS_STATUS_OTHER = 0x7F, + PMBUS_STATUS_MFR_SPECIFIC = 0x80, + PMBUS_STATUS_FAN_12 = 0x81, + PMBUS_STATUS_FAN_34 = 0x82, + + PMBUS_READ_VIN = 0x88, + PMBUS_READ_IIN = 0x89, + PMBUS_READ_VCAP = 0x8A, + PMBUS_READ_VOUT = 0x8B, + PMBUS_READ_IOUT = 0x8C, + PMBUS_READ_TEMPERATURE_1 = 0x8D, + PMBUS_READ_TEMPERATURE_2 = 0x8E, + PMBUS_READ_TEMPERATURE_3 = 0x8F, + PMBUS_READ_FAN_SPEED_1 = 0x90, + PMBUS_READ_FAN_SPEED_2 = 0x91, + PMBUS_READ_FAN_SPEED_3 = 0x92, + PMBUS_READ_FAN_SPEED_4 = 0x93, + PMBUS_READ_DUTY_CYCLE = 0x94, + PMBUS_READ_FREQUENCY = 0x95, + PMBUS_READ_POUT = 0x96, + PMBUS_READ_PIN = 0x97, + + PMBUS_REVISION = 0x98, + PMBUS_MFR_ID = 0x99, + PMBUS_MFR_MODEL = 0x9A, + PMBUS_MFR_REVISION = 0x9B, + PMBUS_MFR_LOCATION = 0x9C, + PMBUS_MFR_DATE = 0x9D, + PMBUS_MFR_SERIAL = 0x9E, + +/* + * Virtual registers. + * Useful to support attributes which are not supported by standard PMBus + * registers but exist as manufacturer specific registers on individual chips. + * Must be mapped to real registers in device specific code. + * + * Semantics: + * Virtual registers are all word size. + * READ registers are read-only; writes are either ignored or return an error. + * RESET registers are read/write. Reading reset registers returns zero + * (used for detection), writing any value causes the associated history to be + * reset. + * Virtual registers have to be handled in device specific driver code. Chip + * driver code returns non-negative register values if a virtual register is + * supported, or a negative error code if not. The chip driver may return + * -ENODATA or any other error code in this case, though an error code other + * than -ENODATA is handled more efficiently and thus preferred. Either case, + * the calling PMBus core code will abort if the chip driver returns an error + * code when reading or writing virtual registers. + */ + PMBUS_VIRT_BASE = 0x100, + PMBUS_VIRT_READ_TEMP_AVG, + PMBUS_VIRT_READ_TEMP_MIN, + PMBUS_VIRT_READ_TEMP_MAX, + PMBUS_VIRT_RESET_TEMP_HISTORY, + PMBUS_VIRT_READ_VIN_AVG, + PMBUS_VIRT_READ_VIN_MIN, + PMBUS_VIRT_READ_VIN_MAX, + PMBUS_VIRT_RESET_VIN_HISTORY, + PMBUS_VIRT_READ_IIN_AVG, + PMBUS_VIRT_READ_IIN_MIN, + PMBUS_VIRT_READ_IIN_MAX, + PMBUS_VIRT_RESET_IIN_HISTORY, + PMBUS_VIRT_READ_PIN_AVG, + PMBUS_VIRT_READ_PIN_MIN, + PMBUS_VIRT_READ_PIN_MAX, + PMBUS_VIRT_RESET_PIN_HISTORY, + PMBUS_VIRT_READ_POUT_AVG, + PMBUS_VIRT_READ_POUT_MIN, + PMBUS_VIRT_READ_POUT_MAX, + PMBUS_VIRT_RESET_POUT_HISTORY, + PMBUS_VIRT_READ_VOUT_AVG, + PMBUS_VIRT_READ_VOUT_MIN, + PMBUS_VIRT_READ_VOUT_MAX, + PMBUS_VIRT_RESET_VOUT_HISTORY, + PMBUS_VIRT_READ_IOUT_AVG, + PMBUS_VIRT_READ_IOUT_MIN, + PMBUS_VIRT_READ_IOUT_MAX, + PMBUS_VIRT_RESET_IOUT_HISTORY, + PMBUS_VIRT_READ_TEMP2_AVG, + PMBUS_VIRT_READ_TEMP2_MIN, + PMBUS_VIRT_READ_TEMP2_MAX, + PMBUS_VIRT_RESET_TEMP2_HISTORY, + + PMBUS_VIRT_READ_VMON, + PMBUS_VIRT_VMON_UV_WARN_LIMIT, + PMBUS_VIRT_VMON_OV_WARN_LIMIT, + PMBUS_VIRT_VMON_UV_FAULT_LIMIT, + PMBUS_VIRT_VMON_OV_FAULT_LIMIT, + PMBUS_VIRT_STATUS_VMON, +}; + +/* + * OPERATION + */ +#define PB_OPERATION_CONTROL_ON BIT(7) + +/* + * CAPABILITY + */ +#define PB_CAPABILITY_SMBALERT BIT(4) +#define PB_CAPABILITY_ERROR_CHECK BIT(7) + +/* + * VOUT_MODE + */ +#define PB_VOUT_MODE_MODE_MASK 0xe0 +#define PB_VOUT_MODE_PARAM_MASK 0x1f + +#define PB_VOUT_MODE_LINEAR 0x00 +#define PB_VOUT_MODE_VID 0x20 +#define PB_VOUT_MODE_DIRECT 0x40 + +/* + * Fan configuration + */ +#define PB_FAN_2_PULSE_MASK (BIT(0) | BIT(1)) +#define PB_FAN_2_RPM BIT(2) +#define PB_FAN_2_INSTALLED BIT(3) +#define PB_FAN_1_PULSE_MASK (BIT(4) | BIT(5)) +#define PB_FAN_1_RPM BIT(6) +#define PB_FAN_1_INSTALLED BIT(7) + +/* + * STATUS_BYTE, STATUS_WORD (lower) + */ +#define PB_STATUS_NONE_ABOVE BIT(0) +#define PB_STATUS_CML BIT(1) +#define PB_STATUS_TEMPERATURE BIT(2) +#define PB_STATUS_VIN_UV BIT(3) +#define PB_STATUS_IOUT_OC BIT(4) +#define PB_STATUS_VOUT_OV BIT(5) +#define PB_STATUS_OFF BIT(6) +#define PB_STATUS_BUSY BIT(7) + +/* + * STATUS_WORD (upper) + */ +#define PB_STATUS_UNKNOWN BIT(8) +#define PB_STATUS_OTHER BIT(9) +#define PB_STATUS_FANS BIT(10) +#define PB_STATUS_POWER_GOOD_N BIT(11) +#define PB_STATUS_WORD_MFR BIT(12) +#define PB_STATUS_INPUT BIT(13) +#define PB_STATUS_IOUT_POUT BIT(14) +#define PB_STATUS_VOUT BIT(15) + +/* + * STATUS_IOUT + */ +#define PB_POUT_OP_WARNING BIT(0) +#define PB_POUT_OP_FAULT BIT(1) +#define PB_POWER_LIMITING BIT(2) +#define PB_CURRENT_SHARE_FAULT BIT(3) +#define PB_IOUT_UC_FAULT BIT(4) +#define PB_IOUT_OC_WARNING BIT(5) +#define PB_IOUT_OC_LV_FAULT BIT(6) +#define PB_IOUT_OC_FAULT BIT(7) + +/* + * STATUS_VOUT, STATUS_INPUT + */ +#define PB_VOLTAGE_UV_FAULT BIT(4) +#define PB_VOLTAGE_UV_WARNING BIT(5) +#define PB_VOLTAGE_OV_WARNING BIT(6) +#define PB_VOLTAGE_OV_FAULT BIT(7) + +/* + * STATUS_INPUT + */ +#define PB_PIN_OP_WARNING BIT(0) +#define PB_IIN_OC_WARNING BIT(1) +#define PB_IIN_OC_FAULT BIT(2) + +/* + * STATUS_TEMPERATURE + */ +#define PB_TEMP_UT_FAULT BIT(4) +#define PB_TEMP_UT_WARNING BIT(5) +#define PB_TEMP_OT_WARNING BIT(6) +#define PB_TEMP_OT_FAULT BIT(7) + +/* + * STATUS_FAN + */ +#define PB_FAN_AIRFLOW_WARNING BIT(0) +#define PB_FAN_AIRFLOW_FAULT BIT(1) +#define PB_FAN_FAN2_SPEED_OVERRIDE BIT(2) +#define PB_FAN_FAN1_SPEED_OVERRIDE BIT(3) +#define PB_FAN_FAN2_WARNING BIT(4) +#define PB_FAN_FAN1_WARNING BIT(5) +#define PB_FAN_FAN2_FAULT BIT(6) +#define PB_FAN_FAN1_FAULT BIT(7) + +/* + * CML_FAULT_STATUS + */ +#define PB_CML_FAULT_OTHER_MEM_LOGIC BIT(0) +#define PB_CML_FAULT_OTHER_COMM BIT(1) +#define PB_CML_FAULT_PROCESSOR BIT(3) +#define PB_CML_FAULT_MEMORY BIT(4) +#define PB_CML_FAULT_PACKET_ERROR BIT(5) +#define PB_CML_FAULT_INVALID_DATA BIT(6) +#define PB_CML_FAULT_INVALID_COMMAND BIT(7) + +enum pmbus_sensor_classes { + PSC_VOLTAGE_IN = 0, + PSC_VOLTAGE_OUT, + PSC_CURRENT_IN, + PSC_CURRENT_OUT, + PSC_POWER, + PSC_TEMPERATURE, + PSC_FAN, + PSC_NUM_CLASSES /* Number of power sensor classes */ +}; + +#define PMBUS_PAGES 32 /* Per PMBus specification */ + +/* Functionality bit mask */ +#define PMBUS_HAVE_VIN BIT(0) +#define PMBUS_HAVE_VCAP BIT(1) +#define PMBUS_HAVE_VOUT BIT(2) +#define PMBUS_HAVE_IIN BIT(3) +#define PMBUS_HAVE_IOUT BIT(4) +#define PMBUS_HAVE_PIN BIT(5) +#define PMBUS_HAVE_POUT BIT(6) +#define PMBUS_HAVE_FAN12 BIT(7) +#define PMBUS_HAVE_FAN34 BIT(8) +#define PMBUS_HAVE_TEMP BIT(9) +#define PMBUS_HAVE_TEMP2 BIT(10) +#define PMBUS_HAVE_TEMP3 BIT(11) +#define PMBUS_HAVE_STATUS_VOUT BIT(12) +#define PMBUS_HAVE_STATUS_IOUT BIT(13) +#define PMBUS_HAVE_STATUS_INPUT BIT(14) +#define PMBUS_HAVE_STATUS_TEMP BIT(15) +#define PMBUS_HAVE_STATUS_FAN12 BIT(16) +#define PMBUS_HAVE_STATUS_FAN34 BIT(17) +#define PMBUS_HAVE_VMON BIT(18) +#define PMBUS_HAVE_STATUS_VMON BIT(19) + +enum pmbus_data_format { linear = 0, direct, vid }; +enum vrm_version { vr11 = 0, vr12 }; + +struct pmbus_driver_info { + int pages; /* Total number of pages */ + enum pmbus_data_format format[PSC_NUM_CLASSES]; + enum vrm_version vrm_version; + /* + * Support one set of coefficients for each sensor type + * Used for chips providing data in direct mode. + */ + int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */ + int b[PSC_NUM_CLASSES]; /* offset */ + int R[PSC_NUM_CLASSES]; /* exponent */ + + u32 func[PMBUS_PAGES]; /* Functionality, per page */ + /* + * The following functions map manufacturing specific register values + * to PMBus standard register values. Specify only if mapping is + * necessary. + * Functions return the register value (read) or zero (write) if + * successful. A return value of -ENODATA indicates that there is no + * manufacturer specific register, but that a standard PMBus register + * may exist. Any other negative return value indicates that the + * register does not exist, and that no attempt should be made to read + * the standard register. + */ + int (*read_byte_data)(struct i2c_client *client, int page, int reg); + int (*read_word_data)(struct i2c_client *client, int page, int reg); + int (*write_word_data)(struct i2c_client *client, int page, int reg, + u16 word); + int (*write_byte)(struct i2c_client *client, int page, u8 value); + /* + * The identify function determines supported PMBus functionality. + * This function is only necessary if a chip driver supports multiple + * chips, and the chip functionality is not pre-determined. + */ + int (*identify)(struct i2c_client *client, + struct pmbus_driver_info *info); + + /* Regulator functionality, if supported by this chip driver. */ + int num_regulators; + const struct regulator_desc *reg_desc; +}; + +/* Regulator ops */ + +extern const struct regulator_ops pmbus_regulator_ops; + +/* Macro for filling in array of struct regulator_desc */ +#define PMBUS_REGULATOR(_name, _id) \ + [_id] = { \ + .name = (_name # _id), \ + .id = (_id), \ + .of_match = of_match_ptr(_name # _id), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &pmbus_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + } + +/* Function declarations */ + +void pmbus_clear_cache(struct i2c_client *client); +int pmbus_set_page(struct i2c_client *client, u8 page); +int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg); +int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word); +int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg); +int pmbus_write_byte(struct i2c_client *client, int page, u8 value); +int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, + u8 value); +int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, + u8 mask, u8 value); +void pmbus_clear_faults(struct i2c_client *client); +bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); +bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); +int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, + struct pmbus_driver_info *info); +int pmbus_do_remove(struct i2c_client *client); +const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client + *client); + +#endif /* PMBUS_H */ \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c b/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c index 57eff4181d..b8ed4bbb08 100644 --- a/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c +++ b/platform/broadcom/sonic-platform-modules-dell/common/dell_pmc.c @@ -45,6 +45,7 @@ #define SMF_READ_DATA_REG_OFFSET 2 #define SMF_REG_ADDR 0x200 #define SMF_PROBE_ADDR 0x210 +#define SMF_RST_SRC_REG 0x20A #define SIO_REG_DEVID 0x1 #define SIO_Z9100_ID 0x1 @@ -502,6 +503,23 @@ static ssize_t show_smf_version(struct device *dev, } +/* SMF Reset Reason */ +static ssize_t show_reset_reason(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + unsigned int ret = 0, val = 0; + struct smf_data *data = dev_get_drvdata(dev); + + ret = inb(SMF_RST_SRC_REG); + + if(ret < 0) + return ret; + + return sprintf(buf, "%x\n", ret); +} + + /* FANIN ATTR */ static ssize_t show_fan_label(struct device *dev, struct device_attribute *attr, char *buf) @@ -1779,10 +1797,14 @@ static SENSOR_DEVICE_ATTR(current_total_power, S_IRUGO, show_psu, NULL, 10); static SENSOR_DEVICE_ATTR(smf_version, S_IRUGO, show_smf_version, NULL, 0); static SENSOR_DEVICE_ATTR(smf_firmware_ver, S_IRUGO, show_smf_version, NULL, 1); +/* SMF Reset Reason */ +static SENSOR_DEVICE_ATTR(smf_reset_reason, S_IRUGO, show_reset_reason, NULL, 1); + static struct attribute *smf_dell_attrs[] = { &sensor_dev_attr_smf_version.dev_attr.attr, &sensor_dev_attr_smf_firmware_ver.dev_attr.attr, + &sensor_dev_attr_smf_reset_reason.dev_attr.attr, &sensor_dev_attr_fan_tray_presence.dev_attr.attr, &sensor_dev_attr_fan1_airflow.dev_attr.attr, &sensor_dev_attr_fan3_airflow.dev_attr.attr, diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.install index dbe2b81131..6a2f15511d 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.install @@ -3,5 +3,7 @@ z9264f/scripts/check_qsfp.sh usr/local/bin z9264f/scripts/platform_sensors.py usr/local/bin z9264f/scripts/sensors usr/bin z9264f/scripts/pcisysfs.py usr/bin +z9264f/scripts/qsfp_irq_enable.py usr/bin z9264f/cfg/z9264f-modules.conf etc/modules-load.d z9264f/systemd/platform-modules-z9264f.service etc/systemd/system +common/platform_reboot usr/share/sonic/device/x86_64-dellemc_z9264f_c3538-r0 diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/sensors b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/sensors index 030d636a15..958cbdcb7b 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/sensors +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/sensors @@ -1,7 +1,3 @@ #!/bin/bash docker exec -i pmon sensors "$@" -#To probe sensors not part of lm-sensors -if [ -r /usr/local/bin/platform_sensors.py ]; then - python /usr/local/bin/platform_sensors.py -fi diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/sensors b/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/sensors index 030d636a15..958cbdcb7b 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/sensors +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/sensors @@ -1,7 +1,3 @@ #!/bin/bash docker exec -i pmon sensors "$@" -#To probe sensors not part of lm-sensors -if [ -r /usr/local/bin/platform_sensors.py ]; then - python /usr/local/bin/platform_sensors.py -fi diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/z9100_platform.sh b/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/z9100_platform.sh index c943e58494..3cc48e5211 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/z9100_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/scripts/z9100_platform.sh @@ -171,6 +171,35 @@ reset_muxes() { io_rd_wr.py --set --val 0xff --offset 0x20b } +# Copy led_proc_init.soc file according to the HWSKU +init_switch_port_led() { + T0="Force10-Z9100-C8D48" + T1="Force10-Z9100-C32" + device="/usr/share/sonic/device" + platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform) + hwsku=$(cat /etc/sonic/config_db.json | grep -A2 "DEVICE_METADATA" | grep "hwsku" | cut -d ":" -f2 | sed 's/"//g' | sed 's/,//g'| xargs ) + + if [ -z "$hwsku" ]; then + #Check minigraph for hwsku + cat /etc/sonic/minigraph.xml | grep $T1 > /dev/null + if [ $? -eq 0 ]; then + hwsku=$T1 + else + hwsku=$T0 + fi + fi + + led_proc_init="$device/$platform/$hwsku/led_proc_init.soc" + + # Remove old HWSKU LED file.. + rm -rf $device/$platform/led_proc_init.soc + + if [ -e $led_proc_init ] && [ ! -e $device/$platform/led_proc_init.soc ]; then + cp $led_proc_init $device/$platform + fi + +} + init_devnum if [[ "$1" == "init" ]]; then @@ -188,6 +217,15 @@ if [[ "$1" == "init" ]]; then switch_board_sfp "new_device" switch_board_qsfp "new_device" xcvr_presence_interrupts "enable" + + #Copy led_proc_init.soc + init_switch_port_led + + value=0x0 + echo $value > /sys/class/i2c-adapter/i2c-14/14-003e/qsfp_lpmode + echo $value > /sys/class/i2c-adapter/i2c-15/15-003e/qsfp_lpmode + echo $value > /sys/class/i2c-adapter/i2c-16/16-003e/qsfp_lpmode + elif [[ "$1" == "deinit" ]]; then xcvr_presence_interrupts "disable" switch_board_sfp "delete_device" diff --git a/platform/broadcom/sonic-platform-modules-dell/z9264f/modules/dell_z9264f_fpga_ocores.c b/platform/broadcom/sonic-platform-modules-dell/z9264f/modules/dell_z9264f_fpga_ocores.c index c08a4c210c..d3a4a51ead 100644 --- a/platform/broadcom/sonic-platform-modules-dell/z9264f/modules/dell_z9264f_fpga_ocores.c +++ b/platform/broadcom/sonic-platform-modules-dell/z9264f/modules/dell_z9264f_fpga_ocores.c @@ -19,6 +19,7 @@ * @file fpga_ocores.c * @brief This is a driver to interface with Linux Open Cores driver for FPGA i2c access * + * 2019/5/9 - PCIe Interrupt supported is added for OIR Events. ************************************************************************/ #include #include @@ -89,7 +90,7 @@ struct fpgapci_dev { unsigned int irq_first; unsigned int irq_length; unsigned int irq_assigned; - + unsigned int xcvr_intr_count; }; static int use_irq = 1; @@ -226,6 +227,14 @@ enum { #define I2C_PCI_BUS_NUM_12 12 #define I2C_PCI_BUS_NUM_16 16 + +#define IRQ_LTCH_STS 0x20 +#define PRSNT_LTCH_STS 0x10 + +#define PORT_CTRL_OFFSET 0x4000 +#define PORT_STS_OFFSET 0x4004 +#define PORT_IRQ_STS_OFFSET 0x4008 +#define PORT_IRQ_EN_OFFSET 0x400C #define MB_BRD_REV_TYPE 0x0008 #define MB_BRD_REV_MASK 0x00f0 #define MB_BRD_REV_00 0x0000 @@ -248,7 +257,7 @@ enum { #define BRD_TYPE_S5232_NON_NEBS 0xc #define BRD_TYPE_S5232_NEBS 0xd -#define FPGA_CTL_REG_SIZE 0x60 +#define FPGA_CTL_REG_SIZE 0x6000 #define MSI_VECTOR_MAP_MASK 0x1f #define MSI_VECTOR_MAP1 0x58 #define I2C_CH1_MSI_MAP_VECT_8 0x00000008 @@ -284,6 +293,8 @@ enum { #define MSI_VECTOR_REV_00 16 #define MSI_VECTOR_REV_01 32 +#define FPGA_MSI_VECTOR_ID_4 4 +#define FPGA_MSI_VECTOR_ID_5 5 #define FPGA_MSI_VECTOR_ID_8 8 #define FPGA_MSI_VECTOR_ID_9 9 #define FPGA_MSI_VECTOR_ID_10 10 @@ -506,6 +517,73 @@ static int fpgai2c_poll(struct fpgalogic_i2c *i2c) return 0; } +static ssize_t get_mod_msi(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int ind = 0, port_status=0, port_irq_status=0; + struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(dev); + PRINT("%s:xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count); + for(ind=0;ind<64;ind++) + { + port_status = ioread32(fpga_ctl_addr + PORT_STS_OFFSET + (ind*16)); + port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status); + } + return sprintf(buf,"0x%04x\n",fpgapci->xcvr_intr_count); +} +static DEVICE_ATTR(port_msi, S_IRUGO, get_mod_msi, NULL); + +static struct attribute *port_attrs[] = { + &dev_attr_port_msi.attr, + NULL, +}; + +static struct attribute_group port_attr_grp = { + .attrs = port_attrs, +}; + + +static irqreturn_t fpgaport_1_32_isr(int irq, void *dev) +{ + struct pci_dev *pdev = dev; + struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&pdev->dev); + int ind = 0, port_status=0, port_irq_status=0; + for(ind=0;ind<32;ind++) + { + port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + if(port_irq_status&(IRQ_LTCH_STS|PRSNT_LTCH_STS)) + { + PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status); + //write on clear + iowrite32( IRQ_LTCH_STS|PRSNT_LTCH_STS,fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + } + } + fpgapci->xcvr_intr_count++; + PRINT("%s: xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count); + sysfs_notify(&pdev->dev.kobj, NULL, "port_msi"); + return IRQ_HANDLED; +} + +static irqreturn_t fpgaport_33_64_isr(int irq, void *dev) +{ + struct pci_dev *pdev = dev; + struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&pdev->dev); + int ind = 0, port_status=0, port_irq_status=0; + for(ind=32;ind<64;ind++) + { + port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + if(port_irq_status| (IRQ_LTCH_STS|PRSNT_LTCH_STS)) + { + PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status); + //write on clear + iowrite32( IRQ_LTCH_STS|PRSNT_LTCH_STS,fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); + } + } + fpgapci->xcvr_intr_count++; + PRINT("%s: xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count); + sysfs_notify(&pdev->dev.kobj, NULL, "port_msi"); + return IRQ_HANDLED; +} + static void fpgai2c_process(struct fpgalogic_i2c *i2c) { struct i2c_msg *msg = i2c->msg; @@ -1028,6 +1106,18 @@ static int register_intr_handler(struct pci_dev *dev, int irq_num_id) switch(irq_num_id) { /* Currently we only support test vector 2 for FPGA Logic I2C channel * controller 1-7 interrupt*/ + case FPGA_MSI_VECTOR_ID_4: + err = request_irq(dev->irq + irq_num_id, fpgaport_1_32_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, dev); + PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_5: + err = request_irq(dev->irq + irq_num_id, fpgaport_33_64_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, dev); + PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); + fpgapci->irq_assigned++; + break; case FPGA_MSI_VECTOR_ID_8: err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[0]); @@ -1074,6 +1164,18 @@ static int register_intr_handler(struct pci_dev *dev, int irq_num_id) ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_03)) { /* FPGA SPEC 4.3.1.34, First i2c channel mapped to vector 8 */ switch (irq_num_id) { + case FPGA_MSI_VECTOR_ID_4: + err = request_irq(dev->irq + irq_num_id, fpgaport_1_32_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, dev); + PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_5: + err = request_irq(dev->irq + irq_num_id, fpgaport_33_64_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, dev); + PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); + fpgapci->irq_assigned++; + break; case FPGA_MSI_VECTOR_ID_8: err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[0]); @@ -1387,6 +1489,7 @@ error_no_msi: static int fpgapci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct fpgapci_dev *fpgapci = 0; + int status = 0; #ifdef TEST PRINT ( " vendor = 0x%x, device = 0x%x, class = 0x%x, bus:slot.func = %02x:%02x.%02x\n", @@ -1404,6 +1507,10 @@ static int fpgapci_probe(struct pci_dev *dev, const struct pci_device_id *id) dev_set_drvdata(&dev->dev, (void*)fpgapci); fpgapci->upstream = find_upstream_dev (dev); + status = sysfs_create_group(&dev->dev.kobj, &port_attr_grp); + if (status) { + printk(KERN_INFO "%s:Cannot create sysfs\n", __FUNCTION__); + } if(fpgapci_setup_device(fpgapci,dev)) { goto error_no_device; diff --git a/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/platform_sensors.py index 3e2e165781..77a9887f9a 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/platform_sensors.py +++ b/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/platform_sensors.py @@ -3,7 +3,7 @@ # autonomous subsystem provides monitoring and management # facility independent of the host CPU. IPMI standard # protocol is used with ipmitool to fetch sensor details. -# Current script support X00 board only. X01 support will +# Current script support X00 board only. X01 support will # be added soon. This provies support for the # following objects: # * Onboard temperature sensors @@ -26,7 +26,6 @@ FAN_PRESENCE = "FAN{0}_prsnt" PSU_PRESENCE = "PSU{0}_state" # Use this for older firmware # PSU_PRESENCE="PSU{0}_prsnt" - ipmi_sdr_list = "" # Dump sensor registers @@ -53,7 +52,7 @@ def get_pmc_register(reg_name): output = item.strip() if not output: - print('\nFailed to fetch: ' + reg_name + ' sensor ') + print('\nFailed to fetch: ' + reg_name + ' sensor ') sys.exit(0) output = output.split('|')[1] @@ -83,8 +82,10 @@ def print_temperature_sensors(): (get_pmc_register('CPU_Near_temp')) print ' CPU Near Temp: ',\ (get_pmc_register('CPU_temp')) - print ' DRAM Temp: ',\ - (get_pmc_register('DRAM1_temp')) + print ' PSU FAN AirFlow Temperature 1: ',\ + (get_pmc_register('PSU1_AF_temp')) + print ' PSU FAN AirFlow Temperature 2: ',\ + (get_pmc_register('PSU2_AF_temp')) ipmi_sensor_dump() @@ -95,15 +96,23 @@ print_temperature_sensors() def print_fan_tray(tray): - Fan_Status = [' Normal', ' Abnormal'] + Fan_Status = [' Normal', ' Abnormal', ' no reading'] Airflow_Direction = ['B2F', 'F2B'] print ' Fan Tray ' + str(tray) + ':' if (tray == 1): - fan1_status = int(get_pmc_register('Fan1_Front_state'), 16) - fan2_status = int(get_pmc_register('Fan1_Rear_state'), 16) + if(int(get_pmc_register('FAN1_prsnt'), 16)): + fan1_status = int(get_pmc_register('Fan1_Front_state'), 16) + fan2_status = int(get_pmc_register('Fan1_Rear_state'), 16) + # BMC taking some time to update + if(fan1_status > 2 or fan2_status > 2): + fan1_status = 2 + fan2_status = 2 + else: + fan1_status = 2 + fan2_status = 2 print ' Fan1 Speed: ',\ get_pmc_register('FAN1_Front_rpm') @@ -116,8 +125,16 @@ def print_fan_tray(tray): elif (tray == 2): - fan1_status = int(get_pmc_register('Fan2_Front_state'), 16) - fan2_status = int(get_pmc_register('Fan2_Rear_state'), 16) + if(int(get_pmc_register('FAN2_prsnt'), 16)): + fan1_status = int(get_pmc_register('Fan2_Front_state'), 16) + fan2_status = int(get_pmc_register('Fan2_Rear_state'), 16) + # BMC taking some time to update + if(fan1_status > 2 or fan2_status > 2): + fan1_status = 2 + fan2_status = 2 + else: + fan1_status = 2 + fan2_status = 2 print ' Fan1 Speed: ',\ get_pmc_register('FAN2_Front_rpm') @@ -130,8 +147,16 @@ def print_fan_tray(tray): elif (tray == 3): - fan1_status = int(get_pmc_register('Fan3_Front_state'), 16) - fan2_status = int(get_pmc_register('Fan3_Rear_state'), 16) + if(int(get_pmc_register('FAN3_prsnt'), 16)): + fan1_status = int(get_pmc_register('Fan3_Front_state'), 16) + fan2_status = int(get_pmc_register('Fan3_Rear_state'), 16) + # BMC taking some time to update + if(fan1_status > 2 or fan2_status > 2): + fan1_status = 2 + fan2_status = 2 + else: + fan1_status = 2 + fan2_status = 2 print ' Fan1 Speed: ',\ get_pmc_register('FAN3_Front_rpm') @@ -144,8 +169,16 @@ def print_fan_tray(tray): elif (tray == 4): - fan1_status = int(get_pmc_register('Fan4_Front_state'), 16) - fan2_status = int(get_pmc_register('Fan4_Rear_state'), 16) + if(int(get_pmc_register('FAN4_prsnt'), 16)): + fan1_status = int(get_pmc_register('Fan4_Front_state'), 16) + fan2_status = int(get_pmc_register('Fan4_Rear_state'), 16) + # BMC taking some time to update + if(fan1_status > 2 or fan2_status > 2): + fan1_status = 2 + fan2_status = 2 + else: + fan1_status = 2 + fan2_status = 2 print ' Fan1 Speed: ',\ get_pmc_register('FAN4_Front_rpm') @@ -169,80 +202,54 @@ for tray in range(1, Z9264F_MAX_FAN_TRAYS + 1): # Print the information for PSU1, PSU2 def print_psu(psu): - Psu_Type = ['Normal', 'Mismatch'] - Psu_Input_Type = ['AC', 'DC'] - PSU_STATUS_TYPE_BIT = 4 - PSU_STATUS_INPUT_TYPE_BIT = 1 - PSU_FAN_PRESENT_BIT = 2 - PSU_FAN_STATUS_BIT = 1 - PSU_FAN_AIR_FLOW_BIT = 0 - Psu_Fan_Presence = ['Present', 'Absent'] - Psu_Fan_Status = ['Normal', 'Abnormal'] - Psu_Fan_Airflow = ['B2F', 'F2B'] - - # print ' Input: ', Psu_Input_Type[psu_input_type] - # print ' Type: ', Psu_Type[psu_type] # PSU FAN details if (psu == 1): - # psu1_fan_status = int(get_pmc_register('PSU1_status'),16) - print ' PSU1:' - print ' FAN Normal Temperature: ',\ + print ' FAN Normal Temperature: ',\ get_pmc_register('PSU1_Normal_temp') - print ' FAN System Temperature: ',\ - get_pmc_register('PSU1_Sys_temp') - print ' FAN Chassis Temperature: ',\ + print ' Chassis Temperature: ',\ get_pmc_register('PSU1_Chass_temp') - print ' FAN AirFlow Temperature: ',\ - get_pmc_register('PSU1AF_temp') + print ' System Temperature: ',\ + get_pmc_register('PSU1_Sys_temp') print ' FAN RPM: ',\ get_pmc_register('PSU1_rpm') - # print ' FAN Status: ', Psu_Fan_Status[psu1_fan_status] - - # PSU input & output monitors - print ' Input Voltage: ',\ + print ' Input Voltage: ',\ get_pmc_register('PSU1_In_volt') - print ' Output Voltage: ',\ + print ' Output Voltage: ',\ get_pmc_register('PSU1_Out_volt') - print ' Input Power: ',\ + print ' Input Power: ',\ get_pmc_register('PSU1_In_watt') - print ' Output Power: ',\ + print ' Output Power: ',\ get_pmc_register('PSU1_Out_watt') - print ' Input Current: ',\ + print ' Input Current: ',\ get_pmc_register('PSU1_In_amp') - print ' Output Current: ',\ + print ' Output Current: ',\ get_pmc_register('PSU1_Out_amp') else: - # psu2_fan_status = int(get_pmc_register('PSU1_status'),16) print ' PSU2:' - print ' FAN Normal Temperature: ',\ + print ' FAN Normal Temperature: ',\ get_pmc_register('PSU2_Normal_temp') - print ' FAN System Temperature: ',\ - get_pmc_register('PSU2_Sys_temp') - print ' FAN Chassis Temperature: ',\ + print ' Chassis Temperature: ',\ get_pmc_register('PSU2_Chass_temp') - print ' FAN AirFlow Temperature: ',\ - get_pmc_register('PSU2AF_temp') + print ' System Temperature: ',\ + get_pmc_register('PSU2_Sys_temp') print ' FAN RPM: ',\ get_pmc_register('PSU2_rpm') - # print ' FAN Status: ', Psu_Fan_Status[psu2_fan_status] - - # PSU input & output monitors - print ' Input Voltage: ',\ + print ' Input Voltage: ',\ get_pmc_register('PSU2_In_volt') - print ' Output Voltage: ',\ + print ' Output Voltage: ',\ get_pmc_register('PSU2_Out_volt') - print ' Input Power: ',\ + print ' Input Power: ',\ get_pmc_register('PSU2_In_watt') - print ' Output Power: ',\ + print ' Output Power: ',\ get_pmc_register('PSU2_Out_watt') - print ' Input Current: ',\ + print ' Input Current: ',\ get_pmc_register('PSU2_In_amp') - print ' Output Current: ',\ + print ' Output Current: ',\ get_pmc_register('PSU2_Out_amp') @@ -254,6 +261,5 @@ for psu in range(1, Z9264F_MAX_PSUS + 1): else: print '\n PSU ', psu, 'Not present' -print '\n Total Power: ',\ +print '\n Total Power: ',\ get_pmc_register('PSU_Total_watt') - diff --git a/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/qsfp_irq_enable.py b/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/qsfp_irq_enable.py new file mode 100755 index 0000000000..b2eb03dd20 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/qsfp_irq_enable.py @@ -0,0 +1,32 @@ +#!/usr/bin/python + +try: + import struct + import sys + from os import * + from mmap import * + +except ImportError as e: + raise ImportError("%s - required module no found" % str(e)) + +BASE_RES_PATH = "/sys/bus/pci/devices/0000:04:00.0/resource0" +PORT_START = 0 +PORT_END = 64 + + +def pci_mem_write(mm, offset, data): + mm.seek(offset) + mm.write(struct.pack('I', data)) + + +def pci_set_value(resource, val, offset): + fd = open(resource, O_RDWR) + mm = mmap(fd, 0) + val = pci_mem_write(mm, offset, val) + mm.close() + close(fd) + return val + +for port_num in range(PORT_START, PORT_END+1): + port_offset = 0x400c + ((port_num) * 16) + pci_set_value(BASE_RES_PATH, 0x30, port_offset) diff --git a/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/z9264f_platform.sh b/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/z9264f_platform.sh index 5002ce72c0..880ba98abb 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/z9264f_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/z9264f_platform.sh @@ -82,7 +82,7 @@ switch_board_modsel() { do port_addr=$(( 16384 + ((i - 1) * 16))) hex=$( printf "0x%x" $port_addr ) - python /usr/bin/pcisysfs.py --set --offset $hex --val 0x41 --res $resource > /dev/null 2>&1 + python /usr/bin/pcisysfs.py --set --offset $hex --val 0x10 --res $resource > /dev/null 2>&1 done } init_devnum @@ -98,6 +98,7 @@ if [ "$1" == "init" ]; then switch_board_qsfp_mux "new_device" switch_board_qsfp "new_device" switch_board_modsel + python /usr/bin/qsfp_irq_enable.py elif [ "$1" == "deinit" ]; then sys_eeprom "delete_device" diff --git a/platform/broadcom/sonic-platform-modules-s6000/modules/dell_s6000_platform.c b/platform/broadcom/sonic-platform-modules-s6000/modules/dell_s6000_platform.c index 5e205973d6..3ac029e73f 100644 --- a/platform/broadcom/sonic-platform-modules-s6000/modules/dell_s6000_platform.c +++ b/platform/broadcom/sonic-platform-modules-s6000/modules/dell_s6000_platform.c @@ -9,6 +9,7 @@ #include #include #include +#include #define S6000_MUX_BASE_NR 10 #define QSFP_MODULE_BASE_NR 20 @@ -20,6 +21,7 @@ #define QSFP_MODULE_NUM 16 #define QSFP_DEVICE_NUM 2 +#define GPIO_I2C_MUX_PIN 10 static void device_release(struct device *dev) { @@ -247,28 +249,59 @@ static struct platform_driver qsfp_mux_driver = { /* TODO */ /* module_platform_driver */ +static int dell_i2c_smbus_read_byte_data(const struct i2c_client *client, + u8 command) +{ + int ret = 0; + + ret = i2c_smbus_read_byte_data(client, command); + if(ret < 0) { + printk(KERN_WARNING "I2C smbus read failed. Resetting mux with gpio10"); + gpio_set_value(GPIO_I2C_MUX_PIN, 1); + gpio_set_value(GPIO_I2C_MUX_PIN, 0); + ret = i2c_smbus_read_byte_data(client, command); + } + return ret; +} + +static int dell_i2c_smbus_write_byte_data(const struct i2c_client *client, + u8 command, u8 value) +{ + int ret = 0; + + ret = i2c_smbus_write_byte_data(client, command, value); + if(ret < 0) + { + printk(KERN_WARNING "I2C smbus write failed. Resetting mux with gpio10"); + gpio_set_value(GPIO_I2C_MUX_PIN, 1); + gpio_set_value(GPIO_I2C_MUX_PIN, 0); + ret = i2c_smbus_write_byte_data(client, command, value); + } + return ret; +} + static ssize_t get_modsel(struct device *dev, struct device_attribute *devattr, char *buf) { int ret; u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x0); + ret = dell_i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x0); if (ret < 0) return sprintf(buf, "na"); data = (u32)ret & 0xff; - ret = i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x1); + ret = dell_i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x1); if (ret < 0) return sprintf(buf, "na"); data |= (u32)(ret & 0xff) << 8; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0xa); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0xa); if (ret < 0) return sprintf(buf, "na"); data |= (u32)(ret & 0xff) << 16; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0xb); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0xb); if (ret < 0) return sprintf(buf, "na"); data |= (u32)(ret & 0xff) << 24; @@ -282,22 +315,22 @@ static ssize_t get_lpmode(struct device *dev, struct device_attribute *devattr, u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x2); + ret = dell_i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x2); if (ret < 0) return sprintf(buf, "na"); data = (u32)ret & 0xff; - ret = i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x3); + ret = dell_i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x3); if (ret < 0) return sprintf(buf, "na"); data |= (u32)(ret & 0xff) << 8; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0xc); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0xc); if (ret < 0) return sprintf(buf, "na"); data |= (u32)(ret & 0xff) << 16; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0xd); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0xd); if (ret < 0) return sprintf(buf, "na"); data |= (u32)(ret & 0xff) << 24; @@ -315,10 +348,10 @@ static ssize_t set_lpmode(struct device *dev, struct device_attribute *devattr, if (err) return err; - i2c_smbus_write_byte_data(pdata[slave_cpld].client, 0x2, (u8)(data & 0xff)); - i2c_smbus_write_byte_data(pdata[slave_cpld].client, 0x3, (u8)((data >> 8) & 0xff)); - i2c_smbus_write_byte_data(pdata[master_cpld].client, 0xc, (u8)((data >> 16) & 0xff)); - i2c_smbus_write_byte_data(pdata[master_cpld].client, 0xd, (u8)((data >> 24) & 0xff)); + dell_i2c_smbus_write_byte_data(pdata[slave_cpld].client, 0x2, (u8)(data & 0xff)); + dell_i2c_smbus_write_byte_data(pdata[slave_cpld].client, 0x3, (u8)((data >> 8) & 0xff)); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0xc, (u8)((data >> 16) & 0xff)); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0xd, (u8)((data >> 24) & 0xff)); return count; } @@ -329,22 +362,22 @@ static ssize_t get_reset(struct device *dev, struct device_attribute *devattr, c u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x6); + ret = dell_i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x6); if (ret < 0) return sprintf(buf, "na"); data = (u32)ret & 0xff; - ret = i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x7); + ret = dell_i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x7); if (ret < 0) return sprintf(buf, "na"); data |= (u32)(ret & 0xff) << 8; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x10); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x10); if (ret < 0) return sprintf(buf, "na"); data |= (u32)(ret & 0xff) << 16; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x11); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x11); if (ret < 0) return sprintf(buf, "na"); data |= (u32)(ret & 0xff) << 24; @@ -362,10 +395,10 @@ static ssize_t set_reset(struct device *dev, struct device_attribute *devattr, c if (err) return err; - i2c_smbus_write_byte_data(pdata[slave_cpld].client, 0x6, (u8)(data & 0xff)); - i2c_smbus_write_byte_data(pdata[slave_cpld].client, 0x7, (u8)((data >> 8)& 0xff)); - i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x10, (u8)((data >> 16) & 0xff)); - i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x11, (u8)((data >> 24) & 0xff)); + dell_i2c_smbus_write_byte_data(pdata[slave_cpld].client, 0x6, (u8)(data & 0xff)); + dell_i2c_smbus_write_byte_data(pdata[slave_cpld].client, 0x7, (u8)((data >> 8)& 0xff)); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x10, (u8)((data >> 16) & 0xff)); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x11, (u8)((data >> 24) & 0xff)); return count; } @@ -376,22 +409,22 @@ static ssize_t get_modprs(struct device *dev, struct device_attribute *devattr, u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x4); + ret = dell_i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x4); if (ret < 0) return sprintf(buf, "read error"); data = (u32)ret & 0xff; - ret = i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x5); + ret = dell_i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0x5); if (ret < 0) return sprintf(buf, "read error"); data |= (u32)(ret & 0xff) << 8; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0xe); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0xe); if (ret < 0) return sprintf(buf, "na"); data |= (u32)(ret & 0xff) << 16; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0xf); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0xf); if (ret < 0) return sprintf(buf, "na"); data |= (u32)(ret & 0xff) << 24; @@ -411,7 +444,7 @@ static ssize_t set_power_reset(struct device *dev, struct device_attribute *deva if (data) { - i2c_smbus_write_byte_data(pdata[system_cpld].client, 0x1, (u8)(0xfd)); + dell_i2c_smbus_write_byte_data(pdata[system_cpld].client, 0x1, (u8)(0xfd)); } return count; @@ -422,7 +455,7 @@ static ssize_t get_power_reset(struct device *dev, struct device_attribute *deva uint8_t ret = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[system_cpld].client, 0x1); + ret = dell_i2c_smbus_read_byte_data(pdata[system_cpld].client, 0x1); if (ret < 0) return sprintf(buf, "read error"); @@ -435,12 +468,12 @@ static ssize_t get_fan_prs(struct device *dev, struct device_attribute *devattr, u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); if (ret < 0) return sprintf(buf, "read error"); data = (u32)((ret & 0xc0) >> 6); - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x9); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x9); if (ret < 0) return sprintf(buf, "read error"); data |= (u32)((ret & 0x01) << 2); @@ -455,7 +488,7 @@ static ssize_t get_psu0_prs(struct device *dev, struct device_attribute *devattr u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x3); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x3); if (ret < 0) return sprintf(buf, "read error"); @@ -471,7 +504,7 @@ static ssize_t get_psu1_prs(struct device *dev, struct device_attribute *devattr u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x3); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x3); if (ret < 0) return sprintf(buf, "read error"); @@ -487,7 +520,7 @@ static ssize_t get_psu0_status(struct device *dev, struct device_attribute *deva u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x3); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x3); if (ret < 0) return sprintf(buf, "read error"); @@ -503,7 +536,7 @@ static ssize_t get_psu1_status(struct device *dev, struct device_attribute *deva u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x3); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x3); if (ret < 0) return sprintf(buf, "read error"); @@ -519,7 +552,7 @@ static ssize_t get_system_led(struct device *dev, struct device_attribute *devat u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); if (ret < 0) return sprintf(buf, "read error"); @@ -570,11 +603,11 @@ static ssize_t set_system_led(struct device *dev, struct device_attribute *devat return -1; } - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); if (ret < 0) return ret; - i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x7, (u8)((ret & 0x9F) | (data << 5))); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x7, (u8)((ret & 0x9F) | (data << 5))); return count; } @@ -585,7 +618,7 @@ static ssize_t get_locator_led(struct device *dev, struct device_attribute *deva u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); if (ret < 0) return sprintf(buf, "read error"); @@ -632,11 +665,11 @@ static ssize_t set_locator_led(struct device *dev, struct device_attribute *deva return -1; } - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); if (ret < 0) return ret; - i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x7, (u8)((ret & 0xE7) | (data << 3))); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x7, (u8)((ret & 0xE7) | (data << 3))); return count; } @@ -647,7 +680,7 @@ static ssize_t get_power_led(struct device *dev, struct device_attribute *devatt u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); if (ret < 0) return sprintf(buf, "read error"); @@ -698,11 +731,11 @@ static ssize_t set_power_led(struct device *dev, struct device_attribute *devatt return -1; } - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); if (ret < 0) return ret; - i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x7, (u8)((ret & 0xF9) | (data << 1))); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x7, (u8)((ret & 0xF9) | (data << 1))); return count; } @@ -713,7 +746,7 @@ static ssize_t get_master_led(struct device *dev, struct device_attribute *devat u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); if (ret < 0) return sprintf(buf, "read error"); @@ -751,11 +784,11 @@ static ssize_t set_master_led(struct device *dev, struct device_attribute *devat return -1; } - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x7); if (ret < 0) return ret; - i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x7, (u8)((ret & 0xFE) | data)); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x7, (u8)((ret & 0xFE) | data)); return count; } @@ -766,7 +799,7 @@ static ssize_t get_fan_led(struct device *dev, struct device_attribute *devattr, u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x9); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x9); if (ret < 0) return sprintf(buf, "read error"); @@ -817,11 +850,11 @@ static ssize_t set_fan_led(struct device *dev, struct device_attribute *devattr, return -1; } - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x9); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x9); if (ret < 0) return ret; - i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x9, (u8)((ret & 0xE7) | (data << 3))); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x9, (u8)((ret & 0xE7) | (data << 3))); return count; } @@ -832,7 +865,7 @@ static ssize_t get_fan0_led(struct device *dev, struct device_attribute *devattr u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); if (ret < 0) return sprintf(buf, "read error"); @@ -879,11 +912,11 @@ static ssize_t set_fan0_led(struct device *dev, struct device_attribute *devattr return -1; } - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); if (ret < 0) return ret; - i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x8, (u8)((ret & 0xFC) | data)); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x8, (u8)((ret & 0xFC) | data)); return count; } @@ -895,7 +928,7 @@ static ssize_t get_fan1_led(struct device *dev, struct device_attribute *devattr u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); if (ret < 0) return sprintf(buf, "read error"); @@ -942,11 +975,11 @@ static ssize_t set_fan1_led(struct device *dev, struct device_attribute *devattr return -1; } - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); if (ret < 0) return ret; - i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x8, (u8)((ret & 0xF3) | (data << 2))); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x8, (u8)((ret & 0xF3) | (data << 2))); return count; } @@ -957,7 +990,7 @@ static ssize_t get_fan2_led(struct device *dev, struct device_attribute *devattr u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); if (ret < 0) return sprintf(buf, "read error"); @@ -1004,11 +1037,11 @@ static ssize_t set_fan2_led(struct device *dev, struct device_attribute *devattr return -1; } - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x8); if (ret < 0) return ret; - i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x8, (u8)((ret & 0xCF) | (data << 4))); + dell_i2c_smbus_write_byte_data(pdata[master_cpld].client, 0x8, (u8)((ret & 0xCF) | (data << 4))); return count; } @@ -1020,7 +1053,7 @@ static ssize_t get_system_cpld_ver(struct device *dev, u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[system_cpld].client, 0x0); + ret = dell_i2c_smbus_read_byte_data(pdata[system_cpld].client, 0x0); if (ret < 0) return sprintf(buf, "read error"); @@ -1036,7 +1069,7 @@ static ssize_t get_master_cpld_ver(struct device *dev, u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x1); + ret = dell_i2c_smbus_read_byte_data(pdata[master_cpld].client, 0x1); if (ret < 0) return sprintf(buf, "read error"); @@ -1052,7 +1085,7 @@ static ssize_t get_slave_cpld_ver(struct device *dev, u32 data = 0; struct cpld_platform_data *pdata = dev->platform_data; - ret = i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0xa); + ret = dell_i2c_smbus_read_byte_data(pdata[slave_cpld].client, 0xa); if (ret < 0) return sprintf(buf, "read error"); @@ -1201,8 +1234,28 @@ static int __init dell_s6000_platform_init(void) struct cpld_platform_data *cpld_pdata; struct qsfp_mux_platform_data *qsfp_pdata; int i; + bool gpio_allocated = false; - printk("delll_s6000_platform module initialization\n"); + printk("dell_s6000_platform module initialization\n"); + + ret = gpio_request(GPIO_I2C_MUX_PIN, "gpio10"); + if(ret < 0) { + printk(KERN_WARNING "Failed to request gpio 10"); + goto error_gpio_init; + } + gpio_allocated = true; + + ret = gpio_export(GPIO_I2C_MUX_PIN, false); + if(ret < 0) { + printk(KERN_WARNING "Failed to export gpio 10"); + goto error_gpio_init; + } + + ret = gpio_direction_output(GPIO_I2C_MUX_PIN, 0); + if(ret < 0) { + printk(KERN_WARNING "Failed to set direction out on gpio 10"); + goto error_gpio_init; + } ret = platform_driver_register(&cpld_driver); if (ret) { @@ -1261,6 +1314,11 @@ error_qsfp_mux_driver: platform_driver_unregister(&cpld_driver); error_cpld_driver: return ret; +error_gpio_init: + if(gpio_allocated) { + gpio_free(GPIO_I2C_MUX_PIN); + } + return ret; } static void __exit dell_s6000_platform_exit(void) @@ -1274,6 +1332,7 @@ static void __exit dell_s6000_platform_exit(void) platform_driver_unregister(&cpld_driver); platform_driver_unregister(&qsfp_mux_driver); + gpio_free(GPIO_I2C_MUX_PIN); } module_init(dell_s6000_platform_init); diff --git a/platform/mellanox/hw-management.mk b/platform/mellanox/hw-management.mk index f473d4da23..e3bf43c336 100644 --- a/platform/mellanox/hw-management.mk +++ b/platform/mellanox/hw-management.mk @@ -1,6 +1,6 @@ # Mellanox HW Management -MLNX_HW_MANAGEMENT_VERSION = 2.0.0.0172 +MLNX_HW_MANAGEMENT_VERSION = 2.0.0175 export MLNX_HW_MANAGEMENT_VERSION diff --git a/platform/mellanox/hw-management/hw-mgmt b/platform/mellanox/hw-management/hw-mgmt index 425a653ea0..f78e386382 160000 --- a/platform/mellanox/hw-management/hw-mgmt +++ b/platform/mellanox/hw-management/hw-mgmt @@ -1 +1 @@ -Subproject commit 425a653ea0d7b27d4502c3ebdc9bb720b6c34bee +Subproject commit f78e386382e5d857af7f69f4040918ffb6f20362 diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index b8657a68f8..b144f2162b 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -15,15 +15,24 @@ try: from sonic_platform.psu import Psu from sonic_platform.fan import Fan from sonic_platform.fan import FAN_PATH + from sonic_platform.sfp import SFP from sonic_platform.watchdog import get_watchdog from os import listdir from os.path import isfile, join import re + import subprocess except ImportError as e: raise ImportError (str(e) + "- required module not found") MLNX_NUM_PSU = 2 +GET_HWSKU_CMD = "sonic-cfggen -d -v DEVICE_METADATA.localhost.hwsku" + +# magic code defnition for port number, qsfp port position of each hwsku +# port_position_tuple = (PORT_START, QSFP_PORT_START, PORT_END, PORT_IN_BLOCK, EEPROM_OFFSET) +hwsku_dict = {'ACS-MSN2700': 0, "LS-SN2700":0, 'ACS-MSN2740': 0, 'ACS-MSN2100': 1, 'ACS-MSN2410': 2, 'ACS-MSN2010': 3, 'ACS-MSN3700': 0, 'ACS-MSN3700C': 0, 'Mellanox-SN2700': 0, 'Mellanox-SN2700-D48C8': 0} +port_position_tuple_list = [(0, 0, 31, 32, 1), (0, 0, 15, 16, 1), (0, 48, 55, 56, 1),(0, 18, 21, 22, 1)] + class Chassis(ChassisBase): """Platform-specific Chassis class""" @@ -50,6 +59,20 @@ class Chassis(ChassisBase): fan = Fan(index, index) self._fan_list.append(fan) + # Initialize SFP list + port_position_tuple = self._get_port_position_tuple_by_sku_name() + self.PORT_START = port_position_tuple[0] + self.QSFP_PORT_START = port_position_tuple[1] + self.PORT_END = port_position_tuple[2] + self.PORTS_IN_BLOCK = port_position_tuple[3] + + for index in range(self.PORT_START, self.PORT_END + 1): + if index in range(QSFP_PORT_START, self.PORTS_IN_BLOCK + 1): + sfp_module = SFP(index, 'QSFP') + else: + sfp_module = SFP(index, 'SFP') + self._psu_list.append(sfp_module) + def _extract_num_of_fans_and_fan_drawers(self): num_of_fan = 0 num_of_drawer = 0 @@ -64,7 +87,13 @@ class Chassis(ChassisBase): if match_obj != None and int(match_obj.group(1)) > num_of_drawer: num_of_drawer = int(match_obj.group(1)) - return num_of_fan, num_of_drawer + return num_of_fan, num_of_drawer + + def _get_port_position_tuple_by_sku_name(self): + p = subprocess.Popen(GET_HWSKU_CMD, shell=True, stdout=subprocess.PIPE) + out, err = p.communicate() + position_tuple = port_position_tuple_list[hwsku_dict[out.rstrip('\n')]] + return position_tuple diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py new file mode 100644 index 0000000000..7f6c4aeaf5 --- /dev/null +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py @@ -0,0 +1,1052 @@ +#!/usr/bin/env python + +############################################################################# +# Mellanox +# +# Module contains an implementation of SONiC Platform Base API and +# provides the FANs status which are available in the platform +# +############################################################################# + +try: + import os.path + import subprocess + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_eeprom import eeprom_dts + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.inf8628 import inf8628InterfaceId + +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +# definitions of the offset and width for values in XCVR info eeprom +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 +XCVR_EXT_TYPE_OFFSET = 1 +XCVR_EXT_TYPE_WIDTH = 1 +XCVR_CONNECTOR_OFFSET = 2 +XCVR_CONNECTOR_WIDTH = 1 +XCVR_COMPLIANCE_CODE_OFFSET = 3 +XCVR_COMPLIANCE_CODE_WIDTH = 8 +XCVR_ENCODING_OFFSET = 11 +XCVR_ENCODING_WIDTH = 1 +XCVR_NBR_OFFSET = 12 +XCVR_NBR_WIDTH = 1 +XCVR_EXT_RATE_SEL_OFFSET = 13 +XCVR_EXT_RATE_SEL_WIDTH = 1 +XCVR_CABLE_LENGTH_OFFSET = 14 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_CABLE_LENGTH_WIDTH_SFP = 6 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_OSFP = 2 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 1 + +# definitions of the offset for values in OSFP info eeprom +OSFP_TYPE_OFFSET = 0 +OSFP_VENDOR_NAME_OFFSET = 129 +OSFP_VENDOR_PN_OFFSET = 148 +OSFP_HW_REV_OFFSET = 164 +OSFP_VENDOR_SN_OFFSET = 166 + +#definitions of the offset and width for values in DOM info eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VLOT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 1 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VLOT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 +SFP_CHANNL_STATUS_OFFSET = 110 +SFP_CHANNL_STATUS_WIDTH = 1 + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') + +sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes','FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia','FibreChannelSpeed') + +qsfp_compliance_code_tup = ('10/40G Ethernet Compliance Code', 'SONET Compliance codes', + 'SAS/SATA compliance codes', 'Gigabit Ethernet Compliant codes', + 'Fibre Channel link length/Transmitter Technology', + 'Fibre Channel transmission media', 'Fibre Channel Speed') + +SFP_PATH = "/var/run/hw-management/qsfp/" +SFP_TYPE = "SFP" +QSFP_TYPE = "QSFP" +OSFP_TYPE = "OSFP" + +class SFP(SfpBase): + """Platform-specific SFP class""" + + def __init__(self, sfp_index, sfp_type): + self.index = sfp_index + 1 + self.sfp_eeprom_path = "qsfp{}".format(self.index) + self.sfp_status_path = "qsfp{}_status".format(self.index) + self.sfp_type = sfp_type + self._dom_capability_detect() + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + ethtool_cmd = "ethtool -m sfp{} 2>/dev/null".format(self.index) + try: + proc = subprocess.Popen(ethtool_cmd, stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + result = stdout.rstrip('\n') + if result != '': + presence = True + + except OSError, e: + raise OSError("Cannot detect sfp") + + return presence + + # Read out any bytes from any offset + def _read_eeprom_specific_bytes(self, offset, num_bytes): + eeprom_raw = [] + ethtool_cmd = "ethtool -m sfp{} hex on offset {} length {}".format(self.index, offset, num_bytes) + try: + output = subprocess.check_output(ethtool_cmd, shell=True) + output_lines = output.splitlines() + first_line_raw = output_lines[0] + if "Offset" in first_line_raw: + for line in output_lines[2:]: + line_split = line.split() + eeprom_raw = eeprom_raw + line_split[1:] + except subprocess.CalledProcessError as e: + return None + + return eeprom_raw + + def _dom_capability_detect(self): + if self.sfp_type == "QSFP": + self.calibration = 1 + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_version_compliance_raw = self._read_eeprom_specific_bytes(QSFP_VERSION_COMPLIANCE_OFFSET, QSFP_VERSION_COMPLIANCE_OFFSET) + qsfp_version_compliance = int(qsfp_version_compliance_raw[0], 16) + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes((offset + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qspf_dom_capability = int(qsfp_dom_capability_raw[0], 16) + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = (qspf_dom_capability & 0x20 != 0) + self.dom_volt_supported = (qspf_dom_capability & 0x10 != 0) + self.dom_rx_power_supported = (qspf_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = (qspf_dom_capability & 0x04 != 0) + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = (qspf_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = True + self.dom_supported = True + self.calibration = 1 + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + elif self.sfp_type == "SFP": + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self._read_eeprom_specific_bytes(XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardwarerev |1*255VCHAR |hardware version of SFP + serialnum |1*255VCHAR |serial number of the SFP + manufacturename |1*255VCHAR |SFP vendor name + modelname |1*255VCHAR |SFP model name + Connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + mominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + ======================================================================== + """ + transceiver_info_dict = {} + compliance_code_dict = {} + + # ToDo: OSFP tranceiver info parsing not fully supported. + # in inf8628.py lack of some memory map definition + # will be implemented when the inf8628 memory map ready + if self.sfp_type == OSFP_TYPE: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_OSFP + + sfpi_obj = inf8628InterfaceId() + if sfpi_obj is None: + return None + + sfp_type_raw = self._read_eeprom_specific_bytes((offset + OSFP_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return None + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes((offset + OSFP_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_vendor_name_raw, 0) + else: + return None + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes((offset + OSFP_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_vendor_pn_raw, 0) + else: + return None + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes((offset + OSFP_HW_REV_OFFSET), vendor_rev_width) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_vendor_rev_raw, 0) + else: + return None + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes((offset + OSFP_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_vendor_sn_raw, 0) + else: + return None + + transceiver_info_dict['type'] = sfp_type_data['data']['type']['value'] + transceiver_info_dict['manufacturename'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['modelname'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardwarerev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serialnum'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = 'N/A' + transceiver_info_dict['vendor_date'] = 'N/A' + transceiver_info_dict['Connector'] = 'N/A' + transceiver_info_dict['encoding'] = 'N/A' + transceiver_info_dict['ext_identifier'] = 'N/A' + transceiver_info_dict['ext_rateselect_compliance'] = 'N/A' + transceiver_info_dict['cable_type'] = 'N/A' + transceiver_info_dict['cable_length'] = 'N/A' + transceiver_info_dict['specification_compliance'] = 'N/A' + transceiver_info_dict['nominal_bit_rate'] = 'N/A' + + else: + if self.sfp_type == QSFP_TYPE: + offset = 128 + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + cable_length_width = XCVR_CABLE_LENGTH_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + sfp_type = 'QSFP' + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return None + + else: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + cable_length_width = XCVR_CABLE_LENGTH_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + sfp_type = 'SFP' + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return None + + sfp_interface_bulk_raw = self._read_eeprom_specific_bytes((offset + XCVR_INTFACE_BULK_OFFSET), interface_info_bulk_width) + if sfp_interface_bulk_raw is not None: + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw, 0) + else: + return None + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_vendor_name_raw, 0) + else: + return None + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_vendor_pn_raw, 0) + else: + return None + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes((offset + XCVR_HW_REV_OFFSET), vendor_rev_width) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_vendor_rev_raw, 0) + else: + return None + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_vendor_sn_raw, 0) + else: + return None + + sfp_vendor_oui_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) + if sfp_vendor_oui_raw is not None: + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_vendor_oui_raw, 0) + else: + return None + + sfp_vendor_date_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH) + if sfp_vendor_date_raw is not None: + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_vendor_date_raw, 0) + else: + return None + + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['manufacturename'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['modelname'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardwarerev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serialnum'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['Connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + + if self.sfp_type == QSFP_TYPE: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str(sfp_interface_bulk_data['data'][key]['value']) + + for key in qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str(sfp_interface_bulk_data['data'][key]['value']) + + for key in sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_info_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + RX LOS |BOOLEAN |RX lost-of-signal status, + | |True if has RX los, False if not. + TX FAULT |BOOLEAN |TX fault status, + | |True if has TX fault, False if not. + Reset status |BOOLEAN |reset status, + | |True if SFP in reset, False if not. + LP mode |BOOLEAN |low power mode status, + | |True in lp mode, False if not. + TX disable |BOOLEAN |TX disable status, + | |True TX disabled, False if not. + TX disabled channel |HEX |disabled TX channles in hex, + | |bits 0 to 3 represent channel 0 + | |to channel 3. + Temperature |INT |module temperature in Celsius + Voltage |INT |supply voltage in mV + TX bias |INT |TX Bias Current in mA + RX power |INT |received optical power in mW + TX power |INT |TX output power in mW + ======================================================================== + """ + transceiver_dom_info_dict = {} + + if self.sfp_type == OSFP_TYPE: + transceiver_dom_info_dict['temperature'] = 'N/A' + transceiver_dom_info_dict['voltage'] = 'N/A' + transceiver_dom_info_dict['rx1power'] = 'N/A' + transceiver_dom_info_dict['rx2power'] = 'N/A' + transceiver_dom_info_dict['rx3power'] = 'N/A' + transceiver_dom_info_dict['rx4power'] = 'N/A' + transceiver_dom_info_dict['tx1bias'] = 'N/A' + transceiver_dom_info_dict['tx2bias'] = 'N/A' + transceiver_dom_info_dict['tx3bias'] = 'N/A' + transceiver_dom_info_dict['tx4bias'] = 'N/A' + transceiver_dom_info_dict['tx1power'] = 'N/A' + transceiver_dom_info_dict['tx2power'] = 'N/A' + transceiver_dom_info_dict['tx3power'] = 'N/A' + transceiver_dom_info_dict['tx4power'] = 'N/A' + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported: + return None + + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes((offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + else: + transceiver_dom_info_dict['temperature'] = 'N/A' + else: + return None + else: + transceiver_dom_info_dict['temperature'] = 'N/A' + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes((offset + QSFP_VLOT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + volt = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + else: + transceiver_dom_info_dict['voltage'] = 'N/A' + else: + return None + else: + transceiver_dom_info_dict['voltage'] = 'N/A' + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Power']['value']) + transceiver_dom_info_dict['tx2power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX2Power']['value']) + transceiver_dom_info_dict['tx3power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX3Power']['value']) + transceiver_dom_info_dict['tx4power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX4Power']['value']) + else: + transceiver_dom_info_dict['tx1power'] = 'N/A' + transceiver_dom_info_dict['tx2power'] = 'N/A' + transceiver_dom_info_dict['tx3power'] = 'N/A' + transceiver_dom_info_dict['tx4power'] = 'N/A' + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX1Power']['value']) + transceiver_dom_info_dict['rx2power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX2Power']['value']) + transceiver_dom_info_dict['rx3power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX3Power']['value']) + transceiver_dom_info_dict['rx4power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX4Power']['value']) + else: + transceiver_dom_info_dict['rx1power'] = 'N/A' + transceiver_dom_info_dict['rx2power'] = 'N/A' + transceiver_dom_info_dict['rx3power'] = 'N/A' + transceiver_dom_info_dict['rx4power'] = 'N/A' + + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + + else: + if not self.dom_supported: + return None + + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = self.calibration + + dom_temperature_raw = self._read_eeprom_specific_bytes((offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + else: + return None + + dom_voltage_raw = self._read_eeprom_specific_bytes((offset + SFP_VLOT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + else: + return None + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + else: + return None + + transceiver_dom_info_dict['temperature'] = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + transceiver_dom_info_dict['voltage'] = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + transceiver_dom_info_dict['rx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RXPower']['value']) + transceiver_dom_info_dict['rx2power'] = 'N/A' + transceiver_dom_info_dict['rx3power'] = 'N/A' + transceiver_dom_info_dict['rx4power'] = 'N/A' + transceiver_dom_info_dict['tx1bias'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TXBias']['value']) + transceiver_dom_info_dict['tx2bias'] = 'N/A' + transceiver_dom_info_dict['tx3bias'] = 'N/A' + transceiver_dom_info_dict['tx4bias'] = 'N/A' + transceiver_dom_info_dict['tx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TXPower']['value']) + transceiver_dom_info_dict['tx2power'] = 'N/A' + transceiver_dom_info_dict['tx3power'] = 'N/A' + transceiver_dom_info_dict['tx4power'] = 'N/A' + + return transceiver_dom_info_dict + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + + Returns: + A Boolean, True if reset enabled, False if disabled + """ + return NotImplementedError + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + + Returns: + A Boolean, True if SFP has RX LOS, False if not. + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + if not self.dom_supported: + return None + + rx_los_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + else: + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x02 != 0) + else: + return None + return rx_los_list + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + + Returns: + A Boolean, True if SFP has TX fault, False if not + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + if not self.dom_supported: + return None + + tx_fault_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + else: + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + else: + return None + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + + Returns: + A Boolean, True if tx_disable is enabled, False if disabled + """ + if not self.dom_supported: + return None + + tx_disable_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + else: + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x80 != 0) + else: + return None + return tx_disable_list + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + return NotImplementedError + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this SFP + + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + return NotImplementedError + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + return NotImplementedError + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + + Returns: + An integer number of current temperature in Celsius + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + offset_xcvr = 128 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes((offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + else: + return None + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = 1 + + dom_temperature_raw = self._read_eeprom_specific_bytes((offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + + Returns: + An integer number of supply voltage in mV + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + offset_xcvr = 128 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes((offset + QSFP_VLOT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + return None + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + sfpd_obj._calibration_type = self.calibration + + dom_voltage_raw = self._read_eeprom_specific_bytes((offset + SFP_VLOT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + offset_xcvr = 128 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX4Bias']['value'])) + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = 1 + + if self.dom_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return None + else: + return None + + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + rx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return None + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + offset_xcvr = 128 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_rx_power_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return None + else: + return None + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return None + else: + return None + return rx_power_list + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + tx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return None + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + offset_xcvr = 128 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_tx_power_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return None + else: + return None + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = 1 + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return None + else: + return None + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + + Returns: + A boolean, True if successful, False if not + """ + return NotImplementedError + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + return NotImplementedError + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + + Returns: + A boolean, True if successful, False if not + """ + return NotImplementedError + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + return NotImplementedError + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + return NotImplementedError diff --git a/platform/mellanox/mlnx-sfpd/scripts/mlnx-sfpd b/platform/mellanox/mlnx-sfpd/scripts/mlnx-sfpd index a1d2e6d9c3..08d1f11880 100644 --- a/platform/mellanox/mlnx-sfpd/scripts/mlnx-sfpd +++ b/platform/mellanox/mlnx-sfpd/scripts/mlnx-sfpd @@ -10,6 +10,7 @@ import os import time import syslog import signal +import select import json import threading from python_sdk_api.sx_api import * @@ -27,9 +28,12 @@ STATUS_PLUGIN = '1' STATUS_PLUGOUT = '0' STATUS_UNKNOWN = '2' -SFPD_LIVENESS_UPDATE_INTERVAL_SECS = 30 +SFPD_LIVENESS_EXPIRE_SECS = 30 -sfp_value_status_dict = {SDK_SFP_STATE_IN:STATUS_PLUGIN, SDK_SFP_STATE_OUT:STATUS_PLUGOUT} +sfp_value_status_dict = { + SDK_SFP_STATE_IN: STATUS_PLUGIN, + SDK_SFP_STATE_OUT: STATUS_PLUGOUT, +} # ========================== Syslog wrappers ========================== def log_info(msg, also_print_to_console=False): @@ -56,188 +60,199 @@ def log_error(msg, also_print_to_console=False): if also_print_to_console: print(msg) -# ========================== Signal Handling ========================== -def signal_handler(sig, frame): - if sig == signal.SIGHUP: - log_info("Caught SIGHUP - ignoring...") - return - elif sig == signal.SIGINT: - log_info("Caught SIGINT - exiting...") - sys.exit(128 + sig) - elif sig == signal.SIGTERM: - log_info("Caught SIGTERM - exiting...") - sys.exit(128 + sig) - else: - log_warning("Caught unhandled signal '" + sig + "'") +# ========================== MlnxSfpd class ========================== +class MlnxSfpd: + ''' Listen to plugin/plugout cable events ''' + SX_OPEN_RETRIES = 20 + SELECT_TIMEOUT = 1 -def sx_recv(fd_p, handle): - # recv parameters - pkt_size = 2000 - pkt_size_p = new_uint32_t_p() - uint32_t_p_assign(pkt_size_p, pkt_size) - pkt = new_uint8_t_arr(pkt_size) - recv_info_p = new_sx_receive_info_t_p() - pmpe_t = sx_event_pmpe_t() - logical_port_list = new_sx_port_log_id_t_arr(4) - port_attributes_list = new_sx_port_attributes_t_arr(64) - port_cnt_p = new_uint32_t_p() - uint32_t_p_assign(port_cnt_p,64) - label_port_list = [] - status = True - module_state = 0 + def __init__(self): + self.swid = 0 + self.running = False + self.handle = None - rc = sx_lib_host_ifc_recv(fd_p, pkt, pkt_size_p, recv_info_p) - if rc != 0: - log_error("event receive exit with error, rc %d" % rc) - status = False - return status, label_port_list, module_state + # Allocate SDK fd and user channel structures + self.rx_fd_p = new_sx_fd_t_p() + self.user_channel_p = new_sx_user_channel_t_p() - pmpe_t = recv_info_p.event_info.pmpe - port_list_size = pmpe_t.list_size - logical_port_list = pmpe_t.log_port_list - module_state = pmpe_t.module_state + self.state_db = SonicV2Connector(host=REDIS_HOSTIP) - for i in range(0, port_list_size): - logical_port = sx_port_log_id_t_arr_getitem(logical_port_list, i) - rc = sx_api_port_device_get(handle, 1 , 0, port_attributes_list, port_cnt_p) - port_cnt = uint32_t_p_value(port_cnt_p) + # Register our signal handlers + signal.signal(signal.SIGHUP, self.signal_handler) + signal.signal(signal.SIGINT, self.signal_handler) + signal.signal(signal.SIGTERM, self.signal_handler) - for i in range(0, port_cnt): - port_attributes = sx_port_attributes_t_arr_getitem(port_attributes_list,i) - if port_attributes.log_port == logical_port: - lable_port = port_attributes.port_mapping.module_port + def signal_handler(self, signum, frame): + if signum == signal.SIGHUP: + log_info("Caught SIGHUP - ignoring...") + elif signum == signal.SIGINT: + log_info("Caught SIGINT - exiting...") + self.running = False + elif signum == signal.SIGTERM: + log_info("Caught SIGINT - exiting...") + self.running = False + else: + log_warning("Caught unhandled signal '{}'".format(signum)) + + def initialize(self): + self.state_db.connect("STATE_DB") + + # open SDK API handle + # retry at most SX_OPEN_RETRIES times to wait + # until SDK is started during system startup + retry = 1 + while True: + rc, self.handle = sx_api_open(None) + if rc == SX_STATUS_SUCCESS: break - label_port_list.append(lable_port) - return status, label_port_list, module_state, + log_warning("failed to open SDK API handle... retrying {}".format(retry)) -def send_sfp_notification(db, interface, state): - sfp_notify = [interface, state] - msg = json.dumps(sfp_notify, separators=(',', ':')) - db.publish('STATE_DB', 'TRANSCEIVER_NOTIFY', msg) - return + time.sleep(2 ** retry) + retry += 1 -def update_sfpd_liveness_key(db, timeout_secs): - if db.exists('STATE_DB', 'MLNX_SFPD_TASK|LIVENESS'): - db.expire('STATE_DB', 'MLNX_SFPD_TASK|LIVENESS', timeout_secs) - else: - db.set('STATE_DB', 'MLNX_SFPD_TASK|LIVENESS', 'value', 'ok') - db.expire('STATE_DB', 'MLNX_SFPD_TASK|LIVENESS', timeout_secs) + if retry > self.SX_OPEN_RETRIES: + raise RuntimeError("failed to open SDK API handle after {} retries".format(retry)) -# Timer thread wrapper class to update mlnx-sfpd liveness info to DB periodically -class sfpd_liveness_update_task: - def __init__(self, db): - self.task_stopping_event = threading.Event() - self.task_timer = None - self.state_db = db + rc = sx_api_host_ifc_open(self.handle, self.rx_fd_p) + if rc != SX_STATUS_SUCCESS: + raise RuntimeError("sx_api_host_ifc_open exited with error, rc {}".format(rc)) - def task_run(self): - if self.task_stopping_event.isSet(): - log_error("Error: sfpd liveness update thread received stop event, exiting...") + self.user_channel_p.type = SX_USER_CHANNEL_TYPE_FD + self.user_channel_p.channel.fd = self.rx_fd_p + + rc = sx_api_host_ifc_trap_id_register_set(self.handle, + SX_ACCESS_CMD_REGISTER, + self.swid, + SX_TRAP_ID_PMPE, + self.user_channel_p) + if rc != SX_STATUS_SUCCESS: + raise RuntimeError("sx_api_host_ifc_trap_id_register_set exited with error, rc {}".format(c)) + + def deinitialize(self): + # remove mlnx-sfpd liveness key in DB if not expired yet + if self.state_db.exists("STATE_DB", "MLNX_SFPD_TASK|LIVENESS"): + self.state_db.delete("STATE_DB", "MLNX_SFPD_TASK|LIVENESS") + + if self.handle is None: return - update_sfpd_liveness_key(self.state_db, 2*SFPD_LIVENESS_UPDATE_INTERVAL_SECS) + # unregister trap id + rc = sx_api_host_ifc_trap_id_register_set(self.handle, + SX_ACCESS_CMD_DEREGISTER, + self.swid, + SX_TRAP_ID_PMPE, + self.user_channel_p) + if rc != SX_STATUS_SUCCESS: + log_error("sx_api_host_ifc_trap_id_register_set exited with error, rc {}".format(rc)) - self.task_timer = threading.Timer(SFPD_LIVENESS_UPDATE_INTERVAL_SECS, self.task_run) - self.task_timer.start() + rc = sx_api_host_ifc_close(self.handle, self.rx_fd_p) + if rc != SX_STATUS_SUCCESS: + log_error("sx_api_host_ifc_close exited with error, rc {}".format(rc)) - def task_stop(self): - self.task_stopping_event.set() - self.task_timer.join() + rc = sx_api_close(self.handle) + if rc != SX_STATUS_SUCCESS: + log_error("sx_api_close exited with error, rc {}".format(rc)) + + def run(self): + self.running = True + + while self.running: + try: + read, _, _ = select.select([self.rx_fd_p.fd], [], [], self.SELECT_TIMEOUT) + except select.error as err: + rc, msg = err + if rc == errno.EAGAIN or rc == errno.EINTR: + continue + else: + raise + + for fd in read: + if fd == self.rx_fd_p.fd: + success, port_list, module_state = self.on_pmpe(self.rx_fd_p) + if not success: + raise RuntimeError("failed to read from {}".format(fd)) + + sfp_state = sfp_value_status_dict.get(module_state, STATUS_UNKNOWN) + if sfp_state == STATUS_UNKNOWN: + log_error("unknown module state {} on port {}".format(module_state, port)) + continue + + for port in port_list: + log_info("SFP on port {} state {}".format(port, sfp_state)) + self.send_sfp_notification(str(port), sfp_state) + + self.update_sfpd_liveness_key(SFPD_LIVENESS_EXPIRE_SECS) + + def send_sfp_notification(self, port, state): + sfp_notify = [port, state] + msg = json.dumps(sfp_notify, separators=(',', ':')) + self.state_db.publish('STATE_DB', 'TRANSCEIVER_NOTIFY', msg) + + def update_sfpd_liveness_key(self, timeout_secs): + if not self.state_db.exists('STATE_DB', 'MLNX_SFPD_TASK|LIVENESS'): + self.state_db.set('STATE_DB', 'MLNX_SFPD_TASK|LIVENESS', 'value', 'ok') + self.state_db.expire('STATE_DB', 'MLNX_SFPD_TASK|LIVENESS', timeout_secs) + + def on_pmpe(self, fd_p): + ''' on port module plug event handler ''' + + # recv parameters + pkt_size = 2000 + pkt_size_p = new_uint32_t_p() + uint32_t_p_assign(pkt_size_p, pkt_size) + pkt = new_uint8_t_arr(pkt_size) + recv_info_p = new_sx_receive_info_t_p() + pmpe_t = sx_event_pmpe_t() + logical_port_list = new_sx_port_log_id_t_arr(4) + port_attributes_list = new_sx_port_attributes_t_arr(64) + port_cnt_p = new_uint32_t_p() + uint32_t_p_assign(port_cnt_p,64) + label_port_list = [] + status = True + module_state = 0 + + rc = sx_lib_host_ifc_recv(fd_p, pkt, pkt_size_p, recv_info_p) + if rc != 0: + log_error("sx_lib_host_ifc_recv exited with error, rc %d" % rc) + status = False + return status, label_port_list, module_state + + pmpe_t = recv_info_p.event_info.pmpe + port_list_size = pmpe_t.list_size + logical_port_list = pmpe_t.log_port_list + module_state = pmpe_t.module_state + + for i in xrange(port_list_size): + logical_port = sx_port_log_id_t_arr_getitem(logical_port_list, i) + rc = sx_api_port_device_get(self.handle, 1 , 0, port_attributes_list, port_cnt_p) + port_cnt = uint32_t_p_value(port_cnt_p) + + for i in xrange(port_cnt): + port_attributes = sx_port_attributes_t_arr_getitem(port_attributes_list,i) + if port_attributes.log_port == logical_port: + lable_port = port_attributes.port_mapping.module_port + break + label_port_list.append(lable_port) + + return status, label_port_list, module_state, # main start def main(): - # Register our signal handlers - signal.signal(signal.SIGHUP, signal_handler) - signal.signal(signal.SIGINT, signal_handler) - signal.signal(signal.SIGTERM, signal_handler) + log_info("mlnx-sfpd daemon started") - # Connect to state db for notification sending - state_db = SonicV2Connector(host=REDIS_HOSTIP) - state_db.connect(state_db.STATE_DB) + sfpd = MlnxSfpd() + try: + sfpd.initialize() + sfpd.run() + except (RuntimeError, select.error) as err: + log_error("error: {}".format(err)) + finally: + sfpd.deinitialize() - # Open SDK handler - log_info("starting mlnx-sfpd...") - rc, handle = sx_api_open(None) - retry_time = 1 - while rc != SX_STATUS_SUCCESS: - time.sleep(2**retry_time) - retry_time += 1 - rc, handle = sx_api_open(None) - if retry_time > 20: - log_error("Failed to open api handle. Please check that SDK is running.") - sys.exit(errno.EACCES) - - # Open recv fd - rx_fd_p = new_sx_fd_t_p() - rc = sx_api_host_ifc_open(handle, rx_fd_p) - if rc != 0: - log_error("sx_api_host_ifc_open exit with error, rc %d" % rc) - exit(rc) - - # Set up general host ifc parameters - swid = 0 - cmd = SX_ACCESS_CMD_REGISTER - uc_p = new_sx_user_channel_t_p() - uc_p.type = SX_USER_CHANNEL_TYPE_FD - uc_p.channel.fd = rx_fd_p - trap_id = SX_TRAP_ID_PMPE - - rc = sx_api_host_ifc_trap_id_register_set(handle, cmd, swid, trap_id, uc_p) - if rc != 0: - log_error("sx_api_host_ifc_trap_id_register_set exit with error, rc %d" % rc) - exit(rc) - - liveness_info_update = sfpd_liveness_update_task(state_db) - liveness_info_update.task_run() - - # Main loop for sfp event listening - log_info("mlnx-sfpd started") - while True: - sfp_state = STATUS_UNKNOWN - rc, port_list, module_state = sx_recv(rx_fd_p, handle) - if not rc: - log_error("Failed to recv event from SDK, please check that SDK is running.") - break - - if module_state in sfp_value_status_dict: sfp_state = sfp_value_status_dict[module_state] - - if sfp_state != STATUS_UNKNOWN: - for port in port_list: - log_info("SFP on port %d state %s" % (port, sfp_state)) - send_sfp_notification(state_db, str(port), sfp_state) - - log_info("sfp change event handling done") - - # Stop liveness update task - liveness_info_update.task_stop() - - # Remove mlnx-sfpd liveness key in DB if not expired yet. - if state_db.exists('STATE_DB', 'MLNX_SFPD_TASK|LIVENESS'): - state_db.delete(state_db, 'MLNX_SFPD_TASK|LIVENESS') - - # unregister trap id - cmd = SX_ACCESS_CMD_DEREGISTER - rc = sx_api_host_ifc_trap_id_register_set(handle, cmd, swid, trap_id, uc_p) - if rc != 0: - log_error("sx_api_host_ifc_trap_id_register_set exit with error, rc %d" % rc) - exit(rc) - - # Close read fp - rc = sx_api_host_ifc_close(handle, rx_fd_p) - if rc != 0: - log_error("sx_api_host_ifc_close exit with error, rc %d" % rc) - exit(rc) - - # Close sdk handler - rc = sx_api_close(handle) - if rc != 0: - log_error("sx_api_close exit with error, rc %d" % rc) - exit(rc) - - log_info("mlnx-sfpd exited") + log_info("mlnx-sfpd daemon exited") if __name__ == '__main__': diff --git a/platform/mellanox/sdk.mk b/platform/mellanox/sdk.mk index 1d209fd5a3..56ef185cdc 100644 --- a/platform/mellanox/sdk.mk +++ b/platform/mellanox/sdk.mk @@ -62,7 +62,7 @@ $(eval $(call add_derived_package,$(SXD_LIBS),$(SXD_LIBS_DEV))) #packages that are required for runtime only PYTHON_SDK_API = python-sdk-api_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(PYTHON_SDK_API)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/python-sdk-api -$(PYTHON_SDK_API)_DEPENDS += $(APPLIBS_DEV) $(SXD_LIBS_DEV) +$(PYTHON_SDK_API)_DEPENDS += $(APPLIBS_DEV) $(SXD_LIBS_DEV) $(SWIG) $(PYTHON_SDK_API)_RDEPENDS += $(APPLIBS) $(SXD_LIBS) SX_KERNEL = sx-kernel_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb diff --git a/platform/nephos/sai.mk b/platform/nephos/sai.mk index af5d1f4e1d..93265dc74c 100644 --- a/platform/nephos/sai.mk +++ b/platform/nephos/sai.mk @@ -1,6 +1,6 @@ SDK_VERSION = 2.0.8 -SAI_VERSION = 1.4.0 -SAI_COMMIT_ID = c818c7 +SAI_VERSION = 1.4.1 +SAI_COMMIT_ID = cbb99f NEPHOS_SAI = libsainps_$(SDK_VERSION)_sai_$(SAI_VERSION)_$(SAI_COMMIT_ID)_amd64.deb $(NEPHOS_SAI)_URL = "https://github.com/NephosInc/SONiC/raw/master/sai/libsainps_$(SDK_VERSION)_sai_$(SAI_VERSION)_$(SAI_COMMIT_ID)_amd64.deb" diff --git a/platform/vs/docker-sonic-vs/supervisord.conf b/platform/vs/docker-sonic-vs/supervisord.conf index 2507391532..2010dc918e 100644 --- a/platform/vs/docker-sonic-vs/supervisord.conf +++ b/platform/vs/docker-sonic-vs/supervisord.conf @@ -100,7 +100,7 @@ stdout_logfile=syslog stderr_logfile=syslog [program:zebra] -command=/usr/lib/frr/zebra -A 127.0.0.1 +command=/usr/lib/frr/zebra -A 127.0.0.1 -s 90000000 -M fpm priority=13 autostart=false autorestart=false @@ -115,6 +115,14 @@ autorestart=false stdout_logfile=syslog stderr_logfile=syslog +[program:staticd] +command=/usr/lib/frr/staticd -A 127.0.0.1 +priority=14 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + [program:fpmsyncd] command=/usr/bin/fpmsyncd priority=15 diff --git a/rules/docker-base-stretch.mk b/rules/docker-base-stretch.mk index 898e018f9b..a2495ed316 100644 --- a/rules/docker-base-stretch.mk +++ b/rules/docker-base-stretch.mk @@ -16,4 +16,5 @@ ifeq ($(INSTALL_DEBUG_TOOLS),y) $(DOCKER_BASE_STRETCH)_DBG_PACKAGES += $($(DOCKER_BASE_STRETCH)_DBG_IMAGE_PACKAGES) endif +SONIC_DOCKER_IMAGES += $(DOCKER_BASE_STRETCH) SONIC_STRETCH_DOCKERS += $(DOCKER_BASE_STRETCH) diff --git a/rules/docker-config-engine-stretch.mk b/rules/docker-config-engine-stretch.mk index a18ed380f6..2a1e36d288 100644 --- a/rules/docker-config-engine-stretch.mk +++ b/rules/docker-config-engine-stretch.mk @@ -9,4 +9,5 @@ $(DOCKER_CONFIG_ENGINE_STRETCH)_LOAD_DOCKERS += $(DOCKER_BASE_STRETCH) $(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_DEPENDS = $($(DOCKER_BASE_STRETCH)_DBG_DEPENDS) $(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_IMAGE_PACKAGES = $($(DOCKER_BASE_STRETCH)_DBG_IMAGE_PACKAGES) +SONIC_DOCKER_IMAGES += $(DOCKER_CONFIG_ENGINE_STRETCH) SONIC_STRETCH_DOCKERS += $(DOCKER_CONFIG_ENGINE_STRETCH) diff --git a/rules/docker-fpm-frr.mk b/rules/docker-fpm-frr.mk index 22da11f29c..fd593c5cb9 100644 --- a/rules/docker-fpm-frr.mk +++ b/rules/docker-fpm-frr.mk @@ -2,7 +2,7 @@ DOCKER_FPM_FRR = docker-fpm-frr.gz $(DOCKER_FPM_FRR)_PATH = $(DOCKERS_PATH)/docker-fpm-frr -$(DOCKER_FPM_FRR)_DEPENDS += $(FRR) $(FRR_PYTHONTOOLS) $(SWSS) +$(DOCKER_FPM_FRR)_DEPENDS += $(FRR) $(SWSS) $(LIBYANG) $(DOCKER_FPM_FRR)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_STRETCH) SONIC_DOCKER_IMAGES += $(DOCKER_FPM_FRR) diff --git a/rules/docker-ptf.mk b/rules/docker-ptf.mk index 2782c45339..aa517bf16d 100644 --- a/rules/docker-ptf.mk +++ b/rules/docker-ptf.mk @@ -4,3 +4,4 @@ DOCKER_PTF = docker-ptf.gz $(DOCKER_PTF)_PATH = $(DOCKERS_PATH)/docker-ptf $(DOCKER_PTF)_DEPENDS += $(LIBTHRIFT) $(PYTHON_THRIFT) $(PTF) SONIC_DOCKER_IMAGES += $(DOCKER_PTF) +SONIC_JESSIE_DOCKERS += $(DOCKER_PTF) diff --git a/rules/frr.mk b/rules/frr.mk index 3d077c4b05..ac110d03f5 100644 --- a/rules/frr.mk +++ b/rules/frr.mk @@ -1,15 +1,21 @@ # FRRouting (frr) package -FRR_VERSION = 6.0.2 -export FRR_VERSION +FRR_VERSION = 7.0.1 +FRR_SUBVERSION = 0 +export FRR_VERSION FRR_SUBVERSION -FRR = frr_$(FRR_VERSION)-1~sonic.debian9+1_amd64.deb -$(FRR)_DEPENDS += $(LIBSNMP_DEV) + +FRR = frr_$(FRR_VERSION)-sonic-$(FRR_SUBVERSION)_amd64.deb +$(FRR)_DEPENDS += $(LIBSNMP_DEV) $(LIBYANG_DEV) +$(FRR)_RDEPENDS += $(LIBYANG) $(FRR)_SRC_PATH = $(SRC_PATH)/sonic-frr SONIC_MAKE_DEBS += $(FRR) +SONIC_STRETCH_DEBS += $(FRR) -# FRRouting pythontools -FRR_PYTHONTOOLS = frr-pythontools_$(FRR_VERSION)-1~sonic.debian9+1_amd64.deb -$(FRR_PYTHONTOOLS)_DEPENDS += $(LIBSNMP_DEV) -$(FRR_PYTHONTOOLS)_SRC_PATH = $(SRC_PATH)/sonic-frr -SONIC_MAKE_DEBS += $(FRR_PYTHONTOOLS) +FRR_PYTHONTOOLS = frr-pythontools_$(FRR_VERSION)-sonic-$(FRR_SUBVERSION)_all.deb +$(eval $(call add_derived_package,$(FRR),$(FRR_PYTHONTOOLS))) + +FRR_DBG = frr-dbgsym_$(FRR_VERSION)-sonic-$(FRR_SUBVERSION)_amd64.deb +$(eval $(call add_derived_package,$(FRR),$(FRR_DBG))) + +export FRR FRR_PYTHONTOOLS FRR_DBG diff --git a/rules/libyang.mk b/rules/libyang.mk new file mode 100644 index 0000000000..e2dabdf304 --- /dev/null +++ b/rules/libyang.mk @@ -0,0 +1,20 @@ +# libyang + +LIBYANG_VERSION_BASE = 0.16 +LIBYANG_VERSION = $(LIBYANG_VERSION_BASE).105 +LIBYANG_SUBVERSION = 1 + +export LIBYANG_VERSION_BASE +export LIBYANG_VERSION +export LIBYANG_SUBVERSION + +LIBYANG = libyang$(LIBYANG_VERSION_BASE)_$(LIBYANG_VERSION)-$(LIBYANG_SUBVERSION)_amd64.deb +$(LIBYANG)_SRC_PATH = $(SRC_PATH)/libyang +$(LIBYANG)_DEPENDS += $(SWIG_BASE) $(SWIG) +SONIC_MAKE_DEBS += $(LIBYANG) +SONIC_STRETCH_DEBS += $(LIBYANG) + +LIBYANG_DEV = libyang-dev_$(LIBYANG_VERSION)-$(LIBYANG_SUBVERSION)_amd64.deb +$(eval $(call add_derived_package,$(LIBYANG),$(LIBYANG_DEV))) + +export LIBYANG LIBYANG_DEV diff --git a/rules/swig.mk b/rules/swig.mk new file mode 100644 index 0000000000..630ac81c9c --- /dev/null +++ b/rules/swig.mk @@ -0,0 +1,22 @@ +# swig + +SWIG_VERSION_BASE = 3.0 +SWIG_VERSION = $(SWIG_VERSION_BASE).12 +SWIG_SUBVERSION = 2 + +export SWIG_VERSION_BASE +export SWIG_VERSION +export SWIG_SUBVERSION + +SWIG_BASE = swig$(SWIG_VERSION_BASE)_$(SWIG_VERSION)-$(SWIG_SUBVERSION)_amd64.deb +$(SWIG_BASE)_SRC_PATH = $(SRC_PATH)/swig +SONIC_MAKE_DEBS += $(SWIG_BASE) +SONIC_STRETCH_DEBS += $(SWIG_BASE) + +SWIG = swig_$(SWIG_VERSION)-$(SWIG_SUBVERSION)_amd64.deb +$(eval $(call add_derived_package,$(SWIG_BASE),$(SWIG))) + +SWIG_DBG = swig$(SWIG_VERSION_BASE)-dbgsym_$(SWIG_VERSION)-$(SWIG_SUBVERSION)_amd64.deb +$(eval $(call add_derived_package,$(SWIG_BASE),$(SWIG_DBG))) + +export SWIG_BASE SWIG SWIG_DBG diff --git a/rules/swss-common.mk b/rules/swss-common.mk index 623410d4cd..c8e21d7d5f 100644 --- a/rules/swss-common.mk +++ b/rules/swss-common.mk @@ -4,7 +4,7 @@ LIBSWSSCOMMON = libswsscommon_1.0.0_amd64.deb $(LIBSWSSCOMMON)_SRC_PATH = $(SRC_PATH)/sonic-swss-common $(LIBSWSSCOMMON)_DEPENDS += $(LIBHIREDIS_DEV) $(LIBNL3_DEV) $(LIBNL_GENL3_DEV) \ $(LIBNL_ROUTE3_DEV) $(LIBNL_NF3_DEV) \ - $(LIBNL_CLI_DEV) + $(LIBNL_CLI_DEV) $(SWIG) $(LIBSWSSCOMMON)_RDEPENDS += $(LIBHIREDIS) $(LIBNL3) $(LIBNL_GENL3) \ $(LIBNL_ROUTE3) $(LIBNL_NF3) $(LIBNL_CLI) SONIC_DPKG_DEBS += $(LIBSWSSCOMMON) diff --git a/slave.mk b/slave.mk index 0e6e2adcb3..6cedda6120 100644 --- a/slave.mk +++ b/slave.mk @@ -471,17 +471,17 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_SIMPLE_DOCKER_IMAGES)) : $(TARGET_PATH)/%.g SONIC_TARGET_LIST += $(addprefix $(TARGET_PATH)/, $(SONIC_SIMPLE_DOCKER_IMAGES)) -# Build stretch docker images only in stretch slave docker, +# Build jessie docker images only in jessie slave docker, # jessie docker images only in jessie slave docker -ifeq ($(BLDENV),stretch) +ifeq ($(BLDENV),) DOCKER_IMAGES_FOR_INSTALLERS := $(sort $(foreach installer,$(SONIC_INSTALLERS),$($(installer)_DOCKERS))) - DOCKER_IMAGES := $(SONIC_STRETCH_DOCKERS) - DOCKER_DBG_IMAGES := $(SONIC_STRETCH_DBG_DOCKERS) - SONIC_STRETCH_DOCKERS_FOR_INSTALLERS = $(filter $(SONIC_STRETCH_DOCKERS),$(DOCKER_IMAGES_FOR_INSTALLERS) $(EXTRA_STRETCH_TARGETS)) - SONIC_STRETCH_DBG_DOCKERS_FOR_INSTALLERS = $(filter $(SONIC_STRETCH_DBG_DOCKERS), $(patsubst %.gz,%-$(DBG_IMAGE_MARK).gz, $(SONIC_STRETCH_DOCKERS_FOR_INSTALLERS))) + DOCKER_IMAGES := $(SONIC_JESSIE_DOCKERS) + DOCKER_DBG_IMAGES := $(SONIC_JESSIE_DBG_DOCKERS) + SONIC_JESSIE_DOCKERS_FOR_INSTALLERS = $(filter $(SONIC_JESSIE_DOCKERS),$(DOCKER_IMAGES_FOR_INSTALLERS) $(EXTRA_JESSIE_TARGETS)) + SONIC_JESSIE_DBG_DOCKERS_FOR_INSTALLERS = $(filter $(SONIC_JESSIE_DBG_DOCKERS), $(patsubst %.gz,%-$(DBG_IMAGE_MARK).gz, $(SONIC_JESSIE_DOCKERS_FOR_INSTALLERS))) else - DOCKER_IMAGES := $(filter-out $(SONIC_STRETCH_DOCKERS), $(SONIC_DOCKER_IMAGES)) - DOCKER_DBG_IMAGES := $(filter-out $(SONIC_STRETCH_DBG_DOCKERS), $(SONIC_DOCKER_DBG_IMAGES)) + DOCKER_IMAGES := $(filter-out $(SONIC_JESSIE_DOCKERS), $(SONIC_DOCKER_IMAGES)) + DOCKER_DBG_IMAGES := $(filter-out $(SONIC_JESSIE_DBG_DOCKERS), $(SONIC_DOCKER_DBG_IMAGES)) endif # Targets for building docker images @@ -593,6 +593,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ $(HEADER) # Pass initramfs and linux kernel explicitly. They are used for all platforms export debs_path="$(STRETCH_DEBS_PATH)" + export files_path="$(FILES_PATH)" export python_debs_path="$(PYTHON_DEBS_PATH)" export initramfs_tools="$(STRETCH_DEBS_PATH)/$(INITRAMFS_TOOLS)" export linux_kernel="$(STRTCH_DEBS_PATH)/$(LINUX_KERNEL)" @@ -719,6 +720,7 @@ stretch : $$(addprefix $(DEBS_PATH)/,$$(SONIC_STRETCH_DEBS)) \ $$(addprefix $(TARGET_PATH)/,$$(SONIC_STRETCH_DOCKERS_FOR_INSTALLERS)) \ $$(addprefix $(TARGET_PATH)/,$$(SONIC_STRETCH_DBG_DOCKERS_FOR_INSTALLERS)) +jessie : $$(addprefix $(TARGET_PATH)/,$$(SONIC_JESSIE_DOCKERS_FOR_INSTALLERS)) ############################################################################### ## Standard targets diff --git a/sonic-slave-stretch/Dockerfile b/sonic-slave-stretch/Dockerfile index ac41f1e77c..9d94d11197 100644 --- a/sonic-slave-stretch/Dockerfile +++ b/sonic-slave-stretch/Dockerfile @@ -62,6 +62,11 @@ RUN apt-get update && apt-get install -y \ libjson-c-dev \ libsystemd-dev \ python-ipaddr \ + libcmocka-dev \ + python3-all-dev \ + python3-all-dbg \ + install-info \ + logrotate \ # For libnl3 (local) build cdbs \ # For SAI meta build @@ -109,7 +114,6 @@ RUN apt-get update && apt-get install -y \ dpatch \ libdb-dev \ iptables-dev \ - swig \ ctags \ # For mellanox sai build libtool-bin \ @@ -228,6 +232,10 @@ RUN apt-get update && apt-get install -y \ python3-colorama \ # For initramfs bash-completion \ +# For sonic vs image build + dosfstools \ + qemu-kvm \ + libvirt-clients \ # For lm-sensors librrd8 \ librrd-dev \ @@ -278,6 +286,9 @@ RUN pip3 install redis # For supervisor build RUN pip install meld3 mock +# For vs image build +RUN pip install pexpect==4.6.0 + # For sonic-utilities build RUN pip install mockredispy==2.9.3 RUN pip install pytest-runner==4.4 @@ -286,6 +297,12 @@ RUN pip install setuptools==40.8.0 # Install dependencies for isc-dhcp-relay build RUN apt-get -y build-dep isc-dhcp +# Install vim +RUN apt-get install -y vim + +# Install rsyslog +RUN apt-get install -y rsyslog + RUN cd /usr/src/gtest && cmake . && make -C /usr/src/gtest RUN mkdir /var/run/sshd diff --git a/src/libteam/0013-teamd-lacp-port-admin-down-recv-not-processing.patch b/src/libteam/0013-teamd-lacp-port-admin-down-recv-not-processing.patch new file mode 100644 index 0000000000..6e6c37e096 --- /dev/null +++ b/src/libteam/0013-teamd-lacp-port-admin-down-recv-not-processing.patch @@ -0,0 +1,22 @@ +diff --git a/teamd/teamd_runner_lacp.c b/teamd/teamd_runner_lacp.c +index 4a3fe6b..19592c5 100644 +--- a/teamd/teamd_runner_lacp.c ++++ b/teamd/teamd_runner_lacp.c +@@ -1182,12 +1182,17 @@ static int lacpdu_recv(struct lacp_port *lacp_port) + struct lacpdu lacpdu; + struct sockaddr_ll ll_from; + int err; ++ bool admin_state; + + err = teamd_recvfrom(lacp_port->sock, &lacpdu, sizeof(lacpdu), 0, + (struct sockaddr *) &ll_from, sizeof(ll_from)); + if (err <= 0) + return err; + ++ admin_state = team_get_ifinfo_admin_state(lacp_port->ctx->ifinfo); ++ if (!admin_state) ++ return 0; ++ + return lacpdu_process(lacp_port, &lacpdu); + } + diff --git a/src/libteam/series b/src/libteam/series index e9ef676ce5..76e5e8177c 100644 --- a/src/libteam/series +++ b/src/libteam/series @@ -7,3 +7,4 @@ 0010-teamd-lacp-update-port-state-according-to-partners-sy.patch 0011-libteam-resynchronize-ifinfo-after-lost-RTNLGRP_LINK-.patch 0012-teamd-do-not-process-lacpdu-before-the-port-ifinfo-i.patch +0013-teamd-lacp-port-admin-down-recv-not-processing.patch diff --git a/src/libyang/Makefile b/src/libyang/Makefile new file mode 100644 index 0000000000..99dedcd1a4 --- /dev/null +++ b/src/libyang/Makefile @@ -0,0 +1,21 @@ +.ONESHELL: +SHELL = /bin/bash +.SHELLFLAGS += -e + +MAIN_TARGET = $(LIBYANG) +DERIVED_TARGETS = $(LIBYANG_DEV) + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + rm -fr ./libyang-$(LIBYANG_VERSION) + wget -O libyang_$(LIBYANG_VERSION).orig.tar.gz 'https://sonicstorage.blob.core.windows.net/packages/libyang_0.16.105.orig.tar.gz?sv=2015-04-05&sr=b&sig=yTWDhl6B9TTXWAQ46zpLiNxUib61W7U0%2F%2FGvhRibKOc%3D&se=2046-09-30T22%3A10%3A27Z&sp=r' + wget -O libyang_$(LIBYANG_VERSION).dsc 'https://sonicstorage.blob.core.windows.net/packages/libyang_0.16.105-1.dsc?sv=2015-04-05&sr=b&sig=eLkO5wzB1C5oKNIaUPro4gwrgEC3EygIO6eCyTzHmeI%3D&se=2046-09-30T22%3A10%3A12Z&sp=r' + wget -O libyang_$(LIBYANG_VERSION)-$(LIBYANG_SUBVERSION).debian.tar.xz 'https://sonicstorage.blob.core.windows.net/packages/libyang_0.16.105-1.debian.tar.xz?sv=2015-04-05&sr=b&sig=AH18p7pKK0xIBVxZuA8EMv9%2FhXbCFKmbWAn7Za8%2BZW4%3D&se=2046-09-30T22%3A09%3A36Z&sp=r' + dpkg-source -x libyang_$(LIBYANG_VERSION).dsc + + pushd ./libyang-$(LIBYANG_VERSION) + dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + popd + + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/src/lldpd/Makefile b/src/lldpd/Makefile index ca0f83aa6d..0d0dadbfde 100644 --- a/src/lldpd/Makefile +++ b/src/lldpd/Makefile @@ -17,7 +17,7 @@ DEBIAN_FILE_URL = $(LLDP_URL)/$(DEBIAN_FILE) $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : # Remove any stale files - rm -rf ./lldpd + rm -rf lldpd-$(LLDPD_VERSION) # download debian LLDPDD wget -NO "$(DSC_FILE)" $(DSC_FILE_URL) diff --git a/src/sonic-config-engine/setup.py b/src/sonic-config-engine/setup.py index 8375b6af89..7ca810ce6a 100755 --- a/src/sonic-config-engine/setup.py +++ b/src/sonic-config-engine/setup.py @@ -16,7 +16,7 @@ setup(name='sonic-config-engine', author='Taoyu Li', author_email='taoyl@microsoft.com', url='https://github.com/Azure/sonic-buildimage', - py_modules=['portconfig', 'minigraph', 'openconfig_acl', 'sonic_platform', 'config_samples'], + py_modules=['portconfig', 'minigraph', 'openconfig_acl', 'sonic_device_util', 'config_samples'], scripts=['sonic-cfggen'], install_requires=['lxml', 'jinja2>=2.10', 'netaddr', 'ipaddr', 'pyyaml', 'pyangbind==0.6.0'], test_suite='setup.get_test_suite', diff --git a/src/sonic-config-engine/sonic-cfggen b/src/sonic-config-engine/sonic-cfggen index f923cc4bc6..3f7951248c 100755 --- a/src/sonic-config-engine/sonic-cfggen +++ b/src/sonic-config-engine/sonic-cfggen @@ -28,9 +28,9 @@ from minigraph import minigraph_encoder from minigraph import parse_xml from minigraph import parse_device_desc_xml from portconfig import get_port_config -from sonic_platform import get_machine_info -from sonic_platform import get_platform_info -from sonic_platform import get_system_mac +from sonic_device_util import get_machine_info +from sonic_device_util import get_platform_info +from sonic_device_util import get_system_mac from config_samples import generate_sample_config from config_samples import get_available_config from swsssdk import ConfigDBConnector @@ -109,13 +109,13 @@ TODO(taoyl): Current version of config db only supports BGP admin states. @staticmethod def to_serialized(data): - for table in data: - if type(data[table]) is dict: - data[table] = OrderedDict(natsorted(data[table].items())) - for key in data[table].keys(): - new_key = ConfigDBConnector.serialize_key(key) - if new_key != key: - data[table][new_key] = data[table].pop(key) + if type(data) is dict: + data = OrderedDict(natsorted(data.items())) + for key in data.keys(): + new_key = ConfigDBConnector.serialize_key(key) + if new_key != key: + data[new_key] = data.pop(key) + data[new_key] = FormatConverter.to_serialized(data[new_key]) return data @staticmethod @@ -162,7 +162,7 @@ def main(): group.add_argument("-t", "--template", help="render the data with the template file") group.add_argument("-v", "--var", help="print the value of a variable, support jinja2 expression") group.add_argument("--var-json", help="print the value of a variable, in json format") - group.add_argument("--write-to-db", help="write config into configdb", action='store_true') + group.add_argument("-w", "--write-to-db", help="write config into configdb", action='store_true') group.add_argument("--print-data", help="print all data", action='store_true') group.add_argument("--preset", help="generate sample configuration from a preset template", choices=get_available_config()) args = parser.parse_args() diff --git a/src/sonic-config-engine/sonic_platform.py b/src/sonic-config-engine/sonic_device_util.py similarity index 90% rename from src/sonic-config-engine/sonic_platform.py rename to src/sonic-config-engine/sonic_device_util.py index 370f6e3a42..ac03ca818d 100644 --- a/src/sonic-config-engine/sonic_platform.py +++ b/src/sonic-config-engine/sonic_device_util.py @@ -5,13 +5,17 @@ import subprocess DOCUMENTATION = ''' --- -module: sonic_platform +module: sonic_device_util version_added: "1.9" -short_description: Retrive platform related facts for a device. +short_description: Retrieve device related facts for a device. description: - - Retrieve platform related facts from config files. + - Retrieve device related facts from config files. ''' +''' +TODO: this file shall be renamed and moved to other places in future +to have it shared with multiple applications. +''' def get_machine_info(): if not os.path.isfile('/host/machine.conf'): return None diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index a841f4d19c..5a6c0f62ce 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -65,6 +65,11 @@ class TestCfgGen(TestCase): output = self.run_script(argument) self.assertEqual(output.strip(), 'value1') + def test_var_json_data(self): + argument = '-m "' + self.sample_graph_simple + '" -p "' + self.port_config + '" --var-json VLAN_MEMBER' + output = self.run_script(argument) + self.assertEqual(output.strip(), '{\n "Vlan1000|Ethernet8": {\n "tagging_mode": "untagged"\n }\n}') + def test_read_yaml(self): argument = '-v yml_item -y ' + os.path.join(self.test_dir, 'test.yml') output = self.run_script(argument) diff --git a/src/sonic-frr/Makefile b/src/sonic-frr/Makefile index c2ccffbbeb..48da9c7211 100644 --- a/src/sonic-frr/Makefile +++ b/src/sonic-frr/Makefile @@ -2,29 +2,15 @@ SHELL = /bin/bash .SHELLFLAGS += -e -MAIN_TARGET = frr_$(FRR_VERSION)-1~sonic.debian9+1_amd64.deb -TOOLS_TARGET = frr-pythontools_$(FRR_VERSION)-1~sonic.debian9+1_amd64.deb -MAIN_TARGET_DBG = frr-dbgsym_$(FRR_VERSION)-1~sonic.debian9+1_amd64.deb -DERIVED_TARGET = $(TOOLS_TARGET) $(MAIN_TARGET_DBG) +MAIN_TARGET = $(FRR) +DERIVED_TARGET = $(FRR_PYTHONTOOLS) $(FRR_DBG) $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : - # Build the package pushd ./frr - - # This could very well be tools/tarsource.sh -V -e sonic - tools/tarsource.sh -V - # This is a no-op but here in case the changelog stops being a symlink - debchange -b -v $(FRR_VERSION)-1~sonic.debian9+1 'SONiC FRR debian package build' - sudo apt-get -y install install-info - dpkg-buildpackage -rfakeroot -b -us -uc -Ppkg.frr.nortrlib - cd .. - mv frr_$(FRR_VERSION)-*_amd64.deb $(MAIN_TARGET) - mv frr-pythontools_$(FRR_VERSION)-*_all.deb $(TOOLS_TARGET) - mv frr-dbgsym_$(FRR_VERSION)-*_amd64.deb $(MAIN_TARGET_DBG) + tools/tarsource.sh -V -e '-sonic' + dpkg-buildpackage -rfakeroot -b -us -uc -Ppkg.frr.nortrlib -j$(SONIC_CONFIG_MAKE_JOBS) + popd mv $(DERIVED_TARGET) $* $(DEST)/ - popd - $(addprefix $(DEST)/, $(DERIVED_TARGET)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) - diff --git a/src/sonic-frr/frr b/src/sonic-frr/frr index 5a35fd3759..cd305c0973 160000 --- a/src/sonic-frr/frr +++ b/src/sonic-frr/frr @@ -1 +1 @@ -Subproject commit 5a35fd375978dd7fce99c4b8ba84b0cdd1f32ac3 +Subproject commit cd305c0973be0baa1173e09f9d72e096c03e7e7e diff --git a/src/sonic-linux-kernel b/src/sonic-linux-kernel index 69ba0c13f6..6fc9850e83 160000 --- a/src/sonic-linux-kernel +++ b/src/sonic-linux-kernel @@ -1 +1 @@ -Subproject commit 69ba0c13f6b984b554dd83fadfaace4e856239ae +Subproject commit 6fc9850e83d0cba3f8eff7c98ea371e131be8d8a diff --git a/src/sonic-quagga b/src/sonic-quagga index 81ad4d25b6..2e192c06b8 160000 --- a/src/sonic-quagga +++ b/src/sonic-quagga @@ -1 +1 @@ -Subproject commit 81ad4d25b618755099be6859f387449132a00229 +Subproject commit 2e192c06b8f526cab6fce710ab5da0223b0ba2b1 diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 1b0d609c6f..8bf43a630f 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 1b0d609c6f9acd1cb868898f019eaade071c85ee +Subproject commit 8bf43a630f8c7a6d028fa1c322685d1ee2d11fb1 diff --git a/src/sonic-swss b/src/sonic-swss index f8792d5777..f437f9fa17 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit f8792d5777868f0d831c915c4b3e02a53579854d +Subproject commit f437f9fa173738f9ccf1b59313cc44c3da0a0c99 diff --git a/src/sonic-swss-common b/src/sonic-swss-common index 8af58ad80d..485db073a1 160000 --- a/src/sonic-swss-common +++ b/src/sonic-swss-common @@ -1 +1 @@ -Subproject commit 8af58ad80df531fc7fe1fa197a1caf2c5520dbb3 +Subproject commit 485db073a17d2ac0cd9d6f29b0b8d7c245c66663 diff --git a/src/sonic-utilities b/src/sonic-utilities index 8d974001a9..09806b8614 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit 8d974001a9dcf51f38091011bc1fecd34ca895ab +Subproject commit 09806b861486091d9db5cb75bdd2cc9428e46844 diff --git a/src/swig/Makefile b/src/swig/Makefile new file mode 100644 index 0000000000..f9deda6a83 --- /dev/null +++ b/src/swig/Makefile @@ -0,0 +1,21 @@ +.ONESHELL: +SHELL = /bin/bash +.SHELLFLAGS += -e + +MAIN_TARGET = $(SWIG_BASE) +DERIVED_TARGETS = $(SWIG) $(SWIG_DBG) + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + rm -fr ./swig-$(SWIG_VERSION) *.deb + wget -O swig_$(SWIG_VERSION).orig.tar.gz 'https://sonicstorage.blob.core.windows.net/packages/swig_3.0.12.orig.tar.gz?sv=2015-04-05&sr=b&sig=kcSKFvlTQZst8Dbb8MUfckGbVEZU5sptFqT2HbwOUtA%3D&se=2046-09-30T22%3A11%3A59Z&sp=r' + wget -O swig_$(SWIG_VERSION).dsc 'https://sonicstorage.blob.core.windows.net/packages/swig_3.0.12-2.dsc?sv=2015-04-05&sr=b&sig=k3eLfmWgmCz1Kx8SYcirX18FSQdJ76ifo%2B9rbJBnrf8%3D&se=2046-09-30T22%3A11%3A45Z&sp=r' + wget -O swig_$(SWIG_VERSION)-$(SWIG_SUBVERSION).debian.tar.xz 'https://sonicstorage.blob.core.windows.net/packages/swig_3.0.12-2.debian.tar.xz?sv=2015-04-05&sr=b&sig=SQICTE%2BR1BO7npUBNwTQjo447OaFz%2BooX6VAm912c7g%3D&se=2046-09-30T22%3A11%3A32Z&sp=r' + dpkg-source -x swig_$(SWIG_VERSION).dsc + + pushd ./swig-$(SWIG_VERSION) + dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + popd + + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/src/tacacs/nss/0004-Skip-accessing-tacacs-servers-for-local-non-tacacs-u.patch b/src/tacacs/nss/0004-Skip-accessing-tacacs-servers-for-local-non-tacacs-u.patch new file mode 100644 index 0000000000..fc0dd46376 --- /dev/null +++ b/src/tacacs/nss/0004-Skip-accessing-tacacs-servers-for-local-non-tacacs-u.patch @@ -0,0 +1,81 @@ +From 228d743b907be6346731cacc9c5d2bc78ce6a4e8 Mon Sep 17 00:00:00 2001 +From: Renuka Manavalan +Date: Mon, 6 May 2019 04:23:26 +0000 +Subject: [PATCH 4/4] Skip accessing tacacs servers for local non-tacacs users. + +--- + nss_tacplus.c | 44 +++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 43 insertions(+), 1 deletion(-) + +diff --git a/nss_tacplus.c b/nss_tacplus.c +index aac5246..f2a86e1 100644 +--- a/nss_tacplus.c ++++ b/nss_tacplus.c +@@ -487,7 +487,7 @@ static int create_or_modify_local_user(const char *name, int level, bool existin + /* + * Lookup user in /etc/passwd, and fill up passwd info if found. + */ +-static int lookup_pw_local(char* username, struct pwbuf *pb, bool *found) ++static int lookup_pw_local(const char* username, struct pwbuf *pb, bool *found) + { + FILE *fp; + struct passwd *pw = NULL; +@@ -517,6 +517,45 @@ static int lookup_pw_local(char* username, struct pwbuf *pb, bool *found) + return ret; + } + ++/* ++ * Return true, if user has entry in /etc/passwd and his gecos ++ * does not match with expected gecos for any tacacs user of any ++ * privilege level. ++ */ ++static bool is_non_tacacs_user(const char *name) ++{ ++ char buf[1024]; ++ struct passwd pw; ++ int err = 0; ++ struct pwbuf pwbuf; ++ bool found = false; ++ bool ret = false; ++ ++ pwbuf.buf = buf; ++ pwbuf.pw = &pw; ++ pwbuf.errnop = &err; ++ pwbuf.buflen = sizeof(buf); ++ ++ lookup_pw_local(name, &pwbuf, &found); ++ ++ if (found && (err == 0)) { ++ int i = MIN_TACACS_USER_PRIV; ++ const useradd_info_t *pinfo = &useradd_grp_list[i]; ++ ++ for(; (i <= MAX_TACACS_USER_PRIV); ++i, ++pinfo) { ++ if ((pinfo->info != NULL) && ++ (strcmp(pinfo->info, pwbuf.pw->pw_gecos) == 0)) { ++ break; ++ } ++ } ++ if (i > MAX_TACACS_USER_PRIV) { ++ /* gecos did not match with gecos of any tacacs user info */ ++ ret = true; ++ } ++ } ++ return ret; ++} ++ + /* + * Lookup local user passwd info for TACACS+ user. If not found, local user will + * be created by user mapping strategy. +@@ -768,6 +807,9 @@ enum nss_status _nss_tacplus_getpwnam_r(const char *name, struct passwd *pw, + syslog(LOG_WARNING, "%s: no tacacs server in config for nss_tacplus", + nssname); + } ++ else if(is_non_tacacs_user(name)) { ++ /* It is non-tacacs user, so bail out */ ++ } + else { + /* marshal the args for the lower level functions */ + pbuf.name = (char *)name; +-- +2.17.1 + diff --git a/src/tacacs/nss/Makefile b/src/tacacs/nss/Makefile index d9c858bdcb..308b05f2c1 100644 --- a/src/tacacs/nss/Makefile +++ b/src/tacacs/nss/Makefile @@ -15,6 +15,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : git am ../0001-Modify-user-map-profile.patch git am ../0002-Enable-modifying-local-user-permission.patch git am ../0003-management-vrf-support.patch + git am ../0004-Skip-accessing-tacacs-servers-for-local-non-tacacs-u.patch dpkg-buildpackage -rfakeroot -b -us -uc popd