diff --git a/.gitignore b/.gitignore index 1d926f3507c..cf04d202e7f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,11 @@ target/ *.buildinfo # Subdirectories in src +src/dhcpmon/debian/* +!src/dhcpmon/debian/changelog +!src/dhcpmon/debian/compat +!src/dhcpmon/debian/control +!src/dhcpmon/debian/rules src/hiredis/* !src/hiredis/Makefile src/igb/* @@ -27,6 +32,9 @@ src/libteam/* src/lldpd/* !src/lldpd/Makefile !src/lldpd/patch/ +src/monit/* +!src/monit/Makefile +!src/monit/patch/ src/mpdecimal/* !src/mpdecimal/Makefile src/python-click/* diff --git a/.gitmodules b/.gitmodules index c214cefecb5..072d37a2a5b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -67,3 +67,6 @@ [submodule "src/redis-dump-load"] path = src/redis-dump-load url = https://github.com/p/redis-dump-load.git +[submodule "src/telemetry/sonic-telemetry"] + path = src/telemetry/sonic-telemetry + url = https://github.com/Azure/sonic-telemetry.git diff --git a/build_debian.sh b/build_debian.sh index bd39013dc8e..e29a7b83d2a 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -93,7 +93,7 @@ sudo LANG=C chroot $FILESYSTEM_ROOT mount proc /proc -t proc ## Pointing apt to public apt mirrors and getting latest packages, needed for latest security updates sudo cp files/apt/sources.list $FILESYSTEM_ROOT/etc/apt/ -sudo cp files/apt/apt.conf.d/{81norecommends,apt-{clean,gzip-indexes,no-languages}} $FILESYSTEM_ROOT/etc/apt/apt.conf.d/ +sudo cp files/apt/apt.conf.d/{81norecommends,apt-{clean,gzip-indexes,no-languages},no-check-valid-until} $FILESYSTEM_ROOT/etc/apt/apt.conf.d/ sudo LANG=C chroot $FILESYSTEM_ROOT bash -c 'apt-mark auto `apt-mark showmanual`' ## Note: set lang to prevent locale warnings in your chroot @@ -120,7 +120,7 @@ sudo dpkg --root=$FILESYSTEM_ROOT -i target/debs/initramfs-tools_*.deb || \ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f sudo dpkg --root=$FILESYSTEM_ROOT -i target/debs/linux-image-${LINUX_KERNEL_VERSION}-amd64_*.deb || \ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f -sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install acl +sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install acl dmidecode hdparm ## Update initramfs for booting with squashfs+overlay cat files/initramfs-tools/modules | sudo tee -a $FILESYSTEM_ROOT/etc/initramfs-tools/modules > /dev/null @@ -215,7 +215,6 @@ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y in openssh-server \ python \ python-setuptools \ - monit \ python-apt \ traceroute \ iputils-ping \ @@ -274,10 +273,6 @@ sudo mv $FILESYSTEM_ROOT/grub-pc-bin*.deb $FILESYSTEM_ROOT/$PLATFORM_DIR/x86_64- ## Disable kexec supported reboot which was installed by default sudo sed -i 's/LOAD_KEXEC=true/LOAD_KEXEC=false/' $FILESYSTEM_ROOT/etc/default/kexec -## Modifty ntp default configuration: disable initial jump (add -x), and disable -## jump when time difference is greater than 1000 seconds (remove -g). -sudo sed -i "s/NTPD_OPTS='-g'/NTPD_OPTS='-x'/" $FILESYSTEM_ROOT/etc/default/ntp - ## Fix ping tools permission so non root user can directly use them ## Note: this is a workaround since aufs doesn't support extended attributes ## Ref: https://github.com/moby/moby/issues/5650#issuecomment-303499489 @@ -313,10 +308,6 @@ EOF sudo sed -i 's/^ListenAddress ::/#ListenAddress ::/' $FILESYSTEM_ROOT/etc/ssh/sshd_config sudo sed -i 's/^#ListenAddress 0.0.0.0/ListenAddress 0.0.0.0/' $FILESYSTEM_ROOT/etc/ssh/sshd_config -## Config monit -sudo cp files/image_config/monit/monitrc $FILESYSTEM_ROOT/etc/monit/ -sudo chmod 600 $FILESYSTEM_ROOT/etc/monit/monitrc - ## Config sysctl sudo mkdir -p $FILESYSTEM_ROOT/var/core sudo augtool --autosave " @@ -344,6 +335,12 @@ set /files/etc/sysctl.conf/net.ipv4.conf.all.arp_ignore 2 set /files/etc/sysctl.conf/net.ipv4.neigh.default.base_reachable_time_ms 1800000 set /files/etc/sysctl.conf/net.ipv6.neigh.default.base_reachable_time_ms 1800000 +set /files/etc/sysctl.conf/net.ipv4.neigh.default.gc_thresh1 1024 +set /files/etc/sysctl.conf/net.ipv6.neigh.default.gc_thresh1 1024 +set /files/etc/sysctl.conf/net.ipv4.neigh.default.gc_thresh2 2048 +set /files/etc/sysctl.conf/net.ipv6.neigh.default.gc_thresh2 2048 +set /files/etc/sysctl.conf/net.ipv4.neigh.default.gc_thresh3 4096 +set /files/etc/sysctl.conf/net.ipv6.neigh.default.gc_thresh3 4096 set /files/etc/sysctl.conf/net.ipv6.conf.default.forwarding 1 set /files/etc/sysctl.conf/net.ipv6.conf.all.forwarding 1 diff --git a/device/arista/x86_64-arista_7050_qx32s/Arista-7050QX32S-Q32 b/device/arista/x86_64-arista_7050_qx32s/Arista-7050QX32S-Q32 new file mode 120000 index 00000000000..6a90d8a3ac7 --- /dev/null +++ b/device/arista/x86_64-arista_7050_qx32s/Arista-7050QX32S-Q32 @@ -0,0 +1 @@ +Arista-7050-QX-32S \ No newline at end of file diff --git a/device/celestica/x86_64-cel_seastone-r0/Seastone-DX010-25-50/port_config.ini b/device/celestica/x86_64-cel_seastone-r0/Seastone-DX010-25-50/port_config.ini index e1af29b0262..bcf1388e7c5 100644 --- a/device/celestica/x86_64-cel_seastone-r0/Seastone-DX010-25-50/port_config.ini +++ b/device/celestica/x86_64-cel_seastone-r0/Seastone-DX010-25-50/port_config.ini @@ -1,113 +1,113 @@ # name lanes alias index speed -Ethernet0 65 Eth1/1 0 25000 -Ethernet1 66 Eth1/2 0 25000 -Ethernet2 67 Eth1/3 0 25000 -Ethernet3 68 Eth1/4 0 25000 -Ethernet4 69 Eth2/1 1 25000 -Ethernet5 70 Eth2/2 1 25000 -Ethernet6 71 Eth2/3 1 25000 -Ethernet7 72 Eth2/4 1 25000 -Ethernet8 73 Eth3/1 2 25000 -Ethernet9 74 Eth3/2 2 25000 -Ethernet10 75 Eth3/3 2 25000 -Ethernet11 76 Eth3/4 2 25000 -Ethernet12 77 Eth4/1 3 25000 -Ethernet13 78 Eth4/2 3 25000 -Ethernet14 79 Eth4/3 3 25000 -Ethernet15 80 Eth4/4 3 25000 -Ethernet16 33 Eth5/1 4 25000 -Ethernet17 34 Eth5/2 4 25000 -Ethernet18 35 Eth5/3 4 25000 -Ethernet19 36 Eth5/4 4 25000 -Ethernet20 37 Eth6/1 5 25000 -Ethernet21 38 Eth6/2 5 25000 -Ethernet22 39 Eth6/3 5 25000 -Ethernet23 40 Eth6/4 5 25000 -Ethernet24 41 Eth7/1 6 25000 -Ethernet25 42 Eth7/2 6 25000 -Ethernet26 43 Eth7/3 6 25000 -Ethernet27 44 Eth7/4 6 25000 -Ethernet28 45 Eth8/1 7 25000 -Ethernet29 46 Eth8/2 7 25000 -Ethernet30 47 Eth8/3 7 25000 -Ethernet31 48 Eth8/4 7 25000 -Ethernet32 49 Eth9/1 8 25000 -Ethernet33 50 Eth9/2 8 25000 -Ethernet34 51 Eth9/3 8 25000 -Ethernet35 52 Eth9/4 8 25000 -Ethernet36 53 Eth10/1 9 25000 -Ethernet37 54 Eth10/2 9 25000 -Ethernet38 55 Eth10/3 9 25000 -Ethernet39 56 Eth10/4 9 25000 -Ethernet40 57 Eth11/1 10 25000 -Ethernet41 58 Eth11/2 10 25000 -Ethernet42 59 Eth11/3 10 25000 -Ethernet43 60 Eth11/4 10 25000 -Ethernet44 61 Eth12/1 11 25000 -Ethernet45 62 Eth12/2 11 25000 -Ethernet46 63 Eth12/3 11 25000 -Ethernet47 64 Eth12/4 11 25000 -Ethernet48 81 Eth13/1 12 25000 -Ethernet49 82 Eth13/2 12 25000 -Ethernet50 83 Eth13/3 12 25000 -Ethernet51 84 Eth13/4 12 25000 -Ethernet52 85 Eth14/1 13 25000 -Ethernet53 86 Eth14/2 13 25000 -Ethernet54 87 Eth14/3 13 25000 -Ethernet55 88 Eth14/4 13 25000 -Ethernet56 89 Eth15/1 14 25000 -Ethernet57 90 Eth15/2 14 25000 -Ethernet58 91 Eth15/3 14 25000 -Ethernet59 92 Eth15/4 14 25000 -Ethernet60 93 Eth16/1 15 25000 -Ethernet61 94 Eth16/2 15 25000 -Ethernet62 95 Eth16/3 15 25000 -Ethernet63 96 Eth16/4 15 25000 -Ethernet64 97 Eth17/1 16 25000 -Ethernet65 98 Eth17/2 16 25000 -Ethernet66 99 Eth17/3 16 25000 -Ethernet67 100 Eth17/4 16 25000 -Ethernet68 101 Eth18/1 17 25000 -Ethernet69 102 Eth18/2 17 25000 -Ethernet70 103 Eth18/3 17 25000 -Ethernet71 104 Eth18/4 17 25000 -Ethernet72 105 Eth19/1 18 25000 -Ethernet73 106 Eth19/2 18 25000 -Ethernet74 107 Eth19/3 18 25000 -Ethernet75 108 Eth19/4 18 25000 -Ethernet76 109 Eth20/1 19 25000 -Ethernet77 110 Eth20/2 19 25000 -Ethernet78 111 Eth20/3 19 25000 -Ethernet79 112 Eth20/4 19 25000 -Ethernet80 1 Eth21/1 20 25000 -Ethernet81 2 Eth21/2 20 25000 -Ethernet82 3 Eth21/3 20 25000 -Ethernet83 4 Eth21/4 20 25000 -Ethernet84 5 Eth22/1 21 25000 -Ethernet85 6 Eth22/2 21 25000 -Ethernet86 7 Eth22/3 21 25000 -Ethernet87 8 Eth22/4 21 25000 -Ethernet88 9 Eth23/1 22 25000 -Ethernet89 10 Eth23/2 22 25000 -Ethernet90 11 Eth23/3 22 25000 -Ethernet91 12 Eth23/4 22 25000 -Ethernet92 13 Eth24/1 23 25000 -Ethernet93 14 Eth24/2 23 25000 -Ethernet94 15 Eth24/3 23 25000 -Ethernet95 16 Eth24/4 23 25000 -Ethernet96 17,18 Eth25/1 24 50000 -Ethernet98 19,20 Eth25/2 24 50000 -Ethernet100 21,22 Eth26/1 25 50000 -Ethernet102 23,24 Eth26/2 25 50000 -Ethernet104 25,26 Eth27/1 26 50000 -Ethernet106 27,28 Eth27/2 26 50000 -Ethernet108 29,30 Eth28/1 27 50000 -Ethernet110 31,32 Eth28/2 27 50000 -Ethernet112 113,114 Eth29/1 28 50000 -Ethernet114 115,116 Eth29/2 28 50000 -Ethernet116 117,118 Eth30/1 29 50000 -Ethernet118 119,120 Eth30/2 29 50000 -Ethernet120 121,122 Eth31/1 30 50000 -Ethernet122 123,124 Eth31/2 30 50000 -Ethernet124 125,126 Eth32/1 31 50000 -Ethernet126 127,128 Eth32/2 31 50000 +Ethernet0 65 Eth1/1 1 25000 +Ethernet1 66 Eth1/2 1 25000 +Ethernet2 67 Eth1/3 1 25000 +Ethernet3 68 Eth1/4 1 25000 +Ethernet4 69 Eth2/1 2 25000 +Ethernet5 70 Eth2/2 2 25000 +Ethernet6 71 Eth2/3 2 25000 +Ethernet7 72 Eth2/4 2 25000 +Ethernet8 73 Eth3/1 3 25000 +Ethernet9 74 Eth3/2 3 25000 +Ethernet10 75 Eth3/3 3 25000 +Ethernet11 76 Eth3/4 3 25000 +Ethernet12 77 Eth4/1 4 25000 +Ethernet13 78 Eth4/2 4 25000 +Ethernet14 79 Eth4/3 4 25000 +Ethernet15 80 Eth4/4 4 25000 +Ethernet16 33 Eth5/1 5 25000 +Ethernet17 34 Eth5/2 5 25000 +Ethernet18 35 Eth5/3 5 25000 +Ethernet19 36 Eth5/4 5 25000 +Ethernet20 37 Eth6/1 6 25000 +Ethernet21 38 Eth6/2 6 25000 +Ethernet22 39 Eth6/3 6 25000 +Ethernet23 40 Eth6/4 6 25000 +Ethernet24 41 Eth7/1 7 25000 +Ethernet25 42 Eth7/2 7 25000 +Ethernet26 43 Eth7/3 7 25000 +Ethernet27 44 Eth7/4 7 25000 +Ethernet28 45 Eth8/1 8 25000 +Ethernet29 46 Eth8/2 8 25000 +Ethernet30 47 Eth8/3 8 25000 +Ethernet31 48 Eth8/4 8 25000 +Ethernet32 49 Eth9/1 9 25000 +Ethernet33 50 Eth9/2 9 25000 +Ethernet34 51 Eth9/3 9 25000 +Ethernet35 52 Eth9/4 9 25000 +Ethernet36 53 Eth10/1 10 25000 +Ethernet37 54 Eth10/2 10 25000 +Ethernet38 55 Eth10/3 10 25000 +Ethernet39 56 Eth10/4 10 25000 +Ethernet40 57 Eth11/1 11 25000 +Ethernet41 58 Eth11/2 11 25000 +Ethernet42 59 Eth11/3 11 25000 +Ethernet43 60 Eth11/4 11 25000 +Ethernet44 61 Eth12/1 12 25000 +Ethernet45 62 Eth12/2 12 25000 +Ethernet46 63 Eth12/3 12 25000 +Ethernet47 64 Eth12/4 12 25000 +Ethernet48 81 Eth13/1 13 25000 +Ethernet49 82 Eth13/2 13 25000 +Ethernet50 83 Eth13/3 13 25000 +Ethernet51 84 Eth13/4 13 25000 +Ethernet52 85 Eth14/1 14 25000 +Ethernet53 86 Eth14/2 14 25000 +Ethernet54 87 Eth14/3 14 25000 +Ethernet55 88 Eth14/4 14 25000 +Ethernet56 89 Eth15/1 15 25000 +Ethernet57 90 Eth15/2 15 25000 +Ethernet58 91 Eth15/3 15 25000 +Ethernet59 92 Eth15/4 15 25000 +Ethernet60 93 Eth16/1 16 25000 +Ethernet61 94 Eth16/2 16 25000 +Ethernet62 95 Eth16/3 16 25000 +Ethernet63 96 Eth16/4 16 25000 +Ethernet64 97 Eth17/1 17 25000 +Ethernet65 98 Eth17/2 17 25000 +Ethernet66 99 Eth17/3 17 25000 +Ethernet67 100 Eth17/4 17 25000 +Ethernet68 101 Eth18/1 18 25000 +Ethernet69 102 Eth18/2 18 25000 +Ethernet70 103 Eth18/3 18 25000 +Ethernet71 104 Eth18/4 18 25000 +Ethernet72 105 Eth19/1 19 25000 +Ethernet73 106 Eth19/2 19 25000 +Ethernet74 107 Eth19/3 19 25000 +Ethernet75 108 Eth19/4 19 25000 +Ethernet76 109 Eth20/1 20 25000 +Ethernet77 110 Eth20/2 20 25000 +Ethernet78 111 Eth20/3 20 25000 +Ethernet79 112 Eth20/4 20 25000 +Ethernet80 1 Eth21/1 21 25000 +Ethernet81 2 Eth21/2 21 25000 +Ethernet82 3 Eth21/3 21 25000 +Ethernet83 4 Eth21/4 21 25000 +Ethernet84 5 Eth22/1 22 25000 +Ethernet85 6 Eth22/2 22 25000 +Ethernet86 7 Eth22/3 22 25000 +Ethernet87 8 Eth22/4 22 25000 +Ethernet88 9 Eth23/1 23 25000 +Ethernet89 10 Eth23/2 23 25000 +Ethernet90 11 Eth23/3 23 25000 +Ethernet91 12 Eth23/4 23 25000 +Ethernet92 13 Eth24/1 24 25000 +Ethernet93 14 Eth24/2 24 25000 +Ethernet94 15 Eth24/3 24 25000 +Ethernet95 16 Eth24/4 24 25000 +Ethernet96 17,18 Eth25/1 25 50000 +Ethernet98 19,20 Eth25/2 25 50000 +Ethernet100 21,22 Eth26/1 26 50000 +Ethernet102 23,24 Eth26/2 26 50000 +Ethernet104 25,26 Eth27/1 27 50000 +Ethernet106 27,28 Eth27/2 27 50000 +Ethernet108 29,30 Eth28/1 28 50000 +Ethernet110 31,32 Eth28/2 28 50000 +Ethernet112 113,114 Eth29/1 29 50000 +Ethernet114 115,116 Eth29/2 29 50000 +Ethernet116 117,118 Eth30/1 30 50000 +Ethernet118 119,120 Eth30/2 30 50000 +Ethernet120 121,122 Eth31/1 31 50000 +Ethernet122 123,124 Eth31/2 31 50000 +Ethernet124 125,126 Eth32/1 32 50000 +Ethernet126 127,128 Eth32/2 32 50000 diff --git a/device/celestica/x86_64-cel_seastone-r0/Seastone-DX010-50-40/port_config.ini b/device/celestica/x86_64-cel_seastone-r0/Seastone-DX010-50-40/port_config.ini index 9a2b38e6da7..0fc9d317176 100644 --- a/device/celestica/x86_64-cel_seastone-r0/Seastone-DX010-50-40/port_config.ini +++ b/device/celestica/x86_64-cel_seastone-r0/Seastone-DX010-50-40/port_config.ini @@ -1,49 +1,49 @@ # name lanes alias index speed -Ethernet0 65,66 Eth1/1 0 50000 -Ethernet2 67,68 Eth1/2 0 50000 -Ethernet4 69,70 Eth2/1 1 50000 -Ethernet6 71,72 Eth2/2 1 50000 -Ethernet8 73,74 Eth3/1 2 50000 -Ethernet10 75,76 Eth3/2 2 50000 -Ethernet12 77,78 Eth4/1 3 50000 -Ethernet14 79,80 Eth4/2 3 50000 -Ethernet16 33,34 Eth5/1 4 50000 -Ethernet18 35,36 Eth5/2 4 50000 -Ethernet20 37,38 Eth6/1 5 50000 -Ethernet22 39,40 Eth6/2 5 50000 -Ethernet24 41,42 Eth7/1 6 50000 -Ethernet26 43,44 Eth7/2 6 50000 -Ethernet28 45,46 Eth8/1 7 50000 -Ethernet30 47,48 Eth8/2 7 50000 -Ethernet32 49,50 Eth9/1 8 50000 -Ethernet34 51,52 Eth9/2 8 50000 -Ethernet36 53,54 Eth10/1 9 50000 -Ethernet38 55,56 Eth10/2 9 50000 -Ethernet40 57,58 Eth11/1 10 50000 -Ethernet42 59,60 Eth11/2 10 50000 -Ethernet44 61,62 Eth12/1 11 50000 -Ethernet46 63,64 Eth12/2 11 50000 -Ethernet48 81,82 Eth13/1 12 50000 -Ethernet50 83,84 Eth13/2 12 50000 -Ethernet52 85,86 Eth14/1 13 50000 -Ethernet54 87,88 Eth14/2 13 50000 -Ethernet56 89,90 Eth15/1 14 50000 -Ethernet58 91,92 Eth15/2 14 50000 -Ethernet60 93,94 Eth16/1 15 50000 -Ethernet62 95,96 Eth16/2 15 50000 -Ethernet64 97,98,99,100 Eth17 16 40000 -Ethernet68 101,102,103,104 Eth18 17 40000 -Ethernet72 105,106,107,108 Eth19 18 40000 -Ethernet76 109,110,111,112 Eth20 19 40000 -Ethernet80 1,2,3,4 Eth21 20 40000 -Ethernet84 5,6,7,8 Eth22 21 40000 -Ethernet88 9,10,11,12 Eth23 22 40000 -Ethernet92 13,14,15,16 Eth24 23 40000 -Ethernet96 17,18,19,20 Eth25 24 40000 -Ethernet100 21,22,23,24 Eth26 25 40000 -Ethernet104 25,26,27,28 Eth27 26 40000 -Ethernet108 29,30,31,32 Eth28 27 40000 -Ethernet112 113,114,115,116 Eth29 28 40000 -Ethernet116 117,118,119,120 Eth30 29 40000 -Ethernet120 121,122,123,124 Eth31 30 40000 -Ethernet124 125,126,127,128 Eth32 31 40000 +Ethernet0 65,66 Eth1/1 1 50000 +Ethernet2 67,68 Eth1/2 1 50000 +Ethernet4 69,70 Eth2/1 2 50000 +Ethernet6 71,72 Eth2/2 2 50000 +Ethernet8 73,74 Eth3/1 3 50000 +Ethernet10 75,76 Eth3/2 3 50000 +Ethernet12 77,78 Eth4/1 4 50000 +Ethernet14 79,80 Eth4/2 4 50000 +Ethernet16 33,34 Eth5/1 5 50000 +Ethernet18 35,36 Eth5/2 5 50000 +Ethernet20 37,38 Eth6/1 6 50000 +Ethernet22 39,40 Eth6/2 6 50000 +Ethernet24 41,42 Eth7/1 7 50000 +Ethernet26 43,44 Eth7/2 7 50000 +Ethernet28 45,46 Eth8/1 8 50000 +Ethernet30 47,48 Eth8/2 8 50000 +Ethernet32 49,50 Eth9/1 9 50000 +Ethernet34 51,52 Eth9/2 9 50000 +Ethernet36 53,54 Eth10/1 10 50000 +Ethernet38 55,56 Eth10/2 10 50000 +Ethernet40 57,58 Eth11/1 11 50000 +Ethernet42 59,60 Eth11/2 11 50000 +Ethernet44 61,62 Eth12/1 12 50000 +Ethernet46 63,64 Eth12/2 12 50000 +Ethernet48 81,82 Eth13/1 13 50000 +Ethernet50 83,84 Eth13/2 13 50000 +Ethernet52 85,86 Eth14/1 14 50000 +Ethernet54 87,88 Eth14/2 14 50000 +Ethernet56 89,90 Eth15/1 15 50000 +Ethernet58 91,92 Eth15/2 15 50000 +Ethernet60 93,94 Eth16/1 16 50000 +Ethernet62 95,96 Eth16/2 16 50000 +Ethernet64 97,98,99,100 Eth17 17 40000 +Ethernet68 101,102,103,104 Eth18 18 40000 +Ethernet72 105,106,107,108 Eth19 19 40000 +Ethernet76 109,110,111,112 Eth20 20 40000 +Ethernet80 1,2,3,4 Eth21 21 40000 +Ethernet84 5,6,7,8 Eth22 22 40000 +Ethernet88 9,10,11,12 Eth23 23 40000 +Ethernet92 13,14,15,16 Eth24 24 40000 +Ethernet96 17,18,19,20 Eth25 25 40000 +Ethernet100 21,22,23,24 Eth26 26 40000 +Ethernet104 25,26,27,28 Eth27 27 40000 +Ethernet108 29,30,31,32 Eth28 28 40000 +Ethernet112 113,114,115,116 Eth29 29 40000 +Ethernet116 117,118,119,120 Eth30 30 40000 +Ethernet120 121,122,123,124 Eth31 31 40000 +Ethernet124 125,126,127,128 Eth32 32 40000 diff --git a/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/buffers.json.j2 b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/buffers.json.j2 new file mode 100644 index 00000000000..2c391214fa6 --- /dev/null +++ b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/buffers.json.j2 @@ -0,0 +1,111 @@ +{# Default values which will be used if no actual configura available #} +{% set default_cable = '40m' %} +{% set default_speed = '10G' %} +{% set default_ports_num = 54 -%} + +{# Port configuration to cable length look-up table #} +{# Each record describes mapping of DUT (DUT port) role and neighbor role to cable length #} +{# Roles described in the minigraph #} +{% set ports2cable = { + 'torrouter_server' : '5m', + 'leafrouter_torrouter' : '40m', + 'spinerouter_leafrouter' : '300m' + } +%} + +{%- macro cable_length(port_name) -%} + {%- set cable_len = [] -%} + {%- for local_port in DEVICE_NEIGHBOR -%} + {%- if local_port == port_name -%} + {%- if DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%} + {%- set neighbor = DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%} + {%- set neighbor_role = neighbor.type -%} + {%- set roles1 = switch_role + '_' + neighbor_role %} + {%- set roles2 = neighbor_role + '_' + switch_role -%} + {%- set roles1 = roles1 | lower -%} + {%- set roles2 = roles2 | lower -%} + {%- if roles1 in ports2cable -%} + {%- if cable_len.append(ports2cable[roles1]) -%}{%- endif -%} + {%- elif roles2 in ports2cable -%} + {%- if cable_len.append(ports2cable[roles2]) -%}{%- endif -%} + {%- endif -%} + {%- endif -%} + {%- endif -%} + {%- endfor -%} + {%- if cable_len -%} + {{ cable_len.0 }} + {%- else -%} + {{ default_cable }} + {%- endif -%} +{% endmacro %} + +{%- if DEVICE_METADATA is defined %} +{%- set switch_role = DEVICE_METADATA['localhost']['type'] %} +{%- endif -%} + +{# Generate list of ports if not defined #} +{% if PORT is not defined %} + {% set PORT = [] %} + {% for port_idx in range(0,default_ports_num) %} + {% if PORT.append("Ethernet%d" % (port_idx)) %}{% endif %} + {% endfor %} +{% endif -%} + +{% set port_names_list = [] %} +{% for port in PORT %} + {%- if port_names_list.append(port) %}{% endif %} +{% endfor %} +{% set port_names = port_names_list | join(',') -%} + +{ + "CABLE_LENGTH": { + "AZURE": { + {% for port in PORT %} + {% set cable = cable_length(port) -%} + "{{ port }}": "{{ cable }}"{%- if not loop.last -%},{% endif %} + + {% endfor %} + } + }, + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "20971328", + "type": "ingress", + "mode": "static" + }, + "ingress_lossy_pool": { + "size": "20971328", + "type": "ingress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "20971328", + "type": "egress", + "mode": "static" + } + }, + "BUFFER_PROFILE": { + "ingress_lossless_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "xon":"78400", + "xoff":"132160", + "size":"3584", + "static_th":"82880" + }, + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossy_pool]", + "size":"3584", + "dynamic_th":"-1" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"3584", + "dynamic_th":"-4" + } + }, + "BUFFER_PG": { + }, + "BUFFER_QUEUE": { + } +} + \ No newline at end of file diff --git a/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/led.bin b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/led.bin new file mode 100644 index 00000000000..201662a1c60 Binary files /dev/null and b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/led.bin differ diff --git a/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/pg_profile_lookup.ini b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/pg_profile_lookup.ini new file mode 100644 index 00000000000..d98b0eca6d1 --- /dev/null +++ b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/pg_profile_lookup.ini @@ -0,0 +1,17 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold + 10000 5m 3584 32256 59136 36736 + 25000 5m 3584 41216 68096 45696 + 40000 5m 3584 47488 74368 51968 + 50000 5m 3584 52864 79744 57344 + 100000 5m 3584 78400 132160 82880 + 10000 40m 3584 32256 59136 36736 + 25000 40m 3584 41216 68096 45696 + 40000 40m 3584 47488 74368 51968 + 50000 40m 3584 52864 79744 57344 + 100000 40m 3584 78400 132160 82880 + 10000 300m 3584 32256 65856 36736 + 25000 300m 3584 41216 84672 45696 + 40000 300m 3584 47488 101024 51968 + 50000 300m 3584 52864 113120 57344 + 100000 300m 3584 78400 198688 82880 \ No newline at end of file diff --git a/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/port_config.ini b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/port_config.ini new file mode 100644 index 00000000000..ab29b7bed9f --- /dev/null +++ b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/port_config.ini @@ -0,0 +1,55 @@ +# name lanes alias index speed +Ethernet0 8 Ethernet1/1 1 10000 +Ethernet1 9 Ethernet2/1 2 10000 +Ethernet2 10 Ethernet3/1 3 10000 +Ethernet3 11 Ethernet4/1 4 10000 +Ethernet4 12 Ethernet5/1 5 10000 +Ethernet5 13 Ethernet6/1 6 10000 +Ethernet6 14 Ethernet7/1 7 10000 +Ethernet7 15 Ethernet8/1 8 10000 +Ethernet8 16 Ethernet9/1 9 10000 +Ethernet9 17 Ethernet10/1 10 10000 +Ethernet10 18 Ethernet11/1 11 10000 +Ethernet11 19 Ethernet12/1 12 10000 +Ethernet12 20 Ethernet13/1 13 10000 +Ethernet13 21 Ethernet14/1 14 10000 +Ethernet14 22 Ethernet15/1 15 10000 +Ethernet15 23 Ethernet16/1 16 10000 +Ethernet16 32 Ethernet17/1 17 10000 +Ethernet17 33 Ethernet18/1 18 10000 +Ethernet18 34 Ethernet19/1 19 10000 +Ethernet19 35 Ethernet20/1 20 10000 +Ethernet20 40 Ethernet21/1 21 10000 +Ethernet21 41 Ethernet22/1 22 10000 +Ethernet22 42 Ethernet23/1 23 10000 +Ethernet23 43 Ethernet24/1 24 10000 +Ethernet24 48 Ethernet25/1 25 10000 +Ethernet25 49 Ethernet26/1 26 10000 +Ethernet26 50 Ethernet27/1 27 10000 +Ethernet27 51 Ethernet28/1 28 10000 +Ethernet28 56 Ethernet29/1 29 10000 +Ethernet29 57 Ethernet30/1 30 10000 +Ethernet30 58 Ethernet31/1 31 10000 +Ethernet31 59 Ethernet32/1 32 10000 +Ethernet32 64 Ethernet33/1 33 10000 +Ethernet33 65 Ethernet34/1 34 10000 +Ethernet34 66 Ethernet35/1 35 10000 +Ethernet35 67 Ethernet36/1 36 10000 +Ethernet36 68 Ethernet37/1 37 10000 +Ethernet37 69 Ethernet38/1 38 10000 +Ethernet38 70 Ethernet39/1 39 10000 +Ethernet39 71 Ethernet40/1 40 10000 +Ethernet40 72 Ethernet41/1 41 10000 +Ethernet41 73 Ethernet42/1 42 10000 +Ethernet42 74 Ethernet43/1 43 10000 +Ethernet43 75 Ethernet44/1 44 10000 +Ethernet44 76 Ethernet45/1 45 10000 +Ethernet45 77 Ethernet46/1 46 10000 +Ethernet46 78 Ethernet47/1 47 10000 +Ethernet47 79 Ethernet48/1 48 10000 +Ethernet48 84,85,86,87 Ethernet49/1 49 100000 +Ethernet49 80,81,82,83 Ethernet50/1 50 100000 +Ethernet50 108,109,110,111 Ethernet51/1 51 100000 +Ethernet51 104,105,106,107 Ethernet52/1 52 100000 +Ethernet52 116,117,118,119 Ethernet53/1 53 100000 +Ethernet53 112,113,114,115 Ethernet54/1 54 100000 diff --git a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.nps.DAC.R0B b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/port_config.nps old mode 100755 new mode 100644 similarity index 82% rename from device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.nps.DAC.R0B rename to device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/port_config.nps index 857e5f1ede5..9c6a5af8e5f --- a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.nps.DAC.R0B +++ b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/port_config.nps @@ -1,60 +1,58 @@ init start stage unit=0 low-level -init set port-map unit=0 port=0 eth-macro=2 lane=0 max-speed=25g active=true -init set port-map unit=0 port=1 eth-macro=2 lane=1 max-speed=25g active=true -init set port-map unit=0 port=2 eth-macro=2 lane=2 max-speed=25g active=true -init set port-map unit=0 port=3 eth-macro=2 lane=3 max-speed=25g active=true -init set port-map unit=0 port=4 eth-macro=3 lane=0 max-speed=25g active=true -init set port-map unit=0 port=5 eth-macro=3 lane=1 max-speed=25g active=true -init set port-map unit=0 port=6 eth-macro=3 lane=2 max-speed=25g active=true -init set port-map unit=0 port=7 eth-macro=3 lane=3 max-speed=25g active=true -init set port-map unit=0 port=8 eth-macro=4 lane=0 max-speed=25g active=true -init set port-map unit=0 port=9 eth-macro=4 lane=1 max-speed=25g active=true -init set port-map unit=0 port=10 eth-macro=4 lane=2 max-speed=25g active=true -init set port-map unit=0 port=11 eth-macro=4 lane=3 max-speed=25g active=true -init set port-map unit=0 port=12 eth-macro=5 lane=0 max-speed=25g active=true -init set port-map unit=0 port=13 eth-macro=5 lane=1 max-speed=25g active=true -init set port-map unit=0 port=14 eth-macro=5 lane=2 max-speed=25g active=true -init set port-map unit=0 port=15 eth-macro=5 lane=3 max-speed=25g active=true -init set port-map unit=0 port=16 eth-macro=8 lane=0 max-speed=25g active=true -init set port-map unit=0 port=17 eth-macro=8 lane=1 max-speed=25g active=true -init set port-map unit=0 port=18 eth-macro=8 lane=2 max-speed=25g active=true -init set port-map unit=0 port=19 eth-macro=8 lane=3 max-speed=25g active=true -init set port-map unit=0 port=20 eth-macro=10 lane=0 max-speed=25g active=true -init set port-map unit=0 port=21 eth-macro=10 lane=1 max-speed=25g active=true -init set port-map unit=0 port=22 eth-macro=10 lane=2 max-speed=25g active=true -init set port-map unit=0 port=23 eth-macro=10 lane=3 max-speed=25g active=true -init set port-map unit=0 port=24 eth-macro=12 lane=0 max-speed=25g active=true -init set port-map unit=0 port=25 eth-macro=12 lane=1 max-speed=25g active=true -init set port-map unit=0 port=26 eth-macro=12 lane=2 max-speed=25g active=true -init set port-map unit=0 port=27 eth-macro=12 lane=3 max-speed=25g active=true -init set port-map unit=0 port=28 eth-macro=14 lane=0 max-speed=25g active=true -init set port-map unit=0 port=29 eth-macro=14 lane=1 max-speed=25g active=true -init set port-map unit=0 port=30 eth-macro=14 lane=2 max-speed=25g active=true -init set port-map unit=0 port=31 eth-macro=14 lane=3 max-speed=25g active=true -init set port-map unit=0 port=32 eth-macro=16 lane=0 max-speed=25g active=true -init set port-map unit=0 port=33 eth-macro=16 lane=1 max-speed=25g active=true -init set port-map unit=0 port=34 eth-macro=16 lane=2 max-speed=25g active=true -init set port-map unit=0 port=35 eth-macro=16 lane=3 max-speed=25g active=true -init set port-map unit=0 port=36 eth-macro=17 lane=0 max-speed=25g active=true -init set port-map unit=0 port=37 eth-macro=17 lane=1 max-speed=25g active=true -init set port-map unit=0 port=38 eth-macro=17 lane=2 max-speed=25g active=true -init set port-map unit=0 port=39 eth-macro=17 lane=3 max-speed=25g active=true -init set port-map unit=0 port=40 eth-macro=18 lane=0 max-speed=25g active=true -init set port-map unit=0 port=41 eth-macro=18 lane=1 max-speed=25g active=true -init set port-map unit=0 port=42 eth-macro=18 lane=2 max-speed=25g active=true -init set port-map unit=0 port=43 eth-macro=18 lane=3 max-speed=25g active=true -init set port-map unit=0 port=44 eth-macro=19 lane=0 max-speed=25g active=true -init set port-map unit=0 port=45 eth-macro=19 lane=1 max-speed=25g active=true -init set port-map unit=0 port=46 eth-macro=19 lane=2 max-speed=25g active=true -init set port-map unit=0 port=47 eth-macro=19 lane=3 max-speed=25g active=true +init set port-map unit=0 port=0 eth-macro=2 lane=0 max-speed=10g active=true +init set port-map unit=0 port=1 eth-macro=2 lane=1 max-speed=10g active=true +init set port-map unit=0 port=2 eth-macro=2 lane=2 max-speed=10g active=true +init set port-map unit=0 port=3 eth-macro=2 lane=3 max-speed=10g active=true +init set port-map unit=0 port=4 eth-macro=3 lane=0 max-speed=10g active=true +init set port-map unit=0 port=5 eth-macro=3 lane=1 max-speed=10g active=true +init set port-map unit=0 port=6 eth-macro=3 lane=2 max-speed=10g active=true +init set port-map unit=0 port=7 eth-macro=3 lane=3 max-speed=10g active=true +init set port-map unit=0 port=8 eth-macro=4 lane=0 max-speed=10g active=true +init set port-map unit=0 port=9 eth-macro=4 lane=1 max-speed=10g active=true +init set port-map unit=0 port=10 eth-macro=4 lane=2 max-speed=10g active=true +init set port-map unit=0 port=11 eth-macro=4 lane=3 max-speed=10g active=true +init set port-map unit=0 port=12 eth-macro=5 lane=0 max-speed=10g active=true +init set port-map unit=0 port=13 eth-macro=5 lane=1 max-speed=10g active=true +init set port-map unit=0 port=14 eth-macro=5 lane=2 max-speed=10g active=true +init set port-map unit=0 port=15 eth-macro=5 lane=3 max-speed=10g active=true +init set port-map unit=0 port=16 eth-macro=8 lane=0 max-speed=10g active=true +init set port-map unit=0 port=17 eth-macro=8 lane=1 max-speed=10g active=true +init set port-map unit=0 port=18 eth-macro=8 lane=2 max-speed=10g active=true +init set port-map unit=0 port=19 eth-macro=8 lane=3 max-speed=10g active=true +init set port-map unit=0 port=20 eth-macro=10 lane=0 max-speed=10g active=true +init set port-map unit=0 port=21 eth-macro=10 lane=1 max-speed=10g active=true +init set port-map unit=0 port=22 eth-macro=10 lane=2 max-speed=10g active=true +init set port-map unit=0 port=23 eth-macro=10 lane=3 max-speed=10g active=true +init set port-map unit=0 port=24 eth-macro=12 lane=0 max-speed=10g active=true +init set port-map unit=0 port=25 eth-macro=12 lane=1 max-speed=10g active=true +init set port-map unit=0 port=26 eth-macro=12 lane=2 max-speed=10g active=true +init set port-map unit=0 port=27 eth-macro=12 lane=3 max-speed=10g active=true +init set port-map unit=0 port=28 eth-macro=14 lane=0 max-speed=10g active=true +init set port-map unit=0 port=29 eth-macro=14 lane=1 max-speed=10g active=true +init set port-map unit=0 port=30 eth-macro=14 lane=2 max-speed=10g active=true +init set port-map unit=0 port=31 eth-macro=14 lane=3 max-speed=10g active=true +init set port-map unit=0 port=32 eth-macro=16 lane=0 max-speed=10g active=true +init set port-map unit=0 port=33 eth-macro=16 lane=1 max-speed=10g active=true +init set port-map unit=0 port=34 eth-macro=16 lane=2 max-speed=10g active=true +init set port-map unit=0 port=35 eth-macro=16 lane=3 max-speed=10g active=true +init set port-map unit=0 port=36 eth-macro=17 lane=0 max-speed=10g active=true +init set port-map unit=0 port=37 eth-macro=17 lane=1 max-speed=10g active=true +init set port-map unit=0 port=38 eth-macro=17 lane=2 max-speed=10g active=true +init set port-map unit=0 port=39 eth-macro=17 lane=3 max-speed=10g active=true +init set port-map unit=0 port=40 eth-macro=18 lane=0 max-speed=10g active=true +init set port-map unit=0 port=41 eth-macro=18 lane=1 max-speed=10g active=true +init set port-map unit=0 port=42 eth-macro=18 lane=2 max-speed=10g active=true +init set port-map unit=0 port=43 eth-macro=18 lane=3 max-speed=10g active=true +init set port-map unit=0 port=44 eth-macro=19 lane=0 max-speed=10g active=true +init set port-map unit=0 port=45 eth-macro=19 lane=1 max-speed=10g active=true +init set port-map unit=0 port=46 eth-macro=19 lane=2 max-speed=10g active=true +init set port-map unit=0 port=47 eth-macro=19 lane=3 max-speed=10g active=true init set port-map unit=0 port=48 eth-macro=21 lane=0 max-speed=100g active=true init set port-map unit=0 port=49 eth-macro=20 lane=0 max-speed=100g active=true -init set port-map unit=0 port=50 eth-macro=23 lane=0 max-speed=100g active=true -init set port-map unit=0 port=51 eth-macro=22 lane=0 max-speed=100g active=true -init set port-map unit=0 port=52 eth-macro=27 lane=0 max-speed=100g active=true -init set port-map unit=0 port=53 eth-macro=26 lane=0 max-speed=100g active=true -init set port-map unit=0 port=54 eth-macro=29 lane=0 max-speed=100g active=true -init set port-map unit=0 port=55 eth-macro=28 lane=0 max-speed=100g active=true +init set port-map unit=0 port=50 eth-macro=27 lane=0 max-speed=100g active=true +init set port-map unit=0 port=51 eth-macro=26 lane=0 max-speed=100g active=true +init set port-map unit=0 port=52 eth-macro=29 lane=0 max-speed=100g active=true +init set port-map unit=0 port=53 eth-macro=28 lane=0 max-speed=100g active=true init set port-map unit=0 port=129 eth-macro=0 lane=1 max-speed=10g active=true guarantee=true cpi=true init set port-map unit=0 port=130 eth-macro=0 lane=0 max-speed=10g active=true guarantee=true cpi=true init-done=true init start stage unit=0 task-rsrc @@ -110,12 +108,10 @@ phy set lane-swap unit=0 portlist=46 lane-cnt=1 property=tx data=0x2 phy set lane-swap unit=0 portlist=47 lane-cnt=1 property=tx data=0x3 phy set lane-swap unit=0 portlist=48 lane-cnt=4 property=tx data=0x3.0.1.2 phy set lane-swap unit=0 portlist=49 lane-cnt=4 property=tx data=0x3.2.1.0 -phy set lane-swap unit=0 portlist=50 lane-cnt=4 property=tx data=0x0.1.2.3 -phy set lane-swap unit=0 portlist=51 lane-cnt=4 property=tx data=0x3.2.0.1 +phy set lane-swap unit=0 portlist=50 lane-cnt=4 property=tx data=0x3.2.1.0 +phy set lane-swap unit=0 portlist=51 lane-cnt=4 property=tx data=0x3.2.1.0 phy set lane-swap unit=0 portlist=52 lane-cnt=4 property=tx data=0x3.2.1.0 phy set lane-swap unit=0 portlist=53 lane-cnt=4 property=tx data=0x3.2.1.0 -phy set lane-swap unit=0 portlist=54 lane-cnt=4 property=tx data=0x3.2.1.0 -phy set lane-swap unit=0 portlist=55 lane-cnt=4 property=tx data=0x3.2.1.0 phy set lane-swap unit=0 portlist=129 lane-cnt=1 property=tx data=0x1 phy set lane-swap unit=0 portlist=130 lane-cnt=1 property=tx data=0x0 phy set lane-swap unit=0 portlist=0 lane-cnt=1 property=rx data=0x0 @@ -168,12 +164,10 @@ phy set lane-swap unit=0 portlist=46 lane-cnt=1 property=rx data=0x0 phy set lane-swap unit=0 portlist=47 lane-cnt=1 property=rx data=0x3 phy set lane-swap unit=0 portlist=48 lane-cnt=4 property=rx data=0x3.1.0.2 phy set lane-swap unit=0 portlist=49 lane-cnt=4 property=rx data=0x3.2.1.0 -phy set lane-swap unit=0 portlist=50 lane-cnt=4 property=rx data=0x3.0.1.2 -phy set lane-swap unit=0 portlist=51 lane-cnt=4 property=rx data=0x3.2.1.0 +phy set lane-swap unit=0 portlist=50 lane-cnt=4 property=rx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=51 lane-cnt=4 property=rx data=0x2.0.1.3 phy set lane-swap unit=0 portlist=52 lane-cnt=4 property=rx data=0x1.0.3.2 -phy set lane-swap unit=0 portlist=53 lane-cnt=4 property=rx data=0x2.0.1.3 -phy set lane-swap unit=0 portlist=54 lane-cnt=4 property=rx data=0x1.0.3.2 -phy set lane-swap unit=0 portlist=55 lane-cnt=4 property=rx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=53 lane-cnt=4 property=rx data=0x1.0.3.2 phy set lane-swap unit=0 portlist=129 lane-cnt=1 property=rx data=0x1 phy set lane-swap unit=0 portlist=130 lane-cnt=1 property=rx data=0x0 phy set polarity-rev unit=0 portlist=0 lane-cnt=1 property=tx data=0x0 @@ -230,8 +224,6 @@ phy set polarity-rev unit=0 portlist=50 lane-cnt=4 property=tx data=0x0.0.0.0 phy set polarity-rev unit=0 portlist=51 lane-cnt=4 property=tx data=0x0.0.0.0 phy set polarity-rev unit=0 portlist=52 lane-cnt=4 property=tx data=0x0.0.0.0 phy set polarity-rev unit=0 portlist=53 lane-cnt=4 property=tx data=0x0.0.0.0 -phy set polarity-rev unit=0 portlist=54 lane-cnt=4 property=tx data=0x0.0.0.0 -phy set polarity-rev unit=0 portlist=55 lane-cnt=4 property=tx data=0x0.0.0.0 phy set polarity-rev unit=0 portlist=129 lane-cnt=1 property=tx data=0x0 phy set polarity-rev unit=0 portlist=130 lane-cnt=1 property=tx data=0x0 phy set polarity-rev unit=0 portlist=0 lane-cnt=1 property=rx data=0x0 @@ -284,12 +276,10 @@ phy set polarity-rev unit=0 portlist=46 lane-cnt=1 property=rx data=0x0 phy set polarity-rev unit=0 portlist=47 lane-cnt=1 property=rx data=0x0 phy set polarity-rev unit=0 portlist=48 lane-cnt=4 property=rx data=0x0.1.1.0 phy set polarity-rev unit=0 portlist=49 lane-cnt=4 property=rx data=0x0.0.0.0 -phy set polarity-rev unit=0 portlist=50 lane-cnt=4 property=rx data=0x1.1.1.1 +phy set polarity-rev unit=0 portlist=50 lane-cnt=4 property=rx data=0x1.1.1.0 phy set polarity-rev unit=0 portlist=51 lane-cnt=4 property=rx data=0x0.0.0.0 phy set polarity-rev unit=0 portlist=52 lane-cnt=4 property=rx data=0x1.1.1.0 phy set polarity-rev unit=0 portlist=53 lane-cnt=4 property=rx data=0x0.0.0.0 -phy set polarity-rev unit=0 portlist=54 lane-cnt=4 property=rx data=0x1.1.1.0 -phy set polarity-rev unit=0 portlist=55 lane-cnt=4 property=rx data=0x0.0.0.0 phy set polarity-rev unit=0 portlist=129 lane-cnt=1 property=rx data=0x0 phy set polarity-rev unit=0 portlist=130 lane-cnt=1 property=rx data=0x0 phy set pre-emphasis unit=0 portlist=0 lane-cnt=1 property=c2 data=0x2 @@ -508,14 +498,6 @@ phy set pre-emphasis unit=0 portlist=53 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis unit=0 portlist=53 lane-cnt=4 property=cn1 data=0x0.0.0.0 phy set pre-emphasis unit=0 portlist=53 lane-cnt=4 property=c0 data=0x1b.1b.1b.1b phy set pre-emphasis unit=0 portlist=53 lane-cnt=4 property=c1 data=0x6.6.6.6 -phy set pre-emphasis unit=0 portlist=54 lane-cnt=4 property=c2 data=0x2.2.2.2 -phy set pre-emphasis unit=0 portlist=54 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis unit=0 portlist=54 lane-cnt=4 property=c0 data=0x1b.1b.1b.1b -phy set pre-emphasis unit=0 portlist=54 lane-cnt=4 property=c1 data=0x6.6.6.6 -phy set pre-emphasis unit=0 portlist=55 lane-cnt=4 property=c2 data=0x2.2.2.2 -phy set pre-emphasis unit=0 portlist=55 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis unit=0 portlist=55 lane-cnt=4 property=c0 data=0x1b.1b.1b.1b -phy set pre-emphasis unit=0 portlist=55 lane-cnt=4 property=c1 data=0x6.6.6.6 phy set pre-emphasis unit=0 portlist=129 lane-cnt=1 property=c2 data=0x1 phy set pre-emphasis unit=0 portlist=129 lane-cnt=1 property=cn1 data=0x1 phy set pre-emphasis unit=0 portlist=129 lane-cnt=1 property=c0 data=0x2 @@ -524,62 +506,60 @@ phy set pre-emphasis unit=0 portlist=130 lane-cnt=1 property=c2 data=0x1 phy set pre-emphasis unit=0 portlist=130 lane-cnt=1 property=cn1 data=0x0 phy set pre-emphasis unit=0 portlist=130 lane-cnt=1 property=c0 data=0x2 phy set pre-emphasis unit=0 portlist=130 lane-cnt=1 property=c1 data=0x3 -port set property unit=0 portlist=0 speed=25g -port set property unit=0 portlist=1 speed=25g -port set property unit=0 portlist=2 speed=25g -port set property unit=0 portlist=3 speed=25g -port set property unit=0 portlist=4 speed=25g -port set property unit=0 portlist=5 speed=25g -port set property unit=0 portlist=6 speed=25g -port set property unit=0 portlist=7 speed=25g -port set property unit=0 portlist=8 speed=25g -port set property unit=0 portlist=9 speed=25g -port set property unit=0 portlist=10 speed=25g -port set property unit=0 portlist=11 speed=25g -port set property unit=0 portlist=12 speed=25g -port set property unit=0 portlist=13 speed=25g -port set property unit=0 portlist=14 speed=25g -port set property unit=0 portlist=15 speed=25g -port set property unit=0 portlist=16 speed=25g -port set property unit=0 portlist=17 speed=25g -port set property unit=0 portlist=18 speed=25g -port set property unit=0 portlist=19 speed=25g -port set property unit=0 portlist=20 speed=25g -port set property unit=0 portlist=21 speed=25g -port set property unit=0 portlist=22 speed=25g -port set property unit=0 portlist=23 speed=25g -port set property unit=0 portlist=24 speed=25g -port set property unit=0 portlist=25 speed=25g -port set property unit=0 portlist=26 speed=25g -port set property unit=0 portlist=27 speed=25g -port set property unit=0 portlist=28 speed=25g -port set property unit=0 portlist=29 speed=25g -port set property unit=0 portlist=30 speed=25g -port set property unit=0 portlist=31 speed=25g -port set property unit=0 portlist=32 speed=25g -port set property unit=0 portlist=33 speed=25g -port set property unit=0 portlist=34 speed=25g -port set property unit=0 portlist=35 speed=25g -port set property unit=0 portlist=36 speed=25g -port set property unit=0 portlist=37 speed=25g -port set property unit=0 portlist=38 speed=25g -port set property unit=0 portlist=39 speed=25g -port set property unit=0 portlist=40 speed=25g -port set property unit=0 portlist=41 speed=25g -port set property unit=0 portlist=42 speed=25g -port set property unit=0 portlist=43 speed=25g -port set property unit=0 portlist=44 speed=25g -port set property unit=0 portlist=45 speed=25g -port set property unit=0 portlist=46 speed=25g -port set property unit=0 portlist=47 speed=25g +port set property unit=0 portlist=0 speed=10g +port set property unit=0 portlist=1 speed=10g +port set property unit=0 portlist=2 speed=10g +port set property unit=0 portlist=3 speed=10g +port set property unit=0 portlist=4 speed=10g +port set property unit=0 portlist=5 speed=10g +port set property unit=0 portlist=6 speed=10g +port set property unit=0 portlist=7 speed=10g +port set property unit=0 portlist=8 speed=10g +port set property unit=0 portlist=9 speed=10g +port set property unit=0 portlist=10 speed=10g +port set property unit=0 portlist=11 speed=10g +port set property unit=0 portlist=12 speed=10g +port set property unit=0 portlist=13 speed=10g +port set property unit=0 portlist=14 speed=10g +port set property unit=0 portlist=15 speed=10g +port set property unit=0 portlist=16 speed=10g +port set property unit=0 portlist=17 speed=10g +port set property unit=0 portlist=18 speed=10g +port set property unit=0 portlist=19 speed=10g +port set property unit=0 portlist=20 speed=10g +port set property unit=0 portlist=21 speed=10g +port set property unit=0 portlist=22 speed=10g +port set property unit=0 portlist=23 speed=10g +port set property unit=0 portlist=24 speed=10g +port set property unit=0 portlist=25 speed=10g +port set property unit=0 portlist=26 speed=10g +port set property unit=0 portlist=27 speed=10g +port set property unit=0 portlist=28 speed=10g +port set property unit=0 portlist=29 speed=10g +port set property unit=0 portlist=30 speed=10g +port set property unit=0 portlist=31 speed=10g +port set property unit=0 portlist=32 speed=10g +port set property unit=0 portlist=33 speed=10g +port set property unit=0 portlist=34 speed=10g +port set property unit=0 portlist=35 speed=10g +port set property unit=0 portlist=36 speed=10g +port set property unit=0 portlist=37 speed=10g +port set property unit=0 portlist=38 speed=10g +port set property unit=0 portlist=39 speed=10g +port set property unit=0 portlist=40 speed=10g +port set property unit=0 portlist=41 speed=10g +port set property unit=0 portlist=42 speed=10g +port set property unit=0 portlist=43 speed=10g +port set property unit=0 portlist=44 speed=10g +port set property unit=0 portlist=45 speed=10g +port set property unit=0 portlist=46 speed=10g +port set property unit=0 portlist=47 speed=10g port set property unit=0 portlist=48 speed=100g port set property unit=0 portlist=49 speed=100g port set property unit=0 portlist=50 speed=100g port set property unit=0 portlist=51 speed=100g port set property unit=0 portlist=52 speed=100g port set property unit=0 portlist=53 speed=100g -port set property unit=0 portlist=54 speed=100g -port set property unit=0 portlist=55 speed=100g port set property unit=0 portlist=129 speed=10g port set property unit=0 portlist=130 speed=1g port set property unit=0 portlist=0 medium-type=sr @@ -636,8 +616,6 @@ port set property unit=0 portlist=50 medium-type=sr4 port set property unit=0 portlist=51 medium-type=sr4 port set property unit=0 portlist=52 medium-type=sr4 port set property unit=0 portlist=53 medium-type=sr4 -port set property unit=0 portlist=54 medium-type=sr4 -port set property unit=0 portlist=55 medium-type=sr4 port set property unit=0 portlist=129 medium-type=kr port set property unit=0 portlist=130 medium-type=x port advertise unit=0 portlist=129 speed-10g-kr @@ -696,7 +674,5 @@ port set property unit=0 portlist=50 admin=enable port set property unit=0 portlist=51 admin=enable port set property unit=0 portlist=52 admin=enable port set property unit=0 portlist=53 admin=enable -port set property unit=0 portlist=54 admin=enable -port set property unit=0 portlist=55 admin=enable -port set property unit=0 portlist=129 admin=enable -port set property unit=0 portlist=130 admin=enable +port set property unit=0 portlist=129 admin=disable +port set property unit=0 portlist=130 admin=disable diff --git a/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/qos.json.j2 b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/qos.json.j2 new file mode 100644 index 00000000000..3e548325ea3 --- /dev/null +++ b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/qos.json.j2 @@ -0,0 +1 @@ +{%- include 'qos_config.j2' %} diff --git a/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/sai.profile b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/sai.profile new file mode 100644 index 00000000000..e7b5f90ac88 --- /dev/null +++ b/device/cig/x86_64-cig_cs5435_54p-r0/Cig-CS5435-54P/sai.profile @@ -0,0 +1,3 @@ +SAI_INIT_LED_CONFIG_FILE=/usr/share/sonic/hwsku/led.bin +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/proc_init.nps +SAI_DSH_CONFIG_FILE=/usr/share/sonic/hwsku/port_config.nps diff --git a/device/cig/x86_64-cig_cs5435_54p-r0/default_sku b/device/cig/x86_64-cig_cs5435_54p-r0/default_sku new file mode 100644 index 00000000000..66b35b61e09 --- /dev/null +++ b/device/cig/x86_64-cig_cs5435_54p-r0/default_sku @@ -0,0 +1 @@ +Cig-CS5435-54P t1 diff --git a/device/cig/x86_64-cig_cs5435_54p-r0/installer.conf b/device/cig/x86_64-cig_cs5435_54p-r0/installer.conf new file mode 100644 index 00000000000..ea6b4f6ebe3 --- /dev/null +++ b/device/cig/x86_64-cig_cs5435_54p-r0/installer.conf @@ -0,0 +1,4 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="pci=noaer" diff --git a/device/cig/x86_64-cig_cs5435_54p-r0/plugins/eeprom.py b/device/cig/x86_64-cig_cs5435_54p-r0/plugins/eeprom.py new file mode 100755 index 00000000000..5019b9c40a9 --- /dev/null +++ b/device/cig/x86_64-cig_cs5435_54p-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/7-0057/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/cig/x86_64-cig_cs5435_54p-r0/plugins/psuutil.py b/device/cig/x86_64-cig_cs5435_54p-r0/plugins/psuutil.py new file mode 100755 index 00000000000..70d50e6c345 --- /dev/null +++ b/device/cig/x86_64-cig_cs5435_54p-r0/plugins/psuutil.py @@ -0,0 +1,93 @@ +# +# psuutil.py +# Platform-specific PSU status interface for SONiC +# + + +import os.path +import logging + +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""" + + SYSFS_PSU_DIR = ["/sys/bus/i2c/devices/5-005a", + "/sys/bus/i2c/devices/5-005b"] + + def __init__(self): + PsuBase.__init__(self) + + + # Get sysfs attribute + def get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open %s file !", attr_path) + + retval = retval.rstrip('\r\n') + return retval + + def get_num_psus(self): + """ + Retrieves the number of PSUs available on the device + :return: An integer, the number of PSUs available on the device + """ + MAX_PSUS = 2 + return MAX_PSUS + + def get_psu_status(self, index): + """ + Retrieves the oprational status of power supply unit (PSU) defined + by index + :param index: An integer, index of the PSU of which to query status + :return: Boolean, True if PSU is operating properly, False if PSU is\ + faulty + """ + status = 0 + attr_file = 'psu_power_good' + attr_path = self.SYSFS_PSU_DIR[index-1] +'/' + attr_file + + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = int(attr_value, 16) + # Check for PSU status + if (attr_value == 1): + status = 1 + + return status + + def get_psu_presence(self, index): + """ + Retrieves the presence status of power supply unit (PSU) defined + by index + :param index: An integer, index of the PSU of which to query status + :return: Boolean, True if PSU is plugged, False if not + """ + status = 0 + psu_absent = 0 + attr_file ='psu_present' + attr_path = self.SYSFS_PSU_DIR[index-1] +'/' + attr_file + + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = int(attr_value, 16) + # Check for PSU presence + if (attr_value == 1): + status = 1 + + return status + diff --git a/device/cig/x86_64-cig_cs5435_54p-r0/plugins/sfputil.py b/device/cig/x86_64-cig_cs5435_54p-r0/plugins/sfputil.py new file mode 100755 index 00000000000..2863b80c995 --- /dev/null +++ b/device/cig/x86_64-cig_cs5435_54p-r0/plugins/sfputil.py @@ -0,0 +1,250 @@ +#!/usr/bin/env python + +try: + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + + +class SfpUtil(SfpUtilBase): + """Platform specific SfpUtill class""" + + _port_start = 1 + _port_end = 54 + _qsfp_port_start = 49 + _ports_in_block = 54 + + _port_to_eeprom_mapping = {} + _global_port_pres_dict = {} + + _port_to_i2c_mapping = { + 1 : 8, + 2 : 9, + 3 : 10, + 4 : 11, + 5 : 12, + 6 : 13, + 7 : 14, + 8 : 15, + 9 : 16, + 10: 17, + 11 : 18, + 12 : 19, + 13 : 20, + 14 : 21, + 15 : 22, + 16 : 23, + 17 : 24, + 18 : 25, + 19 : 26, + 20 : 27, + 21 : 28, + 22 : 29, + 23 : 30, + 24 : 31, + 25 : 32, + 26 : 33, + 27 : 34, + 28 : 35, + 29 : 36, + 30 : 37, + 31 : 38, + 32 : 39, + 33 : 40, + 34 : 41, + 35 : 42, + 36 : 43, + 37 : 44, + 38 : 45, + 39 : 46, + 40 : 47, + 41 : 48, + 42 : 49, + 43 : 50, + 44 : 51, + 45 : 52, + 46 : 53, + 47 : 54, + 48 : 55, + 49 : 56, + 50 : 57, + 51 : 60, + 52 : 61, + 53 : 62, + 54 : 63, + } + + _qsfp_ports = range(_qsfp_port_start, _ports_in_block + 1) + + 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 + + path = "/sys/bus/i2c/devices/{0}-0050/sfp_is_present" + port_ps = path.format(self._port_to_i2c_mapping[port_num]) + + + try: + reg_file = open(port_ps) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + try: + reg_value = reg_file.readline().rstrip() + except IOError as e: + time.sleep(1) + + try: + reg_value = reg_file.readline().rstrip() + except IOError as e: + print "Error:try again to read file failed: %s %s" % (str(e), port_ps) + reg_file.close() + return False + + reg_file.close() + if reg_value == '1': + return True + + reg_file.close() + if reg_value == '1': + return True + + return False + + def init_global_port_presence(self): + for port_num in range(self.port_start, (self.port_end + 1)): + self._global_port_pres_dict[port_num] = '0' + + + def __init__(self): + eeprom_path = '/sys/bus/i2c/devices/{0}-0050/sfp_eeprom' + for x in range(self._port_start, self._port_end + 1): + port_eeprom_path = eeprom_path.format(self._port_to_i2c_mapping[x]) + self._port_to_eeprom_mapping[x] = port_eeprom_path + + self.init_global_port_presence() + SfpUtilBase.__init__(self) + + def reset(self, port_num): + # Check for invalid port_num + if port_num < self._port_start or port_num > self._port_end: + return False + + path = "/sys/bus/i2c/devices/{0}-0050/sfp_port_reset" + port_ps = path.format(self._port_to_i2c_mapping[port_num]) + + try: + reg_file = open(port_ps, 'w') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + #toggle reset + reg_file.seek(0) + reg_file.write('1') + time.sleep(1) + reg_file.seek(0) + reg_file.write('0') + reg_file.close() + return True + + 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._port_end: + return False + + pre_value = self.get_presence(port_num) + if pre_value == False: + return False + + path = "/sys/bus/i2c/devices/{0}-0050/sfp_lpmode" + port_ps = path.format(self._port_to_i2c_mapping[port_num]) + + try: + reg_file = open(port_ps,'w') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_file.seek(0) + + if lpmode == 1: + reg_file.write('1') + elif lpmode == 0: + reg_file.write('0') + reg_file.close() + + return True + + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + + if port_num < self._qsfp_port_start or port_num > self._port_end: + return False + + pre_value = self.get_presence(port_num) + if pre_value == False: + return False + + path = "/sys/bus/i2c/devices/{0}-0050/sfp_lpmode" + port_ps = path.format(self._port_to_i2c_mapping[port_num]) + + try: + reg_file = open(port_ps) + except IOError as e: + print "Error: unable to open file:%s %s" % (str(e), port_ps) + return False + + try: + reg_value = reg_file.readline().rstrip() + except IOError as e: + print "Error: unable to open file:%s %s" % (str(e), port_ps) + reg_file.close() + return False + + reg_file.close() + + if reg_value == '1': + return True + + return False + + def get_transceiver_change_event(self): + port_dict = {} + while True: + 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'): + 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'): + self._global_port_pres_dict[port_num] = '0' + port_dict[port_num] = '0' + + if(len(port_dict) > 0): + return True, port_dict + + time.sleep(0.5) + + + @property + def port_start(self): + return self._port_start + + @property + def port_end(self): + return self._port_end + + @property + def qsfp_ports(self): + return self._qsfp_ports + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping diff --git a/device/cig/x86_64-cig_cs5435_54p-r0/sensors.conf b/device/cig/x86_64-cig_cs5435_54p-r0/sensors.conf new file mode 100644 index 00000000000..f0964c87dae --- /dev/null +++ b/device/cig/x86_64-cig_cs5435_54p-r0/sensors.conf @@ -0,0 +1,13 @@ +# libsensors configuration file + +chip "cs5435_54p_fan-*" + label fan1 "front fan 1" + label fan2 "front fan 2" + label fan3 "front fan 3" + label fan4 "front fan 4" + label fan5 "front fan 5" + label fan6 "rear fan 1" + label fan7 "rear fan 2" + label fan8 "rear fan 3" + label fan9 "rear fan 4" + label fan10 "rear fan 5" diff --git a/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/buffers.json.j2 b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/buffers.json.j2 new file mode 100644 index 00000000000..2c391214fa6 --- /dev/null +++ b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/buffers.json.j2 @@ -0,0 +1,111 @@ +{# Default values which will be used if no actual configura available #} +{% set default_cable = '40m' %} +{% set default_speed = '10G' %} +{% set default_ports_num = 54 -%} + +{# Port configuration to cable length look-up table #} +{# Each record describes mapping of DUT (DUT port) role and neighbor role to cable length #} +{# Roles described in the minigraph #} +{% set ports2cable = { + 'torrouter_server' : '5m', + 'leafrouter_torrouter' : '40m', + 'spinerouter_leafrouter' : '300m' + } +%} + +{%- macro cable_length(port_name) -%} + {%- set cable_len = [] -%} + {%- for local_port in DEVICE_NEIGHBOR -%} + {%- if local_port == port_name -%} + {%- if DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%} + {%- set neighbor = DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%} + {%- set neighbor_role = neighbor.type -%} + {%- set roles1 = switch_role + '_' + neighbor_role %} + {%- set roles2 = neighbor_role + '_' + switch_role -%} + {%- set roles1 = roles1 | lower -%} + {%- set roles2 = roles2 | lower -%} + {%- if roles1 in ports2cable -%} + {%- if cable_len.append(ports2cable[roles1]) -%}{%- endif -%} + {%- elif roles2 in ports2cable -%} + {%- if cable_len.append(ports2cable[roles2]) -%}{%- endif -%} + {%- endif -%} + {%- endif -%} + {%- endif -%} + {%- endfor -%} + {%- if cable_len -%} + {{ cable_len.0 }} + {%- else -%} + {{ default_cable }} + {%- endif -%} +{% endmacro %} + +{%- if DEVICE_METADATA is defined %} +{%- set switch_role = DEVICE_METADATA['localhost']['type'] %} +{%- endif -%} + +{# Generate list of ports if not defined #} +{% if PORT is not defined %} + {% set PORT = [] %} + {% for port_idx in range(0,default_ports_num) %} + {% if PORT.append("Ethernet%d" % (port_idx)) %}{% endif %} + {% endfor %} +{% endif -%} + +{% set port_names_list = [] %} +{% for port in PORT %} + {%- if port_names_list.append(port) %}{% endif %} +{% endfor %} +{% set port_names = port_names_list | join(',') -%} + +{ + "CABLE_LENGTH": { + "AZURE": { + {% for port in PORT %} + {% set cable = cable_length(port) -%} + "{{ port }}": "{{ cable }}"{%- if not loop.last -%},{% endif %} + + {% endfor %} + } + }, + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "20971328", + "type": "ingress", + "mode": "static" + }, + "ingress_lossy_pool": { + "size": "20971328", + "type": "ingress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "20971328", + "type": "egress", + "mode": "static" + } + }, + "BUFFER_PROFILE": { + "ingress_lossless_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "xon":"78400", + "xoff":"132160", + "size":"3584", + "static_th":"82880" + }, + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossy_pool]", + "size":"3584", + "dynamic_th":"-1" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"3584", + "dynamic_th":"-4" + } + }, + "BUFFER_PG": { + }, + "BUFFER_QUEUE": { + } +} + \ No newline at end of file diff --git a/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/led.bin b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/led.bin new file mode 100644 index 00000000000..201662a1c60 Binary files /dev/null and b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/led.bin differ diff --git a/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/pg_profile_lookup.ini b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/pg_profile_lookup.ini new file mode 100644 index 00000000000..d98b0eca6d1 --- /dev/null +++ b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/pg_profile_lookup.ini @@ -0,0 +1,17 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold + 10000 5m 3584 32256 59136 36736 + 25000 5m 3584 41216 68096 45696 + 40000 5m 3584 47488 74368 51968 + 50000 5m 3584 52864 79744 57344 + 100000 5m 3584 78400 132160 82880 + 10000 40m 3584 32256 59136 36736 + 25000 40m 3584 41216 68096 45696 + 40000 40m 3584 47488 74368 51968 + 50000 40m 3584 52864 79744 57344 + 100000 40m 3584 78400 132160 82880 + 10000 300m 3584 32256 65856 36736 + 25000 300m 3584 41216 84672 45696 + 40000 300m 3584 47488 101024 51968 + 50000 300m 3584 52864 113120 57344 + 100000 300m 3584 78400 198688 82880 \ No newline at end of file diff --git a/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/port_config.ini b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/port_config.ini new file mode 100644 index 00000000000..c1982159c07 --- /dev/null +++ b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/port_config.ini @@ -0,0 +1,55 @@ +# name lanes alias index speed +Ethernet0 8 Ethernet1/1 1 25000 +Ethernet1 9 Ethernet2/1 2 25000 +Ethernet2 10 Ethernet3/1 3 25000 +Ethernet3 11 Ethernet4/1 4 25000 +Ethernet4 12 Ethernet5/1 5 25000 +Ethernet5 13 Ethernet6/1 6 25000 +Ethernet6 14 Ethernet7/1 7 25000 +Ethernet7 15 Ethernet8/1 8 25000 +Ethernet8 16 Ethernet9/1 9 25000 +Ethernet9 17 Ethernet10/1 10 25000 +Ethernet10 18 Ethernet11/1 11 25000 +Ethernet11 19 Ethernet12/1 12 25000 +Ethernet12 20 Ethernet13/1 13 25000 +Ethernet13 21 Ethernet14/1 14 25000 +Ethernet14 22 Ethernet15/1 15 25000 +Ethernet15 23 Ethernet16/1 16 25000 +Ethernet16 32 Ethernet17/1 17 25000 +Ethernet17 33 Ethernet18/1 18 25000 +Ethernet18 34 Ethernet19/1 19 25000 +Ethernet19 35 Ethernet20/1 20 25000 +Ethernet20 40 Ethernet21/1 21 25000 +Ethernet21 41 Ethernet22/1 22 25000 +Ethernet22 42 Ethernet23/1 23 25000 +Ethernet23 43 Ethernet24/1 24 25000 +Ethernet24 48 Ethernet25/1 25 25000 +Ethernet25 49 Ethernet26/1 26 25000 +Ethernet26 50 Ethernet27/1 27 25000 +Ethernet27 51 Ethernet28/1 28 25000 +Ethernet28 56 Ethernet29/1 29 25000 +Ethernet29 57 Ethernet30/1 30 25000 +Ethernet30 58 Ethernet31/1 31 25000 +Ethernet31 59 Ethernet32/1 32 25000 +Ethernet32 64 Ethernet33/1 33 25000 +Ethernet33 65 Ethernet34/1 34 25000 +Ethernet34 66 Ethernet35/1 35 25000 +Ethernet35 67 Ethernet36/1 36 25000 +Ethernet36 68 Ethernet37/1 37 25000 +Ethernet37 69 Ethernet38/1 38 25000 +Ethernet38 70 Ethernet39/1 39 25000 +Ethernet39 71 Ethernet40/1 40 25000 +Ethernet40 72 Ethernet41/1 41 25000 +Ethernet41 73 Ethernet42/1 42 25000 +Ethernet42 74 Ethernet43/1 43 25000 +Ethernet43 75 Ethernet44/1 44 25000 +Ethernet44 76 Ethernet45/1 45 25000 +Ethernet45 77 Ethernet46/1 46 25000 +Ethernet46 78 Ethernet47/1 47 25000 +Ethernet47 79 Ethernet48/1 48 25000 +Ethernet48 84,85,86,87 Ethernet49/1 49 100000 +Ethernet49 80,81,82,83 Ethernet50/1 50 100000 +Ethernet50 108,109,110,111 Ethernet51/1 51 100000 +Ethernet51 104,105,106,107 Ethernet52/1 52 100000 +Ethernet52 116,117,118,119 Ethernet53/1 53 100000 +Ethernet53 112,113,114,115 Ethernet54/1 54 10000 diff --git a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.nps.AOC.R0B b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/port_config.nps old mode 100755 new mode 100644 similarity index 92% rename from device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.nps.AOC.R0B rename to device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/port_config.nps index 857e5f1ede5..aca222f5962 --- a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.nps.AOC.R0B +++ b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/port_config.nps @@ -1,24 +1,24 @@ init start stage unit=0 low-level -init set port-map unit=0 port=0 eth-macro=2 lane=0 max-speed=25g active=true -init set port-map unit=0 port=1 eth-macro=2 lane=1 max-speed=25g active=true -init set port-map unit=0 port=2 eth-macro=2 lane=2 max-speed=25g active=true -init set port-map unit=0 port=3 eth-macro=2 lane=3 max-speed=25g active=true -init set port-map unit=0 port=4 eth-macro=3 lane=0 max-speed=25g active=true -init set port-map unit=0 port=5 eth-macro=3 lane=1 max-speed=25g active=true -init set port-map unit=0 port=6 eth-macro=3 lane=2 max-speed=25g active=true -init set port-map unit=0 port=7 eth-macro=3 lane=3 max-speed=25g active=true -init set port-map unit=0 port=8 eth-macro=4 lane=0 max-speed=25g active=true -init set port-map unit=0 port=9 eth-macro=4 lane=1 max-speed=25g active=true -init set port-map unit=0 port=10 eth-macro=4 lane=2 max-speed=25g active=true -init set port-map unit=0 port=11 eth-macro=4 lane=3 max-speed=25g active=true -init set port-map unit=0 port=12 eth-macro=5 lane=0 max-speed=25g active=true -init set port-map unit=0 port=13 eth-macro=5 lane=1 max-speed=25g active=true -init set port-map unit=0 port=14 eth-macro=5 lane=2 max-speed=25g active=true -init set port-map unit=0 port=15 eth-macro=5 lane=3 max-speed=25g active=true -init set port-map unit=0 port=16 eth-macro=8 lane=0 max-speed=25g active=true -init set port-map unit=0 port=17 eth-macro=8 lane=1 max-speed=25g active=true -init set port-map unit=0 port=18 eth-macro=8 lane=2 max-speed=25g active=true -init set port-map unit=0 port=19 eth-macro=8 lane=3 max-speed=25g active=true +init set port-map unit=0 port=0 eth-macro=2 lane=0 max-speed=25g active=true +init set port-map unit=0 port=1 eth-macro=2 lane=1 max-speed=25g active=true +init set port-map unit=0 port=2 eth-macro=2 lane=2 max-speed=25g active=true +init set port-map unit=0 port=3 eth-macro=2 lane=3 max-speed=25g active=true +init set port-map unit=0 port=4 eth-macro=3 lane=0 max-speed=25g active=true +init set port-map unit=0 port=5 eth-macro=3 lane=1 max-speed=25g active=true +init set port-map unit=0 port=6 eth-macro=3 lane=2 max-speed=25g active=true +init set port-map unit=0 port=7 eth-macro=3 lane=3 max-speed=25g active=true +init set port-map unit=0 port=8 eth-macro=4 lane=0 max-speed=25g active=true +init set port-map unit=0 port=9 eth-macro=4 lane=1 max-speed=25g active=true +init set port-map unit=0 port=10 eth-macro=4 lane=2 max-speed=25g active=true +init set port-map unit=0 port=11 eth-macro=4 lane=3 max-speed=25g active=true +init set port-map unit=0 port=12 eth-macro=5 lane=0 max-speed=25g active=true +init set port-map unit=0 port=13 eth-macro=5 lane=1 max-speed=25g active=true +init set port-map unit=0 port=14 eth-macro=5 lane=2 max-speed=25g active=true +init set port-map unit=0 port=15 eth-macro=5 lane=3 max-speed=25g active=true +init set port-map unit=0 port=16 eth-macro=8 lane=0 max-speed=25g active=true +init set port-map unit=0 port=17 eth-macro=8 lane=1 max-speed=25g active=true +init set port-map unit=0 port=18 eth-macro=8 lane=2 max-speed=25g active=true +init set port-map unit=0 port=19 eth-macro=8 lane=3 max-speed=25g active=true init set port-map unit=0 port=20 eth-macro=10 lane=0 max-speed=25g active=true init set port-map unit=0 port=21 eth-macro=10 lane=1 max-speed=25g active=true init set port-map unit=0 port=22 eth-macro=10 lane=2 max-speed=25g active=true @@ -49,12 +49,10 @@ init set port-map unit=0 port=46 eth-macro=19 lane=2 max-speed=25g active=true init set port-map unit=0 port=47 eth-macro=19 lane=3 max-speed=25g active=true init set port-map unit=0 port=48 eth-macro=21 lane=0 max-speed=100g active=true init set port-map unit=0 port=49 eth-macro=20 lane=0 max-speed=100g active=true -init set port-map unit=0 port=50 eth-macro=23 lane=0 max-speed=100g active=true -init set port-map unit=0 port=51 eth-macro=22 lane=0 max-speed=100g active=true -init set port-map unit=0 port=52 eth-macro=27 lane=0 max-speed=100g active=true -init set port-map unit=0 port=53 eth-macro=26 lane=0 max-speed=100g active=true -init set port-map unit=0 port=54 eth-macro=29 lane=0 max-speed=100g active=true -init set port-map unit=0 port=55 eth-macro=28 lane=0 max-speed=100g active=true +init set port-map unit=0 port=50 eth-macro=27 lane=0 max-speed=100g active=true +init set port-map unit=0 port=51 eth-macro=26 lane=0 max-speed=100g active=true +init set port-map unit=0 port=52 eth-macro=29 lane=0 max-speed=100g active=true +init set port-map unit=0 port=53 eth-macro=28 lane=0 max-speed=100g active=true init set port-map unit=0 port=129 eth-macro=0 lane=1 max-speed=10g active=true guarantee=true cpi=true init set port-map unit=0 port=130 eth-macro=0 lane=0 max-speed=10g active=true guarantee=true cpi=true init-done=true init start stage unit=0 task-rsrc @@ -110,12 +108,10 @@ phy set lane-swap unit=0 portlist=46 lane-cnt=1 property=tx data=0x2 phy set lane-swap unit=0 portlist=47 lane-cnt=1 property=tx data=0x3 phy set lane-swap unit=0 portlist=48 lane-cnt=4 property=tx data=0x3.0.1.2 phy set lane-swap unit=0 portlist=49 lane-cnt=4 property=tx data=0x3.2.1.0 -phy set lane-swap unit=0 portlist=50 lane-cnt=4 property=tx data=0x0.1.2.3 -phy set lane-swap unit=0 portlist=51 lane-cnt=4 property=tx data=0x3.2.0.1 +phy set lane-swap unit=0 portlist=50 lane-cnt=4 property=tx data=0x3.2.1.0 +phy set lane-swap unit=0 portlist=51 lane-cnt=4 property=tx data=0x3.2.1.0 phy set lane-swap unit=0 portlist=52 lane-cnt=4 property=tx data=0x3.2.1.0 phy set lane-swap unit=0 portlist=53 lane-cnt=4 property=tx data=0x3.2.1.0 -phy set lane-swap unit=0 portlist=54 lane-cnt=4 property=tx data=0x3.2.1.0 -phy set lane-swap unit=0 portlist=55 lane-cnt=4 property=tx data=0x3.2.1.0 phy set lane-swap unit=0 portlist=129 lane-cnt=1 property=tx data=0x1 phy set lane-swap unit=0 portlist=130 lane-cnt=1 property=tx data=0x0 phy set lane-swap unit=0 portlist=0 lane-cnt=1 property=rx data=0x0 @@ -168,12 +164,10 @@ phy set lane-swap unit=0 portlist=46 lane-cnt=1 property=rx data=0x0 phy set lane-swap unit=0 portlist=47 lane-cnt=1 property=rx data=0x3 phy set lane-swap unit=0 portlist=48 lane-cnt=4 property=rx data=0x3.1.0.2 phy set lane-swap unit=0 portlist=49 lane-cnt=4 property=rx data=0x3.2.1.0 -phy set lane-swap unit=0 portlist=50 lane-cnt=4 property=rx data=0x3.0.1.2 -phy set lane-swap unit=0 portlist=51 lane-cnt=4 property=rx data=0x3.2.1.0 +phy set lane-swap unit=0 portlist=50 lane-cnt=4 property=rx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=51 lane-cnt=4 property=rx data=0x2.0.1.3 phy set lane-swap unit=0 portlist=52 lane-cnt=4 property=rx data=0x1.0.3.2 -phy set lane-swap unit=0 portlist=53 lane-cnt=4 property=rx data=0x2.0.1.3 -phy set lane-swap unit=0 portlist=54 lane-cnt=4 property=rx data=0x1.0.3.2 -phy set lane-swap unit=0 portlist=55 lane-cnt=4 property=rx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=53 lane-cnt=4 property=rx data=0x1.0.3.2 phy set lane-swap unit=0 portlist=129 lane-cnt=1 property=rx data=0x1 phy set lane-swap unit=0 portlist=130 lane-cnt=1 property=rx data=0x0 phy set polarity-rev unit=0 portlist=0 lane-cnt=1 property=tx data=0x0 @@ -230,8 +224,6 @@ phy set polarity-rev unit=0 portlist=50 lane-cnt=4 property=tx data=0x0.0.0.0 phy set polarity-rev unit=0 portlist=51 lane-cnt=4 property=tx data=0x0.0.0.0 phy set polarity-rev unit=0 portlist=52 lane-cnt=4 property=tx data=0x0.0.0.0 phy set polarity-rev unit=0 portlist=53 lane-cnt=4 property=tx data=0x0.0.0.0 -phy set polarity-rev unit=0 portlist=54 lane-cnt=4 property=tx data=0x0.0.0.0 -phy set polarity-rev unit=0 portlist=55 lane-cnt=4 property=tx data=0x0.0.0.0 phy set polarity-rev unit=0 portlist=129 lane-cnt=1 property=tx data=0x0 phy set polarity-rev unit=0 portlist=130 lane-cnt=1 property=tx data=0x0 phy set polarity-rev unit=0 portlist=0 lane-cnt=1 property=rx data=0x0 @@ -284,12 +276,10 @@ phy set polarity-rev unit=0 portlist=46 lane-cnt=1 property=rx data=0x0 phy set polarity-rev unit=0 portlist=47 lane-cnt=1 property=rx data=0x0 phy set polarity-rev unit=0 portlist=48 lane-cnt=4 property=rx data=0x0.1.1.0 phy set polarity-rev unit=0 portlist=49 lane-cnt=4 property=rx data=0x0.0.0.0 -phy set polarity-rev unit=0 portlist=50 lane-cnt=4 property=rx data=0x1.1.1.1 +phy set polarity-rev unit=0 portlist=50 lane-cnt=4 property=rx data=0x1.1.1.0 phy set polarity-rev unit=0 portlist=51 lane-cnt=4 property=rx data=0x0.0.0.0 phy set polarity-rev unit=0 portlist=52 lane-cnt=4 property=rx data=0x1.1.1.0 phy set polarity-rev unit=0 portlist=53 lane-cnt=4 property=rx data=0x0.0.0.0 -phy set polarity-rev unit=0 portlist=54 lane-cnt=4 property=rx data=0x1.1.1.0 -phy set polarity-rev unit=0 portlist=55 lane-cnt=4 property=rx data=0x0.0.0.0 phy set polarity-rev unit=0 portlist=129 lane-cnt=1 property=rx data=0x0 phy set polarity-rev unit=0 portlist=130 lane-cnt=1 property=rx data=0x0 phy set pre-emphasis unit=0 portlist=0 lane-cnt=1 property=c2 data=0x2 @@ -508,14 +498,6 @@ phy set pre-emphasis unit=0 portlist=53 lane-cnt=4 property=c2 data=0x2.2.2.2 phy set pre-emphasis unit=0 portlist=53 lane-cnt=4 property=cn1 data=0x0.0.0.0 phy set pre-emphasis unit=0 portlist=53 lane-cnt=4 property=c0 data=0x1b.1b.1b.1b phy set pre-emphasis unit=0 portlist=53 lane-cnt=4 property=c1 data=0x6.6.6.6 -phy set pre-emphasis unit=0 portlist=54 lane-cnt=4 property=c2 data=0x2.2.2.2 -phy set pre-emphasis unit=0 portlist=54 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis unit=0 portlist=54 lane-cnt=4 property=c0 data=0x1b.1b.1b.1b -phy set pre-emphasis unit=0 portlist=54 lane-cnt=4 property=c1 data=0x6.6.6.6 -phy set pre-emphasis unit=0 portlist=55 lane-cnt=4 property=c2 data=0x2.2.2.2 -phy set pre-emphasis unit=0 portlist=55 lane-cnt=4 property=cn1 data=0x0.0.0.0 -phy set pre-emphasis unit=0 portlist=55 lane-cnt=4 property=c0 data=0x1b.1b.1b.1b -phy set pre-emphasis unit=0 portlist=55 lane-cnt=4 property=c1 data=0x6.6.6.6 phy set pre-emphasis unit=0 portlist=129 lane-cnt=1 property=c2 data=0x1 phy set pre-emphasis unit=0 portlist=129 lane-cnt=1 property=cn1 data=0x1 phy set pre-emphasis unit=0 portlist=129 lane-cnt=1 property=c0 data=0x2 @@ -578,8 +560,6 @@ port set property unit=0 portlist=50 speed=100g port set property unit=0 portlist=51 speed=100g port set property unit=0 portlist=52 speed=100g port set property unit=0 portlist=53 speed=100g -port set property unit=0 portlist=54 speed=100g -port set property unit=0 portlist=55 speed=100g port set property unit=0 portlist=129 speed=10g port set property unit=0 portlist=130 speed=1g port set property unit=0 portlist=0 medium-type=sr @@ -636,8 +616,6 @@ port set property unit=0 portlist=50 medium-type=sr4 port set property unit=0 portlist=51 medium-type=sr4 port set property unit=0 portlist=52 medium-type=sr4 port set property unit=0 portlist=53 medium-type=sr4 -port set property unit=0 portlist=54 medium-type=sr4 -port set property unit=0 portlist=55 medium-type=sr4 port set property unit=0 portlist=129 medium-type=kr port set property unit=0 portlist=130 medium-type=x port advertise unit=0 portlist=129 speed-10g-kr @@ -696,7 +674,5 @@ port set property unit=0 portlist=50 admin=enable port set property unit=0 portlist=51 admin=enable port set property unit=0 portlist=52 admin=enable port set property unit=0 portlist=53 admin=enable -port set property unit=0 portlist=54 admin=enable -port set property unit=0 portlist=55 admin=enable -port set property unit=0 portlist=129 admin=enable -port set property unit=0 portlist=130 admin=enable +port set property unit=0 portlist=129 admin=disable +port set property unit=0 portlist=130 admin=disable diff --git a/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/qos.json.j2 b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/qos.json.j2 new file mode 100644 index 00000000000..3e548325ea3 --- /dev/null +++ b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/qos.json.j2 @@ -0,0 +1 @@ +{%- include 'qos_config.j2' %} diff --git a/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/sai.profile b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/sai.profile new file mode 100644 index 00000000000..e7b5f90ac88 --- /dev/null +++ b/device/cig/x86_64-cig_cs6436_54p-r0/Cig-CS6436-54P/sai.profile @@ -0,0 +1,3 @@ +SAI_INIT_LED_CONFIG_FILE=/usr/share/sonic/hwsku/led.bin +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/proc_init.nps +SAI_DSH_CONFIG_FILE=/usr/share/sonic/hwsku/port_config.nps diff --git a/device/cig/x86_64-cig_cs6436_54p-r0/default_sku b/device/cig/x86_64-cig_cs6436_54p-r0/default_sku new file mode 100644 index 00000000000..24afbb73b77 --- /dev/null +++ b/device/cig/x86_64-cig_cs6436_54p-r0/default_sku @@ -0,0 +1 @@ +Cig-CS6436-54P t1 diff --git a/device/cig/x86_64-cig_cs6436_54p-r0/installer.conf b/device/cig/x86_64-cig_cs6436_54p-r0/installer.conf new file mode 100644 index 00000000000..ea6b4f6ebe3 --- /dev/null +++ b/device/cig/x86_64-cig_cs6436_54p-r0/installer.conf @@ -0,0 +1,4 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="pci=noaer" diff --git a/device/cig/x86_64-cig_cs6436_54p-r0/plugins/eeprom.py b/device/cig/x86_64-cig_cs6436_54p-r0/plugins/eeprom.py new file mode 100755 index 00000000000..5019b9c40a9 --- /dev/null +++ b/device/cig/x86_64-cig_cs6436_54p-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/7-0057/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/cig/x86_64-cig_cs6436_54p-r0/plugins/psuutil.py b/device/cig/x86_64-cig_cs6436_54p-r0/plugins/psuutil.py new file mode 100755 index 00000000000..70d50e6c345 --- /dev/null +++ b/device/cig/x86_64-cig_cs6436_54p-r0/plugins/psuutil.py @@ -0,0 +1,93 @@ +# +# psuutil.py +# Platform-specific PSU status interface for SONiC +# + + +import os.path +import logging + +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""" + + SYSFS_PSU_DIR = ["/sys/bus/i2c/devices/5-005a", + "/sys/bus/i2c/devices/5-005b"] + + def __init__(self): + PsuBase.__init__(self) + + + # Get sysfs attribute + def get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open %s file !", attr_path) + + retval = retval.rstrip('\r\n') + return retval + + def get_num_psus(self): + """ + Retrieves the number of PSUs available on the device + :return: An integer, the number of PSUs available on the device + """ + MAX_PSUS = 2 + return MAX_PSUS + + def get_psu_status(self, index): + """ + Retrieves the oprational status of power supply unit (PSU) defined + by index + :param index: An integer, index of the PSU of which to query status + :return: Boolean, True if PSU is operating properly, False if PSU is\ + faulty + """ + status = 0 + attr_file = 'psu_power_good' + attr_path = self.SYSFS_PSU_DIR[index-1] +'/' + attr_file + + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = int(attr_value, 16) + # Check for PSU status + if (attr_value == 1): + status = 1 + + return status + + def get_psu_presence(self, index): + """ + Retrieves the presence status of power supply unit (PSU) defined + by index + :param index: An integer, index of the PSU of which to query status + :return: Boolean, True if PSU is plugged, False if not + """ + status = 0 + psu_absent = 0 + attr_file ='psu_present' + attr_path = self.SYSFS_PSU_DIR[index-1] +'/' + attr_file + + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = int(attr_value, 16) + # Check for PSU presence + if (attr_value == 1): + status = 1 + + return status + diff --git a/device/cig/x86_64-cig_cs6436_54p-r0/plugins/sfputil.py b/device/cig/x86_64-cig_cs6436_54p-r0/plugins/sfputil.py new file mode 100755 index 00000000000..2863b80c995 --- /dev/null +++ b/device/cig/x86_64-cig_cs6436_54p-r0/plugins/sfputil.py @@ -0,0 +1,250 @@ +#!/usr/bin/env python + +try: + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + + +class SfpUtil(SfpUtilBase): + """Platform specific SfpUtill class""" + + _port_start = 1 + _port_end = 54 + _qsfp_port_start = 49 + _ports_in_block = 54 + + _port_to_eeprom_mapping = {} + _global_port_pres_dict = {} + + _port_to_i2c_mapping = { + 1 : 8, + 2 : 9, + 3 : 10, + 4 : 11, + 5 : 12, + 6 : 13, + 7 : 14, + 8 : 15, + 9 : 16, + 10: 17, + 11 : 18, + 12 : 19, + 13 : 20, + 14 : 21, + 15 : 22, + 16 : 23, + 17 : 24, + 18 : 25, + 19 : 26, + 20 : 27, + 21 : 28, + 22 : 29, + 23 : 30, + 24 : 31, + 25 : 32, + 26 : 33, + 27 : 34, + 28 : 35, + 29 : 36, + 30 : 37, + 31 : 38, + 32 : 39, + 33 : 40, + 34 : 41, + 35 : 42, + 36 : 43, + 37 : 44, + 38 : 45, + 39 : 46, + 40 : 47, + 41 : 48, + 42 : 49, + 43 : 50, + 44 : 51, + 45 : 52, + 46 : 53, + 47 : 54, + 48 : 55, + 49 : 56, + 50 : 57, + 51 : 60, + 52 : 61, + 53 : 62, + 54 : 63, + } + + _qsfp_ports = range(_qsfp_port_start, _ports_in_block + 1) + + 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 + + path = "/sys/bus/i2c/devices/{0}-0050/sfp_is_present" + port_ps = path.format(self._port_to_i2c_mapping[port_num]) + + + try: + reg_file = open(port_ps) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + try: + reg_value = reg_file.readline().rstrip() + except IOError as e: + time.sleep(1) + + try: + reg_value = reg_file.readline().rstrip() + except IOError as e: + print "Error:try again to read file failed: %s %s" % (str(e), port_ps) + reg_file.close() + return False + + reg_file.close() + if reg_value == '1': + return True + + reg_file.close() + if reg_value == '1': + return True + + return False + + def init_global_port_presence(self): + for port_num in range(self.port_start, (self.port_end + 1)): + self._global_port_pres_dict[port_num] = '0' + + + def __init__(self): + eeprom_path = '/sys/bus/i2c/devices/{0}-0050/sfp_eeprom' + for x in range(self._port_start, self._port_end + 1): + port_eeprom_path = eeprom_path.format(self._port_to_i2c_mapping[x]) + self._port_to_eeprom_mapping[x] = port_eeprom_path + + self.init_global_port_presence() + SfpUtilBase.__init__(self) + + def reset(self, port_num): + # Check for invalid port_num + if port_num < self._port_start or port_num > self._port_end: + return False + + path = "/sys/bus/i2c/devices/{0}-0050/sfp_port_reset" + port_ps = path.format(self._port_to_i2c_mapping[port_num]) + + try: + reg_file = open(port_ps, 'w') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + #toggle reset + reg_file.seek(0) + reg_file.write('1') + time.sleep(1) + reg_file.seek(0) + reg_file.write('0') + reg_file.close() + return True + + 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._port_end: + return False + + pre_value = self.get_presence(port_num) + if pre_value == False: + return False + + path = "/sys/bus/i2c/devices/{0}-0050/sfp_lpmode" + port_ps = path.format(self._port_to_i2c_mapping[port_num]) + + try: + reg_file = open(port_ps,'w') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_file.seek(0) + + if lpmode == 1: + reg_file.write('1') + elif lpmode == 0: + reg_file.write('0') + reg_file.close() + + return True + + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + + if port_num < self._qsfp_port_start or port_num > self._port_end: + return False + + pre_value = self.get_presence(port_num) + if pre_value == False: + return False + + path = "/sys/bus/i2c/devices/{0}-0050/sfp_lpmode" + port_ps = path.format(self._port_to_i2c_mapping[port_num]) + + try: + reg_file = open(port_ps) + except IOError as e: + print "Error: unable to open file:%s %s" % (str(e), port_ps) + return False + + try: + reg_value = reg_file.readline().rstrip() + except IOError as e: + print "Error: unable to open file:%s %s" % (str(e), port_ps) + reg_file.close() + return False + + reg_file.close() + + if reg_value == '1': + return True + + return False + + def get_transceiver_change_event(self): + port_dict = {} + while True: + 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'): + 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'): + self._global_port_pres_dict[port_num] = '0' + port_dict[port_num] = '0' + + if(len(port_dict) > 0): + return True, port_dict + + time.sleep(0.5) + + + @property + def port_start(self): + return self._port_start + + @property + def port_end(self): + return self._port_end + + @property + def qsfp_ports(self): + return self._qsfp_ports + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping diff --git a/device/cig/x86_64-cig_cs6436_54p-r0/sensors.conf b/device/cig/x86_64-cig_cs6436_54p-r0/sensors.conf new file mode 100644 index 00000000000..22cd3ccda95 --- /dev/null +++ b/device/cig/x86_64-cig_cs6436_54p-r0/sensors.conf @@ -0,0 +1,13 @@ +# libsensors configuration file + +chip "cs6436_54p_fan-*" + label fan1 "front fan 1" + label fan2 "front fan 2" + label fan3 "front fan 3" + label fan4 "front fan 4" + label fan5 "front fan 5" + label fan6 "rear fan 1" + label fan7 "rear fan 2" + label fan8 "rear fan 3" + label fan9 "rear fan 4" + label fan10 "rear fan 5" diff --git a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/buffers.json.j2 b/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/buffers.json.j2 old mode 100755 new mode 100644 diff --git a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/led.bin b/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/led.bin new file mode 100644 index 00000000000..8b3490ca3b7 Binary files /dev/null and b/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/led.bin differ diff --git a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/pg_profile_lookup.ini b/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/pg_profile_lookup.ini old mode 100755 new mode 100644 diff --git a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.ini b/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.ini old mode 100755 new mode 100644 index 0a25fc0a345..1fd93308de7 --- a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.ini +++ b/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.ini @@ -54,4 +54,4 @@ Ethernet51 88,89,90,91 Ethernet52/1 51 100000 Ethernet52 108,109,110,111 Ethernet53/1 52 100000 Ethernet53 104,105,106,107 Ethernet54/1 53 100000 Ethernet54 116,117,118,119 Ethernet55/1 54 100000 -Ethernet55 112,113,114,115 Ethernet56/1 55 100000 +Ethernet55 112,113,114,115 Ethernet56/1 55 100000 \ No newline at end of file diff --git a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.nps b/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.nps old mode 100755 new mode 100644 index 857e5f1ede5..ec5f0273b9b --- a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.nps +++ b/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/port_config.nps @@ -698,5 +698,5 @@ port set property unit=0 portlist=52 admin=enable port set property unit=0 portlist=53 admin=enable port set property unit=0 portlist=54 admin=enable port set property unit=0 portlist=55 admin=enable -port set property unit=0 portlist=129 admin=enable -port set property unit=0 portlist=130 admin=enable +port set property unit=0 portlist=129 admin=disable +port set property unit=0 portlist=130 admin=disable diff --git a/device/cig/x86_64-cig_cs6436_56p-r0/led_proc_init.nps b/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/proc_init.nps old mode 100755 new mode 100644 similarity index 90% rename from device/cig/x86_64-cig_cs6436_56p-r0/led_proc_init.nps rename to device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/proc_init.nps index 3ba2f35e551..e55ceb0fda3 --- a/device/cig/x86_64-cig_cs6436_56p-r0/led_proc_init.nps +++ b/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/proc_init.nps @@ -1,7 +1,7 @@ #unit NPS_CFG_TYPE_XXX param0 param1 value #---- ---------------- ------ ------ ----- 0 NPS_CFG_TYPE_USE_UNIT_PORT 0 0 1 -0 NPS_CFG_TYPE_LED_CFG 0 0 7 +0 NPS_CFG_TYPE_LED_CFG 0 0 9 0 NPS_CFG_TYPE_CPI_PORT_MODE 129 0 1 0 NPS_CFG_TYPE_CPI_PORT_MODE 130 0 1 0 NPS_CFG_TYPE_USER_BUF_CTRL 0 0 1 diff --git a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/qos.json.j2 b/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/qos.json.j2 old mode 100755 new mode 100644 diff --git a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/sai.profile b/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/sai.profile old mode 100755 new mode 100644 index 880f47910ac..e7b5f90ac88 --- a/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/sai.profile +++ b/device/cig/x86_64-cig_cs6436_56p-r0/Cig-CS6436-56P/sai.profile @@ -1,2 +1,3 @@ -SAI_INIT_CONFIG_FILE=/usr/share/sonic/platform/led_proc_init.nps +SAI_INIT_LED_CONFIG_FILE=/usr/share/sonic/hwsku/led.bin +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/proc_init.nps SAI_DSH_CONFIG_FILE=/usr/share/sonic/hwsku/port_config.nps diff --git a/device/cig/x86_64-cig_cs6436_56p-r0/installer.conf b/device/cig/x86_64-cig_cs6436_56p-r0/installer.conf index 01b63913811..ea6b4f6ebe3 100755 --- a/device/cig/x86_64-cig_cs6436_56p-r0/installer.conf +++ b/device/cig/x86_64-cig_cs6436_56p-r0/installer.conf @@ -1,4 +1,4 @@ -CONSOLE_PORT=0x3e8 -CONSOLE_DEV=2 +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 CONSOLE_SPEED=115200 ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="pci=noaer" diff --git a/device/cig/x86_64-cig_cs6436_56p-r0/plugins/psuutil.py b/device/cig/x86_64-cig_cs6436_56p-r0/plugins/psuutil.py index 137531c36e1..70d50e6c345 100755 --- a/device/cig/x86_64-cig_cs6436_56p-r0/plugins/psuutil.py +++ b/device/cig/x86_64-cig_cs6436_56p-r0/plugins/psuutil.py @@ -5,6 +5,7 @@ import os.path +import logging try: from sonic_psu.psu_base import PsuBase @@ -33,7 +34,7 @@ def get_attr_value(self, attr_path): with open(attr_path, 'r') as fd: retval = fd.read() except Exception as error: - logging.error("Unable to open ", attr_path, " file !") + logging.error("Unable to open %s file !", attr_path) retval = retval.rstrip('\r\n') return retval diff --git a/device/cig/x86_64-cig_cs6436_56p-r0/plugins/sfputil.py b/device/cig/x86_64-cig_cs6436_56p-r0/plugins/sfputil.py index f5fe6c93142..46783fed50c 100755 --- a/device/cig/x86_64-cig_cs6436_56p-r0/plugins/sfputil.py +++ b/device/cig/x86_64-cig_cs6436_56p-r0/plugins/sfputil.py @@ -2,7 +2,7 @@ try: import time - from sonic_sfp.sfputilbase import SfpUtilBase + from sonic_sfp.sfputilbase import SfpUtilBase except ImportError, e: raise ImportError (str(e) + "- required module not found") @@ -16,6 +16,8 @@ class SfpUtil(SfpUtilBase): _ports_in_block = 55 _port_to_eeprom_mapping = {} + _global_port_pres_dict = {} + _port_to_i2c_mapping = { 0 : 8, 1 : 9, @@ -76,14 +78,57 @@ class SfpUtil(SfpUtilBase): } _qsfp_ports = range(_qsfp_port_start, _ports_in_block + 1) + + 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 + path = "/sys/bus/i2c/devices/{0}-0050/sfp_is_present" + port_ps = path.format(self._port_to_i2c_mapping[port_num]) + + + try: + reg_file = open(port_ps) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + try: + reg_value = reg_file.readline().rstrip() + except IOError as e: + time.sleep(1) + + try: + reg_value = reg_file.readline().rstrip() + except IOError as e: + print "Error:try again to read file failed: %s %s" % (str(e), port_ps) + reg_file.close() + return False + + reg_file.close() + if reg_value == '1': + return True + + reg_file.close() + if reg_value == '1': + return True + + return False + + def init_global_port_presence(self): + for port_num in range(self.port_start, (self.port_end + 1)): + self._global_port_pres_dict[port_num] = '0' + + def __init__(self): eeprom_path = '/sys/bus/i2c/devices/{0}-0050/sfp_eeprom' for x in range(self._port_start, self._port_end + 1): port_eeprom_path = eeprom_path.format(self._port_to_i2c_mapping[x]) self._port_to_eeprom_mapping[x] = port_eeprom_path - - SfpUtilBase.__init__(self) + + self.init_global_port_presence() + SfpUtilBase.__init__(self) def reset(self, port_num): # Check for invalid port_num @@ -107,41 +152,88 @@ def reset(self, port_num): reg_file.write('0') reg_file.close() return True + + 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._port_end: + return False + + pre_value = self.get_presence(port_num) + if pre_value == False: + return False + + path = "/sys/bus/i2c/devices/{0}-0050/sfp_lpmode" + port_ps = path.format(self._port_to_i2c_mapping[port_num]) + + try: + reg_file = open(port_ps,'w') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_file.seek(0) + + if lpmode == 1: + reg_file.write('1') + elif lpmode == 0: + 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 - if port_num < self._port_start or port_num > self._port_end: - return False - path = "/sys/bus/i2c/devices/{0}-0050/sfp_is_present" + if port_num < self._qsfp_port_start or port_num > self._port_end: + return False + + pre_value = self.get_presence(port_num) + if pre_value == False: + return False + + path = "/sys/bus/i2c/devices/{0}-0050/sfp_lpmode" port_ps = path.format(self._port_to_i2c_mapping[port_num]) - try: reg_file = open(port_ps) except IOError as e: - print "Error: unable to open file: %s" % str(e) + print "Error: unable to open file:%s %s" % (str(e), port_ps) + return False + + try: + reg_value = reg_file.readline().rstrip() + except IOError as e: + print "Error: unable to open file:%s %s" % (str(e), port_ps) + reg_file.close() return False + + reg_file.close() - reg_value = reg_file.readline().rstrip() if reg_value == '1': return True return False - + 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 + port_dict = {} + while True: + 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'): + 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'): + self._global_port_pres_dict[port_num] = '0' + port_dict[port_num] = '0' + + if(len(port_dict) > 0): + return True, port_dict + + time.sleep(0.5) + @property def port_start(self): diff --git a/device/dell/x86_64-dell_s6000_s1220-r0/sensors.conf b/device/dell/x86_64-dell_s6000_s1220-r0/sensors.conf index c87af11afac..f74a2b3d40a 100644 --- a/device/dell/x86_64-dell_s6000_s1220-r0/sensors.conf +++ b/device/dell/x86_64-dell_s6000_s1220-r0/sensors.conf @@ -7,8 +7,8 @@ # tmp75-i2c-11-4e is an ambient temperature sensor. chip "tmp75-*" - set temp1_max 50 - set temp1_max_hyst 25 + set temp1_max 80 + set temp1_max_hyst 70 # emc1403-i2c-10-4d has following temperature sensors: # temp1: CPU0 external Temp Sensor @@ -32,5 +32,5 @@ chip "jc42-*" set temp1_crit 85 chip "dni_dps460-*" - set temp1_max 50 - set temp2_max 50 + set temp1_max 80 + set temp2_max 80 diff --git a/device/dell/x86_64-dell_s6100_c2538-r0/bin/S6100-BIOS-3.25.0.2-7.bin b/device/dell/x86_64-dell_s6100_c2538-r0/bin/S6100-BIOS-3.25.0.2-7.bin new file mode 100644 index 00000000000..e6371a2602d Binary files /dev/null and b/device/dell/x86_64-dell_s6100_c2538-r0/bin/S6100-BIOS-3.25.0.2-7.bin differ diff --git a/device/dell/x86_64-dell_s6100_c2538-r0/s6100_cpld_upgrade b/device/dell/x86_64-dell_s6100_c2538-r0/s6100_cpld_upgrade index 17739c870d3..81af89a189b 100755 Binary files a/device/dell/x86_64-dell_s6100_c2538-r0/s6100_cpld_upgrade and b/device/dell/x86_64-dell_s6100_c2538-r0/s6100_cpld_upgrade differ diff --git a/dockers/docker-base/Dockerfile.j2 b/dockers/docker-base/Dockerfile.j2 index 79f5b0b5eb1..68a3176ab6e 100644 --- a/dockers/docker-base/Dockerfile.j2 +++ b/dockers/docker-base/Dockerfile.j2 @@ -67,6 +67,9 @@ RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return {%- endfor %} {%- endif %} +## Install redis-tools dependencies +RUN apt-get -y install libjemalloc1 + {% if docker_base_dbgs.strip() -%} # Install common debug-packages {%- for dbg_pkg in docker_base_dbgs.split(' ') %} diff --git a/dockers/docker-base/etc/rsyslog.conf b/dockers/docker-base/etc/rsyslog.conf index 1af66c6e61c..4851ac78447 100644 --- a/dockers/docker-base/etc/rsyslog.conf +++ b/dockers/docker-base/etc/rsyslog.conf @@ -70,6 +70,10 @@ $WorkDirectory /var/spool/rsyslog # $IncludeConfig /etc/rsyslog.d/*.conf +# +# Suppress duplicate messages and report "message repeated n times" +# +$RepeatedMsgReduction on ############### #### RULES #### diff --git a/dockers/docker-base/no-check-valid-until b/dockers/docker-base/no-check-valid-until index 97b9c900518..c7c25d017f7 100644 --- a/dockers/docker-base/no-check-valid-until +++ b/dockers/docker-base/no-check-valid-until @@ -1 +1,4 @@ +# Instruct apt-get to NOT check the "Valid Until" date in Release files +# Once the Debian team archives a repo, they stop updating this date + Acquire::Check-Valid-Until "false"; diff --git a/dockers/docker-database/base_image_files/monit_database b/dockers/docker-database/base_image_files/monit_database new file mode 100644 index 00000000000..c5508922864 --- /dev/null +++ b/dockers/docker-database/base_image_files/monit_database @@ -0,0 +1,7 @@ +############################################################################### +## Monit configuration for database container +## process list: +## redis_server +############################################################################### +check process redis_server matching "/usr/bin/redis-server" + if does not exist for 5 times within 5 cycles then alert diff --git a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 index cd18dfa1310..39358948639 100644 --- a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 +++ b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 @@ -68,5 +68,53 @@ stderr_logfile=syslog {% endif %} {% endfor %} + +[group:dhcpmon] +programs= +{%- set add_preceding_comma = { 'flag': False } %} +{% for vlan_name in VLAN %} +{% if VLAN[vlan_name]['dhcp_servers'] %} +{% if add_preceding_comma.flag %},{% endif %} +{% set _dummy = add_preceding_comma.update({'flag': True}) %} +dhcpmon-{{ vlan_name }} +{%- endif %} +{% endfor %} + + +{# Create a program entry for each DHCP MONitor instance #} +{% set relay_for_ipv4 = { 'flag': False } %} +{% for vlan_name in VLAN %} +{% if VLAN[vlan_name]['dhcp_servers'] %} +{% for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %} +{% if dhcp_server | ipv4 %} +{% set _dummy = relay_for_ipv4.update({'flag': True}) %} +{% endif %} +{% endfor %} +{% if relay_for_ipv4.flag %} +{% set _dummy = relay_for_ipv4.update({'flag': False}) %} +[program:dhcpmon-{{ vlan_name }}] +{# We treat this VLAN as a downstream interface (-id), as we only want to listen for requests #} +command=/usr/sbin/dhcpmon -id {{ vlan_name }} +{#- We treat all other interfaces as upstream interfaces (-iu), as we only want to listen for replies #} +{% for (name, prefix) in VLAN_INTERFACE %} +{% if prefix | ipv4 and name != vlan_name %} -iu {{ name }}{% endif -%} +{% endfor %} +{% for (name, prefix) in INTERFACE %} +{% if prefix | ipv4 %} -iu {{ name }}{% endif -%} +{% endfor %} +{% for (name, prefix) in PORTCHANNEL_INTERFACE %} +{% if prefix | ipv4 %} -iu {{ name }}{% endif -%} +{% endfor %} + +priority=4 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +{% endif %} +{% endif %} +{% endfor %} + {% endif %} {% endif %} diff --git a/dockers/docker-dhcp-relay/start.sh b/dockers/docker-dhcp-relay/start.sh index 54e58dd42a0..dbbf3225108 100755 --- a/dockers/docker-dhcp-relay/start.sh +++ b/dockers/docker-dhcp-relay/start.sh @@ -16,12 +16,12 @@ if [ $(supervisorctl status | grep -c "^isc-dhcp-relay:") -gt 0 ]; then # lifetime of the process. /usr/bin/wait_for_intf.sh - # Allow a bit more time for interfaces to settle before starting the - # relay agent processes. - # FIXME: Remove/decrease this once we determine how to prevent future race - # conditions here. - sleep 180 - # Start all DHCP relay agent(s) supervisorctl start isc-dhcp-relay:* fi + +# If our supervisor config has entries in the "dhcpmon" group... +if [ $(supervisorctl status | grep -c "^dhcpmon:") -gt 0 ]; then + # Start all DHCP Monitor daemon(s) + supervisorctl start dhcpmon:* +fi diff --git a/dockers/docker-fpm-frr/base_image_files/monit_bgp b/dockers/docker-fpm-frr/base_image_files/monit_bgp new file mode 100644 index 00000000000..5b943ea7c0b --- /dev/null +++ b/dockers/docker-fpm-frr/base_image_files/monit_bgp @@ -0,0 +1,23 @@ +############################################################################### +## Monit configuration for BGP container +## process list: +## zebra +## fpmsyncd +## bgpd +## staticd +## bgpcfgd +############################################################################### +check process zebra matching "/usr/lib/frr/zebra" + if does not exist for 5 times within 5 cycles then alert + +check process fpmsyncd matching "fpmsyncd" + if does not exist for 5 times within 5 cycles then alert + +check process bgpd matching "/usr/lib/frr/bgpd" + if does not exist for 5 times within 5 cycles then alert + +check process staticd matching "/usr/lib/frr/staticd" + if does not exist for 5 times within 5 cycles then alert + +check process bgpcfgd matching "python /usr/bin/bgpcfgd" + if does not exist for 5 times within 5 cycles then alert diff --git a/dockers/docker-fpm-quagga/bgpcfgd b/dockers/docker-fpm-quagga/bgpcfgd index 9063c8eef1b..10687df4396 100755 --- a/dockers/docker-fpm-quagga/bgpcfgd +++ b/dockers/docker-fpm-quagga/bgpcfgd @@ -78,6 +78,8 @@ class BGPConfigManager(object): def __init__(self, daemon): self.bgp_asn = None self.meta = None + self.lo_ipv4 = None + self.lo_ipv6 = None self.neig_meta = {} self.bgp_messages = [] self.peers = self.load_peers() # we can have bgp monitors peers here. it could be fixed by adding support for it here @@ -86,9 +88,11 @@ class BGPConfigManager(object): self.bgp_peer_del_template = fabric.from_string('no neighbor {{ neighbor_addr }}') self.bgp_peer_shutdown = fabric.from_string('neighbor {{ neighbor_addr }} shutdown') self.bgp_peer_no_shutdown = fabric.from_string('no neighbor {{ neighbor_addr }} shutdown') + self.zebra_set_src_template = fabric.from_file('zebra.set_src.conf.j2') daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, self.__metadata_handler) daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_NEIGHBOR_METADATA_TABLE_NAME, self.__neighbor_metadata_handler) daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_BGP_NEIGHBOR_TABLE_NAME, self.__bgp_handler) + daemon.add_manager(swsscommon.STATE_DB, swsscommon.STATE_INTERFACE_TABLE_NAME, self.__if_handler) def load_peers(self): peers = set() @@ -136,6 +140,35 @@ class BGPConfigManager(object): syslog.syslog(syslog.LOG_ERR,"Wrong operation '%s' for neighbor metadata handler" % op) self.__update_bgp() + def __if_handler(self, key, op, data): + cmds = [] + if op == swsscommon.SET_COMMAND and key.startswith("Loopback0|") and "state" in data and data["state"] == "ok": + ip_addr_w_mask = key.replace("Loopback0|", "") + slash_pos = ip_addr_w_mask.rfind("/") + if slash_pos == -1: + syslog.syslog(syslog.LOG_ERR, "Wrong Loopback0 ip address'%s'" % ip_addr_w_mask) + return + ip_addr = ip_addr_w_mask[:slash_pos] + try: + if TemplateFabric.is_ipv4(ip_addr) and self.lo_ipv4 is None: + self.lo_ipv4 = ip_addr + txt = self.zebra_set_src_template.render(rm_name="RM_SET_SRC", lo_ip=ip_addr, ip_proto="") + elif TemplateFabric.is_ipv6(ip_addr) and self.lo_ipv6 is None: + self.lo_ipv6 = ip_addr + txt = self.zebra_set_src_template.render(rm_name="RM_SET_SRC6", lo_ip=ip_addr, ip_proto="v6") + else: + syslog.syslog(syslog.LOG_ERR, "Got ambigous ip addres '%s'" % ip_addr) + except: + syslog.syslog(syslog.LOG_ERR, "Error while rendering set src template" % ip_addr) + else: + cmds.append(txt) + syslog.syslog(syslog.LOG_INFO, "Generate set src configuration with Loopback0 ipv4 '%s'" % ip_addr) + elif op == swsscommon.DEL_COMMAND: + syslog.syslog(syslog.LOG_INFO, "Delete command is not supported for set src templates" % ip_addr) + + for cmd in cmds: + self.__apply_cmd(cmd, zebra=True) + def __update_bgp(self): cmds = [] new_bgp_messages = [] @@ -180,7 +213,7 @@ class BGPConfigManager(object): for cmd in cmds: self.__apply_cmd(cmd) - def __apply_cmd(self, cmd): + def __apply_cmd(self, cmd, zebra=False): lines = [line for line in cmd.split("\n") if not line.startswith('!') and line.strip() != ""] if len(lines) == 0: return @@ -198,7 +231,11 @@ class BGPConfigManager(object): chunks.pop() chunks.append(line.strip()) - command = ["vtysh", "-c", "conf t", "-c", "router bgp %s" % self.bgp_asn] + command = ["vtysh", "-c", "conf t"] + if not zebra: + command.append("-c") + command.append("router bgp %s" % self.bgp_asn) + for chunk in chunks: command.append("-c") command.append(chunk) @@ -213,7 +250,7 @@ class BGPConfigManager(object): class Daemon(object): SELECT_TIMEOUT = 1000 - DATABASE_LIST = [ swsscommon.CONFIG_DB ] + DATABASE_LIST = [ swsscommon.CONFIG_DB, swsscommon.STATE_DB ] def __init__(self): self.db_connectors = { db : swsscommon.DBConnector(db, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) for db in Daemon.DATABASE_LIST } diff --git a/dockers/docker-fpm-quagga/supervisord.conf b/dockers/docker-fpm-quagga/supervisord.conf index c4351fafefe..692ee08fc68 100644 --- a/dockers/docker-fpm-quagga/supervisord.conf +++ b/dockers/docker-fpm-quagga/supervisord.conf @@ -31,7 +31,7 @@ stdout_logfile=syslog stderr_logfile=syslog [program:zebra] -command=/usr/lib/quagga/zebra -A 127.0.0.1 +command=/usr/lib/quagga/zebra -A 127.0.0.1 -s 2097152 priority=4 autostart=false autorestart=false diff --git a/dockers/docker-fpm-quagga/zebra.conf.j2 b/dockers/docker-fpm-quagga/zebra.conf.j2 index 4acb474b0e3..b21d3c83495 100644 --- a/dockers/docker-fpm-quagga/zebra.conf.j2 +++ b/dockers/docker-fpm-quagga/zebra.conf.j2 @@ -35,41 +35,6 @@ ip route 0.0.0.0/0 {{ MGMT_INTERFACE[(name, prefix)]['gwaddr'] }} 200 {% endfor %} {% endblock default_route %} ! -{% block source_loopback %} -{% set lo_ipv4_addrs = [] %} -{% set lo_ipv6_addrs = [] %} -{% if LOOPBACK_INTERFACE %} -{% for (name, prefix) in LOOPBACK_INTERFACE %} -{% if name == 'Loopback0' %} -{% if prefix | ipv6 %} -{% if lo_ipv6_addrs.append(prefix) %} -{% endif %} -{% else %} -{% if lo_ipv4_addrs.append(prefix) %} -{% endif %} -{% endif %} -{% endif %} -{% endfor %} -{% endif %} -! Set ip source to loopback for bgp learned routes -{% if lo_ipv4_addrs|length > 0 -%} -route-map RM_SET_SRC permit 10 - set src {{ lo_ipv4_addrs[0] | ip }} -! -{% endif %} -{% if lo_ipv6_addrs|length > 0 %} -route-map RM_SET_SRC6 permit 10 - set src {{ lo_ipv6_addrs[0] | ip }} -! -{% endif %} -ip protocol bgp route-map RM_SET_SRC -! -{% if lo_ipv6_addrs|length > 0 %} -ipv6 protocol bgp route-map RM_SET_SRC6 -! -{% endif %} -{% endblock source_loopback %} -! {% block logging %} log syslog informational log facility local4 diff --git a/dockers/docker-fpm-quagga/zebra.set_src.conf.j2 b/dockers/docker-fpm-quagga/zebra.set_src.conf.j2 new file mode 100644 index 00000000000..4dce3250ed1 --- /dev/null +++ b/dockers/docker-fpm-quagga/zebra.set_src.conf.j2 @@ -0,0 +1,8 @@ +! +! Set ip source to loopback for bgp learned routes +! +route-map {{ rm_name }} permit 10 + set src {{ lo_ip }} +! +ip{{ ip_proto }} protocol bgp route-map {{ rm_name }} +! diff --git a/dockers/docker-lldp-sv2/base_image_files/monit_lldp b/dockers/docker-lldp-sv2/base_image_files/monit_lldp new file mode 100644 index 00000000000..200c52c7d33 --- /dev/null +++ b/dockers/docker-lldp-sv2/base_image_files/monit_lldp @@ -0,0 +1,15 @@ +############################################################################### +## Monit configuration for lldp container +## process list: +## lldpd +## lldp-syncd +## lldpmgrd +############################################################################### +check process lldpd_monitor matching "lldpd: " + if does not exist for 5 times within 5 cycles then alert + +check process lldp_syncd matching "python2 -m lldp_syncd" + if does not exist for 5 times within 5 cycles then alert + +check process lldpmgrd matching "python /usr/bin/lldpmgrd" + if does not exist for 5 times within 5 cycles then alert diff --git a/dockers/docker-lldp-sv2/lldpmgrd b/dockers/docker-lldp-sv2/lldpmgrd index edcdc5c42e4..5dda900287f 100755 --- a/dockers/docker-lldp-sv2/lldpmgrd +++ b/dockers/docker-lldp-sv2/lldpmgrd @@ -157,7 +157,7 @@ class LldpManager(object): # if there is a description available, also configure that if port_desc: - lldpcli_cmd += " description {}".format(port_desc) + lldpcli_cmd += " description '{}'".format(port_desc) else: log_info("Unable to retrieve description for port '{}'. Not adding port description".format(port_name)) diff --git a/dockers/docker-orchagent/Dockerfile.j2 b/dockers/docker-orchagent/Dockerfile.j2 index 54088db30e5..6b835297b7d 100755 --- a/dockers/docker-orchagent/Dockerfile.j2 +++ b/dockers/docker-orchagent/Dockerfile.j2 @@ -11,9 +11,6 @@ RUN apt-get update RUN apt-get install -f -y ifupdown arping libdbus-1-3 libdaemon0 libjansson4 libpython2.7 RUN apt-get install -f -y ndisc6 tcpdump python-scapy -## Install redis-tools dependencies -## TODO: implicitly install dependencies -RUN apt-get -y install libjemalloc1 RUN apt-get install -y libelf1 libmnl0 diff --git a/dockers/docker-orchagent/base_image_files/monit_swss b/dockers/docker-orchagent/base_image_files/monit_swss new file mode 100644 index 00000000000..5928dbd4ddb --- /dev/null +++ b/dockers/docker-orchagent/base_image_files/monit_swss @@ -0,0 +1,43 @@ +############################################################################### +## Monit configuration for swss container +## process list: +## orchagent +## portsyncd +## neighsyncd +## vrfmgrd +## vlanmgrd +## intfmgrd +## portmgrd +## buffermgrd +## nbrmgrd +## vxlanmgrd +############################################################################### +check process orchagent matching "/usr/bin/orchagent -d /var/log/swss" + if does not exist for 5 times within 5 cycles then alert + +check process portsyncd matching "/usr/bin/portsyncd" + if does not exist for 5 times within 5 cycles then alert + +check process neighsyncd matching "/usr/bin/neighsyncd" + if does not exist for 5 times within 5 cycles then alert + +check process vrfmgrd matching "/usr/bin/vrfmgrd" + if does not exist for 5 times within 5 cycles then alert + +check process vlanmgrd matching "/usr/bin/vlanmgrd" + if does not exist for 5 times within 5 cycles then alert + +check process intfmgrd matching "/usr/bin/intfmgrd" + if does not exist for 5 times within 5 cycles then alert + +check process portmgrd matching "/usr/bin/portmgrd" + if does not exist for 5 times within 5 cycles then alert + +check process buffermgrd matching "/usr/bin/buffermgrd -l" + if does not exist for 5 times within 5 cycles then alert + +check process nbrmgrd matching "/usr/bin/nbrmgrd" + if does not exist for 5 times within 5 cycles then alert + +check process vxlanmgrd matching "/usr/bin/vxlanmgrd" + if does not exist for 5 times within 5 cycles then alert diff --git a/dockers/docker-orchagent/orchagent.sh b/dockers/docker-orchagent/orchagent.sh index 06726e335f9..1870363c6bb 100755 --- a/dockers/docker-orchagent/orchagent.sh +++ b/dockers/docker-orchagent/orchagent.sh @@ -4,7 +4,11 @@ # vendor specific code. export platform=`sonic-cfggen -y /etc/sonic/sonic_version.yml -v asic_type` -MAC_ADDRESS=`ip link show eth0 | grep ether | awk '{print $2}'` +MAC_ADDRESS=$(sonic-cfggen -d -v 'DEVICE_METADATA.localhost.mac') +if [ "$MAC_ADDRESS" == "None" ] || [ -z "$MAC_ADDRESS" ]; then + MAC_ADDRESS=$(ip link show eth0 | grep ether | awk '{print $2}') + logger "Mac address not found in Device Metadata, Falling back to eth0" +fi # Create a folder for SwSS record files mkdir -p /var/log/swss diff --git a/dockers/docker-platform-monitor/Dockerfile.j2 b/dockers/docker-platform-monitor/Dockerfile.j2 index 5d621223cc2..6a15f6e08e9 100755 --- a/dockers/docker-platform-monitor/Dockerfile.j2 +++ b/dockers/docker-platform-monitor/Dockerfile.j2 @@ -45,5 +45,6 @@ RUN rm -rf /debs /python-wheels ~/.cache COPY ["start.sh", "lm-sensors.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["ssd_tools/*", "/usr/bin/"] ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-platform-monitor/base_image_files/sensors b/dockers/docker-platform-monitor/base_image_files/cmd_wrapper similarity index 69% rename from dockers/docker-platform-monitor/base_image_files/sensors rename to dockers/docker-platform-monitor/base_image_files/cmd_wrapper index 23a12034f07..74e5dd7ab9c 100755 --- a/dockers/docker-platform-monitor/base_image_files/sensors +++ b/dockers/docker-platform-monitor/base_image_files/cmd_wrapper @@ -7,4 +7,4 @@ if [ -t 1 ] ; then DOCKER_EXEC_FLAGS+="t" fi -docker exec -$DOCKER_EXEC_FLAGS pmon sensors "$@" +docker exec -$DOCKER_EXEC_FLAGS pmon $(basename $0) "$@" diff --git a/dockers/docker-platform-monitor/ssd_tools/SmartCmd b/dockers/docker-platform-monitor/ssd_tools/SmartCmd new file mode 100755 index 00000000000..dae647e4697 Binary files /dev/null and b/dockers/docker-platform-monitor/ssd_tools/SmartCmd differ diff --git a/dockers/docker-platform-monitor/ssd_tools/iSmart b/dockers/docker-platform-monitor/ssd_tools/iSmart new file mode 100755 index 00000000000..c6bba004602 Binary files /dev/null and b/dockers/docker-platform-monitor/ssd_tools/iSmart differ diff --git a/dockers/docker-platform-monitor/supervisord.conf b/dockers/docker-platform-monitor/supervisord.conf index aa947ce2c9a..a0f2b7a387a 100644 --- a/dockers/docker-platform-monitor/supervisord.conf +++ b/dockers/docker-platform-monitor/supervisord.conf @@ -33,9 +33,10 @@ startsecs=0 command=/usr/sbin/fancontrol priority=4 autostart=false -autorestart=false +autorestart=unexpected stdout_logfile=syslog stderr_logfile=syslog +startsecs=10 [program:ledd] command=/usr/bin/ledd diff --git a/dockers/docker-sflow/base_image_files/monit_sflow b/dockers/docker-sflow/base_image_files/monit_sflow new file mode 100644 index 00000000000..d041f81001e --- /dev/null +++ b/dockers/docker-sflow/base_image_files/monit_sflow @@ -0,0 +1,7 @@ +############################################################################### +## Monit configuration for sflow container +## process list: +## sflowmgrd +############################################################################### +check process sflowmgrd matching "/usr/bin/sflowmgrd" + if does not exist for 5 times within 5 cycles then alert diff --git a/dockers/docker-snmp-sv2/base_image_files/monit_snmp b/dockers/docker-snmp-sv2/base_image_files/monit_snmp new file mode 100644 index 00000000000..811f9d14b3d --- /dev/null +++ b/dockers/docker-snmp-sv2/base_image_files/monit_snmp @@ -0,0 +1,11 @@ +############################################################################### +## Monit configuration for snmp container +## process list: +## snmpd +## snmpd_subagent +############################################################################### +check process snmpd matching "/usr/sbin/snmpd -f" + if does not exist for 5 times within 5 cycles then alert + +check process snmp_subagent matching "python3.6 -m sonic_ax_impl" + if does not exist for 5 times within 5 cycles then alert diff --git a/dockers/docker-sonic-telemetry/Dockerfile.j2 b/dockers/docker-sonic-telemetry/Dockerfile.j2 index 6b77f999e5e..90fc13f28c6 100644 --- a/dockers/docker-sonic-telemetry/Dockerfile.j2 +++ b/dockers/docker-sonic-telemetry/Dockerfile.j2 @@ -10,10 +10,6 @@ RUN apt-get update RUN apt-get install -f -y libdbus-1-3 libdaemon0 libjansson4 -## Install redis-tools dependencies -## TODO: implicitly install dependencies -RUN apt-get -y install libjemalloc1 - COPY \ {% for deb in docker_sonic_telemetry_debs.split(' ') -%} debs/{{ deb }}{{' '}} diff --git a/dockers/docker-sonic-telemetry/base_image_files/monit_telemetry b/dockers/docker-sonic-telemetry/base_image_files/monit_telemetry new file mode 100644 index 00000000000..555822c57f8 --- /dev/null +++ b/dockers/docker-sonic-telemetry/base_image_files/monit_telemetry @@ -0,0 +1,11 @@ +############################################################################### +## Monit configuration for telemetry container +## process list: +## telemetry +## dialout_client +############################################################################### +check process telemetry matching "/usr/sbin/telemetry -logtostderr --insecure" + if does not exist for 5 times within 5 cycles then alert + +check process dialout_client matching "/usr/sbin/dialout_client_cli -insecure -logtostderr" + if does not exist for 5 times within 5 cycles then alert diff --git a/dockers/docker-teamd/Dockerfile.j2 b/dockers/docker-teamd/Dockerfile.j2 index cb749ccf8ea..458c0ef3d02 100644 --- a/dockers/docker-teamd/Dockerfile.j2 +++ b/dockers/docker-teamd/Dockerfile.j2 @@ -10,10 +10,6 @@ RUN apt-get update RUN apt-get install -f -y libdbus-1-3 libdaemon0 libjansson4 libpython2.7 -## Install redis-tools dependencies -## TODO: implicitly install dependencies -RUN apt-get -y install libjemalloc1 - COPY \ {% for deb in docker_teamd_debs.split(' ') -%} debs/{{ deb }}{{' '}} diff --git a/dockers/docker-teamd/supervisord.conf b/dockers/docker-teamd/supervisord.conf index 738751d0a59..cce19e5be16 100644 --- a/dockers/docker-teamd/supervisord.conf +++ b/dockers/docker-teamd/supervisord.conf @@ -30,6 +30,7 @@ stderr_logfile=syslog [program:teamsyncd] command=/usr/bin/teamsyncd priority=3 +startsecs=5 autostart=false autorestart=false stdout_logfile=syslog diff --git a/files/Aboot/boot0.j2 b/files/Aboot/boot0.j2 index cd53a7f1863..df1b890ba63 100644 --- a/files/Aboot/boot0.j2 +++ b/files/Aboot/boot0.j2 @@ -215,7 +215,7 @@ platform_specific() { flash_size=3700 echo "amd_iommu=off" >> /tmp/append fi - if [ "$sid" = "Gardena" ] || [ "$sid" = "GardenaSsd" ]; then + if [ "$sid" = "Gardena" ] || [ "$sid" = "GardenaSsd" ] || [ "$sid" = "GardenaE" ]; then aboot_machine=arista_7260cx3_64 flash_size=28000 fi @@ -307,7 +307,7 @@ write_boot_configs() { } run_kexec() { - local cmdline="$(cat $cmdline_image | tr '\n' ' ')" + local cmdline="$(cat $cmdline_image | tr '\n' ' ') $ENV_EXTRA_CMDLINE" 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)}" diff --git a/files/apt/apt.conf.d/no-check-valid-until b/files/apt/apt.conf.d/no-check-valid-until new file mode 100644 index 00000000000..c7c25d017f7 --- /dev/null +++ b/files/apt/apt.conf.d/no-check-valid-until @@ -0,0 +1,4 @@ +# Instruct apt-get to NOT check the "Valid Until" date in Release files +# Once the Debian team archives a repo, they stop updating this date + +Acquire::Check-Valid-Until "false"; diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 index 215bdcc3b8e..1bf0552a29d 100644 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -57,6 +57,11 @@ function postStartAction() sonic-cfggen -j /etc/sonic/config_db.json --write-to-db fi + if [[ "$BOOT_TYPE" == "fast" ]]; then + # set the key to expire in 3 minutes + redis-cli -n 6 SET "FAST_REBOOT|system" "1" "EX" "180" + fi + redis-cli -n 4 SET "CONFIG_DB_INITIALIZED" "1" fi diff --git a/files/build_templates/process-reboot-cause.timer b/files/build_templates/process-reboot-cause.timer new file mode 100644 index 00000000000..222c51a79a0 --- /dev/null +++ b/files/build_templates/process-reboot-cause.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Delays process-reboot-cause until network is stably connected + +[Timer] +OnBootSec=1min 30 sec +Unit=process-reboot-cause.service + +[Install] +WantedBy=timers.target diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index e12ac17b66f..d75e9ef754c 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -34,6 +34,8 @@ FILESYSTEM_ROOT_USR="$FILESYSTEM_ROOT/usr" FILESYSTEM_ROOT_USR_SHARE="$FILESYSTEM_ROOT_USR/share" FILESYSTEM_ROOT_USR_SHARE_SONIC="$FILESYSTEM_ROOT_USR_SHARE/sonic" FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES="$FILESYSTEM_ROOT_USR_SHARE_SONIC/templates" +FILESYSTEM_ROOT_ETC="$FILESYSTEM_ROOT/etc" +FILESYSTEM_ROOT_ETC_SONIC="$FILESYSTEM_ROOT_ETC/sonic" clean_sys() { sudo umount $FILESYSTEM_ROOT/sys/fs/cgroup/* \ @@ -135,9 +137,22 @@ sudo dpkg --root=$FILESYSTEM_ROOT -i target/debs/libnss-tacplus_*.deb || \ sudo LANG=C chroot $FILESYSTEM_ROOT pam-auth-update --remove tacplus sudo sed -i -e '/^passwd/s/ tacplus//' $FILESYSTEM_ROOT/etc/nsswitch.conf +# Install custom-built monit package and SONiC configuration files +sudo dpkg --root=$FILESYSTEM_ROOT -i target/debs/monit_*.deb || \ + sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f +sudo cp $IMAGE_CONFIGS/monit/monitrc $FILESYSTEM_ROOT/etc/monit/ +sudo chmod 600 $FILESYSTEM_ROOT/etc/monit/monitrc +sudo cp $IMAGE_CONFIGS/monit/conf.d/* $FILESYSTEM_ROOT/etc/monit/conf.d/ +sudo chmod 600 $FILESYSTEM_ROOT/etc/monit/conf.d/* + # Copy crontabs sudo cp -f $IMAGE_CONFIGS/cron.d/* $FILESYSTEM_ROOT/etc/cron.d/ +# Copy watchdog-control files +sudo LANG=C cp $IMAGE_CONFIGS/watchdog-control/watchdog-control.sh $FILESYSTEM_ROOT/usr/local/bin/watchdog-control.sh +sudo LANG=C cp $IMAGE_CONFIGS/watchdog-control/watchdog-control.service $FILESYSTEM_ROOT/etc/systemd/system/ +sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable watchdog-control.service + # Copy NTP configuration files and templates sudo cp $IMAGE_CONFIGS/ntp/ntp-config.service $FILESYSTEM_ROOT/etc/systemd/system/ sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable ntp-config.service @@ -177,6 +192,16 @@ sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable hostcfgd.service sudo cp $IMAGE_CONFIGS/hostcfgd/hostcfgd $FILESYSTEM_ROOT/usr/bin/ sudo cp $IMAGE_CONFIGS/hostcfgd/*.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/ +# copy core file uploader files +sudo cp $IMAGE_CONFIGS/corefile_uploader/core_uploader.service $FILESYSTEM_ROOT/etc/systemd/system/ +sudo LANG=C chroot $FILESYSTEM_ROOT systemctl disable core_uploader.service +sudo cp $IMAGE_CONFIGS/corefile_uploader/core_uploader.py $FILESYSTEM_ROOT/usr/bin/ +sudo cp $IMAGE_CONFIGS/corefile_uploader/core_analyzer.rc.json $FILESYSTEM_ROOT_ETC_SONIC/ +sudo chmod og-rw $FILESYSTEM_ROOT_ETC_SONIC/core_analyzer.rc.json +sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install azure-storage +sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install watchdog +sudo https_proxy=$https_proxy LANG=C chroot $FILESYSTEM_ROOT pip install futures + # Copy the buffer configuration template sudo cp $BUILD_TEMPLATES/buffers_config.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/ @@ -220,6 +245,11 @@ sudo cp $IMAGE_CONFIGS/caclmgrd/caclmgrd.service $FILESYSTEM_ROOT/etc/systemd/s sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable caclmgrd.service sudo cp $IMAGE_CONFIGS/caclmgrd/caclmgrd $FILESYSTEM_ROOT/usr/bin/ +# Copy systemd timer configuration +# It implements delayed start of services +sudo cp $BUILD_TEMPLATES/process-reboot-cause.timer $FILESYSTEM_ROOT/etc/systemd/system/ +sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable process-reboot-cause.timer + # Copy process-reboot-cause service files sudo cp $IMAGE_CONFIGS/process-reboot-cause/process-reboot-cause.service $FILESYSTEM_ROOT/etc/systemd/system/ sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable process-reboot-cause.service @@ -328,12 +358,14 @@ sudo cp {{src}} $FILESYSTEM_ROOT/{{dst}} {% if sonic_asic_platform == "mellanox" %} sudo mkdir -p $FILESYSTEM_ROOT/etc/mlnx/cpld/ -sudo cp target/files/$MLNX_FW_FILE $FILESYSTEM_ROOT/etc/mlnx/fw-SPC.mfa +sudo cp target/files/$MLNX_SPC_FW_FILE $FILESYSTEM_ROOT/etc/mlnx/fw-SPC.mfa for MLNX_CPLD_ARCHIVE in $MLNX_CPLD_ARCHIVES; do sudo cp target/files/$MLNX_CPLD_ARCHIVE $FILESYSTEM_ROOT/etc/mlnx/cpld/ done 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 target/files/$HW_MANAGEMENT_WD_SCRIPT $FILESYSTEM_ROOT/usr/bin/$HW_MANAGEMENT_WD_SCRIPT +sudo cp target/files/$MLNX_SSD_FW_UPDATE $FILESYSTEM_ROOT/usr/bin/$MLNX_SSD_FW_UPDATE 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 diff --git a/files/image_config/caclmgrd/caclmgrd b/files/image_config/caclmgrd/caclmgrd index 5e8d83074de..e5744c7ca65 100755 --- a/files/image_config/caclmgrd/caclmgrd +++ b/files/image_config/caclmgrd/caclmgrd @@ -194,13 +194,14 @@ class ControlPlaneAclManager(object): continue # If we haven't determined the IP version for this ACL table yet, - # try to do it now. We determine heuristically based on whether the - # src IP is an IPv4 or IPv6 address. - if not table_ip_version and "SRC_IP" in rule_props and rule_props["SRC_IP"]: - ip_addr = ipaddress.IPAddress(rule_props["SRC_IP"].split("/")[0]) - if isinstance(ip_addr, ipaddress.IPv6Address): + # try to do it now. We attempt to determine heuristically based on + # whether the src or dst IP of this rule is an IPv4 or IPv6 address. + if not table_ip_version: + if (("SRC_IPV6" in rule_props and rule_props["SRC_IPV6"]) or + ("DST_IPV6" in rule_props and rule_props["DST_IPV6"])): table_ip_version = 6 - elif isinstance(ip_addr, ipaddress.IPv4Address): + elif (("SRC_IP" in rule_props and rule_props["SRC_IP"]) or + ("DST_IP" in rule_props and rule_props["DST_IP"])): table_ip_version = 4 # If we were unable to determine whether this ACL table contains @@ -224,7 +225,9 @@ class ControlPlaneAclManager(object): rule_cmd = "ip6tables" if table_ip_version == 6 else "iptables" rule_cmd += " -A INPUT -p {}".format(ip_protocol) - if "SRC_IP" in rule_props and rule_props["SRC_IP"]: + if "SRC_IPV6" in rule_props and rule_props["SRC_IPV6"]: + rule_cmd += " -s {}".format(rule_props["SRC_IPV6"]) + elif "SRC_IP" in rule_props and rule_props["SRC_IP"]: rule_cmd += " -s {}".format(rule_props["SRC_IP"]) rule_cmd += " --dport {}".format(dst_port) diff --git a/files/image_config/corefile_uploader/core_analyzer.rc.json b/files/image_config/corefile_uploader/core_analyzer.rc.json new file mode 100644 index 00000000000..3ffa33fd1e1 --- /dev/null +++ b/files/image_config/corefile_uploader/core_analyzer.rc.json @@ -0,0 +1,17 @@ +{ + "local_work": { + "core_upload": "/tmp/core_upload/" + }, + "azure_sonic_core_storage": { + "account_name": "corefilecollection", + "account_key": "", + "share_name": "corefiles-root" + }, + "metadata_files_in_archive": { + "version": "/etc/sonic/sonic_version.yml", + "core_info": "core_info.json" + }, + "env": { + "https_proxy": "" + } +} diff --git a/files/image_config/corefile_uploader/core_uploader.py b/files/image_config/corefile_uploader/core_uploader.py new file mode 100755 index 00000000000..2ae91ce0896 --- /dev/null +++ b/files/image_config/corefile_uploader/core_uploader.py @@ -0,0 +1,285 @@ +#!/usr/bin/env python + +import os +import time +import tarfile +import socket +import yaml +import json +import syslog +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler +from azure.storage.file import FileService + +global CORE_FILE_PATH, RC_FILE +global hostname, sonicversion, asicname, acctname, acctkey, sharename, cwd +global INIT_CWD +global log_level +global this_file + +this_file = os.path.basename(__file__) + +global cfg +cfg = "" + +CORE_FILE_PATH = "/var/core/" +RC_FILE = "/etc/sonic/core_analyzer.rc.json" +INIT_CWD = "/tmp" + +hostname = "" +sonicversion = "" +asicname = "" +acctname = "" +acctkey = "" +sharename = "" +cwd = [] + +HOURS_4 = (4 * 60 * 60) +PAUSE_ON_FAIL = (60 * 60) +WAIT_FILE_WRITE1 = (10 * 60) +WAIT_FILE_WRITE2= (5 * 60) +POLL_SLEEP = (60 * 60) +MAX_RETRIES = 5 +UPLOAD_PREFIX = "UPLOADED_" + +log_level = syslog.LOG_DEBUG + +def log_msg(lvl, fname, m): + if (lvl <= log_level): + syslog.syslog(lvl, "{}: {}".format(fname, m)) + + if log_level == syslog.LOG_DEBUG: + print("{}: {}".format(fname, m)) + +def log_err(m): + log_msg(syslog.LOG_ERR, this_file, m) + +def log_info(m): + log_msg(syslog.LOG_INFO, this_file, m) + +def log_warn(m): + log_msg(syslog.LOG_WARNING, this_file, m) + +def log_debug(m): + log_msg(syslog.LOG_DEBUG, this_file, m) + + +def make_new_dir(p): + os.system("rm -rf " + p) + os.system("mkdir -p " + p) + +def parse_a_json(data, prefix, val): + for i in data: + if type(data[i]) == dict: + parse_a_json(data[i], prefix + (i,), val) + else: + val[prefix + (i,)] = data[i] + +class config: + parsed_data = {} + cfg_data = {} + + def __init__(self): + while not os.path.exists(RC_FILE): + # Wait here until service restart + log_err("Unable to retrieve Azure storage credentials") + time.sleep (HOURS_4) + + with open(RC_FILE, 'r') as f: + self.parsed_data = json.load(f) + parse_a_json(self.parsed_data, (), self.cfg_data) + + def get_data(self, k): + return self.cfg_data[k] if self.cfg_data.has_key(k) else "" + + def get_dict(self): + return self.parsed_data + + def get_core_info(self, corepath, devicename): + info = {} + info["corefname"] = os.path.basename(corepath) + info["tstamp"] = str(os.stat(corepath).st_ctime) + info["devicename"] = devicename + + lpath = self.get_data(("metadata_files_in_archive", "core_info")) + f = open(lpath, "w+") + f.write(json.dumps(info, indent=4)) + f.close() + + return lpath + + +class Watcher: + + def __init__(self): + self.observer = Observer() + + def run(self): + event_handler = Handler() + self.observer.schedule(event_handler, CORE_FILE_PATH) + self.observer.start() + try: + while True: + time.sleep(POLL_SLEEP) + except: + self.observer.stop() + log_err("Error in watcher") + + self.observer.join() + +def set_env(lst): + for k in lst: + if lst[k]: + os.environ[k] = lst[k] + log_debug("set env {} = {}".format(k, lst[k])) + +class Handler(FileSystemEventHandler): + + @staticmethod + def init(): + global hostname, sonicversion, asicname, acctname, acctkey, sharename + global cwd, cfg + + cfg = config() + + set_env(cfg.get_dict()["env"]) + + hostname = socket.gethostname() + if not hostname: + raise Exception("Failed to read hostname") + + acctname = cfg.get_data(("azure_sonic_core_storage", "account_name")) + acctkey = cfg.get_data(("azure_sonic_core_storage", "account_key")) + sharename = cfg.get_data(("azure_sonic_core_storage", "share_name")) + + if not acctname or not acctkey or not sharename: + while True: + # Wait here until service restart + log_err("Unable to retrieve Azure storage credentials") + time.sleep (HOURS_4) + + with open("/etc/sonic/sonic_version.yml", 'r') as stream: + l = yaml.safe_load(stream) + sonicversion = l['build_version'] + asicname = l['asic_type'] + + if not sonicversion: + raise Exception("Failed to read build_version from /etc/sonic/sonic_version.yml") + + if not asicname: + raise Exception("Failed to read asic_type from /etc/sonic/sonic_version.yml") + + cwd = cfg.get_data(("local_work", "core_upload")).split("/") + if not len(cwd) > 2: + raise Exception("Invalid path for core_upload. Expect a min of two elements in path") + + os.chdir(INIT_CWD) + + @staticmethod + def on_any_event(event): + if event.is_directory: + return None + + elif event.event_type == 'created': + # Take any action here when a file is first created. + log_debug("Received create event - " + event.src_path) + Handler.wait_for_file_write_complete(event.src_path) + Handler.handle_file(event.src_path) + + + @staticmethod + def wait_for_file_write_complete(path): + mtime = 0 + + # Sleep for ample time enough for file dump to complete. + time.sleep(WAIT_FILE_WRITE1) + + # Give another chance & poll until mtime stabilizes + while mtime != os.stat(path).st_mtime: + mtime = os.stat(path).st_mtime + time.sleep(10) + + # A safety pause for double confirmation + time.sleep(WAIT_FILE_WRITE2) + if mtime != os.stat(path).st_mtime: + raise Exception("Dump file creation is too slow: " + path) + # Give up as something is terribly wrong with this file. + + log_debug("File write complete - " + path) + + + @staticmethod + def handle_file(path): + lpath = "/".join(cwd) + make_new_dir(lpath) + os.chdir(lpath) + + # Create a new archive with core & more. + metafiles = cfg.get_dict()["metadata_files_in_archive"] + + fname = os.path.basename(path) + tarf_name = fname + ".tar.gz" + + cfg.get_core_info(path, hostname) + + tar = tarfile.open(tarf_name, "w:gz") + for e in metafiles: + tar.add(metafiles[e]) + tar.add(path) + tar.close() + log_debug("Tar file for upload created: " + tarf_name) + + Handler.upload_file(tarf_name, tarf_name, path) + + log_debug("File uploaded - " + path) + os.chdir(INIT_CWD) + + @staticmethod + def upload_file(fname, fpath, coref): + daemonname = fname.split(".")[0] + i = 0 + fail_msg = "" + + while True: + try: + svc = FileService(account_name=acctname, account_key=acctkey) + + l = [sonicversion, asicname, daemonname, hostname] + e = [] + while len(e) != len(l): + e.append(l[len(e)]) + svc.create_directory(sharename, "/".join(e)) + + log_debug("Remote dir created: " + "/".join(e)) + + svc.create_file_from_path(sharename, "/".join(l), fname, fpath) + log_debug("Remote file created: name{} path{}".format(fname, fpath)) + newcoref = os.path.dirname(coref) + "/" + UPLOAD_PREFIX + os.path.basename(coref) + os.rename(coref, newcoref) + break + + except Exception as ex: + log_err("core uploader failed: Failed during upload (" + coref + ") err: ("+ str(ex) +") retry:" + str(i)) + if not os.path.exists(fpath): + break + i += 1 + time.sleep(PAUSE_ON_FAIL) + + + @staticmethod + def scan(): + for e in os.listdir(CORE_FILE_PATH): + fl = CORE_FILE_PATH + e + if os.path.isfile(fl) and not e.startswith(UPLOAD_PREFIX): + Handler.handle_file(fl) + + +if __name__ == '__main__': + try: + Handler.init() + w = Watcher() + Handler.scan() + w.run() + except Exception as e: + log_err("core uploader failed: " + str(e) + " Exiting ...") + diff --git a/files/image_config/corefile_uploader/core_uploader.service b/files/image_config/corefile_uploader/core_uploader.service new file mode 100644 index 00000000000..09ac1bd5191 --- /dev/null +++ b/files/image_config/corefile_uploader/core_uploader.service @@ -0,0 +1,13 @@ +[Unit] +Description=Host core file uploader daemon +Requires=syslog.service +After=syslog.service + +[Service] +Type=simple +ExecStart=/usr/bin/core_uploader.py +StandardOutput=null +Restart=on-failure + +[Install] +WantedBy=multi-user.target diff --git a/files/image_config/hostcfgd/hostcfgd b/files/image_config/hostcfgd/hostcfgd index 0563947acb8..5e80fd025dc 100755 --- a/files/image_config/hostcfgd/hostcfgd +++ b/files/image_config/hostcfgd/hostcfgd @@ -168,6 +168,11 @@ class AaaCfg(object): if modify_conf: self.modify_conf_file() + def modify_single_file(self, filename, operations=None): + if operations: + cmd = "sed -e {0} {1} > {1}.new; mv -f {1} {1}.old; mv -f {1}.new {1}".format(' -e '.join(operations), filename) + os.system(cmd) + def modify_conf_file(self): auth = self.auth_default.copy() auth.update(self.auth) @@ -193,19 +198,19 @@ class AaaCfg(object): # Modify common-auth include file in /etc/pam.d/login and sshd if os.path.isfile(PAM_AUTH_CONF): - os.system("sed -i -e '/^@include/s/common-auth$/common-auth-sonic/' /etc/pam.d/sshd") - os.system("sed -i -e '/^@include/s/common-auth$/common-auth-sonic/' /etc/pam.d/login") + self.modify_single_file('/etc/pam.d/sshd', [ "'/^@include/s/common-auth$/common-auth-sonic/'" ]) + self.modify_single_file('/etc/pam.d/login', [ "'/^@include/s/common-auth$/common-auth-sonic/'" ]) else: - os.system("sed -i -e '/^@include/s/common-auth-sonic$/common-auth/' /etc/pam.d/sshd") - os.system("sed -i -e '/^@include/s/common-auth-sonic$/common-auth/' /etc/pam.d/login") + self.modify_single_file('/etc/pam.d/sshd', [ "'/^@include/s/common-auth-sonic$/common-auth/'" ]) + self.modify_single_file('/etc/pam.d/login', [ "'/^@include/s/common-auth-sonic$/common-auth/'" ]) # Add tacplus in nsswitch.conf if TACACS+ enable if 'tacacs+' in auth['login']: if os.path.isfile(NSS_CONF): - os.system("sed -i -e '/tacplus/b' -e '/^passwd/s/compat/tacplus &/' /etc/nsswitch.conf") + self.modify_single_file(NSS_CONF, [ "'/tacplus/b'", "'/^passwd/s/compat/tacplus &/'"]) else: if os.path.isfile(NSS_CONF): - os.system("sed -i -e '/^passwd/s/tacplus //' /etc/nsswitch.conf") + self.modify_single_file(NSS_CONF, [ "'/^passwd/s/tacplus //'" ]) # Set tacacs+ server in nss-tacplus conf template_file = os.path.abspath(NSS_TACPLUS_CONF_TEMPLATE) diff --git a/files/image_config/interfaces/interfaces-config.sh b/files/image_config/interfaces/interfaces-config.sh index 29664bcda56..86e30786bf3 100755 --- a/files/image_config/interfaces/interfaces-config.sh +++ b/files/image_config/interfaces/interfaces-config.sh @@ -20,4 +20,6 @@ fi systemctl restart networking -ifdown lo && ifup lo +ifdown --force lo +ip addr flush dev lo +ifup lo diff --git a/files/image_config/monit/conf.d/sonic-host b/files/image_config/monit/conf.d/sonic-host new file mode 100644 index 00000000000..5a67f7a9909 --- /dev/null +++ b/files/image_config/monit/conf.d/sonic-host @@ -0,0 +1,22 @@ +############################################################################### +## Monit configuration for SONiC host OS +## +## This includes system-level monitoring as well as processes which +## run in the host OS (i.e., not inside a Docker container) +############################################################################### + +check filesystem root-overlay with path / + if space usage > 90% for 10 times within 20 cycles then alert + +check filesystem var-log with path /var/log + if space usage > 90% for 10 times within 20 cycles then alert + +check system $HOST + if memory usage > 90% for 10 times within 20 cycles then alert + if cpu usage (user) > 90% for 10 times within 20 cycles then alert + if cpu usage (system) > 90% for 10 times within 20 cycles then alert + +check process rsyslog with pidfile /var/run/rsyslogd.pid + start program = "/bin/systemctl start rsyslog.service" + stop program = "/bin/systemctl stop rsyslog.service" + if totalmem > 800 MB for 10 times within 20 cycles then restart diff --git a/files/image_config/monit/monitrc b/files/image_config/monit/monitrc index f9350733fa4..74068f12d3f 100644 --- a/files/image_config/monit/monitrc +++ b/files/image_config/monit/monitrc @@ -16,16 +16,16 @@ ## ## Start Monit in the background (run as a daemon): # - set daemon 120 # check services at 2-minute intervals -# with start delay 240 # optional: delay the first check by 4-minutes (by -# # default Monit check immediately after Monit start) + set daemon 60 # check services at 1-minute intervals + with start delay 300 # we delay Monit to start monitoring for 5 minutes + # intentionally such that all containers and processes + # have ample time to start up. # # ## Set syslog logging. If you want to log to a standalone log file instead, ## specify the full path to the log file # -# set logfile /var/log/monit.log -set logfile syslog + set logfile syslog # # ## Set the location of the Monit lock file which stores the process id of the @@ -153,8 +153,8 @@ set logfile syslog ## commands to a running Monit daemon. See the Monit Wiki if you want to ## enable SSL for the HTTP interface. # -set httpd unixsocket /var/run/monit.sock and - allow localhost # allow localhost to connect to the server and + set httpd unixsocket /var/run/monit.sock and + allow localhost # allow localhost to connect to the server # ############################################################################### ## Services @@ -294,15 +294,3 @@ set httpd unixsocket /var/run/monit.sock and include /etc/monit/conf.d/* include /etc/monit/conf-enabled/* # -check filesystem root-overlay with path / - if space usage > 90% for 5 times within 10 cycles then alert -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 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 -check process rsyslog with pidfile /var/run/rsyslogd.pid - start program = "/bin/systemctl start rsyslog.service" - stop program = "/bin/systemctl stop rsyslog.service" - if totalmem > 800 MB for 5 times within 10 cycles then restart diff --git a/files/image_config/ntp/ntp.conf.j2 b/files/image_config/ntp/ntp.conf.j2 index 07776292fc6..734a66fd091 100644 --- a/files/image_config/ntp/ntp.conf.j2 +++ b/files/image_config/ntp/ntp.conf.j2 @@ -5,6 +5,10 @@ # /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help +# To avoid ntpd from panic and exit if the drift between new time and +# current system time is large. +tinker panic 0 + driftfile /var/lib/ntp/ntp.drift diff --git a/files/image_config/process-reboot-cause/process-reboot-cause b/files/image_config/process-reboot-cause/process-reboot-cause index 49cfa752641..409deb7d685 100755 --- a/files/image_config/process-reboot-cause/process-reboot-cause +++ b/files/image_config/process-reboot-cause/process-reboot-cause @@ -11,6 +11,7 @@ try: import pwd import sys import syslog + import re except ImportError as err: raise ImportError("%s - required module not found" % str(err)) @@ -22,6 +23,16 @@ REBOOT_CAUSE_DIR = "/host/reboot-cause/" REBOOT_CAUSE_FILE = REBOOT_CAUSE_DIR + "reboot-cause.txt" PREVIOUS_REBOOT_CAUSE_FILE = REBOOT_CAUSE_DIR + "previous-reboot-cause.txt" FIRST_BOOT_PLATFORM_FILE = "/tmp/notify_firstboot_to_platform" +REBOOT_TYPE_KEXEC_FILE = "/proc/cmdline" +# The following SONIC_BOOT_TYPEs come from the warm/fast reboot script which is in sonic-utilities +# Because the system can be rebooted from some old versions, we have to take all possible BOOT options into consideration. +# On 201803, 201807 we have +# BOOT_OPTIONS="$(echo $KERNEL_OPTIONS | sed -e 's/\s*linux\s*/BOOT_IMAGE=/') fast-reboot" +# On 201811 and later we have +# BOOT_OPTIONS="$(echo $KERNEL_OPTIONS | sed -e 's/\s*linux\s*/BOOT_IMAGE=/') SONIC_BOOT_TYPE=${BOOT_TYPE_ARG}" where BOOT_TYPE_ARG can be warm, fastfast or fast +# To extract the commom part of them, we should have the following PATTERN +REBOOT_TYPE_KEXEC_PATTERN_WARM = ".*SONIC_BOOT_TYPE=(warm|fastfast).*" +REBOOT_TYPE_KEXEC_PATTERN_FAST = ".*SONIC_BOOT_TYPE=(fast|fast-reboot).*" UNKNOWN_REBOOT_CAUSE = "Unknown" @@ -47,6 +58,79 @@ def log_error(msg): # ============================= Functions ============================= +def parse_warmfast_reboot_from_proc_cmdline(): + if os.path.isfile(REBOOT_TYPE_KEXEC_FILE): + with open(REBOOT_TYPE_KEXEC_FILE, "r") as cause_file: + cause_file_kexec = cause_file.readline() + m = re.search(REBOOT_TYPE_KEXEC_PATTERN_WARM, cause_file_kexec) + if m and m.group(1): + return 'warm-reboot' + m = re.search(REBOOT_TYPE_KEXEC_PATTERN_FAST, cause_file_kexec) + if m and m.group(1): + return 'fast-reboot' + return None + + +def find_software_reboot_cause(): + software_reboot_cause = UNKNOWN_REBOOT_CAUSE + + if os.path.isfile(REBOOT_CAUSE_FILE): + with open(REBOOT_CAUSE_FILE, "r") as cause_file: + software_reboot_cause = cause_file.readline().rstrip('\n') + log_info("{} indicates the reboot cause: {}".format(REBOOT_CAUSE_FILE, software_reboot_cause)) + else: + log_info("Reboot cause file {} not found".format(REBOOT_CAUSE_FILE)) + + if os.path.isfile(FIRST_BOOT_PLATFORM_FILE): + os.remove(FIRST_BOOT_PLATFORM_FILE) + + return software_reboot_cause + + +def find_proc_cmdline_reboot_cause(): + proc_cmdline_reboot_cause = parse_warmfast_reboot_from_proc_cmdline() + + if proc_cmdline_reboot_cause: + log_info("/proc/cmdline indicates reboot type: {}".format(proc_cmdline_reboot_cause)) + else: + log_info("No reboot cause found from /proc/cmdline") + + return proc_cmdline_reboot_cause + + +def find_hardware_reboot_cause(): + hardware_reboot_cause = None + + # Until all platform vendors have provided sonic_platform packages, + # if there is no sonic_platform package installed, we only provide + # software-related reboot causes. + try: + import sonic_platform + + platform = sonic_platform.platform.Platform() + + chassis = platform.get_chassis() + + hardware_reboot_cause_major, hardware_reboot_cause_minor = chassis.get_reboot_cause() + + if hardware_reboot_cause_major == chassis.REBOOT_CAUSE_NON_HARDWARE: + # The reboot was not caused by hardware. If there is a REBOOT_CAUSE_FILE, it will + # contain any software-related reboot info. We will use it as the previous cause. + pass + elif hardware_reboot_cause_major == chassis.REBOOT_CAUSE_HARDWARE_OTHER: + hardware_reboot_cause = "{} ({})".format(hardware_reboot_cause_major, hardware_reboot_cause_minor) + else: + hardware_reboot_cause = hardware_reboot_cause_major + except ImportError as err: + log_warning("sonic_platform package not installed. Unable to detect hardware reboot causes.") + + if hardware_reboot_cause: + log_info("Platform api indicates reboot cause {}".format(hardware_reboot_cause)) + else: + log_info("No reboot cause found from platform api") + + return hardware_reboot_cause + def main(): log_info("Starting up...") @@ -63,61 +147,37 @@ def main(): if os.path.exists(PREVIOUS_REBOOT_CAUSE_FILE): os.remove(PREVIOUS_REBOOT_CAUSE_FILE) - # Set a default previous reboot cause previous_reboot_cause = UNKNOWN_REBOOT_CAUSE - # Until all platform vendors have provided sonic_platform packages, - # if there is no sonic_platform package installed, we only provide - # software-related reboot causes. - try: - import sonic_platform - - # Check if the previous reboot was caused by hardware - platform = sonic_platform.platform.Platform() - - chassis = platform.get_chassis() - - hardware_reboot_cause, optional_details = chassis.get_reboot_cause() - - if hardware_reboot_cause == chassis.REBOOT_CAUSE_NON_HARDWARE: - # The reboot was not caused by hardware. If there is a REBOOT_CAUSE_FILE, it will - # contain any software-related reboot info. We will use it as the previous cause. - if os.path.isfile(REBOOT_CAUSE_FILE): - cause_file = open(REBOOT_CAUSE_FILE, "r") - previous_reboot_cause = cause_file.readline().rstrip('\n') - cause_file.close() - # If it is FirstTime Boot and previous_reboot_cause is unknown - # and hardware_reboot cause is non_hardware then - # Update the reboot cause as required - if os.path.isfile(FIRST_BOOT_PLATFORM_FILE): - if (previous_reboot_cause == UNKNOWN_REBOOT_CAUSE): - previous_reboot_cause = UNKNOWN_REBOOT_CAUSE - os.remove(FIRST_BOOT_PLATFORM_FILE) - elif hardware_reboot_cause == chassis.REBOOT_CAUSE_HARDWARE_OTHER: - previous_reboot_cause = "{} ({})".format(hardware_reboot_cause, optional_details) - else: - previous_reboot_cause = hardware_reboot_cause - except ImportError as err: - log_warning("sonic_platform package not installed. Unable to detect hardware reboot causes.") + # 1. Check if the previous reboot was warm/fast reboot by testing whether there is "fast|fastfast|warm" in /proc/cmdline + proc_cmdline_reboot_cause = find_proc_cmdline_reboot_cause() + + # 2. Check if the previous reboot was caused by hardware + # If yes, the hardware reboot cause will be treated as the reboot cause + hardware_reboot_cause = find_hardware_reboot_cause() + + # 3. If there is a REBOOT_CAUSE_FILE, it will contain any software-related + # reboot info. We will use it as the previous cause. + software_reboot_cause = find_software_reboot_cause() + + # The main decision logic of the reboot cause: + # If there is a reboot cause indicated by /proc/cmdline, it should be warmreboot/fastreboot + # the software_reboot_cause which is the content of /hosts/reboot-cause/reboot-cause.txt + # will be treated as the reboot cause + # Elif there is a reboot cause indicated by platform API, + # the hardware_reboot_cause will be treated as the reboot cause + # Else the software_reboot_cause will be treated as the reboot cause + if proc_cmdline_reboot_cause is not None: + previous_reboot_cause = software_reboot_cause + elif hardware_reboot_cause is not None: + previous_reboot_cause = hardware_reboot_cause + else: + previous_reboot_cause = software_reboot_cause - # If there is a REBOOT_CAUSE_FILE, it will contain any software-related - # reboot info. We will use it as the previous cause. - if os.path.isfile(REBOOT_CAUSE_FILE): - cause_file = open(REBOOT_CAUSE_FILE, "r") - previous_reboot_cause = cause_file.readline().rstrip('\n') - cause_file.close() - - # If it is FirstTime Boot and previous_reboot_cause is unknown - # Update the reboot cause as required - if os.path.isfile(FIRST_BOOT_PLATFORM_FILE): - if (previous_reboot_cause == UNKNOWN_REBOOT_CAUSE): - previous_reboot_cause = UNKNOWN_REBOOT_CAUSE - os.remove(FIRST_BOOT_PLATFORM_FILE) # Write the previous reboot cause to PREVIOUS_REBOOT_CAUSE_FILE - prev_cause_file = open(PREVIOUS_REBOOT_CAUSE_FILE, "w") - prev_cause_file.write(previous_reboot_cause) - prev_cause_file.close() + with open(PREVIOUS_REBOOT_CAUSE_FILE, "w") as prev_cause_file: + prev_cause_file.write(previous_reboot_cause) # Also log the previous reboot cause to the syslog log_info("Previous reboot cause: {}".format(previous_reboot_cause)) @@ -127,9 +187,8 @@ def main(): os.remove(REBOOT_CAUSE_FILE) # Write a new default reboot cause file for the next reboot - cause_file = open(REBOOT_CAUSE_FILE, "w") - cause_file.write(UNKNOWN_REBOOT_CAUSE) - cause_file.close() + with open(REBOOT_CAUSE_FILE, "w") as cause_file: + cause_file.write(UNKNOWN_REBOOT_CAUSE) if __name__ == "__main__": diff --git a/files/image_config/process-reboot-cause/process-reboot-cause.service b/files/image_config/process-reboot-cause/process-reboot-cause.service index a429339dbe5..b9821f60c42 100644 --- a/files/image_config/process-reboot-cause/process-reboot-cause.service +++ b/files/image_config/process-reboot-cause/process-reboot-cause.service @@ -5,6 +5,3 @@ After=rc-local.service [Service] Type=simple ExecStart=/usr/bin/process-reboot-cause - -[Install] -WantedBy=multi-user.target diff --git a/files/image_config/rsyslog/rsyslog.conf.j2 b/files/image_config/rsyslog/rsyslog.conf.j2 index 063f119f6bd..e714fcec5ab 100644 --- a/files/image_config/rsyslog/rsyslog.conf.j2 +++ b/files/image_config/rsyslog/rsyslog.conf.j2 @@ -64,6 +64,10 @@ $WorkDirectory /var/spool/rsyslog # $IncludeConfig /etc/rsyslog.d/*.conf +# +# Suppress duplicate messages and report "message repeated n times" +# +$RepeatedMsgReduction on ############### #### RULES #### diff --git a/files/image_config/watchdog-control/watchdog-control.service b/files/image_config/watchdog-control/watchdog-control.service new file mode 100644 index 00000000000..579e645e248 --- /dev/null +++ b/files/image_config/watchdog-control/watchdog-control.service @@ -0,0 +1,10 @@ +[Unit] +Description=watchdog control service +After=swss.service + +[Service] +Type=simple +ExecStart=/usr/local/bin/watchdog-control.sh + +[Install] +WantedBy=multi-user.target diff --git a/files/image_config/watchdog-control/watchdog-control.sh b/files/image_config/watchdog-control/watchdog-control.sh new file mode 100755 index 00000000000..124d1c01f63 --- /dev/null +++ b/files/image_config/watchdog-control/watchdog-control.sh @@ -0,0 +1,22 @@ +#! /bin/bash + +VERBOSE=no + +function debug() +{ + /usr/bin/logger "$0 : $1" + if [[ x"${VERBOSE}" == x"yes" ]]; then + echo "$(date) $0: $1" + fi +} + + +function disable_watchdog() +{ + if [[ -x /usr/bin/watchdog ]]; then + debug "Disabling Watchdog during bootup" + /usr/bin/watchdog -d + fi +} + +disable_watchdog diff --git a/files/initramfs-tools/arista-convertfs.j2 b/files/initramfs-tools/arista-convertfs.j2 index 00fe5aa2cfe..e55a8186268 100644 --- a/files/initramfs-tools/arista-convertfs.j2 +++ b/files/initramfs-tools/arista-convertfs.j2 @@ -18,6 +18,8 @@ flash_dev='' block_flash='' aboot_flag='' backup_file='' +prev_os='' +sonic_fast_reboot='' # Wait until get the fullpath of flash device, e.g., /dev/sda wait_get_flash_dev() { @@ -133,12 +135,21 @@ for x in "$@"; do docker_inram=*) docker_inram="${x#docker_inram=}" ;; + prev_os=*) + prev_os="${x#prev_os=}" + ;; + SONIC_BOOT_TYPE=warm*|SONIC_BOOT_TYPE=fast*) + sonic_fast_reboot=true + ;; esac done #Check aboot [ -z "$aboot_flag" ] && exit 0 +# Skip this script for warm-reboot/fast-reboot from sonic +[ "$sonic_fast_reboot" == true ] && [ "$prev_os" != eos ] && exit 0 + # Get flash dev name if [ -z "$block_flash" ]; then echo "Error: flash device info is not provided" diff --git a/files/scripts/arp_update b/files/scripts/arp_update index f7c5ec8bb85..f9541bbe515 100755 --- a/files/scripts/arp_update +++ b/files/scripts/arp_update @@ -46,5 +46,28 @@ while /bin/true; do ip6cmd="ip -6 neigh show | grep -v fe80 | grep $vlan | cut -d ' ' -f 1,3 | $ndisc6cmd" eval `eval $ip6cmd` done + + # sleep here before handling the mismatch as it is not required during startup sleep 300 + + # refresh neighbor entries from APP_DB in case of mismatch with kernel + DBNEIGH=$(redis-cli -n 0 --scan --pattern NEIGH_TABLE*) + KERNEIGH4=$(ip -4 neigh show | grep Vlan | cut -d ' ' -f 1,3 --output-delimiter=',') + KERNEIGH6=$(ip -6 neigh show | grep -v fe80 | grep Vlan | cut -d ' ' -f 1,3 --output-delimiter=',') + for neigh in $DBNEIGH; do + intf="$( cut -d ':' -f 2 <<< "$neigh" )" + ip="$( cut -d ':' -f 3- <<< "$neigh" )" + if [[ $intf == *"Vlan"* ]]; then + if [[ $ip == *"."* ]] && [[ ! $KERNEIGH4 =~ "${ip},${intf}" ]]; then + pingcmd="timeout 0.2 ping -I $intf -n -q -i 0 -c 1 -W 0 $ip >/dev/null" + eval $pingcmd + logger "arp_update: mismatch arp entry, pinging ${ip} on ${intf}" + elif [[ $ip == *":"* ]] && [[ ! $KERNEIGH6 =~ "${ip},${intf}" ]]; then + ping6cmd="timeout 0.2 ping6 -I $intf -n -q -i 0 -c 1 -W 0 $ip >/dev/null" + eval $ping6cmd + logger "arp_update: mismatch v6 nbr entry, pinging ${ip} on ${intf}" + fi + fi + done + done diff --git a/files/scripts/swss.sh b/files/scripts/swss.sh index 9797e833f29..cff19ae74f1 100755 --- a/files/scripts/swss.sh +++ b/files/scripts/swss.sh @@ -146,6 +146,13 @@ stop() { /usr/bin/${SERVICE}.sh stop debug "Stopped ${SERVICE} service..." + # Flush FAST_REBOOT table when swss needs to stop. The only + # time when this would take effect is when fast-reboot + # encountered error, e.g. syncd crashed. And swss needs to + # be restarted. + debug "Clearing FAST_REBOOT flag..." + clean_up_tables 6 "'FAST_REBOOT*'" + # Unlock has to happen before reaching out to peer service unlock_service_state_change diff --git a/files/scripts/syncd.sh b/files/scripts/syncd.sh index ef666b78629..2e450e03182 100755 --- a/files/scripts/syncd.sh +++ b/files/scripts/syncd.sh @@ -64,7 +64,12 @@ function getBootType() TYPE='fastfast' ;; *SONIC_BOOT_TYPE=fast*|*fast-reboot*) - TYPE=$(awk '{ if ($1 <= 180) print "fast"; else print "cold" }' /proc/uptime) + # check that the key exists + if [[ $(redis-cli -n 6 GET "FAST_REBOOT|system") == "1" ]]; then + TYPE='fast' + else + TYPE='cold' + fi ;; *) TYPE='cold' diff --git a/platform/barefoot/docker-syncd-bfn.mk b/platform/barefoot/docker-syncd-bfn.mk index a0c09614417..b75c25951bb 100644 --- a/platform/barefoot/docker-syncd-bfn.mk +++ b/platform/barefoot/docker-syncd-bfn.mk @@ -11,3 +11,4 @@ $(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $(SYNCD_DBG) \ $(LIBSAIMETADATA_DBG) \ $(LIBSAIREDIS_DBG) +$(DOCKER_SYNCD_BASE)_BASE_IMAGE_FILES += monit_syncd:/etc/monit/conf.d diff --git a/platform/barefoot/docker-syncd-bfn/base_image_files/monit_syncd b/platform/barefoot/docker-syncd-bfn/base_image_files/monit_syncd new file mode 100644 index 00000000000..3079618990e --- /dev/null +++ b/platform/barefoot/docker-syncd-bfn/base_image_files/monit_syncd @@ -0,0 +1,7 @@ +############################################################################### +## Monit configuration for syncd container +## process list: +## syncd +############################################################################### +check process syncd matching "/usr/bin/syncd" + if does not exist for 5 times within 5 cycles then alert diff --git a/platform/barefoot/sonic-platform-modules-arista b/platform/barefoot/sonic-platform-modules-arista index 418af37fa5b..17eb60eef00 160000 --- a/platform/barefoot/sonic-platform-modules-arista +++ b/platform/barefoot/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit 418af37fa5ba6f3143bfcd8ea09ad50511334d44 +Subproject commit 17eb60eef00feb7616c4f7ba9dbc7eb2498d83eb diff --git a/platform/broadcom/docker-syncd-brcm.mk b/platform/broadcom/docker-syncd-brcm.mk index ba687800c8f..8d1c33a3757 100644 --- a/platform/broadcom/docker-syncd-brcm.mk +++ b/platform/broadcom/docker-syncd-brcm.mk @@ -16,3 +16,4 @@ $(DOCKER_SYNCD_BASE)_RUN_OPT += -v /host/warmboot:/var/warmboot $(DOCKER_SYNCD_BASE)_BASE_IMAGE_FILES += bcmcmd:/usr/bin/bcmcmd $(DOCKER_SYNCD_BASE)_BASE_IMAGE_FILES += bcmsh:/usr/bin/bcmsh +$(DOCKER_SYNCD_BASE)_BASE_IMAGE_FILES += monit_syncd:/etc/monit/conf.d diff --git a/platform/broadcom/docker-syncd-brcm/base_image_files/monit_syncd b/platform/broadcom/docker-syncd-brcm/base_image_files/monit_syncd new file mode 100644 index 00000000000..0b9ec741cd5 --- /dev/null +++ b/platform/broadcom/docker-syncd-brcm/base_image_files/monit_syncd @@ -0,0 +1,11 @@ +############################################################################### +## Monit configuration for syncd container +## process list: +## syncd +## dsserve +############################################################################### +check process syncd matching "/usr/bin/syncd" + if does not exist for 5 times within 5 cycles then alert + +check process dsserve matching "/usr/bin/dsserve /usr/bin/syncd" + if does not exist for 5 times within 5 cycles then alert diff --git a/platform/broadcom/platform-modules-dell.mk b/platform/broadcom/platform-modules-dell.mk index 5c8032c8b43..23d58c885be 100644 --- a/platform/broadcom/platform-modules-dell.mk +++ b/platform/broadcom/platform-modules-dell.mk @@ -34,3 +34,6 @@ $(DELL_S6000_PLATFORM_MODULE)_PLATFORM = x86_64-dell_s6000_s1220-r0 $(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S6000_PLATFORM_MODULE))) SONIC_STRETCH_DEBS += $(DELL_Z9100_PLATFORM_MODULE) + +#flashrom tool +$(shell ./$(PLATFORM_PATH)/sonic-platform-modules-dell/tools/flashrom.sh > /dev/null 2>&1) diff --git a/platform/broadcom/sai.mk b/platform/broadcom/sai.mk index 131c65a42d8..d2e2b70c40f 100644 --- a/platform/broadcom/sai.mk +++ b/platform/broadcom/sai.mk @@ -1,9 +1,9 @@ -BRCM_SAI = libsaibcm_3.5.3.3-1_amd64.deb -$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/jessie/libsaibcm_3.5.3.3-1_amd64.deb?sv=2015-04-05&sr=b&sig=ZRpT%2BiP%2BiaBJzTdb4ho%2F1FkH%2Bwc%2B9xwiQf2fsRQKe0Y%3D&se=2033-07-26T04%3A26%3A34Z&sp=r" +BRCM_SAI = libsaibcm_3.5.3.4-1_amd64.deb +$(BRCM_SAI)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/jessie/libsaibcm_3.5.3.4-1_amd64.deb?sv=2015-04-05&sr=b&sig=YWM5jgpf8xVjNyQBo9Kx5CxOTKnnQGumjSiogn6ZY48%3D&se=2033-10-11T20%3A51%3A04Z&sp=r" -BRCM_SAI_DEV = libsaibcm-dev_3.5.3.3-1_amd64.deb +BRCM_SAI_DEV = libsaibcm-dev_3.5.3.4-1_amd64.deb $(eval $(call add_derived_package,$(BRCM_SAI),$(BRCM_SAI_DEV))) -$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/jessie/libsaibcm-dev_3.5.3.3-1_amd64.deb?sv=2015-04-05&sr=b&sig=yblqGyx256cZXEsn3pp0Pz94srsz%2BwPys9wZB0TMM3o%3D&se=2033-07-26T04%3A26%3A13Z&sp=r" +$(BRCM_SAI_DEV)_URL = "https://sonicstorage.blob.core.windows.net/packages/bcmsai/3.5/jessie/libsaibcm-dev_3.5.3.4-1_amd64.deb?sv=2015-04-05&sr=b&sig=EmoKe1tSTA2k39xI5kgM6FZMnLETgl75%2B0F9e8XH9N4%3D&se=2033-10-11T20%3A50%3A43Z&sp=r" SONIC_ONLINE_DEBS += $(BRCM_SAI) $(BRCM_SAI_DEV)_DEPENDS += $(BRCM_SAI) diff --git a/platform/broadcom/sonic-platform-modules-arista b/platform/broadcom/sonic-platform-modules-arista index 418af37fa5b..fcbc6da4091 160000 --- a/platform/broadcom/sonic-platform-modules-arista +++ b/platform/broadcom/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit 418af37fa5ba6f3143bfcd8ea09ad50511334d44 +Subproject commit fcbc6da4091edc0d4a850f7347a81a30ae465cc6 diff --git a/platform/broadcom/sonic-platform-modules-dell/common/dell_lpc_mon.sh b/platform/broadcom/sonic-platform-modules-dell/common/dell_lpc_mon.sh new file mode 100755 index 00000000000..0f8d24a7f51 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/common/dell_lpc_mon.sh @@ -0,0 +1,46 @@ +#!/bin/bash +REV=$(lspci -xxx -s 0:0.0 | grep rev | awk -F 'rev ' '{print $2}' | sed 's/)//') +if [ $REV -gt 2 ] +then + exit 0 +fi + +test_val=(55 aa) +num_val=${#test_val[@]} +index=0 +poll_interval=300 +cpld_scratch_reg=0x102 +smf_scratch_reg=0x202 + +function log_crit() { + local msg=$1 + + `logger -p user.crit -t DELL_LPC_BUS_MON $msg` +} + +function validate_lpc() { + local reg=$1 + local val=$2 + local reg_str="CPLD scratch register" + + if [ $reg == $smf_scratch_reg ] + then + reg_str="SMF scratch register" + fi + io_rd_wr.py --set --val $val --offset $reg + get_val=$(io_rd_wr.py --get --offset $reg | cut -d " " -f3) + if [ $val != $get_val ] + then + log_crit "LPC bus has deteriorated on this unit. \ + $reg_str has value $get_val while expected is $val \ + Please contact technical support" + fi +} +while true +do + val=${test_val[$index]} + validate_lpc $cpld_scratch_reg $val + validate_lpc $smf_scratch_reg $val + index=$(((index+1)%num_val)) + sleep $poll_interval +done diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install index 600afe805ab..0d16c5a2995 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install @@ -4,7 +4,12 @@ common/dell_i2c_utils.sh usr/local/bin common/io_rd_wr.py usr/local/bin common/fstrim.timer etc/systemd/system common/fstrim.service etc/systemd/system +common/dell_lpc_mon.sh usr/local/bin s6100/scripts/platform_sensors.py usr/local/bin +s6100/scripts/platform_watchdog_enable.sh usr/local/bin +s6100/scripts/platform_watchdog_disable.sh usr/local/bin s6100/scripts/sensors usr/bin s6100/systemd/platform-modules-s6100.service etc/systemd/system s6100/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-dell_s6100_c2538-r0 +s6100/systemd/s6100-lpc-monitor.service etc/systemd/system +tools/flashrom/flashrom usr/local/bin/ diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.postinst b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.postinst index 1c220633451..e1df0962ff5 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.postinst +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.postinst @@ -8,4 +8,8 @@ systemctl start fstrim.timer depmod -a systemctl enable platform-modules-s6100.service systemctl start platform-modules-s6100.service + +systemctl enable s6100-lpc-monitor.service +systemctl start s6100-lpc-monitor.service + #DEBHELPER# diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.install index 08f27cce47d..27bd6d71f14 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.install @@ -1,6 +1,7 @@ z9100/scripts/check_qsfp.sh usr/local/bin z9100/scripts/z9100_platform.sh usr/local/bin common/dell_i2c_utils.sh usr/local/bin +common/dell_lpc_mon.sh usr/local/bin common/io_rd_wr.py usr/local/bin common/fstrim.timer etc/systemd/system common/fstrim.service etc/systemd/system @@ -10,3 +11,4 @@ z9100/scripts/sensors usr/bin z9100/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-dell_z9100_c2538-r0 z9100/cfg/z9100-modules.conf etc/modules-load.d z9100/systemd/platform-modules-z9100.service etc/systemd/system +z9100/systemd/z9100-lpc-monitor.service etc/systemd/system diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.postinst b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.postinst index 61039dcd70d..5de2c290337 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.postinst +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9100.postinst @@ -10,4 +10,7 @@ systemctl enable platform-modules-z9100.service systemctl start platform-modules-z9100.service +systemctl enable z9100-lpc-monitor.service +systemctl start z9100-lpc-monitor.service + #DEBHELPER# diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/platform_watchdog_disable.sh b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/platform_watchdog_disable.sh new file mode 100755 index 00000000000..c3a90f3e89b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/platform_watchdog_disable.sh @@ -0,0 +1,13 @@ +#!/bin/bash +#This script is used to disable SMF Watchdog Timer + +wd_status=-1 +enabled=0 + +# Disable Watchdog if enabled +wd_status=$(io_rd_wr.py --get --offset 0x207 | cut -d " " -f3) + +if [[ $wd_status -eq $enabled ]]; then + echo "Disabling Watchdog Timer.." + io_rd_wr.py --set --val 1 --offset 0x207 +fi diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/platform_watchdog_enable.sh b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/platform_watchdog_enable.sh new file mode 100755 index 00000000000..804627b5e2f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/platform_watchdog_enable.sh @@ -0,0 +1,8 @@ +#!/bin/bash +#This script is used to enable SMF Watchdog Timer + +# Set watchdog to 180 seconds +io_rd_wr.py --set --val 3 --offset 0x206 + +# Enable watchdog timer +io_rd_wr.py --set --val 0 --offset 0x207 diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh index 974d0662d56..52eb757ad69 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/scripts/s6100_platform.sh @@ -259,6 +259,11 @@ if [[ "$1" == "init" ]]; then modprobe dell_s6100_lpc track_reboot_reason + # Disable Watchdog Timer + if [[ -e /usr/local/bin/platform_watchdog_disable.sh ]]; then + /usr/local/bin/platform_watchdog_disable.sh + fi + cpu_board_mux "new_device" switch_board_mux "new_device" sys_eeprom "new_device" diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/systemd/s6100-lpc-monitor.service b/platform/broadcom/sonic-platform-modules-dell/s6100/systemd/s6100-lpc-monitor.service new file mode 100644 index 00000000000..86dac18a310 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/systemd/s6100-lpc-monitor.service @@ -0,0 +1,12 @@ +[Unit] +Description=Dell S6100 LPC bus monitoring poller +DefaultDependencies=no + +[Service] +User=root +ExecStart=/usr/local/bin/dell_lpc_mon.sh +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target + diff --git a/platform/broadcom/sonic-platform-modules-dell/tools/0002-Flashrom-support-for-Intel-Rangeley-and-Denverton-CP.patch b/platform/broadcom/sonic-platform-modules-dell/tools/0002-Flashrom-support-for-Intel-Rangeley-and-Denverton-CP.patch new file mode 100644 index 00000000000..ab77df9c4d3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/tools/0002-Flashrom-support-for-Intel-Rangeley-and-Denverton-CP.patch @@ -0,0 +1,8510 @@ +From 482e06109190eb918208820fd94c8f4a6963f77e Mon Sep 17 00:00:00 2001 +From: paavaanan +Date: Tue, 21 May 2019 10:40:59 -0400 +Subject: [PATCH] Intel-Rangeley-stripped-code-changes + +--- + 82802ab.c | 1 + + Makefile | 109 +++- + README | 26 +- + at45db.c | 562 ++++++++++++++++ + atahpt.c | 2 + + board_enable.c | 19 +- + buspirate_spi.c | 7 +- + cbtable.c | 7 +- + chipdrivers.h | 21 +- + chipset_enable.c | 610 +++++++++++------ + cli_classic.c | 40 +- + dmi.c | 332 ++++++++-- + dnv_smi_spi.c | 185 ++++++ + drkaiser.c | 14 +- + flash.h | 56 +- + flashchips.c | 791 +++++++++++++++++++---- + flashchips.h | 27 +- + flashrom.c | 162 ++++- + ft2232_spi.c | 6 + + gfxnvidia.c | 14 +- + hwaccess.h | 6 + + ich_descriptors.c | 104 +++ + ich_descriptors.h | 104 +++ + ichspi.c | 557 ++++++++++++++-- + internal.c | 5 +- + it85spi.c | 3 + + it87spi.c | 47 +- + layout.c | 126 +++- + linux_spi.c | 12 +- + mcp6x_spi.c | 15 +- + nic3com.c | 2 + + nicintel.c | 29 +- + nicintel_spi.c | 26 +- + nicnatsemi.c | 2 + + nicrealtek.c | 2 + + ogp_spi.c | 14 +- + pcidev.c | 2 +- + physmap.c | 170 +++-- + pony_spi.c | 1 + + print.c | 15 +- + programmer.h | 28 +- + rayer_spi.c | 196 ++++-- + satamv.c | 19 +- + satasii.c | 18 +- + sb600spi.c | 208 +++++- + serial.c | 113 ++-- + serprog.c | 165 +++-- + spi25.c | 35 +- + spi25_statusreg.c | 2 +- + stm50.c | 115 ++++ + udelay.c | 10 +- + util/getrevision.sh | 311 +++++++++ + util/ich_descriptors_tool/ich_descriptors_tool.c | 8 +- + util/z60_flashrom.rules | 4 + + 54 files changed, 4553 insertions(+), 912 deletions(-) + create mode 100644 at45db.c + create mode 100644 dnv_smi_spi.c + create mode 100644 stm50.c + create mode 100755 util/getrevision.sh + +diff --git a/82802ab.c b/82802ab.c +index 608995d..2a43813 100644 +--- a/82802ab.c ++++ b/82802ab.c +@@ -89,6 +89,7 @@ int probe_82802ab(struct flashctx *flash) + return 1; + } + ++/* FIXME: needs timeout */ + uint8_t wait_82802ab(struct flashctx *flash) + { + uint8_t status; +diff --git a/Makefile b/Makefile +index 6e41e5d..d66039a 100644 +--- a/Makefile ++++ b/Makefile +@@ -39,6 +39,7 @@ CFLAGS ?= -Os -Wall -Wshadow + EXPORTDIR ?= . + AR ?= ar + RANLIB ?= ranlib ++DOSLIBS_BASE ?= .. + # The following parameter changes the default programmer that will be used if there is no -p/--programmer + # argument given when running flashrom. The predefined setting does not enable any default so that every + # user has to declare the programmer he wants to use on every run. The rationale for this to be not set +@@ -50,7 +51,8 @@ RANLIB ?= ranlib + # values are those specified in enum programmer in programmer.h (which depend on other CONFIG_* options + # evaluated below, namely those that enable/disable the various programmers). + # Compilation will fail for unspecified values. +-CONFIG_DEFAULT_PROGRAMMER ?= PROGRAMMER_INVALID ++#CONFIG_DEFAULT_PROGRAMMER ?= PROGRAMMER_INVALID ++CONFIG_DEFAULT_PROGRAMMER ?= PROGRAMMER_INTERNAL + + # If your compiler spits out excessive warnings, run make WARNERROR=no + # You shouldn't have to change this flag. +@@ -61,10 +63,13 @@ CFLAGS += -Werror + endif + + ############################################################################### +-# General OS/architecture specific settings. ++# General OS-specific settings. ++# 1. Prepare for later by gathering information about host and target OS ++# 2. Set compiler flags and parameters according to OSes ++# 3. Likewise verify user-supplied CONFIG_* variables. + + # HOST_OS is only used to work around local toolchain issues. +-HOST_OS ?= $(shell uname) ++HOST_OS ?= $(shell uname) + ifeq ($(HOST_OS), MINGW32_NT-5.1) + # Explicitly set CC = gcc on MinGW, otherwise: "cc: command not found". + CC = gcc +@@ -94,13 +99,24 @@ CPPFLAGS += -I/usr/local/include + LDFLAGS += -L/usr/local/lib + endif + ++ifeq ($(TARGET_OS), NetBSD) ++CPPFLAGS += -I/usr/pkg/include ++LDFLAGS += -L/usr/pkg/lib ++endif ++ ++ifeq ($(TARGET_OS), DragonFlyBSD) ++CPPFLAGS += -I/usr/pkg/include ++LDFLAGS += -L/usr/pkg/lib ++endif ++ + ifeq ($(TARGET_OS), DOS) + EXEC_SUFFIX := .exe +-CPPFLAGS += -I../libgetopt ++CPPFLAGS += -I$(DOSLIBS_BASE)/libgetopt + # DJGPP has odd uint*_t definitions which cause lots of format string warnings. + CFLAGS += -Wno-format + # FIXME Check if we can achieve the same effect with -L../libgetopt -lgetopt +-LIBS += ../libgetopt/libgetopt.a ++LIBS += -lgetopt ++LDFLAGS += -L$(DOSLIBS_BASE)/libgetopt/ + # Bus Pirate, Serprog and PonyProg are not supported under DOS (missing serial support). + ifeq ($(CONFIG_BUSPIRATE_SPI), yes) + UNSUPPORTED_FEATURES += CONFIG_BUSPIRATE_SPI=yes +@@ -215,6 +231,10 @@ endif + endif + + ifeq ($(TARGET_OS), libpayload) ++ifeq ($(MAKECMDGOALS),) ++.DEFAULT_GOAL := libflashrom.a ++$(info Setting default goal to libflashrom.a) ++endif + FLASHROM_CFLAGS += -DSTANDALONE + ifeq ($(CONFIG_DUMMY), yes) + UNSUPPORTED_FEATURES += CONFIG_DUMMY=yes +@@ -263,6 +283,10 @@ override CONFIG_LINUX_SPI = no + endif + endif + ++############################################################################### ++# General architecture-specific settings. ++# Like above for the OS, below we verify user-supplied options depending on the target architecture. ++ + # Determine the destination processor architecture. + # IMPORTANT: The following line must be placed before ARCH is ever used + # (of course), but should come after any lines setting CC because the line +@@ -307,10 +331,10 @@ endif + ############################################################################### + # Flash chip drivers and bus support infrastructure. + +-CHIP_OBJS = jedec.o stm50flw0x0x.o w39.o w29ee011.o \ ++CHIP_OBJS = jedec.o stm50.o w39.o w29ee011.o \ + sst28sf040.o m29f400bt.o 82802ab.o pm49fl00x.o \ + sst49lfxxxc.o sst_fwhub.o flashchips.o spi.o spi25.o spi25_statusreg.o \ +- opaque.o sfdp.o en29lv640b.o ++ opaque.o sfdp.o en29lv640b.o at45db.o + + ############################################################################### + # Library code. +@@ -322,18 +346,22 @@ LIB_OBJS = layout.o flashrom.o udelay.o programmer.o + + CLI_OBJS = cli_classic.o cli_output.o print.o + +-# Set the flashrom version string from the highest revision number +-# of the checked out flashrom files. ++# Set the flashrom version string from the highest revision number of the checked out flashrom files. + # Note to packagers: Any tree exported with "make export" or "make tarball" + # will not require subversion. The downloadable snapshots are already exported. +-SVNVERSION := $(shell LC_ALL=C svnversion -cn . 2>/dev/null | sed -e "s/.*://" -e "s/\([0-9]*\).*/\1/" | grep "[0-9]" || LC_ALL=C svn info . 2>/dev/null | awk '/^Revision:/ {print $$2 }' | grep "[0-9]" || LC_ALL=C git svn info . 2>/dev/null | awk '/^Revision:/ {print $$2 }' | grep "[0-9]" || echo unknown) ++SVNVERSION := r1781 + + RELEASE := 0.9.7 +-VERSION := $(RELEASE)-r$(SVNVERSION) ++VERSION := $(RELEASE)-$(SVNVERSION) + RELEASENAME ?= $(VERSION) + + SVNDEF := -D'FLASHROM_VERSION="$(VERSION)"' + ++F10FLAGS := -DFORCE10_SPI_CHANGE ++ ++############################################################################### ++# Default settings of CONFIG_* variables. ++ + # Always enable internal/onboard support for now. + CONFIG_INTERNAL ?= yes + +@@ -425,16 +453,39 @@ endif + endif + + ############################################################################### ++# Handle CONFIG_* variables that depend on others set (and verified) above. ++ ++# The external DMI decoder (dmidecode) does not work in libpayload. Bail out if the internal one got disabled. ++ifeq ($(TARGET_OS), libpayload) ++ifeq ($(CONFIG_INTERNAL), yes) ++ifeq ($(CONFIG_INTERNAL_DMI), no) ++UNSUPPORTED_FEATURES += CONFIG_INTERNAL_DMI=no ++else ++override CONFIG_INTERNAL_DMI = yes ++endif ++endif ++endif ++ ++# Use internal DMI/SMBIOS decoder by default instead of relying on dmidecode. ++CONFIG_INTERNAL_DMI ?= yes ++ ++############################################################################### + # Programmer drivers and programmer support infrastructure. ++# Depending on the CONFIG_* variables set and verified above we set compiler flags and parameters below. ++ ++FEATURE_CFLAGS += -DDELL_DENVERTON_SUPPORT -DDELL_AVOTON_SUPPORT + + FEATURE_CFLAGS += -D'CONFIG_DEFAULT_PROGRAMMER=$(CONFIG_DEFAULT_PROGRAMMER)' + + ifeq ($(CONFIG_INTERNAL), yes) + FEATURE_CFLAGS += -D'CONFIG_INTERNAL=1' +-PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o dmi.o internal.o ++PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o internal.o + ifeq ($(ARCH), x86) + PROGRAMMER_OBJS += it87spi.o it85spi.o sb600spi.o amd_imc.o wbsio_spi.o mcp6x_spi.o +-PROGRAMMER_OBJS += ichspi.o ich_descriptors.o ++PROGRAMMER_OBJS += ichspi.o ich_descriptors.o dmi.o dnv_smi_spi.o ++ifeq ($(CONFIG_INTERNAL_DMI), yes) ++FEATURE_CFLAGS += -D'CONFIG_INTERNAL_DMI=1' ++endif + else + endif + NEED_PCI := yes +@@ -597,9 +648,9 @@ PCILIBS += -lpciutils -lpci + PCILIBS += -l$(shell uname -p) + else + ifeq ($(TARGET_OS), DOS) +-# FIXME There needs to be a better way to do this +-CPPFLAGS += -I../libpci/include +-PCILIBS += ../libpci/lib/libpci.a ++CPPFLAGS += -I$(DOSLIBS_BASE)/libpci/include ++LDFLAGS += -L$(DOSLIBS_BASE)/libpci/lib/ ++PCILIBS += -lpci + else + PCILIBS += -lpci + ifeq ($(TARGET_OS), OpenBSD) +@@ -635,10 +686,11 @@ FEATURE_LIBS += $(shell LC_ALL=C grep -q "NEEDLIBZ := yes" .libdeps && printf "% + LIBFLASHROM_OBJS = $(CHIP_OBJS) $(PROGRAMMER_OBJS) $(LIB_OBJS) + OBJS = $(CLI_OBJS) $(LIBFLASHROM_OBJS) + +-all: hwlibs features $(PROGRAM)$(EXEC_SUFFIX) ++all: hwlibs features $(PROGRAM)$(EXEC_SUFFIX) $(PROGRAM).8 + ifeq ($(ARCH), x86) + @+$(MAKE) -C util/ich_descriptors_tool/ TARGET_OS=$(TARGET_OS) EXEC_SUFFIX=$(EXEC_SUFFIX) + endif ++default: all + + $(PROGRAM)$(EXEC_SUFFIX): $(OBJS) + $(CC) $(LDFLAGS) -o $(PROGRAM)$(EXEC_SUFFIX) $(OBJS) $(LIBS) $(PCILIBS) $(FEATURE_LIBS) $(USBLIBS) +@@ -653,13 +705,13 @@ libflashrom.a: $(LIBFLASHROM_OBJS) + TAROPTIONS = $(shell LC_ALL=C tar --version|grep -q GNU && echo "--owner=root --group=root") + + %.o: %.c .features +- $(CC) -MMD $(CFLAGS) $(CPPFLAGS) $(FLASHROM_CFLAGS) $(FEATURE_CFLAGS) $(SVNDEF) -o $@ -c $< ++ $(CC) -MMD $(CFLAGS) $(CPPFLAGS) $(FLASHROM_CFLAGS) $(FEATURE_CFLAGS) $(SVNDEF) $(F10FLAGS) -o $@ -c $< + + # Make sure to add all names of generated binaries here. + # This includes all frontends and libflashrom. + # We don't use EXEC_SUFFIX here because we want to clean everything. + clean: +- rm -f $(PROGRAM) $(PROGRAM).exe libflashrom.a *.o *.d ++ rm -f $(PROGRAM) $(PROGRAM).exe libflashrom.a *.o *.d $(PROGRAM).8 + @+$(MAKE) -C util/ich_descriptors_tool/ clean + + distclean: clean +@@ -698,11 +750,20 @@ compiler: featuresavailable + @echo $(TARGET_OS)|wc -w|grep -q '^[[:blank:]]*1[[:blank:]]*$$' || \ + ( echo "unknown. Aborting."; exit 1) + @printf "%s\n" '$(TARGET_OS)' ++ifeq ($(TARGET_OS), libpayload) ++ @$(CC) --version 2>&1 | grep -q coreboot || \ ++ ( echo "Warning: It seems you are not using coreboot's reference compiler."; \ ++ echo "This might work but usually does not, please beware." ) ++endif + + define LIBPCI_TEST + /* Avoid a failing test due to libpci header symbol shadowing breakage */ + #define index shadow_workaround_index ++#if !defined __NetBSD__ && !defined __DragonFly__ + #include ++#else ++#include ++#endif + struct pci_access *pacc; + int main(int argc, char **argv) + { +@@ -853,16 +914,20 @@ endif + @$(DIFF) -q .features.tmp .features >/dev/null 2>&1 && rm .features.tmp || mv .features.tmp .features + @rm -f .featuretest.c .featuretest$(EXEC_SUFFIX) + +-install: $(PROGRAM)$(EXEC_SUFFIX) ++$(PROGRAM).8: $(PROGRAM).8.tmpl ++ @sed -e '1 s#".*".*#"$(shell ./util/getrevision.sh -d $(PROGRAM).8.tmpl)" "$(VERSION)"#' <$< >$@ ++ ++install: $(PROGRAM)$(EXEC_SUFFIX) $(PROGRAM).8 + mkdir -p $(DESTDIR)$(PREFIX)/sbin + mkdir -p $(DESTDIR)$(MANDIR)/man8 + $(INSTALL) -m 0755 $(PROGRAM)$(EXEC_SUFFIX) $(DESTDIR)$(PREFIX)/sbin + $(INSTALL) -m 0644 $(PROGRAM).8 $(DESTDIR)$(MANDIR)/man8 + +-export: ++export: $(PROGRAM).8 + @rm -rf $(EXPORTDIR)/flashrom-$(RELEASENAME) + @svn export -r BASE . $(EXPORTDIR)/flashrom-$(RELEASENAME) + @sed "s/^SVNVERSION.*/SVNVERSION := $(SVNVERSION)/" Makefile >$(EXPORTDIR)/flashrom-$(RELEASENAME)/Makefile ++ @cp $(PROGRAM).8 "$(EXPORTDIR)/flashrom-$(RELEASENAME)/$(PROGRAM).8" + @LC_ALL=C svn log >$(EXPORTDIR)/flashrom-$(RELEASENAME)/ChangeLog + @echo Exported $(EXPORTDIR)/flashrom-$(RELEASENAME)/ + +@@ -876,6 +941,6 @@ djgpp-dos: clean + libpayload: clean + make CC="CC=i386-elf-gcc lpgcc" AR=i386-elf-ar RANLIB=i386-elf-ranlib + +-.PHONY: all clean distclean compiler hwlibs features export tarball dos featuresavailable ++.PHONY: all install clean distclean compiler hwlibs features export tarball dos featuresavailable + + -include $(OBJS:.o=.d) +diff --git a/README b/README +index 7f24cca..b3e50a6 100644 +--- a/README ++++ b/README +@@ -80,11 +80,9 @@ To compile on Solaris, use: + + gmake LDFLAGS="-L$pathtolibpci" CC="gcc -I$pathtopciheaders" CFLAGS=-O2 + +-To compile on NetBSD or DragonFly BSD, use: ++To compile on NetBSD or DragonFly BSD (with pciutils, libftdi, libusb installed in /usr/pkg/), use: + +- ln -s /usr/pkg/include/pciutils pci +- gmake CPPFLAGS="-I. -I/usr/pkg/include" \ +- LDFLAGS="-L/usr/pkg/lib -Wl,-rpath-link,/usr/pkg/lib" ++ gmake + + To compile on OpenBSD, use: + +@@ -105,20 +103,24 @@ To cross-compile on Linux for DOS: + djcrx-2.04pre_20090725-13ap.i386.rpm + The cross toolchain packages for your distribution may have slightly different + names (look for packages named *djgpp*). +- Download pciutils 3.1.5 and apply http://assembler.cz/flashrom/pciutils.patch +- Download and compile http://assembler.cz/flashrom/libgetopt/ ++ ++ You will need the following library source trees containing their compiled ++ static libraries either in the parent directory of the flashrom source or ++ specify the base folder on compile time with the DOSLIBS_BASE parameter. ++ The default as described above is equal to calling ++ 'make djgpp-dos DOSLIBS_BASE=..' ++ ++ To get and build said libraries... ++ Download pciutils 3.1.5 and apply http://flashrom.org/File:Pciutils.patch.gz + Compile pciutils, see README.DJGPP for instructions. ++ Download and compile http://flashrom.org/File:Libgetopt.tar.gz + Enter the flashrom directory. +- ../libpci should contain pciutils source and binaries. +- ../libgetopt should contain getopt.a from libgetopt. + Run either (change settings where appropriate) + make CC=i586-pc-msdosdjgpp-gcc STRIP=i586-pc-msdosdjgpp-strip + or (above settings hardcoded) + make djgpp-dos +- You might have to add WARNERROR=no to the make command line. +- To run flashrom.exe, download and unpack +- http://homer.rice.edu/~sandmann/cwsdpmi/csdpmi7b.zip and make sure +- CWSDPMI.EXE is in the current directory. ++ To run flashrom.exe, download http://flashrom.org/File:Csdpmi7b.zip and ++ unpack CWSDPMI.EXE into the current directory or one in PATH. + + To cross-compile on Linux for Windows: + +diff --git a/at45db.c b/at45db.c +new file mode 100644 +index 0000000..5c90418 +--- /dev/null ++++ b/at45db.c +@@ -0,0 +1,562 @@ ++/* ++ * Support for Atmel AT45DB series DataFlash chips. ++ * This file is part of the flashrom project. ++ * ++ * Copyright (C) 2012 Aidan Thornton ++ * Copyright (C) 2013 Stefan Tauner ++ * ++ * 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; version 2 of the License. ++ * ++ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include ++#include "flash.h" ++#include "chipdrivers.h" ++#include "programmer.h" ++#include "spi.h" ++ ++/* Status register bits */ ++#define AT45DB_READY (1<<7) ++#define AT45DB_CMP (1<<6) ++#define AT45DB_PROT (1<<1) ++#define AT45DB_POWEROF2 (1<<0) ++ ++/* Opcodes */ ++#define AT45DB_STATUS 0xD7 /* NB: this is a block erase command on most other chips(!). */ ++#define AT45DB_DISABLE_PROTECT 0x3D, 0x2A, 0x7F, 0x9A ++#define AT45DB_READ_ARRAY 0xE8 ++#define AT45DB_READ_PROTECT 0x32 ++#define AT45DB_READ_LOCKDOWN 0x35 ++#define AT45DB_PAGE_ERASE 0x81 ++#define AT45DB_BLOCK_ERASE 0x50 ++#define AT45DB_SECTOR_ERASE 0x7C ++#define AT45DB_CHIP_ERASE 0xC7 ++#define AT45DB_CHIP_ERASE_ADDR 0x94809A /* Magic address. See usage. */ ++#define AT45DB_BUFFER1_WRITE 0x84 ++#define AT45DB_BUFFER1_PAGE_PROGRAM 0x88 ++/* Buffer 2 is unused yet. ++#define AT45DB_BUFFER2_WRITE 0x87 ++#define AT45DB_BUFFER2_PAGE_PROGRAM 0x89 ++*/ ++ ++static uint8_t at45db_read_status_register(struct flashctx *flash, uint8_t *status) ++{ ++ static const uint8_t cmd[] = { AT45DB_STATUS }; ++ ++ int ret = spi_send_command(flash, sizeof(cmd), 1, cmd, status); ++ if (ret != 0) ++ msg_cerr("Reading the status register failed!\n"); ++ else ++ msg_cspew("Status register: 0x%02x.\n", *status); ++ return ret; ++} ++ ++int spi_disable_blockprotect_at45db(struct flashctx *flash) ++{ ++ static const uint8_t cmd[4] = { AT45DB_DISABLE_PROTECT }; /* NB: 4 bytes magic number */ ++ int ret = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL); ++ if (ret != 0) { ++ msg_cerr("Sending disable lockdown failed!\n"); ++ return ret; ++ } ++ uint8_t status; ++ ret = at45db_read_status_register(flash, &status); ++ if (ret != 0 || ((status & AT45DB_PROT) != 0)) { ++ msg_cerr("Disabling lockdown failed!\n"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static unsigned int at45db_get_sector_count(struct flashctx *flash) ++{ ++ unsigned int i, j; ++ unsigned int cnt = 0; ++ for (i = 0; i < NUM_ERASEFUNCTIONS; i++) { ++ if (flash->chip->block_erasers[i].block_erase == &spi_erase_at45db_sector) { ++ for (j = 0; j < NUM_ERASEREGIONS; j++) { ++ cnt += flash->chip->block_erasers[i].eraseblocks[j].count; ++ } ++ } ++ } ++ msg_cspew("%s: number of sectors=%u\n", __func__, cnt); ++ return cnt; ++} ++ ++/* Reads and prettyprints protection/lockdown registers. ++ * Some elegance of the printouts had to be cut down a bit to share this code. */ ++static uint8_t at45db_prettyprint_protection_register(struct flashctx *flash, uint8_t opcode, const char *regname) ++{ ++ const uint8_t cmd[] = { opcode, 0, 0, 0 }; ++ /* The first two sectors share the first result byte. */ ++ uint8_t buf[at45db_get_sector_count(flash) - 1]; ++ ++ int ret = spi_send_command(flash, sizeof(cmd), sizeof(buf), cmd, buf); ++ if (ret != 0) { ++ msg_cerr("Reading the %s register failed!\n", regname); ++ return ret; ++ } ++ ++ unsigned int i; ++ for (i = 0; i < sizeof(buf); i++) { ++ if (buf[i] != 0x00) ++ break; ++ if (i == sizeof(buf) - 1) { ++ msg_cdbg("No Sector is %sed.\n", regname); ++ return 0; ++ } ++ } ++ ++ /* TODO: print which addresses are mapped to (un)locked sectors. */ ++ msg_cdbg("Sector 0a is %s%sed.\n", ((buf[0] & 0xC0) == 0x00) ? "un" : "", regname); ++ msg_cdbg("Sector 0b is %s%sed.\n", ((buf[0] & 0x30) == 0x00) ? "un" : "", regname); ++ for (i = 1; i < sizeof(buf); i++) ++ msg_cdbg("Sector %2u is %s%sed.\n", i, (buf[i] == 0x00) ? "un" : "", regname); ++ ++ return 0; ++} ++ ++/* bit 7: busy flag ++ * bit 6: memory/buffer compare result ++ * bit 5-2: density (encoding see below) ++ * bit 1: protection enabled (soft or hard) ++ * bit 0: "power of 2" page size indicator (e.g. 1 means 256B; 0 means 264B) ++ * ++ * 5-2 encoding: bit 2 is always 1, bits 3-5 encode the density as "2^(bits - 1)" in Mb e.g.: ++ * AT45DB161D 1011 16Mb */ ++int spi_prettyprint_status_register_at45db(struct flashctx *flash) ++{ ++ uint8_t status; ++ if (at45db_read_status_register(flash, &status) != 0) { ++ return 1; ++ } ++ ++ /* AT45DB321C does not support lockdown or a page size of a power of 2... */ ++ const bool isAT45DB321C = (strcmp(flash->chip->name, "AT45DB321C") == 0); ++ msg_cdbg("Chip status register is 0x%02x\n", status); ++ msg_cdbg("Chip status register: Bit 7 / Ready is %sset\n", (status & AT45DB_READY) ? "" : "not "); ++ msg_cdbg("Chip status register: Bit 6 / Compare match is %sset\n", (status & AT45DB_CMP) ? "" : "not "); ++ spi_prettyprint_status_register_bit(status, 5); ++ spi_prettyprint_status_register_bit(status, 4); ++ spi_prettyprint_status_register_bit(status, 3); ++ spi_prettyprint_status_register_bit(status, 2); ++ const uint8_t dens = (status >> 3) & 0x7; /* Bit 2 is always 1, we use the other bits only */ ++ msg_cdbg("Chip status register: Density is %u Mb\n", 1 << (dens - 1)); ++ msg_cdbg("Chip status register: Bit 1 / Protection is %sset\n", (status & AT45DB_PROT) ? "" : "not "); ++ ++ if (isAT45DB321C) ++ spi_prettyprint_status_register_bit(status, 0); ++ else ++ msg_cdbg("Chip status register: Bit 0 / \"Power of 2\" is %sset\n", ++ (status & AT45DB_POWEROF2) ? "" : "not "); ++ ++ if (status & AT45DB_PROT) ++ at45db_prettyprint_protection_register(flash, AT45DB_READ_PROTECT, "protect"); ++ ++ if (!isAT45DB321C) ++ at45db_prettyprint_protection_register(flash, AT45DB_READ_LOCKDOWN, "lock"); ++ ++ return 0; ++} ++ ++/* Probe function for AT45DB* chips that support multiple page sizes. */ ++int probe_spi_at45db(struct flashctx *flash) ++{ ++ uint8_t status; ++ struct flashchip *chip = flash->chip; ++ ++ if (!probe_spi_rdid(flash)) ++ return 0; ++ ++ /* Some AT45DB* chips support two different page sizes each (e.g. 264 and 256 B). In order to tell which ++ * page size this chip has we need to read the status register. */ ++ if (at45db_read_status_register(flash, &status) != 0) ++ return 0; ++ ++ /* We assume sane power-of-2 page sizes and adjust the chip attributes in case this is not the case. */ ++ if ((status & AT45DB_POWEROF2) == 0) { ++ chip->total_size = (chip->total_size / 32) * 33; ++ chip->page_size = (chip->page_size / 32) * 33; ++ ++ unsigned int i, j; ++ for (i = 0; i < NUM_ERASEFUNCTIONS; i++) { ++ struct block_eraser *eraser = &chip->block_erasers[i]; ++ for (j = 0; j < NUM_ERASEREGIONS; j++) { ++ eraser->eraseblocks[j].size = (eraser->eraseblocks[j].size / 32) * 33; ++ } ++ } ++ } ++ ++ switch (chip->page_size) { ++ case 256: chip->gran = write_gran_256bytes; break; ++ case 264: chip->gran = write_gran_264bytes; break; ++ case 512: chip->gran = write_gran_512bytes; break; ++ case 528: chip->gran = write_gran_528bytes; break; ++ case 1024: chip->gran = write_gran_1024bytes; break; ++ case 1056: chip->gran = write_gran_1056bytes; break; ++ default: ++ msg_cerr("%s: unknown page size %d.\n", __func__, chip->page_size); ++ return 0; ++ } ++ ++ msg_cdbg2("%s: total size %i kB, page size %i B\n", __func__, chip->total_size * 1024, chip->page_size); ++ ++ return 1; ++} ++ ++/* Returns the minimum number of bits needed to represent the given address. ++ * FIXME: use mind-blowing implementation. ++ * FIXME: move to utility module. */ ++static uint32_t address_to_bits(uint32_t addr) ++{ ++ unsigned int lzb = 0; ++ while (((1 << (31 - lzb)) & ~addr) != 0) ++ lzb++; ++ return 32 - lzb; ++} ++ ++/* In case of non-power-of-two page sizes we need to convert the address flashrom uses to the address the ++ * DataFlash chips use. The latter uses a segmented address space where the page address is encoded in the ++ * more significant bits and the offset within the page is encoded in the less significant bits. The exact ++ * partition depends on the page size. ++ */ ++static unsigned int at45db_convert_addr(unsigned int addr, unsigned int page_size) ++{ ++ unsigned int page_bits = address_to_bits(page_size - 1); ++ unsigned int at45db_addr = ((addr / page_size) << page_bits) | (addr % page_size); ++ msg_cspew("%s: addr=0x%x, page_size=%u, page_bits=%u -> at45db_addr=0x%x\n", ++ __func__, addr, page_size, page_bits, at45db_addr); ++ return at45db_addr; ++} ++ ++int spi_read_at45db(struct flashctx *flash, uint8_t *buf, unsigned int addr, unsigned int len) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ if ((addr + len) > total_size) { ++ msg_cerr("%s: tried to read beyond flash boundary: addr=%u, len=%u, size=%u\n", ++ __func__, addr, len, total_size); ++ return 1; ++ } ++ ++ /* We have to split this up into chunks to fit within the programmer's read size limit, but those ++ * chunks can cross page boundaries. */ ++ const unsigned int max_data_read = flash->pgm->spi.max_data_read; ++ const unsigned int max_chunk = (max_data_read > 0) ? max_data_read : page_size; ++ while (addr < len) { ++ unsigned int chunk = min(max_chunk, len); ++ int ret = spi_nbyte_read(flash, at45db_convert_addr(addr, page_size), buf + addr, chunk); ++ if (ret) { ++ msg_cerr("%s: error sending read command!\n", __func__); ++ return ret; ++ } ++ addr += chunk; ++ } ++ ++ return 0; ++} ++ ++/* Legacy continuous read, used where spi_read_at45db() is not available. ++ * The first 4 (dummy) bytes read need to be discarded. */ ++int spi_read_at45db_e8(struct flashctx *flash, uint8_t *buf, unsigned int addr, unsigned int len) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ if ((addr + len) > total_size) { ++ msg_cerr("%s: tried to read beyond flash boundary: addr=%u, len=%u, size=%u\n", ++ __func__, addr, len, total_size); ++ return 1; ++ } ++ ++ /* We have to split this up into chunks to fit within the programmer's read size limit, but those ++ * chunks can cross page boundaries. */ ++ const unsigned int max_data_read = flash->pgm->spi.max_data_read; ++ const unsigned int max_chunk = (max_data_read > 0) ? max_data_read : page_size; ++ while (addr < len) { ++ const unsigned int addr_at45 = at45db_convert_addr(addr, page_size); ++ const unsigned char cmd[] = { ++ AT45DB_READ_ARRAY, ++ (addr_at45 >> 16) & 0xff, ++ (addr_at45 >> 8) & 0xff, ++ (addr_at45 >> 0) & 0xff ++ }; ++ /* We need to leave place for 4 dummy bytes and handle them explicitly. */ ++ unsigned int chunk = min(max_chunk, len + 4); ++ uint8_t tmp[chunk]; ++ int ret = spi_send_command(flash, sizeof(cmd), chunk, cmd, tmp); ++ if (ret) { ++ msg_cerr("%s: error sending read command!\n", __func__); ++ return ret; ++ } ++ /* Copy result without dummy bytes into buf and advance address counter respectively. */ ++ memcpy(buf + addr, tmp + 4, chunk - 4); ++ addr += chunk - 4; ++ } ++ return 0; ++} ++ ++/* Returns 0 when ready, 1 on errors and timeouts. */ ++static int at45db_wait_ready (struct flashctx *flash, unsigned int us, unsigned int retries) ++{ ++ while (true) { ++ uint8_t status; ++ int ret = at45db_read_status_register(flash, &status); ++ if ((status & AT45DB_READY) == AT45DB_READY) ++ return 0; ++ if (ret != 0 || retries-- == 0) ++ return 1; ++ programmer_delay(us); ++ } ++} ++ ++static int at45db_erase(struct flashctx *flash, uint8_t opcode, unsigned int at45db_addr, unsigned int stepsize, unsigned int retries) ++{ ++ const uint8_t cmd[] = { ++ opcode, ++ (at45db_addr >> 16) & 0xff, ++ (at45db_addr >> 8) & 0xff, ++ (at45db_addr >> 0) & 0xff ++ }; ++ ++ /* Send erase command. */ ++ int ret = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL); ++ if (ret != 0) { ++ msg_cerr("%s: error sending erase command!\n", __func__); ++ return ret; ++ } ++ ++ /* Wait for completion. */ ++ ret = at45db_wait_ready(flash, stepsize, retries); ++ if (ret != 0) ++ msg_cerr("%s: chip did not became ready again after sending the erase command!\n", __func__); ++ ++ return ret; ++} ++ ++int spi_erase_at45db_page(struct flashctx *flash, unsigned int addr, unsigned int blocklen) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ ++ if ((addr % page_size) != 0 || (blocklen % page_size) != 0) { ++ msg_cerr("%s: cannot erase partial pages: addr=%u, blocklen=%u\n", __func__, addr, blocklen); ++ return 1; ++ } ++ ++ if ((addr + blocklen) > total_size) { ++ msg_cerr("%s: tried to erase a block beyond flash boundary: addr=%u, blocklen=%u, size=%u\n", ++ __func__, addr, blocklen, total_size); ++ return 1; ++ } ++ ++ /* Needs typically about 35 ms for completion, so let's wait 100 ms in 500 us steps. */ ++ return at45db_erase(flash, AT45DB_PAGE_ERASE, at45db_convert_addr(addr, page_size), 500, 200); ++} ++ ++int spi_erase_at45db_block(struct flashctx *flash, unsigned int addr, unsigned int blocklen) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ ++ if ((addr % page_size) != 0 || (blocklen % page_size) != 0) { // FIXME: should check blocks not pages ++ msg_cerr("%s: cannot erase partial pages: addr=%u, blocklen=%u\n", __func__, addr, blocklen); ++ return 1; ++ } ++ ++ if ((addr + blocklen) > total_size) { ++ msg_cerr("%s: tried to erase a block beyond flash boundary: addr=%u, blocklen=%u, size=%u\n", ++ __func__, addr, blocklen, total_size); ++ return 1; ++ } ++ ++ /* Needs typically between 20 and 100 ms for completion, so let's wait 300 ms in 1 ms steps. */ ++ return at45db_erase(flash, AT45DB_BLOCK_ERASE, at45db_convert_addr(addr, page_size), 1000, 300); ++} ++ ++int spi_erase_at45db_sector(struct flashctx *flash, unsigned int addr, unsigned int blocklen) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ ++ if ((addr % page_size) != 0 || (blocklen % page_size) != 0) { // FIXME: should check sectors not pages ++ msg_cerr("%s: cannot erase partial pages: addr=%u, blocklen=%u\n", __func__, addr, blocklen); ++ return 1; ++ } ++ ++ if ((addr + blocklen) > total_size) { ++ msg_cerr("%s: tried to erase a sector beyond flash boundary: addr=%u, blocklen=%u, size=%u\n", ++ __func__, addr, blocklen, total_size); ++ return 1; ++ } ++ ++ /* Needs typically about 5 s for completion, so let's wait 20 seconds in 200 ms steps. */ ++ return at45db_erase(flash, AT45DB_SECTOR_ERASE, at45db_convert_addr(addr, page_size), 200000, 100); ++} ++ ++int spi_erase_at45db_chip(struct flashctx *flash, unsigned int addr, unsigned int blocklen) ++{ ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ ++ if ((addr + blocklen) > total_size) { ++ msg_cerr("%s: tried to erase beyond flash boundary: addr=%u, blocklen=%u, size=%u\n", ++ __func__, addr, blocklen, total_size); ++ return 1; ++ } ++ ++ /* Needs typically from about 5 to over 60 s for completion, so let's wait 100 s in 500 ms steps. ++ * NB: the address is not a real address but a magic number. This hack allows to share code. */ ++ return at45db_erase(flash, AT45DB_CHIP_ERASE, AT45DB_CHIP_ERASE_ADDR, 500000, 200); ++} ++ ++/* This one is really special and works only for AT45CS1282. It uses two different opcodes depending on the ++ * address and has an asymmetric layout. */ ++int spi_erase_at45cs_sector(struct flashctx *flash, unsigned int addr, unsigned int blocklen) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ const struct block_eraser be = flash->chip->block_erasers[0]; ++ const unsigned int sec_0a_top = be.eraseblocks[0].size; ++ const unsigned int sec_0b_top = be.eraseblocks[0].size + be.eraseblocks[1].size; ++ ++ if ((addr + blocklen) > total_size) { ++ msg_cerr("%s: tried to erase a sector beyond flash boundary: addr=%u, blocklen=%u, size=%u\n", ++ __func__, addr, blocklen, total_size); ++ return 1; ++ } ++ ++ bool partial_range = false; ++ uint8_t opcode = 0x7C; /* Used for all but sector 0a. */ ++ if (addr < sec_0a_top) { ++ opcode = 0x50; ++ /* One single sector of 8 pages at address 0. */ ++ if (addr != 0 || blocklen != (8 * page_size)) ++ partial_range = true; ++ } else if (addr < sec_0b_top) { ++ /* One single sector of 248 pages adjacent to the first. */ ++ if (addr != sec_0a_top || blocklen != (248 * page_size)) ++ partial_range = true; ++ } else { ++ /* The rest is filled by 63 aligned sectors of 256 pages. */ ++ if ((addr % (256 * page_size)) != 0 || (blocklen % (256 * page_size)) != 0) ++ partial_range = true; ++ } ++ if (partial_range) { ++ msg_cerr("%s: cannot erase partial sectors: addr=%u, blocklen=%u\n", __func__, addr, blocklen); ++ return 1; ++ } ++ ++ /* Needs up to 4 s for completion, so let's wait 20 seconds in 200 ms steps. */ ++ return at45db_erase(flash, opcode, at45db_convert_addr(addr, page_size), 200000, 100); ++} ++ ++static int at45db_fill_buffer1(struct flashctx *flash, uint8_t *bytes, unsigned int off, unsigned int len) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ if ((off + len) > page_size) { ++ msg_cerr("Tried to write %u bytes at offset %u into a buffer of only %u B.\n", ++ len, off, page_size); ++ return 1; ++ } ++ ++ /* Create a suitable buffer to store opcode, address and data chunks for buffer1. */ ++ const unsigned int max_data_write = flash->pgm->spi.max_data_write; ++ const unsigned int max_chunk = (max_data_write > 0 && max_data_write <= page_size) ? ++ max_data_write : page_size; ++ uint8_t buf[4 + max_chunk]; ++ ++ buf[0] = AT45DB_BUFFER1_WRITE; ++ while (off < page_size) { ++ unsigned int cur_chunk = min(max_chunk, page_size - off); ++ buf[1] = (off >> 16) & 0xff; ++ buf[2] = (off >> 8) & 0xff; ++ buf[3] = (off >> 0) & 0xff; ++ memcpy(&buf[4], bytes + off, cur_chunk); ++ int ret = spi_send_command(flash, 4 + cur_chunk, 0, buf, NULL); ++ if (ret != 0) { ++ msg_cerr("%s: error sending buffer write!\n", __func__); ++ return ret; ++ } ++ off += cur_chunk; ++ } ++ return 0; ++} ++ ++static int at45db_commit_buffer1(struct flashctx *flash, unsigned int at45db_addr) ++{ ++ const uint8_t cmd[] = { ++ AT45DB_BUFFER1_PAGE_PROGRAM, ++ (at45db_addr >> 16) & 0xff, ++ (at45db_addr >> 8) & 0xff, ++ (at45db_addr >> 0) & 0xff ++ }; ++ ++ /* Send buffer to device. */ ++ int ret = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL); ++ if (ret != 0) { ++ msg_cerr("%s: error sending buffer to main memory command!\n", __func__); ++ return ret; ++ } ++ ++ /* Wait for completion (typically a few ms). */ ++ ret = at45db_wait_ready(flash, 250, 200); // 50 ms ++ if (ret != 0) { ++ msg_cerr("%s: chip did not became ready again!\n", __func__); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int at45db_program_page(struct flashctx *flash, uint8_t *buf, unsigned int at45db_addr) ++{ ++ int ret = at45db_fill_buffer1(flash, buf, 0, flash->chip->page_size); ++ if (ret != 0) { ++ msg_cerr("%s: filling the buffer failed!\n", __func__); ++ return ret; ++ } ++ ++ ret = at45db_commit_buffer1(flash, at45db_addr); ++ if (ret != 0) { ++ msg_cerr("%s: committing page failed!\n", __func__); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int spi_write_at45db(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size; ++ ++ if ((start % page_size) != 0 || (len % page_size) != 0) { ++ msg_cerr("%s: cannot write partial pages: start=%u, len=%u\n", __func__, start, len); ++ return 1; ++ } ++ ++ if ((start + len) > (total_size * 1024)) { ++ msg_cerr("%s: tried to write beyond flash boundary: start=%u, len=%u, size=%u\n", ++ __func__, start, len, total_size); ++ return 1; ++ } ++ ++ unsigned int i; ++ for (i = 0; i < len; i += page_size) { ++ if (at45db_program_page(flash, buf + i, at45db_convert_addr(start + i, page_size)) != 0) { ++ msg_cerr("Writing page %u failed!\n", i); ++ return 1; ++ } ++ } ++ return 0; ++} +diff --git a/atahpt.c b/atahpt.c +index f8be8c4..242e14a 100644 +--- a/atahpt.c ++++ b/atahpt.c +@@ -69,6 +69,8 @@ int atahpt_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_4); ++ if (!io_base_addr) ++ return 1; + + /* Enable flash access. */ + reg32 = pci_read_long(dev, REG_FLASH_ACCESS); +diff --git a/board_enable.c b/board_enable.c +index 074cabb..e2a5fe2 100644 +--- a/board_enable.c ++++ b/board_enable.c +@@ -1488,6 +1488,7 @@ static int intel_ich_gpio_set(int gpio, int raise) + {0x24D0, 0x58, 0x1BFF0000, 0x00030305, 0}, /* 82801EB/ER (ICH5/ICH5R) */ + {0x2640, 0x48, 0x1BFF0000, 0x00030307, 0}, /* 82801FB/FR (ICH6/ICH6R) */ + {0x2641, 0x48, 0x1BFF0000, 0x00030307, 0}, /* 82801FBM (ICH6M) */ ++ {0x27B0, 0x48, 0xFFFFFFFF, 0x000300FF, 0}, /* 82801GDH (ICH7 DH) */ + {0x27B8, 0x48, 0xFFFFFFFF, 0x000300FF, 0}, /* 82801GB/GR (ICH7 Family) */ + {0x27B9, 0x48, 0xFFEBFFFE, 0x000300FE, 0}, /* 82801GBM (ICH7-M) */ + {0x27BD, 0x48, 0xFFEBFFFE, 0x000300FE, 0}, /* 82801GHM (ICH7-M DH) */ +@@ -1665,6 +1666,7 @@ static int intel_ich_gpio_set(int gpio, int raise) + * - abit IP35 Pro: Intel P35 + ICH9R + * - ASUS P5LD2 + * - ASUS P5LD2-VM ++ * - ASUS P5LD2-VM DH + */ + static int intel_ich_gpio16_raise(void) + { +@@ -2266,13 +2268,13 @@ static int p2_whitelist_laptop(void) + * NOTE: Please add boards that _don't_ need such enables or don't work yet + * to the respective tables in print.c. Thanks! + * +- * We use 2 sets of IDs here, you're free to choose which is which. This ++ * We use 2 sets of PCI IDs here, you're free to choose which is which. This + * is to provide a very high degree of certainty when matching a board on + * the basis of subsystem/card IDs. As not every vendor handles + * subsystem/card IDs in a sane manner. + * + * Keep the second set NULLed if it should be ignored. Keep the subsystem IDs +- * NULLed if they don't identify the board fully and if you can't use DMI. ++ * and the dmi identifier NULLed if they don't identify the board fully to disable autodetection. + * But please take care to provide an as complete set of pci ids as possible; + * autodetection is the preferred behaviour and we would like to make sure that + * matches are unique. +@@ -2306,6 +2308,7 @@ const struct board_match board_matches[] = { + #if defined(__i386__) || defined(__x86_64__) + {0x10DE, 0x0547, 0x147B, 0x1C2F, 0x10DE, 0x0548, 0x147B, 0x1C2F, NULL, NULL, NULL, P3, "abit", "AN-M2", 0, NT, nvidia_mcp_gpio2_raise}, + {0x1106, 0x0282, 0x147B, 0x1415, 0x1106, 0x3227, 0x147B, 0x1415, "^AV8 ", NULL, NULL, P3, "abit", "AV8", 0, OK, board_abit_av8}, ++ {0x8086, 0x7190, 0, 0, 0x8086, 0x7110, 0, 0, NULL /* "^I440BX-W977$" */, "abit", "bf6", P3, "abit", "BF6", 0, OK, intel_piix4_gpo26_lower}, + {0x8086, 0x7190, 0, 0, 0x8086, 0x7110, 0, 0, "^i440BX-W977 (BM6)$", NULL, NULL, P3, "abit", "BM6", 0, OK, intel_piix4_gpo26_lower}, + {0x8086, 0x24d3, 0x147b, 0x1014, 0x8086, 0x2578, 0x147b, 0x1014, NULL, NULL, NULL, P3, "abit", "IC7", 0, NT, intel_ich_gpio23_raise}, + {0x8086, 0x2930, 0x147b, 0x1084, 0x11ab, 0x4364, 0x147b, 0x1084, NULL, NULL, NULL, P3, "abit", "IP35", 0, OK, intel_ich_gpio16_raise}, +@@ -2330,6 +2333,7 @@ const struct board_match board_matches[] = { + {0x8086, 0x2570, 0x1849, 0x2570, 0x8086, 0x24d3, 0x1849, 0x24d0, NULL, NULL, NULL, P3, "ASRock", "775i65G", 0, OK, intel_ich_gpio23_raise}, + {0x10DE, 0x0060, 0x1043, 0x80AD, 0x10DE, 0x01E0, 0x1043, 0x80C0, NULL, NULL, NULL, P3, "ASUS", "A7N8X-VM/400", 0, OK, it8712f_gpio12_raise}, + {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3065, 0x1043, 0x80ED, NULL, NULL, NULL, P3, "ASUS", "A7V600-X", 0, OK, it8712f_gpio31_raise}, ++ {0x1106, 0x3177, 0x1043, 0x80F9, 0x1106, 0x3205, 0x1043, 0x80F9, NULL, NULL, NULL, P3, "ASUS", "A7V8X-MX", 0, OK, w836xx_memw_enable_2e}, + {0x1106, 0x3177, 0x1043, 0x80A1, 0x1106, 0x3205, 0x1043, 0x8118, NULL, NULL, NULL, P3, "ASUS", "A7V8X-MX SE", 0, OK, w836xx_memw_enable_2e}, + {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3177, 0x1043, 0x808C, NULL, NULL, NULL, P3, "ASUS", "A7V8X", 0, OK, it8703f_gpio51_raise}, + {0x1106, 0x3099, 0x1043, 0x807F, 0x1106, 0x3147, 0x1043, 0x808C, NULL, NULL, NULL, P3, "ASUS", "A7V333", 0, OK, it8703f_gpio51_raise}, +@@ -2372,12 +2376,14 @@ const struct board_match board_matches[] = { + {0x8086, 0x27b8, 0x1043, 0x2a22, 0x8086, 0x2770, 0x1043, 0x2a22, "^P5LP-LE$", NULL, NULL, P3, "ASUS", "P5LP-LE (Epson OEM)", 0, OK, intel_ich_gpio34_raise}, + {0x8086, 0x27da, 0x1043, 0x8179, 0x8086, 0x27b8, 0x1043, 0x8179, "^P5LD2$", NULL, NULL, P3, "ASUS", "P5LD2", 0, NT, intel_ich_gpio16_raise}, + {0x8086, 0x27da, 0x1043, 0x8179, 0x8086, 0x27b8, 0x1043, 0x8179, "^P5LD2-VM$", NULL, NULL, P3, "ASUS", "P5LD2-VM", 0, NT, intel_ich_gpio16_raise}, ++ {0x8086, 0x27b0, 0x1043, 0x8179, 0x8086, 0x2770, 0x1043, 0x817a, "^P5LD2-VM DH$", NULL, NULL, P3, "ASUS", "P5LD2-VM DH", 0, OK, intel_ich_gpio16_raise}, + {0x10DE, 0x0030, 0x1043, 0x818a, 0x8086, 0x100E, 0x1043, 0x80EE, NULL, NULL, NULL, P3, "ASUS", "P5ND2-SLI Deluxe", 0, OK, nvidia_mcp_gpio10_raise}, + {0x10DE, 0x0260, 0x1043, 0x81BC, 0x10DE, 0x026C, 0x1043, 0x829E, "^P5N-D$", NULL, NULL, P3, "ASUS", "P5N-D", 0, OK, it8718f_gpio63_raise}, + {0x10DE, 0x0260, 0x1043, 0x81BC, 0x10DE, 0x026C, 0x1043, 0x8249, "^P5N-E SLI$",NULL, NULL, P3, "ASUS", "P5N-E SLI", 0, NT, it8718f_gpio63_raise}, + {0x8086, 0x24dd, 0x1043, 0x80a6, 0x8086, 0x2570, 0x1043, 0x8157, NULL, NULL, NULL, P3, "ASUS", "P5PE-VM", 0, OK, intel_ich_gpio21_raise}, + {0x8086, 0x2443, 0x1043, 0x8027, 0x8086, 0x1130, 0x1043, 0x8027, "^CUSL2-C", NULL, NULL, P3, "ASUS", "CUSL2-C", 0, OK, intel_ich_gpio21_raise}, + {0x8086, 0x2443, 0x1043, 0x8027, 0x8086, 0x1130, 0x1043, 0x8027, "^TUSL2-C", NULL, NULL, P3, "ASUS", "TUSL2-C", 0, NT, intel_ich_gpio21_raise}, ++ {0x1106, 0x3059, 0x1106, 0x4161, 0x1106, 0x3065, 0x1106, 0x0102, NULL, NULL, NULL, P3, "Bcom/Clientron", "WinNET P680", 0, OK, w836xx_memw_enable_2e}, + {0x1106, 0x3177, 0x1106, 0x3177, 0x1106, 0x3116, 0x1106, 0x3116, "^KM266-8235$", "biostar", "m7viq", P3, "Biostar", "M7VIQ", 0, NT, w83697xx_memw_enable_2e}, + {0x10b7, 0x9055, 0x1028, 0x0082, 0x8086, 0x7190, 0, 0, NULL, NULL, NULL, P3, "Dell", "OptiPlex GX1", 0, OK, intel_piix4_gpo30_lower}, + {0x8086, 0x3590, 0x1028, 0x016c, 0x1000, 0x0030, 0x1028, 0x016c, NULL, NULL, NULL, P3, "Dell", "PowerEdge 1850", 0, OK, intel_ich_gpio23_raise}, +@@ -2452,6 +2458,12 @@ const struct board_match board_matches[] = { + {0x1106, 0x0259, 0x1106, 0xAA07, 0x1106, 0x3227, 0x1106, 0xAA07, NULL, NULL, NULL, P3, "VIA", "EPIA EK", 0, NT, via_vt823x_gpio9_raise}, + {0x1106, 0x3177, 0x1106, 0xAA01, 0x1106, 0x3123, 0x1106, 0xAA01, NULL, NULL, NULL, P3, "VIA", "EPIA M/MII/...", 0, OK, via_vt823x_gpio15_raise}, + {0x1106, 0x0259, 0x1106, 0x3227, 0x1106, 0x3065, 0x1106, 0x3149, NULL, NULL, NULL, P3, "VIA", "EPIA-N/NL", 0, OK, via_vt823x_gpio9_raise}, ++#ifdef DELL_AVOTON_SUPPORT ++ {0x8086, 0x1f38, 0x8086, 0x7270, 0, 0, 0, 0, NULL, NULL, NULL, P2, "DELL", "AVOTON", 0, OK, p2_not_a_laptop}, ++#endif ++#if DELL_DENVERTON_SUPPORT == 1 ++ {0x8086, 0x19dc, 0x8086, 0x7270, 0, 0, 0, 0, NULL, NULL, NULL, P2, "DELL", "DENVERTON", 0, OK, p2_not_a_laptop}, ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + #endif + { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, P3, NULL, NULL, 0, NT, NULL}, /* end marker */ + }; +@@ -2559,6 +2571,7 @@ const static struct board_match *board_match_pci_ids(enum board_match_phase phas + } + } + ++#if defined(__i386__) || defined(__x86_64__) + if (board->dmi_pattern) { + if (!has_dmi_support) { + msg_pwarn("Warning: Can't autodetect %s %s, DMI info unavailable.\n", +@@ -2571,7 +2584,7 @@ const static struct board_match *board_match_pci_ids(enum board_match_phase phas + continue; + } + } +- ++#endif // defined(__i386__) || defined(__x86_64__) + return board; + } + +diff --git a/buspirate_spi.c b/buspirate_spi.c +index 9d229f4..f0e84bc 100644 +--- a/buspirate_spi.c ++++ b/buspirate_spi.c +@@ -250,6 +250,7 @@ int buspirate_spi_init(void) + if (!bp_commbuf) { + bp_commbufsize = 0; + msg_perr("Out of memory!\n"); ++ free(dev); + return ERROR_OOM; + } + bp_commbufsize = DEFAULT_BUFSIZE; +@@ -263,8 +264,12 @@ int buspirate_spi_init(void) + return ret; + } + +- if (register_shutdown(buspirate_spi_shutdown, NULL)) ++ if (register_shutdown(buspirate_spi_shutdown, NULL) != 0) { ++ bp_commbufsize = 0; ++ free(bp_commbuf); ++ bp_commbuf = NULL; + return 1; ++ } + + /* This is the brute force version, but it should work. + * It is likely to fail if a previous flashrom run was aborted during a write with the new SPI commands +diff --git a/cbtable.c b/cbtable.c +index e262a84..c100bbb 100644 +--- a/cbtable.c ++++ b/cbtable.c +@@ -261,7 +261,7 @@ int cb_parse_table(const char **vendor, const char **model) + #else + start = 0x0; + #endif +- table_area = physmap_try_ro("low megabyte", start, BYTES_TO_MAP - start); ++ table_area = physmap_ro_unaligned("low megabyte", start, BYTES_TO_MAP - start); + if (ERROR_PTR == table_area) { + msg_perr("Failed getting access to coreboot low tables.\n"); + return -1; +@@ -276,8 +276,9 @@ int cb_parse_table(const char **vendor, const char **model) + if (forward->tag == LB_TAG_FORWARD) { + start = forward->forward; + start &= ~(getpagesize() - 1); +- physunmap(table_area, BYTES_TO_MAP); +- table_area = physmap_try_ro("high tables", start, BYTES_TO_MAP); ++ physunmap_unaligned(table_area, BYTES_TO_MAP); ++ // FIXME: table_area is never unmapped below, nor is it unmapped above in the no-forward case ++ table_area = physmap_ro_unaligned("high tables", start, BYTES_TO_MAP); + if (ERROR_PTR == table_area) { + msg_perr("Failed getting access to coreboot high tables.\n"); + return -1; +diff --git a/chipdrivers.h b/chipdrivers.h +index 091d14c..851e90a 100644 +--- a/chipdrivers.h ++++ b/chipdrivers.h +@@ -64,6 +64,7 @@ int spi_write_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start, + /* spi25_statusreg.c */ + uint8_t spi_read_status_register(struct flashctx *flash); + int spi_write_status_register(struct flashctx *flash, int status); ++void spi_prettyprint_status_register_bit(uint8_t status, int bit); + int spi_prettyprint_status_register_plain(struct flashctx *flash); + int spi_prettyprint_status_register_default_welwip(struct flashctx *flash); + int spi_prettyprint_status_register_default_bp1(struct flashctx *flash); +@@ -109,6 +110,19 @@ int read_opaque(struct flashctx *flash, uint8_t *buf, unsigned int start, unsign + int write_opaque(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); + int erase_opaque(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen); + ++/* at45db.c */ ++int probe_spi_at45db(struct flashctx *flash); ++int spi_prettyprint_status_register_at45db(struct flashctx *flash); ++int spi_disable_blockprotect_at45db(struct flashctx *flash); ++int spi_read_at45db(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); ++int spi_read_at45db_e8(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); ++int spi_write_at45db(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); ++int spi_erase_at45db_page(struct flashctx *flash, unsigned int addr, unsigned int blocklen); ++int spi_erase_at45db_block(struct flashctx *flash, unsigned int addr, unsigned int blocklen); ++int spi_erase_at45db_sector(struct flashctx *flash, unsigned int addr, unsigned int blocklen); ++int spi_erase_at45db_chip(struct flashctx *flash, unsigned int addr, unsigned int blocklen); ++int spi_erase_at45cs_sector(struct flashctx *flash, unsigned int addr, unsigned int blocklen); ++ + /* 82802ab.c */ + uint8_t wait_82802ab(struct flashctx *flash); + int probe_82802ab(struct flashctx *flash); +@@ -179,9 +193,10 @@ int printlock_at49f(struct flashctx *flash); + /* w29ee011.c */ + int probe_w29ee011(struct flashctx *flash); + +-/* stm50flw0x0x.c */ +-int erase_sector_stm50flw0x0x(struct flashctx *flash, unsigned int block, unsigned int blocksize); +-int unlock_stm50flw0x0x(struct flashctx *flash); ++/* stm50.c */ ++int erase_sector_stm50(struct flashctx *flash, unsigned int block, unsigned int blocksize); ++int unlock_stm50_uniform(struct flashctx *flash); ++int unlock_stm50_nonuniform(struct flashctx *flash); + + /* en29lv640b.c */ + int probe_en29lv640b(struct flashctx *flash); +diff --git a/chipset_enable.c b/chipset_enable.c +index a2df263..8a8ab66 100644 +--- a/chipset_enable.c ++++ b/chipset_enable.c +@@ -41,6 +41,17 @@ + + #if defined(__i386__) || defined(__x86_64__) + ++#if DELL_AVOTON_SUPPORT == 1 ++uint8_t is_avoton = 0; ++#endif /* DELL_AVOTON_SUPPORT == 1 */ ++ ++#if DELL_DENVERTON_SUPPORT == 1 ++uint8_t is_dnv = 0; ++uint32_t dnv_bios_region_start = 0x00; ++uint32_t dnv_bios_region_size = 0x00; ++uint32_t dnv_bios_region_limit = 0x00; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + static int enable_flash_ali_m1533(struct pci_dev *dev, const char *name) + { + uint8_t tmp; +@@ -260,20 +271,44 @@ static int enable_flash_piix4(struct pci_dev *dev, const char *name) + return 0; + } + +-/* +- * See ie. page 375 of "Intel I/O Controller Hub 7 (ICH7) Family Datasheet" +- * http://download.intel.com/design/chipsets/datashts/30701303.pdf +- */ +-static int enable_flash_ich(struct pci_dev *dev, const char *name, uint8_t bios_cntl) ++/* Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, in Poulsbo, Tunnel Creek and other Atom ++ * chipsets/SoCs it is even 32b, but just treating it as 8 bit wide seems to work fine in practice. */ ++static int enable_flash_ich_bios_cntl(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl) + { + uint8_t old, new, wanted; + +- /* +- * Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, in Tunnel Creek it is even 32b, but +- * just treating it as 8 bit wide seems to work fine in practice. +- */ +- wanted = old = pci_read_byte(dev, bios_cntl); ++ switch (ich_generation) { ++ case CHIPSET_ICH_UNKNOWN: ++ return ERROR_FATAL; ++ /* Non-SPI-capable */ ++ case CHIPSET_ICH: ++ case CHIPSET_ICH2345: ++ break; ++ /* Atom chipsets are special: The second byte of BIOS_CNTL (D9h) contains a prefetch bit similar to what ++ * other SPI-capable chipsets have at DCh. ++ * The Tunnel Creek datasheet contains a lot of details about the SPI controller, among other things it ++ * mentions that the prefetching and caching does only happen for direct memory reads. ++ * Therefore - at least for Tunnel Creek - it should not matter to flashrom because we use the ++ * programmed access only and not memory mapping. */ ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_POULSBO: ++ case CHIPSET_CENTERTON: ++ old = pci_read_byte(dev, bios_cntl + 1); ++ msg_pdbg("BIOS Prefetch Enable: %sabled, ", (old & 1) ? "en" : "dis"); ++ break; ++ case CHIPSET_ICH7: ++ default: /* Future version might behave the same */ ++ old = (pci_read_byte(dev, bios_cntl) >> 2) & 0x3; ++ msg_pdbg("SPI Read Configuration: "); ++ if (old == 3) ++ msg_pdbg("invalid prefetching/caching settings, "); ++ else ++ msg_pdbg("prefetching %sabled, caching %sabled, ", ++ (old & 0x2) ? "en" : "dis", ++ (old & 0x1) ? "dis" : "en"); ++ } + ++ wanted = old = pci_read_byte(dev, bios_cntl); + /* + * Quote from the 6 Series datasheet (Document Number: 324645-004): + * "Bit 5: SMM BIOS Write Protect Disable (SMM_BWP) +@@ -283,11 +318,23 @@ static int enable_flash_ich(struct pci_dev *dev, const char *name, uint8_t bios_ + * + * Try to unset it in any case. + * It won't hurt and makes sense in some cases according to Stefan Reinauer. ++ * ++ * At least in Centerton aforementioned bit is located at bit 7. It is unspecified in all other Atom ++ * and Desktop chipsets before Ibex Peak/5 Series, but we reset bit 5 anyway. + */ +- wanted &= ~(1 << 5); ++ int smm_bwp_bit; ++ if (ich_generation == CHIPSET_CENTERTON) ++ smm_bwp_bit = 7; ++ else ++ smm_bwp_bit = 5; ++ wanted &= ~(1 << smm_bwp_bit); + +- /* Set BIOS Write Enable */ +- wanted |= (1 << 0); ++ /* Tunnel Creek has a cache disable at bit 2 of the lowest BIOS_CNTL byte. */ ++ if (ich_generation == CHIPSET_TUNNEL_CREEK) ++ wanted |= (1 << 2); ++ ++ wanted |= (1 << 0); /* Set BIOS Write Enable */ ++ wanted &= ~(1 << 1); /* Disable lock (futile) */ + + /* Only write the register if it's necessary */ + if (wanted != old) { +@@ -299,64 +346,79 @@ static int enable_flash_ich(struct pci_dev *dev, const char *name, uint8_t bios_ + msg_pdbg("\nBIOS_CNTL = 0x%02x: ", new); + msg_pdbg("BIOS Lock Enable: %sabled, ", (new & (1 << 1)) ? "en" : "dis"); + msg_pdbg("BIOS Write Enable: %sabled\n", (new & (1 << 0)) ? "en" : "dis"); +- if (new & (1 << 5)) ++ if (new & (1 << smm_bwp_bit)) + msg_pwarn("Warning: BIOS region SMM protection is enabled!\n"); + +- + if (new != wanted) +- msg_pwarn("Warning: Setting Bios Control at 0x%x from 0x%02x to 0x%02x on %s failed.\n" +- "New value is 0x%02x.\n", bios_cntl, old, wanted, name, new); ++ msg_pwarn("Warning: Setting Bios Control at 0x%x from 0x%02x to 0x%02x failed.\n" ++ "New value is 0x%02x.\n", bios_cntl, old, wanted, new); + +- /* Return an error if we could not set the write enable */ ++ /* Return an error if we could not set the write enable only. */ + if (!(new & (1 << 0))) + return -1; + + return 0; + } + +-static int enable_flash_ich_4e(struct pci_dev *dev, const char *name) ++static int enable_flash_ich_fwh_decode(struct pci_dev *dev, enum ich_chipset ich_generation) + { +- /* +- * Note: ICH5 has registers similar to FWH_SEL1, FWH_SEL2 and +- * FWH_DEC_EN1, but they are called FB_SEL1, FB_SEL2, FB_DEC_EN1 and +- * FB_DEC_EN2. +- */ +- internal_buses_supported = BUS_FWH; +- return enable_flash_ich(dev, name, 0x4e); +-} +- +-static int enable_flash_ich_dc(struct pci_dev *dev, const char *name) +-{ +- uint32_t fwh_conf; +- int i, tmp; +- char *idsel = NULL; +- int max_decode_fwh_idsel = 0, max_decode_fwh_decode = 0; +- int contiguous = 1; ++ uint8_t fwh_sel1 = 0, fwh_sel2 = 0, fwh_dec_en_lo = 0, fwh_dec_en_hi = 0; /* silence compilers */ ++ bool implemented = 0; ++ switch (ich_generation) { ++ case CHIPSET_ICH: ++ /* FIXME: Unlike later chipsets, ICH and ICH-0 do only support mapping of the top-most 4MB ++ * and therefore do only feature FWH_DEC_EN (E3h, different default too) and FWH_SEL (E8h). */ ++ break; ++ case CHIPSET_ICH2345: ++ fwh_sel1 = 0xe8; ++ fwh_sel2 = 0xee; ++ fwh_dec_en_lo = 0xf0; ++ fwh_dec_en_hi = 0xe3; ++ implemented = 1; ++ break; ++ case CHIPSET_POULSBO: ++ case CHIPSET_TUNNEL_CREEK: ++ /* FIXME: Similar to ICH and ICH-0, Tunnel Creek and Poulsbo do only feature one register each, ++ * FWH_DEC_EN (D7h) and FWH_SEL (D0h). */ ++ break; ++ case CHIPSET_CENTERTON: ++ /* FIXME: Similar to above FWH_DEC_EN (D4h) and FWH_SEL (D0h). */ ++ break; ++ case CHIPSET_ICH6: ++ case CHIPSET_ICH7: ++ default: /* Future version might behave the same */ ++ fwh_sel1 = 0xd0; ++ fwh_sel2 = 0xd4; ++ fwh_dec_en_lo = 0xd8; ++ fwh_dec_en_hi = 0xd9; ++ implemented = 1; ++ break; ++ } + +- idsel = extract_programmer_param("fwh_idsel"); ++ char *idsel = extract_programmer_param("fwh_idsel"); + if (idsel && strlen(idsel)) { +- uint64_t fwh_idsel_old, fwh_idsel; ++ if (!implemented) { ++ msg_perr("Error: fwh_idsel= specified, but (yet) unsupported on this chipset.\n"); ++ goto idsel_garbage_out; ++ } + errno = 0; + /* Base 16, nothing else makes sense. */ +- fwh_idsel = (uint64_t)strtoull(idsel, NULL, 16); ++ uint64_t fwh_idsel = (uint64_t)strtoull(idsel, NULL, 16); + if (errno) { +- msg_perr("Error: fwh_idsel= specified, but value could " +- "not be converted.\n"); ++ msg_perr("Error: fwh_idsel= specified, but value could not be converted.\n"); + goto idsel_garbage_out; + } + if (fwh_idsel & 0xffff000000000000ULL) { +- msg_perr("Error: fwh_idsel= specified, but value had " +- "unused bits set.\n"); ++ msg_perr("Error: fwh_idsel= specified, but value had unused bits set.\n"); + goto idsel_garbage_out; + } +- fwh_idsel_old = pci_read_long(dev, 0xd0); ++ uint64_t fwh_idsel_old = pci_read_long(dev, fwh_sel1); + fwh_idsel_old <<= 16; +- fwh_idsel_old |= pci_read_word(dev, 0xd4); +- msg_pdbg("\nSetting IDSEL from 0x%012" PRIx64 " to " +- "0x%012" PRIx64 " for top 16 MB.", fwh_idsel_old, +- fwh_idsel); +- rpci_write_long(dev, 0xd0, (fwh_idsel >> 16) & 0xffffffff); +- rpci_write_word(dev, 0xd4, fwh_idsel & 0xffff); ++ fwh_idsel_old |= pci_read_word(dev, fwh_sel2); ++ msg_pdbg("\nSetting IDSEL from 0x%012" PRIx64 " to 0x%012" PRIx64 " for top 16 MB.", ++ fwh_idsel_old, fwh_idsel); ++ rpci_write_long(dev, fwh_sel1, (fwh_idsel >> 16) & 0xffffffff); ++ rpci_write_word(dev, fwh_sel2, fwh_idsel & 0xffff); + /* FIXME: Decode settings are not changed. */ + } else if (idsel) { + msg_perr("Error: fwh_idsel= specified, but no value given.\n"); +@@ -366,15 +428,23 @@ idsel_garbage_out: + } + free(idsel); + ++ if (!implemented) { ++ msg_pdbg2("FWH IDSEL handling is not implemented on this chipset."); ++ return 0; ++ } ++ + /* Ignore all legacy ranges below 1 MB. + * We currently only support flashing the chip which responds to + * IDSEL=0. To support IDSEL!=0, flashbase and decode size calculations + * have to be adjusted. + */ ++ int max_decode_fwh_idsel = 0, max_decode_fwh_decode = 0; ++ bool contiguous = 1; ++ uint32_t fwh_conf = pci_read_long(dev, fwh_sel1); ++ int i; + /* FWH_SEL1 */ +- fwh_conf = pci_read_long(dev, 0xd0); + for (i = 7; i >= 0; i--) { +- tmp = (fwh_conf >> (i * 4)) & 0xf; ++ int tmp = (fwh_conf >> (i * 4)) & 0xf; + msg_pdbg("\n0x%08x/0x%08x FWH IDSEL: 0x%x", + (0x1ff8 + i) * 0x80000, + (0x1ff0 + i) * 0x80000, +@@ -386,9 +456,9 @@ idsel_garbage_out: + } + } + /* FWH_SEL2 */ +- fwh_conf = pci_read_word(dev, 0xd4); ++ fwh_conf = pci_read_word(dev, fwh_sel2); + for (i = 3; i >= 0; i--) { +- tmp = (fwh_conf >> (i * 4)) & 0xf; ++ int tmp = (fwh_conf >> (i * 4)) & 0xf; + msg_pdbg("\n0x%08x/0x%08x FWH IDSEL: 0x%x", + (0xff4 + i) * 0x100000, + (0xff0 + i) * 0x100000, +@@ -401,9 +471,11 @@ idsel_garbage_out: + } + contiguous = 1; + /* FWH_DEC_EN1 */ +- fwh_conf = pci_read_word(dev, 0xd8); ++ fwh_conf = pci_read_byte(dev, fwh_dec_en_hi); ++ fwh_conf <<= 8; ++ fwh_conf |= pci_read_byte(dev, fwh_dec_en_lo); + for (i = 7; i >= 0; i--) { +- tmp = (fwh_conf >> (i + 0x8)) & 0x1; ++ int tmp = (fwh_conf >> (i + 0x8)) & 0x1; + msg_pdbg("\n0x%08x/0x%08x FWH decode %sabled", + (0x1ff8 + i) * 0x80000, + (0x1ff0 + i) * 0x80000, +@@ -415,7 +487,7 @@ idsel_garbage_out: + } + } + for (i = 3; i >= 0; i--) { +- tmp = (fwh_conf >> i) & 0x1; ++ int tmp = (fwh_conf >> i) & 0x1; + msg_pdbg("\n0x%08x/0x%08x FWH decode %sabled", + (0xff4 + i) * 0x100000, + (0xff0 + i) * 0x100000, +@@ -429,99 +501,66 @@ idsel_garbage_out: + max_rom_decode.fwh = min(max_decode_fwh_idsel, max_decode_fwh_decode); + msg_pdbg("\nMaximum FWH chip size: 0x%x bytes", max_rom_decode.fwh); + +- /* If we're called by enable_flash_ich_dc_spi, it will override +- * internal_buses_supported anyway. +- */ +- internal_buses_supported = BUS_FWH; +- return enable_flash_ich(dev, name, 0xdc); ++ return 0; + } + +-static int enable_flash_poulsbo(struct pci_dev *dev, const char *name) ++static int enable_flash_ich_fwh(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl) + { +- uint16_t old, new; + int err; + +- if ((err = enable_flash_ich(dev, name, 0xd8)) != 0) ++ /* Configure FWH IDSEL decoder maps. */ ++ if ((err = enable_flash_ich_fwh_decode(dev, ich_generation)) != 0) + return err; + +- old = pci_read_byte(dev, 0xd9); +- msg_pdbg("BIOS Prefetch Enable: %sabled, ", +- (old & 1) ? "en" : "dis"); +- new = old & ~1; +- +- if (new != old) +- rpci_write_byte(dev, 0xd9, new); +- + internal_buses_supported = BUS_FWH; +- return 0; ++ return enable_flash_ich_bios_cntl(dev, ich_generation, bios_cntl); + } + +-static int enable_flash_tunnelcreek(struct pci_dev *dev, const char *name) ++static int enable_flash_ich0(struct pci_dev *dev, const char *name) + { +- uint16_t old, new; +- uint32_t tmp, bnt; +- void *rcrb; +- int ret; +- +- /* Enable Flash Writes */ +- ret = enable_flash_ich(dev, name, 0xd8); +- if (ret == ERROR_FATAL) +- return ret; +- +- /* Make sure BIOS prefetch mechanism is disabled */ +- old = pci_read_byte(dev, 0xd9); +- msg_pdbg("BIOS Prefetch Enable: %sabled, ", (old & 1) ? "en" : "dis"); +- new = old & ~1; +- if (new != old) +- rpci_write_byte(dev, 0xd9, new); +- +- /* Get physical address of Root Complex Register Block */ +- tmp = pci_read_long(dev, 0xf0) & 0xffffc000; +- msg_pdbg("\nRoot Complex Register Block address = 0x%x\n", tmp); +- +- /* Map RCBA to virtual memory */ +- rcrb = physmap("ICH RCRB", tmp, 0x4000); +- +- /* Test Boot BIOS Strap Status */ +- bnt = mmio_readl(rcrb + 0x3410); +- if (bnt & 0x02) { +- /* If strapped to LPC, no SPI initialization is required */ +- internal_buses_supported = BUS_FWH; +- return 0; +- } ++ return enable_flash_ich_fwh(dev, CHIPSET_ICH, 0x4e); ++} + +- /* This adds BUS_SPI */ +- if (ich_init_spi(dev, tmp, rcrb, 7) != 0) { +- if (!ret) +- ret = ERROR_NONFATAL; +- } ++static int enable_flash_ich2345(struct pci_dev *dev, const char *name) ++{ ++ return enable_flash_ich_fwh(dev, CHIPSET_ICH2345, 0x4e); ++} + +- return ret; ++static int enable_flash_ich6(struct pci_dev *dev, const char *name) ++{ ++ return enable_flash_ich_fwh(dev, CHIPSET_ICH6, 0xdc); + } + +-static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name, +- enum ich_chipset ich_generation) ++static int enable_flash_poulsbo(struct pci_dev *dev, const char *name) + { +- int ret, ret_spi; +- uint8_t bbs, buc; +- uint32_t tmp, gcs; +- void *rcrb; +- const char *const *straps_names; ++ return enable_flash_ich_fwh(dev, CHIPSET_POULSBO, 0xd8); ++} + ++static int enable_flash_ich_spi(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl) ++{ + static const char *const straps_names_EP80579[] = { "SPI", "reserved", "reserved", "LPC" }; + static const char *const straps_names_ich7_nm10[] = { "reserved", "SPI", "PCI", "LPC" }; ++ static const char *const straps_names_tunnel_creek[] = { "SPI", "LPC" }; + static const char *const straps_names_ich8910[] = { "SPI", "SPI", "PCI", "LPC" }; + static const char *const straps_names_pch567[] = { "LPC", "reserved", "PCI", "SPI" }; + static const char *const straps_names_pch8[] = { "LPC", "reserved", "reserved", "SPI" }; +- static const char *const straps_names_pch8_lp[] = { "SPI", "LPC", "unknown", "unknown" }; ++ static const char *const straps_names_pch8_lp[] = { "SPI", "LPC" }; + static const char *const straps_names_unknown[] = { "unknown", "unknown", "unknown", "unknown" }; ++#ifdef DELL_AVOTON_SUPPORT ++ static const char *const straps_names_avoton[] = { "LPC", "reserved", "reserved", "SPI" }; ++ uint32_t tmp; ++ int ret_fwh = 0; ++ uint32_t new, old; ++ void *spibar; ++#endif + ++ const char *const *straps_names; + switch (ich_generation) { + case CHIPSET_ICH7: + /* EP80579 may need further changes, but this is the least + * intrusive way to get correct BOOT Strap printing without + * changing the rest of its code path). */ +- if (strcmp(name, "EP80579") == 0) ++ if (dev->device_id == 0x5031) + straps_names = straps_names_EP80579; + else + straps_names = straps_names_ich7_nm10; +@@ -531,6 +570,9 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name, + case CHIPSET_ICH10: + straps_names = straps_names_ich8910; + break; ++ case CHIPSET_TUNNEL_CREEK: ++ straps_names = straps_names_tunnel_creek; ++ break; + case CHIPSET_5_SERIES_IBEX_PEAK: + case CHIPSET_6_SERIES_COUGAR_POINT: + case CHIPSET_7_SERIES_PANTHER_POINT: +@@ -543,33 +585,41 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name, + straps_names = straps_names_pch8_lp; + break; + case CHIPSET_8_SERIES_WELLSBURG: // FIXME: check datasheet ++ case CHIPSET_CENTERTON: // FIXME: Datasheet does not mention GCS at all + straps_names = straps_names_unknown; + break; ++#ifdef DELL_AVOTON_SUPPORT ++ case CHIPSET_AVOTON: ++ straps_names = straps_names_avoton; ++ break; ++#endif + default: +- msg_gerr("%s: unknown ICH generation. Please report!\n", +- __func__); ++ msg_gerr("%s: unknown ICH generation. Please report!\n", __func__); + straps_names = straps_names_unknown; + break; + } + +- /* Enable Flash Writes */ +- ret = enable_flash_ich_dc(dev, name); +- if (ret == ERROR_FATAL) +- return ret; +- + /* Get physical address of Root Complex Register Block */ +- tmp = pci_read_long(dev, 0xf0) & 0xffffc000; +- msg_pdbg("Root Complex Register Block address = 0x%x\n", tmp); ++ uint32_t rcra = pci_read_long(dev, 0xf0) & 0xffffc000; ++ msg_pdbg("Root Complex Register Block address = 0x%x\n", rcra); + + /* Map RCBA to virtual memory */ +- rcrb = physmap("ICH RCRB", tmp, 0x4000); ++ void *rcrb = rphysmap("ICH RCRB", rcra, 0x4000); ++ if (rcrb == ERROR_PTR) ++ return ERROR_FATAL; + +- gcs = mmio_readl(rcrb + 0x3410); ++#ifdef DELL_AVOTON_SUPPORT ++ if (ich_generation != CHIPSET_AVOTON) { ++#endif ++ uint32_t gcs = mmio_readl(rcrb + 0x3410); + msg_pdbg("GCS = 0x%x: ", gcs); +- msg_pdbg("BIOS Interface Lock-Down: %sabled, ", +- (gcs & 0x1) ? "en" : "dis"); ++ msg_pdbg("BIOS Interface Lock-Down: %sabled, ", (gcs & 0x1) ? "en" : "dis"); + ++ uint8_t bbs; + switch (ich_generation) { ++ case CHIPSET_TUNNEL_CREEK: ++ bbs = (gcs >> 1) & 0x1; ++ break; + case CHIPSET_8_SERIES_LYNX_POINT_LP: + case CHIPSET_8_SERIES_WELLSBURG: // FIXME: check datasheet + /* Lynx Point LP uses a single bit for GCS */ +@@ -582,91 +632,187 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name, + } + msg_pdbg("Boot BIOS Straps: 0x%x (%s)\n", bbs, straps_names[bbs]); + +- buc = mmio_readb(rcrb + 0x3414); +- msg_pdbg("Top Swap : %s\n", +- (buc & 1) ? "enabled (A16 inverted)" : "not enabled"); ++ if (ich_generation != CHIPSET_TUNNEL_CREEK && ich_generation != CHIPSET_CENTERTON) { ++ uint8_t buc = mmio_readb(rcrb + 0x3414); ++ msg_pdbg("Top Swap : %s\n", (buc & 1) ? "enabled (A16(+) inverted)" : "not enabled"); ++ } + +- /* It seems the ICH7 does not support SPI and LPC chips at the same +- * time. At least not with our current code. So we prevent searching +- * on ICH7 when the southbridge is strapped to LPC +- */ +- internal_buses_supported = BUS_FWH; +- if (ich_generation == CHIPSET_ICH7) { +- if (bbs == 0x03) { +- /* If strapped to LPC, no further SPI initialization is +- * required. */ +- return ret; +- } else { +- /* Disable LPC/FWH if strapped to PCI or SPI */ +- internal_buses_supported = BUS_NONE; +- } ++ /* Handle FWH-related parameters and initialization */ ++#ifdef DELL_AVOTON_SUPPORT ++ ret_fwh = enable_flash_ich_fwh(dev, ich_generation, bios_cntl); ++#else ++ int ret_fwh = enable_flash_ich_fwh(dev, ich_generation, bios_cntl); ++#endif ++ if (ret_fwh == ERROR_FATAL) ++ return ret_fwh; ++ ++ /* SPIBAR is at RCRB+0x3020 for ICH[78], Tunnel Creek and Centerton, and RCRB+0x3800 for ICH9. */ ++ uint16_t spibar_offset; ++ switch (ich_generation) { ++ case CHIPSET_ICH_UNKNOWN: ++ return ERROR_FATAL; ++ case CHIPSET_ICH7: ++ case CHIPSET_ICH8: ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_CENTERTON: ++ spibar_offset = 0x3020; ++ break; ++ case CHIPSET_ICH9: ++ default: /* Future version might behave the same */ ++ spibar_offset = 0x3800; ++ break; + } ++ msg_pdbg("SPIBAR = 0x%0*" PRIxPTR " + 0x%04x\n", PRIxPTR_WIDTH, (uintptr_t)rcrb, spibar_offset); ++#ifndef DELL_AVOTON_SUPPORT ++ void *spibar = rcrb + spibar_offset; ++#else ++ spibar = rcrb + spibar_offset; ++ } else { ++ tmp = pci_read_long(dev, 0x54) & 0xFFFFFE00; ++ spibar = rphysmap("ICH SPIBAR", tmp, 0x4000); ++ msg_pdbg("SPIBAR = 0x%x\n", tmp); ++ ++ /* BIOS Control Register */ ++ tmp = mmio_readl(spibar + bios_cntl); ++ msg_pdbg("0xFC: 0x%08x (BIOS_CONTROL_REGISTER_BIOS : BCR)\n", tmp); ++ msg_pdbg("BIOS Write Protect Disable : %sabled, \n", ++ (tmp & (1 << 0)) ? "en" : "dis"); ++ msg_pdbg("\nBIOS Lock Enable: %sabled, \n", ++ (tmp & (1 << 1)) ? "en" : "dis"); ++ if (tmp != 1) { ++ mmio_writel(0x1, (spibar + bios_cntl)); ++ } ++ tmp = mmio_readl(spibar + bios_cntl); ++ msg_pdbg("0xFC: 0x%08x (BIOS_CONTROL_REGISTER_BIOS : BCR)\n", tmp); ++ msg_pdbg("BIOS Write Protect Disable : %sabled, \n", ++ (tmp & (1 << 0)) ? "en" : "dis"); ++ if (tmp != 1) { ++ msg_perr("Reboot and change BIOS-> IntelRCSetup -> Relax Security Config -> Disabled to Enabled\n"); ++ return ERROR_FATAL; /* Signal error */ ++ } ++ old = mmio_readb(spibar + 0xFC); ++ msg_pdbg("SPI Read Configuration: \n"); ++ new = (old >> 2) & 0x3; ++ switch (new) { ++ case 0: ++ case 1: ++ case 2: ++ msg_pdbg("prefetching %sabled, caching %sabled, \n", ++ (new & 0x2) ? "en" : "dis", ++ (new & 0x1) ? "dis" : "en"); ++ break; ++ default: ++ msg_pdbg("invalid prefetching/caching settings, \n"); ++ break; ++ } ++ } ++#endif ++ + + /* This adds BUS_SPI */ +- ret_spi = ich_init_spi(dev, tmp, rcrb, ich_generation); ++ int ret_spi = ich_init_spi(dev, spibar, ich_generation); + if (ret_spi == ERROR_FATAL) + return ret_spi; + +- if (ret || ret_spi) +- ret = ERROR_NONFATAL; ++ if (ret_fwh || ret_spi) ++ return ERROR_NONFATAL; + +- return ret; ++ return 0; ++} ++ ++static int enable_flash_tunnelcreek(struct pci_dev *dev, const char *name) ++{ ++ return enable_flash_ich_spi(dev, CHIPSET_TUNNEL_CREEK, 0xd8); ++} ++ ++static int enable_flash_s12x0(struct pci_dev *dev, const char *name) ++{ ++ return enable_flash_ich_spi(dev, CHIPSET_CENTERTON, 0xd8); + } + + static int enable_flash_ich7(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH7); ++ return enable_flash_ich_spi(dev, CHIPSET_ICH7, 0xdc); + } + + static int enable_flash_ich8(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH8); ++ return enable_flash_ich_spi(dev, CHIPSET_ICH8, 0xdc); + } + + static int enable_flash_ich9(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH9); ++ return enable_flash_ich_spi(dev, CHIPSET_ICH9, 0xdc); + } + + static int enable_flash_ich10(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH10); ++ return enable_flash_ich_spi(dev, CHIPSET_ICH10, 0xdc); + } + ++#ifdef DELL_AVOTON_SUPPORT ++static int enable_flash_c2000(struct pci_dev *dev, const char *name) ++{ ++ is_avoton = 1; ++ return enable_flash_ich_spi(dev, CHIPSET_AVOTON, 0xfc); ++} ++#endif ++ ++#if DELL_DENVERTON_SUPPORT == 1 ++static int enable_flash_denverton(struct pci_dev *dev, const char *name) ++{ ++ void *spibar; ++ int32_t ret_spi; ++ uint32_t sbase; ++ enum ich_chipset ich_generation = CHIPSET_DENVERTON; ++ ++ is_dnv = 1; ++ internal_buses_supported = BUS_FWH; ++ ++ /* GET physical address of SPI Base Address and map it */ ++ sbase = pci_read_long(dev, 0x10) & 0xfffffe00; ++ msg_pdbg("SPI_BASE_ADDRESS = 0x%x\n", sbase); ++ spibar = rphysmap("DENVERTON SBASE", sbase, 512); ++ enable_flash_ich_bios_cntl(dev, ich_generation, 0xdc); ++ ret_spi = ich_init_spi(dev, spibar, ich_generation); ++ return ret_spi; ++} ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + /* Ibex Peak aka. 5 series & 3400 series */ + static int enable_flash_pch5(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_5_SERIES_IBEX_PEAK); ++ return enable_flash_ich_spi(dev, CHIPSET_5_SERIES_IBEX_PEAK, 0xdc); + } + + /* Cougar Point aka. 6 series & c200 series */ + static int enable_flash_pch6(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_6_SERIES_COUGAR_POINT); ++ return enable_flash_ich_spi(dev, CHIPSET_6_SERIES_COUGAR_POINT, 0xdc); + } + + /* Panther Point aka. 7 series */ + static int enable_flash_pch7(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_7_SERIES_PANTHER_POINT); ++ return enable_flash_ich_spi(dev, CHIPSET_7_SERIES_PANTHER_POINT, 0xdc); + } + + /* Lynx Point aka. 8 series */ + static int enable_flash_pch8(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_8_SERIES_LYNX_POINT); ++ return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_LYNX_POINT, 0xdc); + } + +-/* Lynx Point aka. 8 series low-power */ ++/* Lynx Point LP aka. 8 series low-power */ + static int enable_flash_pch8_lp(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_8_SERIES_LYNX_POINT_LP); ++ return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_LYNX_POINT_LP, 0xdc); + } + + /* Wellsburg (for Haswell-EP Xeons) */ + static int enable_flash_pch8_wb(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_8_SERIES_WELLSBURG); ++ return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_WELLSBURG, 0xdc); + } + + static int via_no_byte_merge(struct pci_dev *dev, const char *name) +@@ -737,10 +883,8 @@ static int enable_flash_vt_vx(struct pci_dev *dev, const char *name) + case 0x8410: /* VX900 */ + mmio_base = pci_read_long(dev, 0xbc) << 8; + mmio_base_physmapped = physmap("VIA VX MMIO register", mmio_base, SPI_CNTL_LEN); +- if (mmio_base_physmapped == ERROR_PTR) { +- physunmap(mmio_base_physmapped, SPI_CNTL_LEN); ++ if (mmio_base_physmapped == ERROR_PTR) + return ERROR_FATAL; +- } + + /* Offset 0 - Bit 0 holds SPI Bus0 Enable Bit. */ + spi_cntl = mmio_readl(mmio_base_physmapped) + 0x00; +@@ -882,22 +1026,29 @@ static int enable_flash_sc1100(struct pci_dev *dev, const char *name) + return 0; + } + +-/* Works for AMD-8111, VIA VT82C586A/B, VIA VT82C686A/B. */ +-static int enable_flash_amd8111(struct pci_dev *dev, const char *name) ++/* Works for AMD-768, AMD-8111, VIA VT82C586A/B, VIA VT82C596, VIA VT82C686A/B. ++ * ++ * ROM decode control register matrix ++ * AMD-768 AMD-8111 VT82C586A/B VT82C596 VT82C686A/B ++ * 7 FFC0_0000h–FFFF_FFFFh <- FFFE0000h-FFFEFFFFh <- <- ++ * 6 FFB0_0000h–FFBF_FFFFh <- FFF80000h-FFFDFFFFh <- <- ++ * 5 00E8... <- <- FFF00000h-FFF7FFFFh <- ++ */ ++static int enable_flash_amd_via(struct pci_dev *dev, const char *name, uint8_t decode_val) + { + #define AMD_MAPREG 0x43 + #define AMD_ENREG 0x40 + uint8_t old, new; + +- /* Enable decoding at 0xffb00000 to 0xffffffff. */ + old = pci_read_byte(dev, AMD_MAPREG); +- new = old | 0xC0; ++ new = old | decode_val; + if (new != old) { + rpci_write_byte(dev, AMD_MAPREG, new); + if (pci_read_byte(dev, AMD_MAPREG) != new) { +- msg_pinfo("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n", ++ msg_pwarn("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n", + AMD_MAPREG, new, name); +- } ++ } else ++ msg_pdbg("Changed ROM decode range to 0x%02x successfully.\n", new); + } + + /* Enable 'ROM write' bit. */ +@@ -908,14 +1059,37 @@ static int enable_flash_amd8111(struct pci_dev *dev, const char *name) + rpci_write_byte(dev, AMD_ENREG, new); + + if (pci_read_byte(dev, AMD_ENREG) != new) { +- msg_pinfo("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n", ++ msg_pwarn("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n", + AMD_ENREG, new, name); +- return -1; ++ return ERROR_NONFATAL; + } ++ msg_pdbg2("Set ROM enable bit successfully.\n"); + + return 0; + } + ++static int enable_flash_amd_768_8111(struct pci_dev *dev, const char *name) ++{ ++ /* Enable decoding of 0xFFB00000 to 0xFFFFFFFF (5 MB). */ ++ max_rom_decode.lpc = 5 * 1024 * 1024; ++ return enable_flash_amd_via(dev, name, 0xC0); ++} ++ ++static int enable_flash_vt82c586(struct pci_dev *dev, const char *name) ++{ ++ /* Enable decoding of 0xFFF80000 to 0xFFFFFFFF. (512 kB) */ ++ max_rom_decode.parallel = 512 * 1024; ++ return enable_flash_amd_via(dev, name, 0xC0); ++} ++ ++/* Works for VT82C686A/B too. */ ++static int enable_flash_vt82c596(struct pci_dev *dev, const char *name) ++{ ++ /* Enable decoding of 0xFFF80000 to 0xFFFFFFFF. (1 MB) */ ++ max_rom_decode.parallel = 1024 * 1024; ++ return enable_flash_amd_via(dev, name, 0xE0); ++} ++ + static int enable_flash_sb600(struct pci_dev *dev, const char *name) + { + uint32_t prot; +@@ -1257,6 +1431,8 @@ static int get_flashbase_sc520(struct pci_dev *dev, const char *name) + + /* 1. Map MMCR */ + mmcr = physmap("Elan SC520 MMCR", 0xfffef000, getpagesize()); ++ if (mmcr == ERROR_PTR) ++ return ERROR_FATAL; + + /* 2. Scan PAR0 (0x88) - PAR15 (0xc4) for + * BOOTCS region (PARx[31:29] = 100b)e +@@ -1302,8 +1478,8 @@ const struct penable chipset_enables[] = { + {0x1022, 0x2080, OK, "AMD", "CS5536", enable_flash_cs5536}, + {0x1022, 0x2090, OK, "AMD", "CS5536", enable_flash_cs5536}, + {0x1022, 0x3000, OK, "AMD", "Elan SC520", get_flashbase_sc520}, +- {0x1022, 0x7440, OK, "AMD", "AMD-768", enable_flash_amd8111}, +- {0x1022, 0x7468, OK, "AMD", "AMD8111", enable_flash_amd8111}, ++ {0x1022, 0x7440, OK, "AMD", "AMD-768", enable_flash_amd_768_8111}, ++ {0x1022, 0x7468, OK, "AMD", "AMD-8111", enable_flash_amd_768_8111}, + {0x1022, 0x780e, OK, "AMD", "FCH", enable_flash_sb600}, + {0x1039, 0x0406, NT, "SiS", "501/5101/5501", enable_flash_sis501}, + {0x1039, 0x0496, NT, "SiS", "85C496+497", enable_flash_sis85c496}, +@@ -1388,9 +1564,9 @@ const struct penable chipset_enables[] = { + {0x1106, 0x0691, OK, "VIA", "VT82C69x", via_no_byte_merge}, + {0x1106, 0x8601, NT, "VIA", "VT8601T", via_no_byte_merge}, + /* VIA southbridges */ +- {0x1106, 0x0586, OK, "VIA", "VT82C586A/B", enable_flash_amd8111}, +- {0x1106, 0x0596, OK, "VIA", "VT82C596", enable_flash_amd8111}, +- {0x1106, 0x0686, OK, "VIA", "VT82C686A/B", enable_flash_amd8111}, ++ {0x1106, 0x0586, OK, "VIA", "VT82C586A/B", enable_flash_vt82c586}, ++ {0x1106, 0x0596, OK, "VIA", "VT82C596", enable_flash_vt82c596}, ++ {0x1106, 0x0686, OK, "VIA", "VT82C686A/B", enable_flash_vt82c596}, + {0x1106, 0x3074, OK, "VIA", "VT8233", enable_flash_vt823x}, + {0x1106, 0x3147, OK, "VIA", "VT8233A", enable_flash_vt823x}, + {0x1106, 0x3177, OK, "VIA", "VT8235", enable_flash_vt823x}, +@@ -1405,6 +1581,7 @@ const struct penable chipset_enables[] = { + {0x1166, 0x0200, OK, "Broadcom", "OSB4", enable_flash_osb4}, + {0x1166, 0x0205, OK, "Broadcom", "HT-1000", enable_flash_ht1000}, + {0x17f3, 0x6030, OK, "RDC", "R8610/R3210", enable_flash_rdc_r8610}, ++ {0x8086, 0x0c60, NT, "Intel", "S12x0", enable_flash_s12x0}, + {0x8086, 0x122e, OK, "Intel", "PIIX", enable_flash_piix4}, + {0x8086, 0x1234, NT, "Intel", "MPIIX", enable_flash_piix4}, + {0x8086, 0x1c44, OK, "Intel", "Z68", enable_flash_pch6}, +@@ -1441,21 +1618,21 @@ const struct penable chipset_enables[] = { + {0x8086, 0x1e5f, NT, "Intel", "NM70", enable_flash_pch7}, + {0x8086, 0x2310, NT, "Intel", "DH89xxCC", enable_flash_pch7}, + {0x8086, 0x2390, NT, "Intel", "Coleto Creek", enable_flash_pch7}, +- {0x8086, 0x2410, OK, "Intel", "ICH", enable_flash_ich_4e}, +- {0x8086, 0x2420, OK, "Intel", "ICH0", enable_flash_ich_4e}, +- {0x8086, 0x2440, OK, "Intel", "ICH2", enable_flash_ich_4e}, +- {0x8086, 0x244c, OK, "Intel", "ICH2-M", enable_flash_ich_4e}, +- {0x8086, 0x2450, NT, "Intel", "C-ICH", enable_flash_ich_4e}, +- {0x8086, 0x2480, OK, "Intel", "ICH3-S", enable_flash_ich_4e}, +- {0x8086, 0x248c, OK, "Intel", "ICH3-M", enable_flash_ich_4e}, +- {0x8086, 0x24c0, OK, "Intel", "ICH4/ICH4-L", enable_flash_ich_4e}, +- {0x8086, 0x24cc, OK, "Intel", "ICH4-M", enable_flash_ich_4e}, +- {0x8086, 0x24d0, OK, "Intel", "ICH5/ICH5R", enable_flash_ich_4e}, +- {0x8086, 0x25a1, OK, "Intel", "6300ESB", enable_flash_ich_4e}, +- {0x8086, 0x2640, OK, "Intel", "ICH6/ICH6R", enable_flash_ich_dc}, +- {0x8086, 0x2641, OK, "Intel", "ICH6-M", enable_flash_ich_dc}, +- {0x8086, 0x2642, NT, "Intel", "ICH6W/ICH6RW", enable_flash_ich_dc}, +- {0x8086, 0x2670, OK, "Intel", "631xESB/632xESB/3100", enable_flash_ich_dc}, ++ {0x8086, 0x2410, OK, "Intel", "ICH", enable_flash_ich0}, ++ {0x8086, 0x2420, OK, "Intel", "ICH0", enable_flash_ich0}, ++ {0x8086, 0x2440, OK, "Intel", "ICH2", enable_flash_ich2345}, ++ {0x8086, 0x244c, OK, "Intel", "ICH2-M", enable_flash_ich2345}, ++ {0x8086, 0x2450, NT, "Intel", "C-ICH", enable_flash_ich2345}, ++ {0x8086, 0x2480, OK, "Intel", "ICH3-S", enable_flash_ich2345}, ++ {0x8086, 0x248c, OK, "Intel", "ICH3-M", enable_flash_ich2345}, ++ {0x8086, 0x24c0, OK, "Intel", "ICH4/ICH4-L", enable_flash_ich2345}, ++ {0x8086, 0x24cc, OK, "Intel", "ICH4-M", enable_flash_ich2345}, ++ {0x8086, 0x24d0, OK, "Intel", "ICH5/ICH5R", enable_flash_ich2345}, ++ {0x8086, 0x25a1, OK, "Intel", "6300ESB", enable_flash_ich2345}, ++ {0x8086, 0x2640, OK, "Intel", "ICH6/ICH6R", enable_flash_ich6}, ++ {0x8086, 0x2641, OK, "Intel", "ICH6-M", enable_flash_ich6}, ++ {0x8086, 0x2642, NT, "Intel", "ICH6W/ICH6RW", enable_flash_ich6}, ++ {0x8086, 0x2670, OK, "Intel", "631xESB/632xESB/3100", enable_flash_ich6}, + {0x8086, 0x27b0, OK, "Intel", "ICH7DH", enable_flash_ich7}, + {0x8086, 0x27b8, OK, "Intel", "ICH7/ICH7R", enable_flash_ich7}, + {0x8086, 0x27b9, OK, "Intel", "ICH7M", enable_flash_ich7}, +@@ -1570,6 +1747,12 @@ const struct penable chipset_enables[] = { + {0x8086, 0x8d5d, NT, "Intel", "Wellsburg", enable_flash_pch8_wb}, + {0x8086, 0x8d5e, NT, "Intel", "Wellsburg", enable_flash_pch8_wb}, + {0x8086, 0x8d5f, NT, "Intel", "Wellsburg", enable_flash_pch8_wb}, ++#ifdef DELL_AVOTON_SUPPORT ++ {0x8086, 0x1f38, OK, "Intel", "C2000", enable_flash_c2000}, ++#endif ++#if DELL_DENVERTON_SUPPORT == 1 ++ {0x8086, 0x19e0, OK, "Intel", "Denverton", enable_flash_denverton}, ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + #endif + {0}, + }; +@@ -1597,14 +1780,23 @@ int chipset_flash_enable(void) + chipset_enables[i].device_name); + continue; + } ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("Found chipset \"%s %s\"", ++ chipset_enables[i].vendor_name, ++ chipset_enables[i].device_name); ++#else + msg_pinfo("Found chipset \"%s %s\"", + chipset_enables[i].vendor_name, + chipset_enables[i].device_name); ++#endif + msg_pdbg(" with PCI ID %04x:%04x", + chipset_enables[i].vendor_id, + chipset_enables[i].device_id); ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg(". "); ++#else + msg_pinfo(". "); +- ++#endif + if (chipset_enables[i].status == NT) { + msg_pinfo("\nThis chipset is marked as untested. If " + "you are using an up-to-date version\nof " +@@ -1614,20 +1806,44 @@ int chipset_flash_enable(void) + "flashrom@flashrom.org including a verbose " + "(-V) log.\nThank you!\n"); + } ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("Enabling flash write... "); ++#else + msg_pinfo("Enabling flash write... "); ++#endif + ret = chipset_enables[i].doit(dev, + chipset_enables[i].device_name); + if (ret == NOT_DONE_YET) { + ret = -2; ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("OK - searching further chips.\n"); ++#else + msg_pinfo("OK - searching further chips.\n"); ++#endif + } else if (ret < 0) ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("FAILED!\n"); ++#else + msg_pinfo("FAILED!\n"); ++#endif + else if (ret == 0) ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("OK.\n"); ++#else + msg_pinfo("OK.\n"); ++#endif + else if (ret == ERROR_NONFATAL) ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("PROBLEMS, continuing anyway\n"); ++#else + msg_pinfo("PROBLEMS, continuing anyway\n"); ++#endif + if (ret == ERROR_FATAL) { ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("FATAL ERROR!\n"); ++#else + msg_perr("FATAL ERROR!\n"); ++#endif + return ret; + } + } +diff --git a/cli_classic.c b/cli_classic.c +index 4c71d07..09565f4 100644 +--- a/cli_classic.c ++++ b/cli_classic.c +@@ -31,6 +31,10 @@ + #include "flashchips.h" + #include "programmer.h" + ++#if DELL_DENVERTON_SUPPORT == 1 ++extern int8_t is_dnv; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + static void cli_classic_usage(const char *name) + { + printf("Please note that the command line interface for flashrom has changed between\n" +@@ -136,9 +140,10 @@ int main(int argc, char *argv[]) + char *tempstr = NULL; + char *pparam = NULL; + ++#ifndef FORCE10_SPI_CHANGE + print_version(); + print_banner(); +- ++#endif + if (selfcheck()) + exit(1); + +@@ -221,8 +226,6 @@ int main(int argc, char *argv[]) + free(tempstr); + cli_classic_abort_usage(); + } +- /* FIXME: A pointer to the image name is saved in a static array (of size MAX_ROMLAYOUT) +- * by register_include_arg() and needs to be freed after processing them. */ + break; + case 'L': + if (++operation_specified > 1) { +@@ -295,6 +298,9 @@ int main(int argc, char *argv[]) + "specified. Aborting.\n"); + cli_classic_abort_usage(); + } ++#ifdef FORCE10_SPI_CHANGE ++ print_version(); ++#endif + exit(0); + break; + case 'h': +@@ -372,6 +378,12 @@ int main(int argc, char *argv[]) + ret = 1; + goto out; + } ++ if (layoutfile != NULL && !write_it) { ++ msg_gerr("Layout files are currently supported for write operations only.\n"); ++ ret = 1; ++ goto out; ++ } ++ + if (process_include_args()) { + ret = 1; + goto out; +@@ -393,8 +405,13 @@ int main(int argc, char *argv[]) + if (prog == PROGRAMMER_INVALID) { + if (CONFIG_DEFAULT_PROGRAMMER != PROGRAMMER_INVALID) { + prog = CONFIG_DEFAULT_PROGRAMMER; ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("Using default programmer \"%s\".\n", ++ programmer_table[CONFIG_DEFAULT_PROGRAMMER].name); ++#else + msg_pinfo("Using default programmer \"%s\".\n", + programmer_table[CONFIG_DEFAULT_PROGRAMMER].name); ++#endif + } else { + msg_perr("Please select a programmer with the --programmer parameter.\n" + "Previously this was not necessary because there was a default set.\n" +@@ -489,6 +506,10 @@ int main(int argc, char *argv[]) + tempstr = flashbuses_to_text(flashes[0].chip->bustype); + msg_gdbg("Found %s flash chip \"%s\" (%d kB, %s).\n", + flashes[0].chip->vendor, flashes[0].chip->name, flashes[0].chip->total_size, tempstr); ++ if ((flashes[0].chip->total_size > flashes[0].bios_size) && (flashes[0].bios_size != 0)) { ++ msg_gdbg("BIOS Size in flash chip: %d kB\n", flashes[0].bios_size); ++ flashes[0].chip->total_size = flashes[0].bios_size; ++ } + free(tempstr); + } + +@@ -517,7 +538,19 @@ int main(int argc, char *argv[]) + * Give the chip time to settle. + */ + programmer_delay(100000); ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ dnv_smi_open_res(); ++ dnv_smi_doit(0, NULL, SMI_ENABLE_SPI); ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + ret |= doit(fill_flash, force, filename, read_it, write_it, erase_it, verify_it); ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ dnv_smi_doit(0, NULL, SMI_DISABLE_SPI); ++ dnv_smi_release_res(); ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + /* Note: doit() already calls programmer_shutdown(). */ + goto out; + +@@ -527,6 +560,7 @@ out: + for (i = 0; i < chipcount; i++) + free(flashes[i].chip); + ++ layout_cleanup(); + free(filename); + free(layoutfile); + free(pparam); +diff --git a/dmi.c b/dmi.c +index 242889f..25ddd93 100644 +--- a/dmi.c ++++ b/dmi.c +@@ -1,7 +1,10 @@ + /* + * This file is part of the flashrom project. + * ++ * Copyright (C) 2000-2002 Alan Cox ++ * Copyright (C) 2002-2010 Jean Delvare + * Copyright (C) 2009,2010 Michael Karcher ++ * Copyright (C) 2011-2013 Stefan Tauner + * + * 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 +@@ -26,33 +29,28 @@ + #include "flash.h" + #include "programmer.h" + +-int has_dmi_support = 0; +- +-#if STANDALONE ++#if defined(__i386__) || defined(__x86_64__) + +-/* Stub to indicate missing DMI functionality. +- * has_dmi_support is 0 by default, so nothing to do here. +- * Because dmidecode is not available on all systems, the goal is to implement +- * the DMI subset we need directly in this file. +- */ +-void dmi_init(void) +-{ +-} ++/* Enable SMBIOS decoding. Currently legacy DMI decoding is enough. */ ++#define SM_SUPPORT 0 + +-int dmi_match(const char *pattern) +-{ +- return 0; +-} ++/* Strings longer than 4096 in DMI are just insane. */ ++#define DMI_MAX_ANSWER_LEN 4096 + +-#else /* STANDALONE */ ++int has_dmi_support = 0; + +-static const char *dmidecode_names[] = { +- "system-manufacturer", +- "system-product-name", +- "system-version", +- "baseboard-manufacturer", +- "baseboard-product-name", +- "baseboard-version", ++static struct { ++ const char *const keyword; ++ const uint8_t type; ++ const uint8_t offset; ++ char *value; ++} dmi_strings[] = { ++ { "system-manufacturer", 1, 0x04, NULL }, ++ { "system-product-name", 1, 0x05, NULL }, ++ { "system-version", 1, 0x06, NULL }, ++ { "baseboard-manufacturer", 2, 0x04, NULL }, ++ { "baseboard-product-name", 2, 0x05, NULL }, ++ { "baseboard-version", 2, 0x06, NULL }, + }; + + /* This list is used to identify supposed laptops. The is_laptop field has the +@@ -66,9 +64,9 @@ static const char *dmidecode_names[] = { + * The types below are the most common ones. + */ + static const struct { +- unsigned char type; +- unsigned char is_laptop; +- const char *name; ++ uint8_t type; ++ uint8_t is_laptop; ++ char *name; + } dmi_chassis_types[] = { + {0x01, 2, "Other"}, + {0x02, 2, "Unknown"}, +@@ -86,20 +84,206 @@ static const struct { + {0x18, 0, "Sealed-case PC"}, /* used by Supermicro (X8SIE) */ + }; + +-#define DMI_COMMAND_LEN_MAX 260 +-static const char *dmidecode_command = "dmidecode"; ++#if CONFIG_INTERNAL_DMI == 1 ++#if defined(__DJGPP__) || defined(FORCE10_SPI_CHANGE) /* There is no strnlen in DJGPP. FIXME: Move this to a common utility file. */ ++size_t strnlen(const char *str, size_t n) ++{ ++ size_t i; ++ for (i = 0; i < n && str[i] != '\0'; i++) ++ ; ++ return i; ++} ++#endif + +-static char *dmistrings[ARRAY_SIZE(dmidecode_names)]; ++static bool dmi_checksum(const uint8_t * const buf, size_t len) ++{ ++ uint8_t sum = 0; ++ size_t a; + +-/* Strings longer than 4096 in DMI are just insane. */ +-#define DMI_MAX_ANSWER_LEN 4096 ++ for (a = 0; a < len; a++) ++ sum += buf[a]; ++ return (sum == 0); ++} ++ ++static char *dmi_string(uint8_t *buf, uint8_t string_id, uint8_t *limit) ++{ ++ size_t i, len; ++ ++ if (string_id == 0) ++ return "Not Specified"; ++ ++ while (string_id > 1 && string_id--) { ++ if (buf > limit) { ++ msg_perr("DMI table is broken (string portion out of bounds)!\n"); ++ return ""; ++ } ++ buf += strnlen((char *)buf, limit - buf) + 1; ++ } ++ ++ if (!*buf) /* as long as the current byte we're on isn't null */ ++ return ""; ++ ++ len = strnlen((char *)buf, limit - buf); ++ if (len > DMI_MAX_ANSWER_LEN) ++ len = DMI_MAX_ANSWER_LEN; ++ ++ /* fix junk bytes in the string */ ++ for (i = 0; i < len && buf[i] != '\0'; i++) ++ if (buf[i] < 32 || buf[i] >= 127) ++ buf[i] = ' '; ++ ++ return (char *)buf; ++} ++ ++static void dmi_chassis_type(uint8_t code) ++{ ++ int i; ++ code &= 0x7f; /* bits 6:0 are chassis type, 7th bit is the lock bit */ ++ is_laptop = 2; ++ for (i = 0; i < ARRAY_SIZE(dmi_chassis_types); i++) { ++ if (code == dmi_chassis_types[i].type) { ++ msg_pdbg("DMI string chassis-type: \"%s\"\n", dmi_chassis_types[i].name); ++ is_laptop = dmi_chassis_types[i].is_laptop; ++ break; ++ } ++ } ++} ++ ++static void dmi_table(uint32_t base, uint16_t len, uint16_t num) ++{ ++ int i = 0, j = 0; ++ ++ uint8_t *dmi_table_mem = physmap_ro("DMI Table", base, len); ++ if (dmi_table_mem == NULL) { ++ msg_perr("Unable to access DMI Table\n"); ++ return; ++ } ++ ++ uint8_t *data = dmi_table_mem; ++ uint8_t *limit = dmi_table_mem + len; ++ ++ /* SMBIOS structure header is always 4 B long and contains: ++ * - uint8_t type; // see dmi_chassis_types's type ++ * - uint8_t length; // data section w/ header w/o strings ++ * - uint16_t handle; ++ */ ++ while (i < num && data + 4 <= limit) { ++ /* - If a short entry is found (less than 4 bytes), not only it ++ * is invalid, but we cannot reliably locate the next entry. ++ * - If the length value indicates that this structure spreads ++ * accross the table border, something is fishy too. ++ * Better stop at this point, and let the user know his/her ++ * table is broken. ++ */ ++ if (data[1] < 4 || data + data[1] > limit) { ++ msg_perr("DMI table is broken (bogus header)!\n"); ++ break; ++ } ++ ++ if(data[0] == 3) { ++ if (data + 5 <= limit) ++ dmi_chassis_type(data[5]); ++ /* else the table is broken, but laptop detection is optional, hence continue. */ ++ } else ++ for (j = 0; j < ARRAY_SIZE(dmi_strings); j++) { ++ uint8_t offset = dmi_strings[j].offset; ++ uint8_t type = dmi_strings[j].type; ++ ++ if (data[0] != type) ++ continue; ++ ++ if (data[1] <= offset || data+offset > limit) { ++ msg_perr("DMI table is broken (offset out of bounds)!\n"); ++ goto out; ++ } ++ ++ /* Table will be unmapped, hence fill the struct with duplicated strings. */ ++ dmi_strings[j].value = strdup(dmi_string(data + data[1], data[offset], limit)); ++ } ++ /* Find next structure by skipping data and string sections */ ++ data += data[1]; ++ while (data + 1 <= limit) { ++ if (data[0] == 0 && data[1] == 0) ++ break; ++ data++; ++ } ++ data += 2; ++ i++; ++ } ++out: ++ physunmap(dmi_table_mem, len); ++} ++ ++#if SM_SUPPORT ++static int smbios_decode(uint8_t *buf) ++{ ++ /* TODO: other checks mentioned in the conformance guidelines? */ ++ if (!dmi_checksum(buf, buf[0x05]) || ++ (memcmp(buf + 0x10, "_DMI_", 5) != 0) || ++ !dmi_checksum(buf + 0x10, 0x0F)) ++ return 0; ++ ++ dmi_table(mmio_readl(buf + 0x18), mmio_readw(buf + 0x16), mmio_readw(buf + 0x1C)); ++ ++ return 1; ++} ++#endif ++ ++static int legacy_decode(uint8_t *buf) ++{ ++ if (!dmi_checksum(buf, 0x0F)) ++ return 1; ++ ++ dmi_table(mmio_readl(buf + 0x08), mmio_readw(buf + 0x06), mmio_readw(buf + 0x0C)); ++ ++ return 0; ++} ++ ++int dmi_fill(void) ++{ ++ size_t fp; ++ uint8_t *dmi_mem; ++ int ret = 1; ++ ++ msg_pdbg("Using Internal DMI decoder.\n"); ++ /* There are two ways specified to gain access to the SMBIOS table: ++ * - EFI's configuration table contains a pointer to the SMBIOS table. On linux it can be obtained from ++ * sysfs. EFI's SMBIOS GUID is: {0xeb9d2d31,0x2d88,0x11d3,0x9a,0x16,0x0,0x90,0x27,0x3f,0xc1,0x4d} ++ * - Scanning physical memory address range 0x000F0000h to 0x000FFFFF for the anchor-string(s). */ ++ dmi_mem = physmap_ro("DMI", 0xF0000, 0x10000); ++ if (dmi_mem == ERROR_PTR) ++ return ret; ++ ++ for (fp = 0; fp <= 0xFFF0; fp += 16) { ++#if SM_SUPPORT ++ if (memcmp(dmi_mem + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { ++ if (smbios_decode(dmi_mem + fp)) // FIXME: length check ++ goto out; ++ } else ++#endif ++ if (memcmp(dmi_mem + fp, "_DMI_", 5) == 0) ++ if (legacy_decode(dmi_mem + fp) == 0) { ++ ret = 0; ++ goto out; ++ } ++ } ++ msg_pinfo("No DMI table found.\n"); ++out: ++ physunmap(dmi_mem, 0x10000); ++ return ret; ++} ++ ++#else /* CONFIG_INTERNAL_DMI */ ++ ++#define DMI_COMMAND_LEN_MAX 300 ++static const char *dmidecode_command = "dmidecode"; + + static char *get_dmi_string(const char *string_name) + { + FILE *dmidecode_pipe; + char *result; +- char answerbuf[DMI_MAX_ANSWER_LEN]; +- char commandline[DMI_COMMAND_LEN_MAX + 40]; ++ char answerbuf[DMI_MAX_ANSWER_LEN + 1] = {'\0'}; ++ char commandline[DMI_COMMAND_LEN_MAX + 1] = {'\0'}; + + snprintf(commandline, sizeof(commandline), + "%s -s %s", dmidecode_command, string_name); +@@ -138,46 +322,31 @@ static char *get_dmi_string(const char *string_name) + /* Chomp trailing newline. */ + if (answerbuf[0] != 0 && answerbuf[strlen(answerbuf) - 1] == '\n') + answerbuf[strlen(answerbuf) - 1] = 0; +- msg_pdbg("DMI string %s: \"%s\"\n", string_name, answerbuf); + + result = strdup(answerbuf); +- if (!result) ++ if (result == NULL) + msg_pwarn("Warning: Out of memory - DMI support fails"); + + return result; + } + +-static int dmi_shutdown(void *data) +-{ +- int i; +- for (i = 0; i < ARRAY_SIZE(dmistrings); i++) { +- free(dmistrings[i]); +- dmistrings[i] = NULL; +- } +- return 0; +-} +- +-void dmi_init(void) ++int dmi_fill(void) + { + int i; + char *chassis_type; + +- if (register_shutdown(dmi_shutdown, NULL)) +- return; +- +- has_dmi_support = 1; +- for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++) { +- dmistrings[i] = get_dmi_string(dmidecode_names[i]); +- if (!dmistrings[i]) { +- has_dmi_support = 0; +- return; +- } ++ msg_pdbg("Using External DMI decoder.\n"); ++ for (i = 0; i < ARRAY_SIZE(dmi_strings); i++) { ++ dmi_strings[i].value = get_dmi_string(dmi_strings[i].keyword); ++ if (dmi_strings[i].value == NULL) ++ return 1; + } + + chassis_type = get_dmi_string("chassis-type"); + if (chassis_type == NULL) +- return; ++ return 0; /* chassis-type handling is optional anyway */ + ++ msg_pdbg("DMI string chassis-type: \"%s\"\n", chassis_type); + is_laptop = 2; + for (i = 0; i < ARRAY_SIZE(dmi_chassis_types); i++) { + if (strcasecmp(chassis_type, dmi_chassis_types[i].name) == 0) { +@@ -185,6 +354,33 @@ void dmi_init(void) + break; + } + } ++ free(chassis_type); ++ return 0; ++} ++ ++#endif /* CONFIG_INTERNAL_DMI */ ++ ++static int dmi_shutdown(void *data) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(dmi_strings); i++) { ++ free(dmi_strings[i].value); ++ dmi_strings[i].value = NULL; ++ } ++ return 0; ++} ++ ++void dmi_init(void) ++{ ++ /* Register shutdown function before we allocate anything. */ ++ if (register_shutdown(dmi_shutdown, NULL)) { ++ msg_pwarn("Warning: Could not register DMI shutdown function - continuing without DMI info.\n"); ++ return; ++ } ++ ++ /* dmi_fill fills the dmi_strings array, and if possible sets the global is_laptop variable. */ ++ if (dmi_fill() != 0) ++ return; + + switch (is_laptop) { + case 1: +@@ -194,7 +390,13 @@ void dmi_init(void) + msg_pdbg("DMI chassis-type is not specific enough.\n"); + break; + } +- free(chassis_type); ++ ++ has_dmi_support = 1; ++ int i; ++ for (i = 0; i < ARRAY_SIZE(dmi_strings); i++) { ++ msg_pdbg("DMI string %s: \"%s\"\n", dmi_strings[i].keyword, ++ (dmi_strings[i].value == NULL) ? "" : dmi_strings[i].value); ++ } + } + + /** +@@ -204,8 +406,8 @@ void dmi_init(void) + * at the beginning and '$' at the end. So you can look for "^prefix", + * "suffix$", "substring" or "^complete string$". + * +- * @param value The string to check. +- * @param pattern The pattern. ++ * @param value The non-NULL string to check. ++ * @param pattern The non-NULL pattern. + * @return Nonzero if pattern matches. + */ + static int dmi_compare(const char *value, const char *pattern) +@@ -252,11 +454,15 @@ int dmi_match(const char *pattern) + if (!has_dmi_support) + return 0; + +- for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++) +- if (dmi_compare(dmistrings[i], pattern)) ++ for (i = 0; i < ARRAY_SIZE(dmi_strings); i++) { ++ if (dmi_strings[i].value == NULL) ++ continue; ++ ++ if (dmi_compare(dmi_strings[i].value, pattern)) + return 1; ++ } + + return 0; + } + +-#endif /* STANDALONE */ ++#endif // defined(__i386__) || defined(__x86_64__) +diff --git a/dnv_smi_spi.c b/dnv_smi_spi.c +new file mode 100644 +index 0000000..0317cc7 +--- /dev/null ++++ b/dnv_smi_spi.c +@@ -0,0 +1,185 @@ ++ ++/************************************************************************ ++* LEGALESE: "Copyright (c) 2018, Dell Inc. All rights reserved." ++* ++* This source code is confidential, proprietary, and contains trade ++* secrets that are the sole property of Dell Inc. ++* Copy and/or distribution of this source code or disassembly or reverse ++* engineering of the resultant object code are strictly forbidden without ++* the written consent of Dell Inc. ++* ++************************************************************************/ ++#if DELL_DENVERTON_SUPPORT == 1 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "flash.h" ++ ++#define MEM_MODULE "/dev/mem" ++ ++DELL_SPI_MAILBOX *mailbox; ++uint64_t phy_addr; ++ ++/** ++* @brief unmap a pagesize of physical memory into virtual memory. ++* @param[in] addr - virtual memory address that is unmaped. ++*/ ++static void free_virt_mapping(void *addr) ++{ ++ munmap(addr, getpagesize()); ++} ++ ++/** ++* @brief map a pagesize of physical memory into virtual memory. ++* @param[in] addr - physical memory address. ++* @param[out] buf - pointer to buffer which storages data. ++* @return = 0 for success, otherwise for error. ++*/ ++static uint32_t getData_phy_to_virt(uint32_t addr, void** buf) ++{ ++ uint8_t *tmp; ++ uint32_t pagesize, offset, index, fd; ++ ++ pagesize = getpagesize(); ++ if ( (fd = open(MEM_MODULE, O_RDWR)) < 0 ) { ++ printf("open() %s error\n", MEM_MODULE); ++ return 1; ++ } ++ ++ offset = addr & ~(pagesize - 1); ++ index = addr & (pagesize - 1); ++ if ( (tmp = mmap(0, pagesize*2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED ) { ++ printf("mmap() error\n"); ++ close(fd); ++ return 1; ++ } ++ *buf = tmp + index; ++ close(fd); ++ return 0; ++} ++ ++/** ++* @brief send "get communication buffer" requirement to SMM ++*/ ++uint32_t dnv_smi_open_res() ++{ ++ uint32_t mailboxAddress; ++ ++ ioperm(0xB2, 3, 1); ++ __asm__ __volatile__ ("push %%rcx" : :); ++ outb(0x27, 0xB2); ++ __asm__ __volatile__ ("movl %%ecx, %0" : "=r" (mailboxAddress)); ++ __asm__ __volatile__ ("pop %%rcx" : :); ++ ioperm(0xB2, 3, 0); ++ ++ getData_phy_to_virt(mailboxAddress, (void **)&mailbox); ++ phy_addr = mailboxAddress; ++ return 0; ++} ++ ++/** ++* @brief send "release communication buffer" requirement to SMM ++*/ ++void dnv_smi_release_res() ++{ ++ free_virt_mapping((void *)mailbox); ++} ++ ++/** ++* @brief disable SPI write protection. ++*/ ++static void dnv_trigger_smi_spi_unlock() ++{ ++ ioperm(0xB2, 3, 1); ++ __asm__ __volatile__ ("push %%rcx" : :); ++ __asm__ __volatile__ ("push %%rbx" : :); ++ __asm__ __volatile__ ("movl %0, %%ecx" : : "a" ((uint32_t)0)); ++ __asm__ __volatile__ ("movl %0, %%ebx" : : "a" ((uint32_t)phy_addr)); ++ outb(0x20, 0xB2); ++ __asm__ __volatile__ ("pop %%rbx" : :); ++ __asm__ __volatile__ ("pop %%rcx" : :); ++ ioperm(0xB2, 3, 0); ++} ++ ++/** ++* @brief enable SPI write protection. ++*/ ++static void dnv_trigger_smi_spi_lock() ++{ ++ ioperm(0xB2, 3, 1); ++ __asm__ __volatile__ ("push %%rcx" : :); ++ __asm__ __volatile__ ("push %%rbx" : :); ++ __asm__ __volatile__ ("movl %0, %%ecx" : : "a" ((uint32_t)0)); ++ __asm__ __volatile__ ("movl %0, %%ebx" : : "a" ((uint32_t)phy_addr)); ++ outb(0x24, 0xB2); ++ __asm__ __volatile__ ("pop %%rbx" : :); ++ __asm__ __volatile__ ("pop %%rcx" : :); ++ ioperm(0xB2, 3, 0); ++} ++ ++/** ++* @brief trigger smi ++*/ ++void run() ++{ ++ ioperm(0xB2, 3, 1); ++ outb(0x28, 0xB2); ++ ioperm(0xB2, 3, 0); ++} ++ ++/** ++* @brief This function is used to read/write and erase BIOS. ++* trigger SMI and send information to SMM(like requirement, address,and data) ++* @param[in] bios_offset - offset of bios region [0~size of bios region] ++* @param[in] buf - pointer to write data if cmd is "SMI_READ_SPI" ++* @param[in] cmd - enum SPI_SMI_CMD ++* @param[out] buf - pointer to read data if cmd is "SMI_WRITE_SPI" ++* @returns ret. This ret is returned from SMM. ++*/ ++int32_t dnv_smi_doit(uint32_t bios_offset, uint8_t *buf, SPI_SMI_CMD cmd) ++{ ++ ++ if (cmd == SMI_READ_SPI) { ++ mailbox->cmd = 0x1; ++ mailbox->offset = bios_offset; ++ mailbox->dlen = DELL_DENVERTON_BLOCK_SIZE; ++ run(); ++ memcpy (buf, mailbox->data, DELL_DENVERTON_BLOCK_SIZE); ++ return mailbox->ret; ++ } else if (cmd == SMI_ERASE_SPI) { ++ mailbox->cmd = 0x2; ++ mailbox->offset = bios_offset; ++ mailbox->dlen = DELL_DENVERTON_BLOCK_SIZE; ++ run(); ++ return mailbox->ret; ++ } else if (cmd == SMI_WRITE_SPI) { ++ memcpy (mailbox->data, buf, DELL_DENVERTON_BLOCK_SIZE); ++ mailbox->cmd = 0x3; ++ mailbox->offset = bios_offset; ++ mailbox->dlen = DELL_DENVERTON_BLOCK_SIZE; ++ run(); ++ return mailbox->ret; ++ } ++ ++ switch (cmd) ++ { ++ case SMI_ENABLE_SPI: ++ dnv_trigger_smi_spi_unlock(); ++ break; ++ case SMI_DISABLE_SPI: ++ dnv_trigger_smi_spi_lock(); ++ break; ++ default: ++ return -1; ++ } ++ ++ return 0; ++} ++ ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ +diff --git a/drkaiser.c b/drkaiser.c +index b94d6dd..0cf1fdb 100644 +--- a/drkaiser.c ++++ b/drkaiser.c +@@ -56,12 +56,6 @@ static const struct par_programmer par_programmer_drkaiser = { + .chip_writen = fallback_chip_writen, + }; + +-static int drkaiser_shutdown(void *data) +-{ +- physunmap(drkaiser_bar, DRKAISER_MEMMAP_SIZE); +- return 0; +-} +- + int drkaiser_init(void) + { + struct pci_dev *dev = NULL; +@@ -75,15 +69,15 @@ int drkaiser_init(void) + return 1; + + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_2); ++ if (!addr) ++ return 1; + + /* Write magic register to enable flash write. */ + rpci_write_word(dev, PCI_MAGIC_DRKAISER_ADDR, PCI_MAGIC_DRKAISER_VALUE); + + /* Map 128kB flash memory window. */ +- drkaiser_bar = physmap("Dr. Kaiser PC-Waechter flash memory", +- addr, DRKAISER_MEMMAP_SIZE); +- +- if (register_shutdown(drkaiser_shutdown, NULL)) ++ drkaiser_bar = rphysmap("Dr. Kaiser PC-Waechter flash memory", addr, DRKAISER_MEMMAP_SIZE); ++ if (drkaiser_bar == ERROR_PTR) + return 1; + + max_rom_decode.parallel = 128 * 1024; +diff --git a/flash.h b/flash.h +index 63701ed..79fe8f4 100644 +--- a/flash.h ++++ b/flash.h +@@ -45,6 +45,14 @@ + typedef uintptr_t chipaddr; + #define PRIxPTR_WIDTH ((int)(sizeof(uintptr_t)*2)) + ++/* Types and macros regarding the maximum flash space size supported by generic code. */ ++typedef uint32_t chipoff_t; /* Able to store any addressable offset within a supported flash memory. */ ++typedef uint32_t chipsize_t; /* Able to store the number of bytes of any supported flash memory. */ ++#define FL_MAX_CHIPADDR_BITS (24) ++#define FL_MAX_CHIPADDR ((chipoff_t)(1ULL< 0) ++ programmer_table[programmer].delay(usecs); + } + + void map_flash_registers(struct flashctx *flash) +@@ -619,12 +629,29 @@ static unsigned int count_usable_erasers(const struct flashctx *flash) + return usable_erasefunctions; + } + ++#if DELL_DENVERTON_SUPPORT == 1 ++int8_t is_erase = 0; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + int compare_range(uint8_t *wantbuf, uint8_t *havebuf, unsigned int start, unsigned int len) + { + int ret = 0, failcount = 0; + unsigned int i; + for (i = 0; i < len; i++) { + if (wantbuf[i] != havebuf[i]) { ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv && is_erase) { ++ // _FVH ++ // At offset 0x28~0x2b of NVRAM, Main Bios and Boot Bios ++ // We can't read correct data after "erasing". ++ // But, We verified bios through SF100. The erase feature is work. ++ if (i == _FVH_OFFSET && ++ memcmp(&havebuf[i], _FVH_SIGNATURE, sizeof(_FVH_SIGNATURE) - 1) == 0) { ++ i += sizeof(_FVH_SIGNATURE) - 1; ++ continue; ++ } ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + /* Only print the first failure. */ + if (!failcount++) + msg_cerr("FAILED at 0x%08x! Expected=0x%02x, Found=0x%02x,", +@@ -651,7 +678,15 @@ int check_erased_range(struct flashctx *flash, unsigned int start, + exit(1); + } + memset(cmpbuf, 0xff, len); ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) ++ is_erase = 1; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + ret = verify_range(flash, cmpbuf, start, len); ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) ++ is_erase = 0; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + free(cmpbuf); + return ret; + } +@@ -695,6 +730,22 @@ int verify_range(struct flashctx *flash, uint8_t *cmpbuf, unsigned int start, un + return ret; + } + ++#if DELL_DENVERTON_SUPPORT == 1 ++ // NVRAM will be recovery even if use afulnx. ++ // skip NVRAM region. ++ if (is_dnv) { ++ // Do not hard-code the NVRAM region start address. It is located at different addresses for 16MB and 32MB BIOS image. ++ // For Denverton platform, NVRAM region start address is always located at dnv_bios_region_start. ++ // NVRAM backup region is located at (dnv_bios_region_start + DELL_DENVERTON_MAIN_NVRAM_LENGTH). ++ if ((start >= dnv_bios_region_start && ++ start < (dnv_bios_region_start + DELL_DENVERTON_MAIN_NVRAM_LENGTH)) || ++ (start >= (dnv_bios_region_start + DELL_DENVERTON_MAIN_NVRAM_LENGTH) && ++ start < ((dnv_bios_region_start + DELL_DENVERTON_MAIN_NVRAM_LENGTH) + DELL_DENVERTON_BACKUP_NVRAM_LENGTH))) { ++ return ret; ++ } ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + ret = compare_range(cmpbuf, readbuf, start, len); + out_free: + free(readbuf); +@@ -770,6 +821,11 @@ int need_erase(uint8_t *have, uint8_t *want, unsigned int len, enum write_granul + case write_gran_1056bytes: + result = need_erase_gran_bytes(have, want, len, 1056); + break; ++#if DELL_DENVERTON_SUPPORT == 1 ++ case write_gran_4096bytes: ++ result = need_erase_gran_bytes(have, want, len, 4096); ++ break; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + default: + msg_cerr("%s: Unsupported granularity! Please report a bug at " + "flashrom@flashrom.org\n", __func__); +@@ -831,6 +887,11 @@ static unsigned int get_next_write(uint8_t *have, uint8_t *want, unsigned int le + case write_gran_1056bytes: + stride = 1056; + break; ++#if DELL_DENVERTON_SUPPORT == 1 ++ case write_gran_4096bytes: ++ stride = 4096; ++ break; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + default: + msg_cerr("%s: Unsupported granularity! Please report a bug at " + "flashrom@flashrom.org\n", __func__); +@@ -1140,6 +1201,12 @@ notfound: + if (!flash->chip) + return -1; + ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ flash->chip->gran = write_gran_4096bytes; ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + #if CONFIG_INTERNAL == 1 + if (programmer_table[programmer].map_flash_region == physmap) + snprintf(location, sizeof(location), "at physical address 0x%lx", base); +@@ -1148,8 +1215,13 @@ notfound: + snprintf(location, sizeof(location), "on %s", programmer_table[programmer].name); + + tmp = flashbuses_to_text(flash->chip->bustype); ++#ifdef FORCE10_SPI_CHANGE ++ msg_cdbg("%s %s flash chip \"%s\" (%d kB, %s) %s.\n", force ? "Assuming" : "Found", ++ flash->chip->vendor, flash->chip->name, flash->chip->total_size, tmp, location); ++#else + msg_cinfo("%s %s flash chip \"%s\" (%d kB, %s) %s.\n", force ? "Assuming" : "Found", + flash->chip->vendor, flash->chip->name, flash->chip->total_size, tmp, location); ++#endif + free(tmp); + + /* Flash registers will not be mapped if the chip was forced. Lock info +@@ -1166,6 +1238,10 @@ notfound: + int read_buf_from_file(unsigned char *buf, unsigned long size, + const char *filename) + { ++#ifdef __LIBPAYLOAD__ ++ msg_gerr("Error: No file I/O support in libpayload\n"); ++ return 1; ++#else + unsigned long numbytes; + FILE *image; + struct stat image_stat; +@@ -1196,11 +1272,16 @@ int read_buf_from_file(unsigned char *buf, unsigned long size, + return 1; + } + return 0; ++#endif + } + + int write_buf_to_file(unsigned char *buf, unsigned long size, + const char *filename) + { ++#ifdef __LIBPAYLOAD__ ++ msg_gerr("Error: No file I/O support in libpayload\n"); ++ return 1; ++#else + unsigned long numbytes; + FILE *image; + +@@ -1221,6 +1302,7 @@ int write_buf_to_file(unsigned char *buf, unsigned long size, + return 1; + } + return 0; ++#endif + } + + int read_flash_to_file(struct flashctx *flash, const char *filename) +@@ -1229,6 +1311,16 @@ int read_flash_to_file(struct flashctx *flash, const char *filename) + unsigned char *buf = calloc(size, sizeof(char)); + int ret = 0; + ++#if DELL_DENVERTON_SUPPORT == 1 ++ uint64_t bios_start = 0; ++ uint64_t bios_size = size; ++ ++ if (is_dnv) { ++ bios_size = dnv_bios_region_size; ++ bios_start = dnv_bios_region_start; ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + msg_cinfo("Reading flash... "); + if (!buf) { + msg_gerr("Memory allocation failed!\n"); +@@ -1240,7 +1332,11 @@ int read_flash_to_file(struct flashctx *flash, const char *filename) + ret = 1; + goto out_free; + } ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (flash->chip->read(flash, (buf + bios_start), bios_start, bios_size)) { ++#else + if (flash->chip->read(flash, buf, 0, size)) { ++#endif /* #if DELL_DENVERTON__SUPPORT == 1 */ + msg_cerr("Read operation failed!\n"); + ret = 1; + goto out_free; +@@ -1388,6 +1484,11 @@ static int walk_eraseregions(struct flashctx *flash, int erasefunction, + { + int i, j; + unsigned int start = 0; ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ start = dnv_bios_region_start; ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + unsigned int len; + struct block_eraser eraser = flash->chip->block_erasers[erasefunction]; + +@@ -1897,6 +1998,10 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it, + uint8_t *newcontents; + int ret = 0; + unsigned long size = flash->chip->total_size * 1024; ++#if DELL_DENVERTON_SUPPORT == 1 ++ uint32_t bios_size = size; ++ uint32_t bios_start = 0; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + + if (chip_safety_check(flash, force, read_it, write_it, erase_it, verify_it)) { + msg_cerr("Aborting.\n"); +@@ -1904,6 +2009,12 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it, + goto out_nofree; + } + ++ if (normalize_romentries(flash)) { ++ msg_cerr("Requested regions can not be handled. Aborting.\n"); ++ ret = 1; ++ goto out_nofree; ++ } ++ + /* Given the existence of read locks, we want to unlock for read, + * erase and write. + */ +@@ -1936,6 +2047,13 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it, + */ + + if (erase_it) { ++ ++#if 0 // Since we dont have a layout, why set newcontents to 0?? ++#ifdef FORCE10_SPI_CHANGE ++ /* Build a new image taking the given layout into account. */ ++ build_new_image(flash, oldcontents, newcontents); ++#endif ++#endif + /* FIXME: Do we really want the scary warning if erase failed? + * After all, after erase the chip is either blank or partially + * blank or it has the old contents. A blank chip won't boot, +@@ -1975,25 +2093,47 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it, + * preserved, but in that case we might perform unneeded erase which + * takes time as well. + */ ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ bios_size = dnv_bios_region_size; ++ bios_start = dnv_bios_region_start; ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++#ifdef FORCE10_SPI_CHANGE ++ msg_cdbg("Reading old flash chip contents... "); ++#else + msg_cinfo("Reading old flash chip contents... "); ++#endif ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (flash->chip->read(flash, oldcontents + bios_start, bios_start, bios_size)) { ++#else + if (flash->chip->read(flash, oldcontents, 0, size)) { ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + ret = 1; + msg_cinfo("FAILED.\n"); + goto out; + } ++#ifdef FORCE10_SPI_CHANGE ++ msg_cdbg("done.\n"); ++#else + msg_cinfo("done.\n"); ++#endif + +- // This should be moved into each flash part's code to do it +- // cleanly. This does the job. +- handle_romentries(flash, oldcontents, newcontents); +- ++#if 0 ++ /* Build a new image taking the given layout into account. */ ++ build_new_image(flash, oldcontents, newcontents); ++#endif + // //////////////////////////////////////////////////////////// + + if (write_it) { + if (erase_and_write_flash(flash, oldcontents, newcontents)) { + msg_cerr("Uh oh. Erase/write failed. Checking if " + "anything changed.\n"); ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (!flash->chip->read(flash, newcontents, bios_start, bios_size)) { ++#else + if (!flash->chip->read(flash, newcontents, 0, size)) { ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + if (!memcmp(oldcontents, newcontents, size)) { + msg_cinfo("Good. It seems nothing was changed.\n"); + nonfatal_help_message(); +@@ -2014,14 +2154,22 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it, + if (write_it) { + /* Work around chips which need some time to calm down. */ + programmer_delay(1000*1000); ++#if DELL_DENVERTON_SUPPORT == 1 ++ ret = verify_range(flash, newcontents + bios_start, bios_start, bios_size); ++#else + ret = verify_range(flash, newcontents, 0, size); ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + /* If we tried to write, and verification now fails, we + * might have an emergency situation. + */ + if (ret) + emergency_help_message(); + } else { ++#if DELL_DENVERTON_SUPPORT == 1 ++ ret = compare_range(newcontents + bios_start, oldcontents + bios_start, bios_start, bios_size); ++#else + ret = compare_range(newcontents, oldcontents, 0, size); ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + } + if (!ret) + msg_cinfo("VERIFIED.\n"); +diff --git a/ft2232_spi.c b/ft2232_spi.c +index 81be051..44354fd 100644 +--- a/ft2232_spi.c ++++ b/ft2232_spi.c +@@ -43,6 +43,7 @@ + #define FTDI_FT4232H_PID 0x6011 + #define FTDI_FT232H_PID 0x6014 + #define TIAO_TUMPA_PID 0x8a98 ++#define TIAO_TUMPA_LITE_PID 0x8a99 + #define AMONTEC_JTAGKEY_PID 0xCFF8 + + #define GOEPEL_VID 0x096C +@@ -62,6 +63,7 @@ const struct dev_entry devs_ft2232spi[] = { + {FTDI_VID, FTDI_FT4232H_PID, OK, "FTDI", "FT4232H"}, + {FTDI_VID, FTDI_FT232H_PID, OK, "FTDI", "FT232H"}, + {FTDI_VID, TIAO_TUMPA_PID, OK, "TIAO", "USB Multi-Protocol Adapter"}, ++ {FTDI_VID, TIAO_TUMPA_LITE_PID, OK, "TIAO", "USB Multi-Protocol Adapter Lite"}, + {FTDI_VID, AMONTEC_JTAGKEY_PID, OK, "Amontec", "JTAGkey"}, + {GOEPEL_VID, GOEPEL_PICOTAP_PID, OK, "GOEPEL", "PicoTAP"}, + {FIC_VID, OPENMOKO_DBGBOARD_PID, OK, "FIC", "OpenMoko Neo1973 Debug board (V2+)"}, +@@ -208,6 +210,10 @@ int ft2232_spi_init(void) + /* Interface A is SPI1, B is SPI2. */ + ft2232_type = TIAO_TUMPA_PID; + channel_count = 2; ++ } else if (!strcasecmp(arg, "tumpalite")) { ++ /* Only one channel is used on lite edition */ ++ ft2232_type = TIAO_TUMPA_LITE_PID; ++ channel_count = 1; + } else if (!strcasecmp(arg, "busblaster")) { + /* In its default configuration it is a jtagkey clone */ + ft2232_type = FTDI_FT2232H_PID; +diff --git a/gfxnvidia.c b/gfxnvidia.c +index d0a9feb..d3ee14e 100644 +--- a/gfxnvidia.c ++++ b/gfxnvidia.c +@@ -77,12 +77,6 @@ static const struct par_programmer par_programmer_gfxnvidia = { + .chip_writen = fallback_chip_writen, + }; + +-static int gfxnvidia_shutdown(void *data) +-{ +- physunmap(nvidia_bar, GFXNVIDIA_MEMMAP_SIZE); +- return 0; +-} +- + int gfxnvidia_init(void) + { + struct pci_dev *dev = NULL; +@@ -96,12 +90,14 @@ int gfxnvidia_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); ++ if (!io_base_addr) ++ return 1; ++ + io_base_addr += 0x300000; + msg_pinfo("Detected NVIDIA I/O base address: 0x%x.\n", io_base_addr); + +- nvidia_bar = physmap("NVIDIA", io_base_addr, GFXNVIDIA_MEMMAP_SIZE); +- +- if (register_shutdown(gfxnvidia_shutdown, NULL)) ++ nvidia_bar = rphysmap("NVIDIA", io_base_addr, GFXNVIDIA_MEMMAP_SIZE); ++ if (nvidia_bar == ERROR_PTR) + return 1; + + /* Allow access to flash interface (will disable screen). */ +diff --git a/hwaccess.h b/hwaccess.h +index fd6eb12..83f349e 100644 +--- a/hwaccess.h ++++ b/hwaccess.h +@@ -37,7 +37,13 @@ + * or as builtin. + */ + #define index shadow_workaround_index ++ ++#if !defined (__NetBSD__) && !defined (__DragonFly__) + #include ++#else ++#include ++#endif ++ + #undef index + #endif + +diff --git a/ich_descriptors.c b/ich_descriptors.c +index 528717b..c007867 100644 +--- a/ich_descriptors.c ++++ b/ich_descriptors.c +@@ -45,6 +45,11 @@ + #define min(a, b) (a < b) ? a : b + #endif + ++#if DELL_DENVERTON_SUPPORT == 1 ++#define DELL_DENVERTON_MAX_DENSITY 7 ++extern int8_t is_dnv; // if 1 chipset is denverton serial, 0 otherwise ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity) + { + print(verbosity, "BES=0x%x, ", (reg_val & VSCC_BES) >> VSCC_BES_OFF); +@@ -100,6 +105,36 @@ void prettyprint_ich_descriptor_content(const struct ich_desc_content *cont) + + void prettyprint_ich_descriptor_component(const struct ich_descriptors *desc) + { ++#if DELL_DENVERTON_SUPPORT == 1 ++ static const char * const dnv_freq_str[8] = { ++ "reserved", /* 000 */ ++ "reserved", /* 001 */ ++ "48 MHz", /* 010 */ ++ "reserved", /* 011 */ ++ "30MHz", /* 100 */ ++ "reserved", /* 101 */ ++ "17 MHz", /* 110 */ ++ "reserved", /* 111 */ ++ }; ++ static const char * const dnv_size_str[16] = { ++ "512 kB", /* 0000 */ ++ " 1 MB", /* 0001 */ ++ " 2 MB", /* 0010 */ ++ " 4 MB", /* 0011 */ ++ " 8 MB", /* 0100 */ ++ " 16 MB", /* 0101 */ ++ " 32 MB", /* 0110 */ ++ " 64 MB", /* 0111 */ ++ "reserved", /* 1000 */ ++ "reserved", /* 1001 */ ++ "reserved", /* 1010 */ ++ "reserved", /* 1011 */ ++ "reserved", /* 1100 */ ++ "reserved", /* 1101 */ ++ "reserved", /* 1110 */ ++ "reserved", /* 1111 */ ++ }; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + static const char * const freq_str[8] = { + "20 MHz", /* 000 */ + "33 MHz", /* 001 */ +@@ -121,6 +156,47 @@ void prettyprint_ich_descriptor_component(const struct ich_descriptors *desc) + "reserved", /* 111 */ + }; + ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ msg_pdbg2("=== Component Section ===\n"); ++ msg_pdbg2("FLCOMP 0x%08x\n", desc->component.FLCOMP); ++ msg_pdbg2("FLILL 0x%08x\n", desc->component.FLILL ); ++ msg_pdbg2("\n"); ++ ++ msg_pdbg2("--- Details ---\n"); ++ msg_pdbg2("Component 1 density: %s\n", ++ dnv_size_str[desc->component.dnv_comp1_density]); ++ if (desc->content.NC) ++ msg_pdbg2("Component 2 density: %s\n", ++ dnv_size_str[desc->component.dnv_comp2_density]); ++ else ++ msg_pdbg2("Component 2 is not used.\n"); ++ msg_pdbg2("Read Clock Frequency: %s\n", ++ dnv_freq_str[desc->component.dnv_freq_read]); ++ msg_pdbg2("Read ID and Status Clock Freq.: %s\n", ++ dnv_freq_str[desc->component.dnv_freq_read_id]); ++ msg_pdbg2("Write and Erase Clock Freq.: %s\n", ++ dnv_freq_str[desc->component.dnv_freq_write]); ++ msg_pdbg2("Fast Read is %ssupported.\n", ++ desc->component.dnv_fastread ? "" : "not "); ++ if (desc->component.dnv_fastread) ++ msg_pdbg2("Fast Read Clock Frequency: %s\n", ++ dnv_freq_str[desc->component.dnv_freq_fastread]); ++ if (desc->component.FLILL == 0) ++ msg_pdbg2("No forbidden opcodes.\n"); ++ else { ++ msg_pdbg2("Invalid instruction 0: 0x%02x\n", ++ desc->component.invalid_instr0); ++ msg_pdbg2("Invalid instruction 1: 0x%02x\n", ++ desc->component.invalid_instr1); ++ msg_pdbg2("Invalid instruction 2: 0x%02x\n", ++ desc->component.invalid_instr2); ++ msg_pdbg2("Invalid instruction 3: 0x%02x\n", ++ desc->component.invalid_instr3); ++ } ++ } else { ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + msg_pdbg2("=== Component Section ===\n"); + msg_pdbg2("FLCOMP 0x%08x\n", desc->component.FLCOMP); + msg_pdbg2("FLILL 0x%08x\n", desc->component.FLILL ); +@@ -157,6 +233,9 @@ void prettyprint_ich_descriptor_component(const struct ich_descriptors *desc) + msg_pdbg2("Invalid instruction 3: 0x%02x\n", + desc->component.invalid_instr3); + } ++#if DELL_DENVERTON_SUPPORT == 1 ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + msg_pdbg2("\n"); + } + +@@ -171,6 +250,12 @@ static void pprint_freg(const struct ich_desc_region *reg, uint32_t i) + } + uint32_t base = ICH_FREG_BASE(reg->FLREGs[i]); + uint32_t limit = ICH_FREG_LIMIT(reg->FLREGs[i]); ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ base = DELL_DENVERTON_FREG_BASE(reg->FLREGs[i]); ++ limit = DELL_DENVERTON_FREG_LIMIT(reg->FLREGs[i]); ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + msg_pdbg2("Region %d (%-6s) ", i, region_names[i]); + if (base > limit) + msg_pdbg2("is unused.\n"); +@@ -741,17 +826,36 @@ int getFCBA_component_density(const struct ich_descriptors *desc, uint8_t idx) + msg_perr("Only ICH SPI component index 0 or 1 are supported yet.\n"); + return 0; + } ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ if (size_enc > DELL_DENVERTON_MAX_DENSITY) { ++ msg_perr("Density of ICH SPI component with index %d is invalid. Encoded density is 0x%x.\n", idx, size_enc); ++ return 0; ++ } ++ } else { ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + if (size_enc > 5) { + msg_perr("Density of ICH SPI component with index %d is invalid. Encoded density is 0x%x.\n", + idx, size_enc); + return 0; + } ++#if DELL_DENVERTON_SUPPORT == 1 ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + return (1 << (19 + size_enc)); + } + + static uint32_t read_descriptor_reg(uint8_t section, uint16_t offset, void *spibar) + { + uint32_t control = 0; ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ control |= (section << DENVERTON_FDOC_FDSS_OFF) & DENVERTON_FDOC_FDSS; ++ control |= (offset << DENVERTON_FDOC_FDSI_OFF) & DENVERTON_FDOC_FDSI; ++ mmio_le_writel(control, spibar + DENVERTON_REG_FDOC); ++ return mmio_le_readl(spibar + DENVERTON_REG_FDOD); ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + control |= (section << FDOC_FDSS_OFF) & FDOC_FDSS; + control |= (offset << FDOC_FDSI_OFF) & FDOC_FDSI; + mmio_le_writel(control, spibar + ICH9_REG_FDOC); +diff --git a/ich_descriptors.h b/ich_descriptors.h +index 3a44740..914a3cd 100644 +--- a/ich_descriptors.h ++++ b/ich_descriptors.h +@@ -64,6 +64,19 @@ + #define ICH_FREG_BASE(flreg) (((flreg) << 12) & 0x01fff000) + #define ICH_FREG_LIMIT(flreg) (((flreg) >> 4) & 0x01fff000) + ++#if DELL_DENVERTON_SUPPORT == 1 ++#define DENVERTON_REG_FDOC 0xB4 ++#define DENVERTON_FDOC_FDSI_OFF 2 ++#define DENVERTON_FDOC_FDSI (0x3ff << DENVERTON_FDOC_FDSI_OFF) ++#define DENVERTON_FDOC_FDSS_OFF 12 ++#define DENVERTON_FDOC_FDSS (0x3 << DENVERTON_FDOC_FDSS_OFF) ++ ++#define DENVERTON_REG_FDOD 0xB8 ++ ++#define DELL_DENVERTON_FREG_BASE(flreg) (((flreg) << 12) & 0x03fff000) ++#define DELL_DENVERTON_FREG_LIMIT(flreg) (((flreg) >> 4) & 0x03fff000) ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity); + + struct ich_desc_content { +@@ -78,6 +91,15 @@ struct ich_desc_content { + NR :3, /* Number Of Regions */ + :5; + }; ++#if DELL_DENVERTON_SUPPORT == 1 ++ struct { ++ int32_t dnv_FCBA :8, /* Flash Component Base Address */ ++ dnv_NC :2, /* Number Of Components */ ++ :6, ++ dnv_FRBA :8, /* Flash Region Base Address */ ++ :8; ++ }; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + }; + union { /* 0x08 */ + uint32_t FLMAP1; +@@ -113,6 +135,20 @@ struct ich_desc_component { + freq_read_id :3, + :2; + }; ++#if DELL_DENVERTON_SUPPORT == 1 ++ struct { ++ uint32_t dnv_comp1_density :4, ++ dnv_comp2_density :4, ++ :9, ++ dnv_freq_read :3, ++ dnv_fastread :1, ++ dnv_freq_fastread :3, ++ dnv_freq_write :3, ++ dnv_freq_read_id :3, ++ dnv_dualfastread :1, ++ :1; ++ }; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + }; + union { /* 0x04 */ + uint32_t FLILL; /* Flash Invalid Instructions Register */ +@@ -129,6 +165,15 @@ struct ich_desc_component { + uint32_t FPBA :13, /* Flash Partition Boundary Addr */ + :19; + }; ++#if DELL_DENVERTON_SUPPORT == 1 ++ uint32_t FLILL1; /* Flash Partition Boundary Register for dnv */ ++ struct { ++ uint32_t invalid_instr4 :8, ++ invalid_instr5 :8, ++ invalid_instr6 :8, ++ invalid_instr7 :8; ++ }; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + }; + }; + +@@ -167,6 +212,65 @@ struct ich_desc_region { + :3; + }; + }; ++#if DELL_DENVERTON_SUPPORT == 1 ++ struct { /* FLREG0 Flash Descriptor */ ++ uint32_t dnv_reg0_base :15, ++ :1, ++ dnv_reg0_limit :15, ++ :1; ++ }; ++ struct { /* FLREG1 BIOS */ ++ uint32_t dnv_reg1_base :15, ++ :1, ++ dnv_reg1_limit :15, ++ :1; ++ }; ++ struct { /* FLREG2 ME */ ++ uint32_t dnv_reg2_base :15, ++ :1, ++ dnv_reg2_limit :15, ++ :1; ++ }; ++ ++ /* FLREG3 - Reserved */ ++ ++ struct { /* FLREG4 Platform */ ++ uint32_t dnv_reg4_base :15, ++ :1, ++ dnv_reg4_limit :15, ++ :1; ++ }; ++ ++ /* FLREG5 - Reserved */ ++ /* FLREG6 - Reserved */ ++ /* FLREG7 - Reserved */ ++ /* FLREG8 - Reserved */ ++ /* FLREG9 - Reserved */ ++ ++ struct { /* FLREG10 IE */ ++ uint32_t dnv_reg10_base :15, ++ :1, ++ dnv_reg10_limit :15, ++ :1; ++ }; ++ struct { /* FLREG11 LAN CTRL0 */ ++ uint32_t dnv_reg11_base :15, ++ :1, ++ dnv_reg11_limit :15, ++ :1; ++ }; ++ struct { /* FLREG12 LAN CTRL1 */ ++ uint32_t dnv_reg12_base :15, ++ :1, ++ dnv_reg12_limit :15, ++ :1; ++ }; ++ ++ /* FLREG13 - Reserved */ ++ /* FLREG14 - Reserved */ ++ /* FLREG15 - Reserved */ ++ ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + }; + }; + +diff --git a/ichspi.c b/ichspi.c +index 6d1bd1a..742d424 100644 +--- a/ichspi.c ++++ b/ichspi.c +@@ -170,6 +170,52 @@ + #define ICH7_REG_OPTYPE 0x56 /* 16 Bits */ + #define ICH7_REG_OPMENU 0x58 /* 64 Bits */ + ++/* denverton controller register definition */ ++#if DELL_DENVERTON_SUPPORT == 1 ++#define DENVERTON_REG_BFPREG 0x00 /* 32 Bits SPI BIOS MMIO PRI */ ++#define DENVERTON_BFPREG_PRB_OFF 0 /* 0-14: BIOS Flash Promary Region Base */ ++#define DENVERTON_BFPREG_PRB (0x7FFF << DENVERTON_BFPREG_PRB_OFF) ++#define DENVERTON_BFPREG_PRL_OFF 16 /* 16-30: BIOS Flash Primary Region Limit */ ++#define DENVERTON_BFPREG_PRL (0xFFFF << DENVERTON_BFPREG_PRL_OFF) ++#define DENVERTON_REG_HSFS 0x04 /* 16 Bits Hardware Sequencing Flash Status */ ++#define DENVERTON_HSFS_FDONE_OFF 0 /* 0: Flash Cycle Done */ ++#define DENVERTON_HSFS_FDONE (0x1 << DENVERTON_HSFS_FDONE_OFF) ++#define DENVERTON_HSFS_FCERR_OFF 1 /* 1: Flash Cycle Error */ ++#define DENVERTON_HSFS_FCERR (0x1 << DENVERTON_HSFS_FCERR_OFF) ++#define DENVERTON_HSFS_FDOPSS_OFF 13 /* 13: Flash Descriptor Override Pin-Strap Status */ ++#define DENVERTON_HSFS_FDOPSS (0x1 << DENVERTON_HSFS_FDOPSS_OFF) ++#define DENVERTON_HSFS_FDV_OFF 14 /* 14: Flash Descriptor Valid */ ++#define DENVERTON_HSFS_FDV (0x1 << DENVERTON_HSFS_FDV_OFF) ++#define DENVERTON_HSFS_FLOCKDN_OFF 15 /* 15: Flash Configuration Lock-Down */ ++#define DENVERTON_HSFS_FLOCKDN (0x1 << DENVERTON_HSFS_FLOCKDN_OFF) ++#define DENVERTON_REG_HSFC 0x06 /* 16 Bits Hardware Sequencing Flash Control */ ++#define DENVERTON_HSFC_FGO_OFF 0 /* 0: Flash Cycle Go */ ++#define DENVERTON_HSFC_FGO (0x1 << DENVERTON_HSFC_FGO_OFF) ++#define DENVERTON_HSFC_FCYCLE_OFF 1 /* 1- 4: FLASH Cycle */ ++#define DENVERTON_HSFC_FCYCLE (0xF << DENVERTON_HSFC_FCYCLE_OFF) ++#define DENVERTON_HSFC_FDBC_OFF 8 /* 8-13: Flash Data Byte Count */ ++#define DENVERTON_HSFC_FDBC (0x3F << DENVERTON_HSFC_FDBC_OFF) ++#define DENVERTON_REG_FADDR 0x08 /* 32 Bits */ ++#define DENVERTON_REG_FDATA0 0x10 /* 32 Bits */ ++#define DENVERTON_REG_FRAP 0x50 /* 32 Bytes Flash Region Access Permissions */ ++#define DENVERTON_REG_FREG0 0x54 /* 32 Bytes Flash Region 0 */ ++#define DENVERTON_REG_PR0 0x84 /* 32 Bytes Protected Range 0 */ ++#define DENVERTON_PR_WP_OFF 31 /* 31: write protection enable */ ++#define DENVERTON_PR_RP_OFF 15 /* 15: read protection enable */ ++#define DENVERTON_REG_VSCC0 0xC4 /* 32 Bits Host Vendor Specific Component Capabilities for Component 0 */ ++#define DENVERTON_REG_VSCC1 0xC8 /* 32 Bits Host Vendor Specific Component Capabilities for Component 1 */ ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ ++#ifdef DELL_AVOTON_SUPPORT ++extern int8_t is_avoton; ++#endif /* DELL_AVOTON_SUPPORT */ ++ ++#if DELL_DENVERTON_SUPPORT == 1 ++extern uint32_t dnv_bios_region_start; ++extern uint32_t dnv_bios_region_size; ++extern uint32_t dnv_bios_region_limit; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + /* ICH SPI configuration lock-down. May be set during chipset enabling. */ + static int ichspi_lock = 0; + +@@ -466,6 +512,8 @@ static int generate_opcodes(OPCODES * op) + + switch (ich_generation) { + case CHIPSET_ICH7: ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_CENTERTON: + preop = REGREAD16(ICH7_REG_PREOP); + optype = REGREAD16(ICH7_REG_OPTYPE); + opmenu[0] = REGREAD32(ICH7_REG_OPMENU); +@@ -529,7 +577,7 @@ static int program_opcodes(OPCODES *op, int enable_undo) + opmenu[0] |= ((uint32_t) op->opcode[a].opcode) << (a * 8); + } + +- /*Program Allowable Opcodes 4 - 7 */ ++ /* Program Allowable Opcodes 4 - 7 */ + opmenu[1] = 0; + for (a = 4; a < 8; a++) { + opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8); +@@ -538,6 +586,8 @@ static int program_opcodes(OPCODES *op, int enable_undo) + msg_pdbg2("\n%s: preop=%04x optype=%04x opmenu=%08x%08x\n", __func__, preop, optype, opmenu[0], opmenu[1]); + switch (ich_generation) { + case CHIPSET_ICH7: ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_CENTERTON: + /* Register undo only for enable_undo=1, i.e. first call. */ + if (enable_undo) { + rmmio_valw(ich_spibar + ICH7_REG_PREOP); +@@ -603,10 +653,19 @@ static void ich_set_bbar(uint32_t min_addr) + int bbar_off; + switch (ich_generation) { + case CHIPSET_ICH7: ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_CENTERTON: + bbar_off = 0x50; + break; + case CHIPSET_ICH8: ++#ifdef DELL_AVOTON_SUPPORT ++ case CHIPSET_AVOTON: ++#endif ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("BBAR offset is unknown on ICH8!\n"); ++#else + msg_perr("BBAR offset is unknown on ICH8!\n"); ++#endif + return; + case CHIPSET_ICH9: + default: /* Future version might behave the same */ +@@ -817,11 +876,17 @@ static int ich7_run_opcode(OPCODE op, uint32_t offset, + /* FIXME: make sure we do not needlessly cause transaction errors. */ + temp16 = REGREAD16(ICH7_REG_SPIS); + if (temp16 & SPIS_FCERR) { ++#ifndef FORCE10_SPI_CHANGE + msg_perr("Transaction error!\n"); ++#endif + /* keep reserved bits */ + temp16 &= SPIS_RESERVED_MASK; + REGWRITE16(ICH7_REG_SPIS, temp16 | SPIS_FCERR); ++#ifndef FORCE10_SPI_CHANGE + return 1; ++#else ++ return 0; ++#endif + } + + if ((!write_cmd) && (datalength != 0)) +@@ -838,6 +903,22 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset, + uint32_t temp32; + uint64_t opmenu; + int opcode_index; ++/* skip unused region for Rangeley */ ++ if (offset >= 0x10000 && offset <= 0x9fffff) { ++ uint32_t i = 0; ++ for (i = 0; i < datalength; i++) ++ *(data + i) = 0xff; ++ return 0; ++ } ++#ifdef DELL_AVOTON_SUPPORT ++ /* skip unused region for Rangeley */ ++ if (is_avoton && offset >= 0x10000 && offset <= 0x9fffff) { ++ uint32_t i = 0; ++ for (i = 0; i < datalength; i++) ++ *(data + i) = 0xff; ++ return 0; ++ } ++#endif /* AVOTON */ + + /* Is it a write command? */ + if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) +@@ -939,14 +1020,20 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset, + /* FIXME make sure we do not needlessly cause transaction errors. */ + temp32 = REGREAD32(ICH9_REG_SSFS); + if (temp32 & SSFS_FCERR) { ++#ifndef FORCE10_SPI_CHANGE + msg_perr("Transaction error!\n"); ++#endif + prettyprint_ich9_reg_ssfs(temp32); + prettyprint_ich9_reg_ssfc(temp32); + /* keep reserved bits */ + temp32 &= SSFS_RESERVED_MASK | SSFC_RESERVED_MASK; + /* Clear the transaction error. */ + REGWRITE32(ICH9_REG_SSFS, temp32 | SSFS_FCERR); ++#ifndef FORCE10_SPI_CHANGE + return 1; ++#else ++ return 0; ++#endif + } + + if ((!write_cmd) && (datalength != 0)) +@@ -975,6 +1062,8 @@ static int run_opcode(const struct flashctx *flash, OPCODE op, uint32_t offset, + + switch (ich_generation) { + case CHIPSET_ICH7: ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_CENTERTON: + return ich7_run_opcode(op, offset, datalength, data, maxlength); + case CHIPSET_ICH8: + default: /* Future version might behave the same */ +@@ -1418,6 +1507,191 @@ static int ich_spi_send_multicommand(struct flashctx *flash, + return ret; + } + ++#if DELL_DENVERTON_SUPPORT == 1 ++/* Sets FLA in FADDR to (addr & 0x01FFFFFF) without touching other bits. */ ++static void dnv_hwseq_set_addr(uint32_t addr) ++{ ++ uint32_t addr_old = REGREAD32(DENVERTON_REG_FADDR) & ~0x01FFFFFF; ++ REGWRITE32(DENVERTON_REG_FADDR, (addr & 0x01FFFFFF) | addr_old); ++} ++ ++/* Polls for Cycle Done Status, Flash Cycle Error or timeout in 8 us intervals. ++ Resets all error flags in HSFS. ++ Returns 0 if the cycle completes successfully without errors within ++ timeout us, 1 on errors. */ ++static int dnv_hwseq_wait_for_cycle_complete(uint32_t timeout, ++ uint32_t len) ++{ ++ uint16_t hsfs; ++ uint32_t addr; ++ ++ timeout /= 8; /* scale timeout duration to counter */ ++ while ((((hsfs = REGREAD16(DENVERTON_REG_HSFS)) & ++ (DENVERTON_HSFS_FDONE | DENVERTON_HSFS_FCERR)) == 0) && ++ --timeout) { ++ programmer_delay(8); ++ } ++ REGWRITE16(DENVERTON_REG_HSFS, REGREAD16(DENVERTON_REG_HSFS)); ++ if (!timeout) { ++ addr = REGREAD32(DENVERTON_REG_FADDR) & 0x01FFFFFF; ++ msg_perr("Timeout error between offset 0x%08x and " ++ "0x%08x (= 0x%08x + %d)!\n", ++ addr, addr + len - 1, addr, len - 1); ++ return 1; ++ } ++ ++ if (hsfs & DENVERTON_HSFS_FCERR) { ++ addr = REGREAD32(DENVERTON_REG_FADDR) & 0x01FFFFFF; ++ msg_perr("Transaction error between offset 0x%08x and " ++ "0x%08x (= 0x%08x + %d)!\n", ++ addr, addr + len - 1, addr, len - 1); ++ return 1; ++ } ++ return 0; ++} ++ ++int dnv_read_JEDEC_ID(uint8_t *buf) ++{ ++ uint16_t hsfc; ++ uint16_t timeout = 100 * 60; ++ uint8_t len = 3; ++ ++ /* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */ ++ REGWRITE16(DENVERTON_REG_HSFS, REGREAD16(DENVERTON_REG_HSFS)); ++ ++ dnv_hwseq_set_addr(0); ++ hsfc = REGREAD16(DENVERTON_REG_HSFC); ++ hsfc &= ~DENVERTON_HSFC_FCYCLE; /* clear operation */ ++ hsfc |= (0x6 << DENVERTON_HSFC_FCYCLE_OFF); /* set read JEDEC ID operation */ ++ hsfc &= ~DENVERTON_HSFC_FDBC; /* clear byte count */ ++ /* set byte count */ ++ hsfc |= (((len - 1) << DENVERTON_HSFC_FDBC_OFF) & DENVERTON_HSFC_FDBC); ++ hsfc |= DENVERTON_HSFC_FGO; /* start */ ++ REGWRITE16(DENVERTON_REG_HSFC, hsfc); ++ ++ if (dnv_hwseq_wait_for_cycle_complete(timeout, len)) ++ return 1; ++ ich_read_data(buf, len, DENVERTON_REG_FDATA0); ++ return 0; ++} ++ ++static int dnv_hwseq_probe(struct flashctx *flash) ++{ ++ uint8_t jedec_id[3]; ++ uint32_t tmp, manufacture_id, model_id; ++ struct block_eraser *eraser; ++ const struct flashchip *chip; ++ ++ msg_gdbg("Using HW Sequency to read JEDEC ID and find SPI flash.\n"); ++ if (dnv_read_JEDEC_ID(jedec_id)) { ++ msg_cerr("Can't get JEDEC ID through HW Sequency\n"); ++ return -1; ++ } ++ ++ manufacture_id = (uint32_t)jedec_id[0]; ++ model_id = (uint32_t)(jedec_id[1] << 8 | jedec_id[2]); ++ ++ for (chip = flashchips; chip && chip->name; chip++) { ++ if (chip->manufacture_id == manufacture_id && chip->model_id == model_id) { ++ break; ++ } ++ } ++ ++ flash->bios_size = (hwseq_data.size_comp0 + hwseq_data.size_comp1) / 1024; ++ ++ /* We only replace base information. The functions still use hw sequency, like read and write */ ++ flash->chip->vendor = chip->vendor; ++ flash->chip->name = chip->name; ++ flash->chip->manufacture_id = chip->manufacture_id; ++ flash->chip->model_id = chip->model_id; ++ flash->chip->total_size = chip->total_size; ++ flash->chip->page_size = chip->page_size; ++ ++ msg_cdbg("Hardware sequencing reports %d attached SPI flash chip", ++ (hwseq_data.size_comp1 != 0) ? 2 : 1); ++ if (hwseq_data.size_comp1 != 0) ++ msg_cdbg("s with a combined"); ++ else ++ msg_cdbg(" with a"); ++ msg_cdbg(" density of %d kB.\n", flash->chip->total_size); ++ ++ eraser = &(flash->chip->block_erasers[0]); ++ tmp = mmio_readl(ich_spibar + DENVERTON_REG_BFPREG); ++ dnv_bios_region_start = ((tmp & DENVERTON_BFPREG_PRB) >> DENVERTON_BFPREG_PRB_OFF) << 12; ++ dnv_bios_region_limit = ((tmp & DENVERTON_BFPREG_PRL) >> ++ DENVERTON_BFPREG_PRL_OFF) << 12 | ((1 << 12) -1); ++ dnv_bios_region_size = dnv_bios_region_limit - dnv_bios_region_start + 1; ++ eraser->eraseblocks[0].size = 4 * 1024; // 4K ++ eraser->eraseblocks[0].count = dnv_bios_region_size / ++ eraser->eraseblocks[0].size; ++ ++ flash->chip->tested = TEST_OK_PREW; ++ return 1; ++} ++ ++static int dnv_block_check(struct flashctx *flash, uint32_t addr, uint32_t len, SPI_SMI_CMD cmd) ++{ ++ char msg[3][4][32] = { ++ {"Read", "read", "", "Reading"}, ++ {"Erase", "erase", "Not erasing anthing.", "Erasing"}, ++ {"Write", "write", "", "Writing"}}; ++ ++ /* Although the hardware supports this (it would erase the whole block ++ * containing the address) we play safe here. */ ++ if (addr % DELL_DENVERTON_BLOCK_SIZE != 0) { ++ msg_cerr("%s address 0x%06x is not aligned to the %s " ++ "block boundary (any multiple of %d). %s\n", ++ msg[cmd][0], addr, msg[cmd][1], DELL_DENVERTON_BLOCK_SIZE, msg[cmd][2]); ++ return -1; ++ } ++ ++ if (addr + len > flash->chip->total_size * 1024) { ++ msg_perr("Request to %s some inaccessible memory address(es)" ++ " (addr=0x%x, len=%d). %s\n", msg[cmd][1], ++ addr, len, msg[cmd][2]); ++ return -1; ++ } ++ ++ msg_pdbg("%s %d bytes starting at 0x%06x.\n", msg[cmd][3], len, addr); ++ return 0; ++} ++ ++static int dnv_smi_spi(struct flashctx *flash, uint8_t *buf, uint32_t addr, ++ uint32_t len, SPI_SMI_CMD cmd) ++{ ++ int32_t ret = 0; ++ uint32_t block_index = 0; ++ ++ ret = dnv_block_check(flash, addr, len, cmd); ++ if (ret == 0) { ++ for (block_index = 0; block_index * DELL_DENVERTON_BLOCK_SIZE < len; block_index++ ) { ++ if ((ret = dnv_smi_doit(addr - dnv_bios_region_start, buf, cmd)) != 0) { ++ break; ++ } ++ buf += DELL_DENVERTON_BLOCK_SIZE; ++ addr += DELL_DENVERTON_BLOCK_SIZE; ++ } ++ } ++ return ret; ++} ++ ++static int dnv_smi_erase_spi(struct flashctx *flash, uint32_t addr, uint32_t len) ++{ ++ return dnv_smi_spi(flash, NULL, addr, len, SMI_ERASE_SPI); ++} ++ ++static int dnv_smi_read_spi(struct flashctx *flash, uint8_t *buf, uint32_t addr, uint32_t len) ++{ ++ return dnv_smi_spi(flash, buf, addr, len, SMI_READ_SPI); ++} ++ ++static int dnv_smi_write_spi(struct flashctx *flash, uint8_t *buf, uint32_t addr, uint32_t len) ++{ ++ return dnv_smi_spi(flash, buf, addr, len, SMI_WRITE_SPI); ++} ++ ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + #define ICH_BMWAG(x) ((x >> 24) & 0xff) + #define ICH_BMRAG(x) ((x >> 16) & 0xff) + #define ICH_BRWA(x) ((x >> 8) & 0xff) +@@ -1452,6 +1726,9 @@ static int ich9_handle_frap(uint32_t frap, int i) + msg_pdbg("FREG%i: %s region (0x%08x-0x%08x) is %s.\n", i, + region_names[i], base, (limit | 0x0fff), + access_names[rwperms]); ++#ifdef FORCE10_SPI_CHANGE ++ add_romentry(base, (limit | 0x0fff), region_names[i]); ++#endif + return 0; + } + +@@ -1514,6 +1791,90 @@ static void ich9_set_pr(int i, int read_prot, int write_prot) + msg_gspew("resulted in 0x%08x.\n", mmio_readl(addr)); + } + ++#if DELL_DENVERTON_SUPPORT == 1 ++/* returns 0 if region is unused or r/w */ ++static int dnv_handle_frap(uint32_t frap, int32_t i) ++{ ++ static const char *const access_names[4] = { ++ "locked", "read-only", "write-only", "read-write" ++ }; ++ static const char *const region_names[5] = { ++ "Flash Descriptor", "BIOS", "Management Engine", ++ "Gigabit Ethernet", "Platform Data" ++ }; ++ uint32_t base, limit; ++ int32_t rwperms = (((ICH_BRWA(frap) >> i) & 1) << 1) | ++ (((ICH_BRRA(frap) >> i) & 1) << 0); ++ int32_t offset = DENVERTON_REG_FREG0 + i * 4; ++ uint32_t freg = mmio_readl(ich_spibar + offset); ++ ++ base = ICH_FREG_BASE(freg); ++ limit = ICH_FREG_LIMIT(freg); ++ if (base > limit || (freg == 0 && i > 0)) { ++ /* this FREG is disabled */ ++ msg_pdbg2("0x%02X: 0x%08x FREG%i: %s region is unused.\n", ++ offset, freg, i, region_names[i]); ++ return 0; ++ } ++ msg_pdbg("0x%02X: 0x%08x ", offset, freg); ++ if (rwperms == 0x3) { ++ msg_pdbg("FREG%i: %s region (0x%08x-0x%08x) is %s.\n", i, ++ region_names[i], base, (limit | 0x0fff), ++ access_names[rwperms]); ++ return 0; ++ } ++ ++ msg_pwarn("FREG%i: Warning: %s region (0x%08x-0x%08x) is %s.\n", i, ++ region_names[i], base, (limit | 0x0fff), ++ access_names[rwperms]); ++ return 1; ++} ++ ++/* returns 0 if range is unused (i.e. r/w) */ ++static int dnv_handle_pr(int32_t i) ++{ ++ static const char *const access_names[3] = { ++ "locked", "read-only", "write-only" ++ }; ++ uint8_t off = DENVERTON_REG_PR0 + (i * 4); ++ uint32_t pr = mmio_readl(ich_spibar + off); ++ uint32_t rwperms = ICH_PR_PERMS(pr); ++ ++ if (rwperms == 0x3) { ++ msg_pdbg2("0x%02X: 0x%08x (PR%u is unused)\n", off, pr, i); ++ return 0; ++ } ++ ++ msg_pdbg("0x%02X: 0x%08x ", off, pr); ++ msg_pwarn("PR%u: Warning: 0x%08x-0x%08x is %s.\n", i, ICH_FREG_BASE(pr), ++ ICH_FREG_LIMIT(pr) | 0x0fff, access_names[rwperms]); ++ return 1; ++} ++ ++/* Set/Clear the read and write protection enable bits of PR register @i ++ * according to @read_prot and @write_prot. */ ++static void dnv_set_pr(int32_t i, int32_t read_prot, int32_t write_prot) ++{ ++ void *addr = ich_spibar + DENVERTON_REG_PR0 + (i * 4); ++ uint32_t old = mmio_readl(addr); ++ uint32_t new; ++ ++ msg_gspew("PR%u is 0x%08x", i, old); ++ new = old & ~((1 << DENVERTON_PR_RP_OFF) | (1 << DENVERTON_PR_WP_OFF)); ++ if (read_prot) ++ new |= (1 << DENVERTON_PR_RP_OFF); ++ if (write_prot) ++ new |= (1 << DENVERTON_PR_WP_OFF); ++ if (old == new) { ++ msg_gspew(" already.\n"); ++ return; ++ } ++ msg_gspew(", trying to set it to 0x%08x ", new); ++ rmmio_writel(new, addr); ++ msg_gspew("resulted in 0x%08x.\n", mmio_readl(addr)); ++} ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + static const struct spi_programmer spi_programmer_ich7 = { + .type = SPI_CONTROLLER_ICH7, + .max_data_read = 64, +@@ -1545,12 +1906,21 @@ static const struct opaque_programmer opaque_programmer_ich_hwseq = { + .erase = ich_hwseq_block_erase, + }; + +-int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, +- enum ich_chipset ich_gen) ++#if DELL_DENVERTON_SUPPORT == 1 ++static const struct opaque_programmer opaque_master_dnv_hwseq = { ++ .max_data_read = 64, ++ .max_data_write = 64, ++ .probe = dnv_hwseq_probe, ++ .read = dnv_smi_read_spi, ++ .write = dnv_smi_write_spi, ++ .erase = dnv_smi_erase_spi, ++}; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ ++int ich_init_spi(struct pci_dev *dev, void *spibar, enum ich_chipset ich_gen) + { + int i; +- uint8_t old, new; +- uint16_t spibar_offset, tmp2; ++ uint16_t tmp2; + uint32_t tmp; + char *arg; + int ich_spi_force = 0; +@@ -1564,42 +1934,18 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, + } ich_spi_mode = ich_auto; + + ich_generation = ich_gen; +- +- switch (ich_generation) { +- case CHIPSET_ICH_UNKNOWN: +- return ERROR_FATAL; +- case CHIPSET_ICH7: +- case CHIPSET_ICH8: +- spibar_offset = 0x3020; +- break; +- case CHIPSET_ICH9: +- default: /* Future version might behave the same */ +- spibar_offset = 0x3800; +- break; +- } +- +- /* SPIBAR is at RCRB+0x3020 for ICH[78] and RCRB+0x3800 for ICH9. */ +- msg_pdbg("SPIBAR = 0x%x + 0x%04x\n", base, spibar_offset); +- +- /* Assign Virtual Address */ +- ich_spibar = rcrb + spibar_offset; ++ ich_spibar = spibar; + + switch (ich_generation) { + case CHIPSET_ICH7: ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_CENTERTON: + msg_pdbg("0x00: 0x%04x (SPIS)\n", + mmio_readw(ich_spibar + 0)); + msg_pdbg("0x02: 0x%04x (SPIC)\n", + mmio_readw(ich_spibar + 2)); + msg_pdbg("0x04: 0x%08x (SPIA)\n", + mmio_readl(ich_spibar + 4)); +- for (i = 0; i < 8; i++) { +- int offs; +- offs = 8 + (i * 8); +- msg_pdbg("0x%02x: 0x%08x (SPID%d)\n", offs, +- mmio_readl(ich_spibar + offs), i); +- msg_pdbg("0x%02x: 0x%08x (SPID%d+4)\n", offs + 4, +- mmio_readl(ich_spibar + offs + 4), i); +- } + ichspi_bbar = mmio_readl(ich_spibar + 0x50); + msg_pdbg("0x50: 0x%08x (BBAR)\n", + ichspi_bbar); +@@ -1625,7 +1971,123 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, + ich_set_bbar(0); + register_spi_programmer(&spi_programmer_ich7); + break; ++#if DELL_DENVERTON_SUPPORT == 1 ++ case CHIPSET_DENVERTON: ++ ++ tmp2 = mmio_readw(ich_spibar + DENVERTON_REG_HSFS); ++ msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2); ++ if (tmp2 & DENVERTON_HSFS_FLOCKDN) { ++ msg_pwarn("Warning: SPI Configuration Lockdown activated.\n"); ++ ichspi_lock = 1; ++ } ++ if (tmp2 & DENVERTON_HSFS_FDV) ++ desc_valid = 1; ++ if (!(tmp2 & DENVERTON_HSFS_FDOPSS) && desc_valid) ++ msg_pinfo("The Flash Descriptor Override Strap-Pin is set. " ++ "Restrictions implied by\n" ++ "the Master Section of the flash descriptor are " ++ "NOT in effect. Please note\n" ++ "that Protected Range (PR) restrictions still apply.\n"); ++ if (desc_valid) { ++ tmp2 = mmio_readw(ich_spibar + DENVERTON_REG_HSFC); ++ msg_pdbg("0x06: 0x%04x (HSFC)\n", tmp2); ++ } ++ ++ tmp = mmio_readl(ich_spibar + DENVERTON_REG_FADDR); ++ msg_pdbg2("0x08: 0x%08x (FADDR)\n", tmp); ++ ++ if (desc_valid) { ++ tmp = mmio_readl(ich_spibar + DENVERTON_REG_FRAP); ++ msg_pdbg("0x50: 0x%08x (FRAP)", tmp); ++ ++ /* Handle FREGx and FRAP registers */ ++ for (i=0; i < 5; i++) ++ ich_spi_rw_restricted |= dnv_handle_frap(tmp, i); ++ if (ich_spi_rw_restricted) ++ msg_pwarn("Not all flash regions are freely accessible " ++ "by flashrom. This is most likely\n" ++ "due to an active ME. " ++ "Please see http://flashrom.org/ME for details.\n"); ++ } ++ ++ /* Handle PR registers */ ++ for (i = 0; i < 5; i++) { ++ if (!ichspi_lock) ++ dnv_set_pr(i, 0, 0); ++ ich_spi_rw_restricted |= dnv_handle_pr(i); ++ } ++ ++ if (ich_spi_force) ++ msg_pinfo("Continuing with write support because " ++ "the user forced us to!\n"); ++ ++ if (desc_valid) { ++ tmp = mmio_readl(ich_spibar + DENVERTON_REG_VSCC0); ++ msg_pdbg("0xC4: 0x%08x (VSCC0)\n", tmp); ++ ++ tmp = mmio_readl(ich_spibar + DENVERTON_REG_VSCC1); ++ msg_pdbg("0xC8: 0x%08x (VSCC1)\n", tmp); ++ ++ if (read_ich_descriptors_via_fdo(ich_spibar, &desc) == ICH_RET_OK) ++ prettyprint_ich_descriptors(ich_gen, &desc); ++ ++ /* If the descriptor is valid and indicates multiple ++ * flash devices we need to use hwseq to be able to ++ * access the second flash device. ++ */ ++ if (ich_spi_mode == ich_auto && desc.content.NC != 0) { ++ msg_pinfo("Enabling hardware sequencing due to " ++ "multiple flash chips detected.\n"); ++ ich_spi_mode = ich_hwseq; ++ } ++ } ++ ++ if (ich_spi_mode == ich_auto && ichspi_lock) { ++ msg_pinfo("Enabling hardware sequencing because " ++ "some important opcode is locked.\n"); ++ ich_spi_mode = ich_hwseq; ++ } ++ ++ if (ich_spi_mode == ich_auto && ichspi_lock) { ++ msg_pinfo("Enabling hardware sequencing because " ++ "some important opcode is locked.\n"); ++ ich_spi_mode = ich_hwseq; ++ } ++ ++ if (ich_spi_mode == ich_hwseq) { ++ if (!desc_valid) { ++ msg_perr("Hardware sequencing was requested " ++ "but the flash descriptor is not valid. Aborting.\n"); ++ return ERROR_FATAL; ++ } ++ ++ uint32_t tmpi = getFCBA_component_density(&desc, 0); ++ if (tmpi < 0) { ++ msg_perr("Could not determine density of " ++ "flash component %d.\n", 0); ++ return ERROR_FATAL; ++ } ++ hwseq_data.size_comp0 = tmpi; ++ ++ tmpi = getFCBA_component_density(&desc, 1); ++ if (tmpi < 0) { ++ msg_perr("Could not determine density of flash component %d.\n", 1); ++ return ERROR_FATAL; ++ } ++ hwseq_data.size_comp1 = tmpi; ++ ++ register_opaque_programmer(&opaque_master_dnv_hwseq); ++ } else { ++ msg_perr("[%s:%d] Error!!!\n", __func__, __LINE__); ++ return -1; ++ } ++ ++ break; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + case CHIPSET_ICH8: ++#ifdef DELL_AVOTON_SUPPORT ++ case CHIPSET_AVOTON: ++#endif + default: /* Future version might behave the same */ + arg = extract_programmer_param("ich_spi_mode"); + if (arg && !strcmp(arg, "hwseq")) { +@@ -1669,7 +2131,11 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, + msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2); + prettyprint_ich9_reg_hsfs(tmp2); + if (tmp2 & HSFS_FLOCKDN) { ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("Warning: SPI Configuration Lockdown activated.\n"); ++#else + msg_pwarn("Warning: SPI Configuration Lockdown activated.\n"); ++#endif + ichspi_lock = 1; + } + if (tmp2 & HSFS_FDV) +@@ -1690,6 +2156,7 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, + msg_pdbg2("0x08: 0x%08x (FADDR)\n", tmp); + + if (desc_valid) { ++ + tmp = mmio_readl(ich_spibar + ICH9_REG_FRAP); + msg_pdbg("0x50: 0x%08x (FRAP)\n", tmp); + msg_pdbg("BMWAG 0x%02x, ", ICH_BMWAG(tmp)); +@@ -1750,10 +2217,15 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, + msg_pdbg("VSCC: "); + prettyprint_ich_reg_vscc(tmp, MSG_DEBUG); + } else { ++#ifdef DELL_AVOTON_SUPPORT ++ if (ich_generation != CHIPSET_AVOTON) { ++#endif + ichspi_bbar = mmio_readl(ich_spibar + ICH9_REG_BBAR); + msg_pdbg("0xA0: 0x%08x (BBAR)\n", + ichspi_bbar); +- ++#ifdef DELL_AVOTON_SUPPORT ++ } ++#endif + if (desc_valid) { + tmp = mmio_readl(ich_spibar + ICH9_REG_LVSCC); + msg_pdbg("0xC4: 0x%08x (LVSCC)\n", tmp); +@@ -1811,21 +2283,6 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, + break; + } + +- old = pci_read_byte(dev, 0xdc); +- msg_pdbg("SPI Read Configuration: "); +- new = (old >> 2) & 0x3; +- switch (new) { +- case 0: +- case 1: +- case 2: +- msg_pdbg("prefetching %sabled, caching %sabled, ", +- (new & 0x2) ? "en" : "dis", +- (new & 0x1) ? "dis" : "en"); +- break; +- default: +- msg_pdbg("invalid prefetching/caching settings, "); +- break; +- } + return 0; + } + +@@ -1844,7 +2301,9 @@ int via_init_spi(struct pci_dev *dev, uint32_t mmio_base) + { + int i; + +- ich_spibar = physmap("VIA SPI MMIO registers", mmio_base, 0x70); ++ ich_spibar = rphysmap("VIA SPI MMIO registers", mmio_base, 0x70); ++ if (ich_spibar == ERROR_PTR) ++ return ERROR_FATAL; + /* Do we really need no write enable? Like the LPC one at D17F0 0x40 */ + + /* Not sure if it speaks all these bus protocols. */ +diff --git a/internal.c b/internal.c +index ab3c81f..30b184f 100644 +--- a/internal.c ++++ b/internal.c +@@ -331,9 +331,8 @@ int internal_init(void) + return ret; + + #if defined(__i386__) || defined(__x86_64__) +- /* Probe unconditionally for IT87* LPC->SPI translation and for +- * IT87* Parallel write enable. +- */ ++ /* Probe unconditionally for ITE Super I/O chips. This enables LPC->SPI translation on IT87* and ++ * parallel writes on IT8705F. Also, this handles the manual chip select for Gigabyte's DualBIOS. */ + init_superio_ite(); + #endif + +diff --git a/it85spi.c b/it85spi.c +index 0b074eb..7efc680 100644 +--- a/it85spi.c ++++ b/it85spi.c +@@ -262,6 +262,9 @@ static int it85xx_spi_common_init(struct superio s) + * Major TODO here, and it will be a lot of work. + */ + base = (chipaddr)physmap("it85 communication", 0xFFFFF000, 0x1000); ++ if (base == (chipaddr)ERROR_PTR) ++ return 1; ++ + msg_pdbg("%s():%d base=0x%08x\n", __func__, __LINE__, + (unsigned int)base); + ce_high = (unsigned char *)(base + 0xE00); /* 0xFFFFFE00 */ +diff --git a/it87spi.c b/it87spi.c +index 8e4e0ad..be7f234 100644 +--- a/it87spi.c ++++ b/it87spi.c +@@ -27,6 +27,7 @@ + + #include + #include ++#include + #include "flash.h" + #include "chipdrivers.h" + #include "programmer.h" +@@ -36,7 +37,7 @@ + #define ITE_SUPERIO_PORT1 0x2e + #define ITE_SUPERIO_PORT2 0x4e + +-uint16_t it8716f_flashport = 0; ++static uint16_t it8716f_flashport = 0; + /* use fast 33MHz SPI (<>0) or slow 16MHz (0) */ + static int fast_spi = 1; + +@@ -124,10 +125,40 @@ static const struct spi_programmer spi_programmer_it87xx = { + static uint16_t it87spi_probe(uint16_t port) + { + uint8_t tmp = 0; +- char *portpos = NULL; + uint16_t flashport = 0; + + enter_conf_mode_ite(port); ++ ++ char *param = extract_programmer_param("dualbiosindex"); ++ if (param != NULL) { ++ sio_write(port, 0x07, 0x07); /* Select GPIO LDN */ ++ tmp = sio_read(port, 0xEF); ++ if (*param == '\0') { /* Print current setting only. */ ++ free(param); ++ } else { ++ char *dualbiosindex_suffix; ++ errno = 0; ++ long chip_index = strtol(param, &dualbiosindex_suffix, 0); ++ free(param); ++ if (errno != 0 || *dualbiosindex_suffix != '\0' || chip_index < 0 || chip_index > 1) { ++ msg_perr("DualBIOS: Invalid chip index requested - choose 0 or 1.\n"); ++ exit_conf_mode_ite(port); ++ return 1; ++ } ++ if (chip_index != (tmp & 1)) { ++ msg_pdbg("DualBIOS: Previous chip index: %d\n", tmp & 1); ++ sio_write(port, 0xEF, (tmp & 0xFE) | chip_index); ++ tmp = sio_read(port, 0xEF); ++ if ((tmp & 1) != chip_index) { ++ msg_perr("DualBIOS: Chip selection failed.\n"); ++ exit_conf_mode_ite(port); ++ return 1; ++ } ++ } ++ } ++ msg_pinfo("DualBIOS: Selected chip: %d\n", tmp & 1); ++ } ++ + /* NOLDN, reg 0x24, mask out lowest bit (suspend) */ + tmp = sio_read(port, 0x24) & 0xFE; + /* Check if LPC->SPI translation is active. */ +@@ -163,11 +194,11 @@ static uint16_t it87spi_probe(uint16_t port) + flashport |= sio_read(port, 0x65); + msg_pdbg("Serial flash port 0x%04x\n", flashport); + /* Non-default port requested? */ +- portpos = extract_programmer_param("it87spiport"); +- if (portpos) { ++ param = extract_programmer_param("it87spiport"); ++ if (param) { + char *endptr = NULL; + unsigned long forced_flashport; +- forced_flashport = strtoul(portpos, &endptr, 0); ++ forced_flashport = strtoul(param, &endptr, 0); + /* Port 0, port >0x1000, unaligned ports and garbage strings + * are rejected. + */ +@@ -180,7 +211,8 @@ static uint16_t it87spi_probe(uint16_t port) + msg_perr("Error: it87spiport specified, but no valid " + "port specified.\nPort must be a multiple of " + "0x8 and lie between 0x100 and 0xff8.\n"); +- free(portpos); ++ exit_conf_mode_ite(port); ++ free(param); + return 1; + } else { + flashport = (uint16_t)forced_flashport; +@@ -190,7 +222,7 @@ static uint16_t it87spi_probe(uint16_t port) + sio_write(port, 0x65, (flashport & 0xff)); + } + } +- free(portpos); ++ free(param); + exit_conf_mode_ite(port); + it8716f_flashport = flashport; + if (internal_buses_supported & BUS_SPI) +@@ -228,6 +260,7 @@ int init_superio_ite(void) + case 0x8716: + case 0x8718: + case 0x8720: ++ case 0x8728: + ret |= it87spi_probe(superios[i].port); + break; + default: +diff --git a/layout.c b/layout.c +index 1bd3152..d00c16c 100644 +--- a/layout.c ++++ b/layout.c +@@ -3,6 +3,7 @@ + * + * Copyright (C) 2005-2008 coresystems GmbH + * (Written by Stefan Reinauer for coresystems GmbH) ++ * Copyright (C) 2011-2013 Stefan Tauner + * + * 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 +@@ -25,24 +26,23 @@ + #include "flash.h" + #include "programmer.h" + +-static int romimages = 0; +- + #define MAX_ROMLAYOUT 32 + + typedef struct { +- unsigned int start; +- unsigned int end; ++ chipoff_t start; ++ chipoff_t end; + unsigned int included; + char name[256]; +-} romlayout_t; ++} romentry_t; + +-/* include_args lists arguments specified at the command line with -i. They +- * must be processed at some point so that desired regions are marked as +- * "included" in the rom_entries list. +- */ ++/* rom_entries store the entries specified in a layout file and associated run-time data */ ++static romentry_t rom_entries[MAX_ROMLAYOUT]; ++static int num_rom_entries = 0; /* the number of successfully parsed rom_entries */ ++ ++/* include_args holds the arguments specified at the command line with -i. They must be processed at some point ++ * so that desired regions are marked as "included" in the rom_entries list. */ + static char *include_args[MAX_ROMLAYOUT]; +-static int num_include_args = 0; /* the number of valid entries. */ +-static romlayout_t rom_entries[MAX_ROMLAYOUT]; ++static int num_include_args = 0; /* the number of valid include_args. */ + + #ifndef __LIBPAYLOAD__ + int read_romlayout(char *name) +@@ -62,12 +62,13 @@ int read_romlayout(char *name) + while (!feof(romlayout)) { + char *tstr1, *tstr2; + +- if (romimages >= MAX_ROMLAYOUT) { ++ if (num_rom_entries >= MAX_ROMLAYOUT) { + msg_gerr("Maximum number of ROM images (%i) in layout " + "file reached.\n", MAX_ROMLAYOUT); ++ fclose(romlayout); + return 1; + } +- if (2 != fscanf(romlayout, "%s %s\n", tempstr, rom_entries[romimages].name)) ++ if (2 != fscanf(romlayout, "%s %s\n", tempstr, rom_entries[num_rom_entries].name)) + continue; + #if 0 + // fscanf does not like arbitrary comments like that :( later +@@ -82,13 +83,13 @@ int read_romlayout(char *name) + fclose(romlayout); + return 1; + } +- rom_entries[romimages].start = strtol(tstr1, (char **)NULL, 16); +- rom_entries[romimages].end = strtol(tstr2, (char **)NULL, 16); +- rom_entries[romimages].included = 0; +- romimages++; ++ rom_entries[num_rom_entries].start = strtol(tstr1, (char **)NULL, 16); ++ rom_entries[num_rom_entries].end = strtol(tstr2, (char **)NULL, 16); ++ rom_entries[num_rom_entries].included = 0; ++ num_rom_entries++; + } + +- for (i = 0; i < romimages; i++) { ++ for (i = 0; i < num_rom_entries; i++) { + msg_gdbg("romlayout %08x - %08x named %s\n", + rom_entries[i].start, + rom_entries[i].end, rom_entries[i].name); +@@ -100,6 +101,33 @@ int read_romlayout(char *name) + } + #endif + ++ ++#ifdef FORCE10_SPI_CHANGE ++int add_romentry(chipoff_t start, chipoff_t end, const char *name) ++{ ++ int len = 0; ++ ++ if (num_rom_entries >= MAX_ROMLAYOUT) { ++ msg_gerr("Maximum number of ROM images (%i) in layout " ++ "file reached.\n", MAX_ROMLAYOUT); ++ return 1; ++ } ++ rom_entries[num_rom_entries].start = start; ++ rom_entries[num_rom_entries].end = end; ++ rom_entries[num_rom_entries].included = 1; ++ len = strlen(name); ++ if (len > 256) { ++ msg_gdbg("terminating rom entry name to 256 as it exceeds max length\n"); ++ len = 255; ++ } ++ strncpy(rom_entries[num_rom_entries].name, name, len); ++ msg_gdbg("Adding rom entry: %08x - %08x named %s\n", rom_entries[num_rom_entries].start, ++ rom_entries[num_rom_entries].end, rom_entries[num_rom_entries].name); ++ num_rom_entries++; ++ return 0; ++} ++#endif ++ + /* returns the index of the entry (or a negative value if it is not found) */ + int find_include_arg(const char *const name) + { +@@ -139,11 +167,11 @@ static int find_romentry(char *name) + { + int i; + +- if (!romimages) ++ if (num_rom_entries == 0) + return -1; + + msg_gspew("Looking for region \"%s\"... ", name); +- for (i = 0; i < romimages; i++) { ++ for (i = 0; i < num_rom_entries; i++) { + if (!strcmp(rom_entries[i].name, name)) { + rom_entries[i].included = 1; + msg_gspew("found.\n"); +@@ -166,7 +194,7 @@ int process_include_args(void) + return 0; + + /* User has specified an area, but no layout file is loaded. */ +- if (!romimages) { ++ if (num_rom_entries == 0) { + msg_gerr("Region requested (with -i \"%s\"), " + "but no layout data is available.\n", + include_args[0]); +@@ -190,15 +218,30 @@ int process_include_args(void) + return 0; + } + +-romlayout_t *get_next_included_romentry(unsigned int start) ++void layout_cleanup(void) ++{ ++ int i; ++ for (i = 0; i < num_include_args; i++) { ++ free(include_args[i]); ++ include_args[i] = NULL; ++ } ++ num_include_args = 0; ++ ++ for (i = 0; i < num_rom_entries; i++) { ++ rom_entries[i].included = 0; ++ } ++ num_rom_entries = 0; ++} ++ ++romentry_t *get_next_included_romentry(unsigned int start) + { + int i; + unsigned int best_start = UINT_MAX; +- romlayout_t *best_entry = NULL; +- romlayout_t *cur; ++ romentry_t *best_entry = NULL; ++ romentry_t *cur; + + /* First come, first serve for overlapping regions. */ +- for (i = 0; i < romimages; i++) { ++ for (i = 0; i < num_rom_entries; i++) { + cur = &rom_entries[i]; + if (!cur->included) + continue; +@@ -217,18 +260,43 @@ romlayout_t *get_next_included_romentry(unsigned int start) + return best_entry; + } + +-int handle_romentries(const struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents) ++/* Validate and - if needed - normalize layout entries. */ ++int normalize_romentries(const struct flashctx *flash) ++{ ++ chipsize_t total_size = flash->chip->total_size * 1024; ++ int ret = 0; ++ ++ int i; ++ for (i = 0; i < num_rom_entries; i++) { ++ if (rom_entries[i].start >= total_size || rom_entries[i].end >= total_size) { ++ msg_gwarn("Warning: Address range of region \"%s\" exceeds the current chip's " ++ "address space.\n", rom_entries[i].name); ++ if (rom_entries[i].included) ++ ret = 1; ++ } ++ if (rom_entries[i].start > rom_entries[i].end) { ++ msg_gerr("Error: Size of the address range of region \"%s\" is not positive.\n", ++ rom_entries[i].name); ++ ret = 1; ++ } ++ } ++ ++ return ret; ++} ++ ++int build_new_image(const struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents) + { + unsigned int start = 0; +- romlayout_t *entry; ++ romentry_t *entry; + unsigned int size = flash->chip->total_size * 1024; + + /* If no regions were specified for inclusion, assume + * that the user wants to write the complete new image. + */ ++#ifndef FORCE10_SPI_CHANGE + if (num_include_args == 0) + return 0; +- ++#endif + /* Non-included romentries are ignored. + * The union of all included romentries is used from the new image. + */ +@@ -239,7 +307,7 @@ int handle_romentries(const struct flashctx *flash, uint8_t *oldcontents, uint8_ + memcpy(newcontents + start, oldcontents + start, + size - start); + break; +- } ++ } + /* For non-included region, copy from old content. */ + if (entry->start > start) + memcpy(newcontents + start, oldcontents + start, +diff --git a/linux_spi.c b/linux_spi.c +index d12fceb..f0c6404 100644 +--- a/linux_spi.c ++++ b/linux_spi.c +@@ -60,7 +60,7 @@ static const struct spi_programmer spi_programmer_linux = { + int linux_spi_init(void) + { + char *p, *endp, *dev; +- uint32_t speed = 0; ++ uint32_t speed_hz = 0; + /* FIXME: make the following configurable by CLI options. */ + /* SPI mode 0 (beware this also includes: MSB first, CS active low and others */ + const uint8_t mode = SPI_MODE_0; +@@ -68,7 +68,7 @@ int linux_spi_init(void) + + p = extract_programmer_param("spispeed"); + if (p && strlen(p)) { +- speed = (uint32_t)strtoul(p, &endp, 10) * 1024; ++ speed_hz = (uint32_t)strtoul(p, &endp, 10) * 1000; + if (p == endp) { + msg_perr("%s: invalid clock: %s kHz\n", __func__, p); + free(p); +@@ -98,14 +98,14 @@ int linux_spi_init(void) + return 1; + /* We rely on the shutdown function for cleanup from here on. */ + +- if (speed > 0) { +- if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) { ++ if (speed_hz > 0) { ++ if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed_hz) == -1) { + msg_perr("%s: failed to set speed to %d Hz: %s\n", +- __func__, speed, strerror(errno)); ++ __func__, speed_hz, strerror(errno)); + return 1; + } + +- msg_pdbg("Using %d kHz clock\n", speed); ++ msg_pdbg("Using %d kHz clock\n", speed_hz/1000); + } + + if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) { +diff --git a/mcp6x_spi.c b/mcp6x_spi.c +index ac40557..20e9bd8 100644 +--- a/mcp6x_spi.c ++++ b/mcp6x_spi.c +@@ -135,25 +135,20 @@ int mcp6x_spi_init(int want_spi) + + /* Accessing a NULL pointer BAR is evil. Don't do it. */ + if (!mcp6x_spibaraddr && want_spi) { +- msg_perr("Error: Chipset is strapped for SPI, but MCP SPI BAR " +- "is invalid.\n"); ++ msg_perr("Error: Chipset is strapped for SPI, but MCP SPI BAR is invalid.\n"); + return 1; + } else if (!mcp6x_spibaraddr && !want_spi) { + msg_pdbg("MCP SPI is not used.\n"); + return 0; + } else if (mcp6x_spibaraddr && !want_spi) { +- msg_pdbg("Strange. MCP SPI BAR is valid, but chipset apparently" +- " doesn't have SPI enabled.\n"); ++ msg_pdbg("Strange. MCP SPI BAR is valid, but chipset apparently doesn't have SPI enabled.\n"); + /* FIXME: Should we enable SPI anyway? */ + return 0; + } + /* Map the BAR. Bytewise/wordwise access at 0x530 and 0x540. */ +- mcp6x_spibar = physmap("NVIDIA MCP6x SPI", mcp6x_spibaraddr, 0x544); +- +-#if 0 +- /* FIXME: Run the physunmap in a shutdown function. */ +- physunmap(mcp6x_spibar, 0x544); +-#endif ++ mcp6x_spibar = rphysmap("NVIDIA MCP6x SPI", mcp6x_spibaraddr, 0x544); ++ if (mcp6x_spibar == ERROR_PTR) ++ return 1; + + status = mmio_readw(mcp6x_spibar + 0x530); + msg_pdbg("SPI control is 0x%04x, req=%i, gnt=%i\n", +diff --git a/nic3com.c b/nic3com.c +index 8d67b54..27e28c7 100644 +--- a/nic3com.c ++++ b/nic3com.c +@@ -96,6 +96,8 @@ int nic3com_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); ++ if (!io_base_addr) ++ return 1; + + id = dev->device_id; + +diff --git a/nicintel.c b/nicintel.c +index 56678e7..98ba29f 100644 +--- a/nicintel.c ++++ b/nicintel.c +@@ -59,13 +59,6 @@ static const struct par_programmer par_programmer_nicintel = { + .chip_writen = fallback_chip_writen, + }; + +-static int nicintel_shutdown(void *data) +-{ +- physunmap(nicintel_control_bar, NICINTEL_CONTROL_MEMMAP_SIZE); +- physunmap(nicintel_bar, NICINTEL_MEMMAP_SIZE); +- return 0; +-} +- + int nicintel_init(void) + { + struct pci_dev *dev = NULL; +@@ -83,18 +76,19 @@ int nicintel_init(void) + return 1; + + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_2); +- nicintel_bar = physmap("Intel NIC flash", addr, NICINTEL_MEMMAP_SIZE); ++ if (!addr) ++ return 1; ++ ++ nicintel_bar = rphysmap("Intel NIC flash", addr, NICINTEL_MEMMAP_SIZE); + if (nicintel_bar == ERROR_PTR) +- goto error_out_unmap; ++ return 1; + + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); +- /* FIXME: This is not an aligned mapping. Use 4k? */ +- nicintel_control_bar = physmap("Intel NIC control/status reg", +- addr, NICINTEL_CONTROL_MEMMAP_SIZE); +- if (nicintel_control_bar == ERROR_PTR) +- goto error_out; ++ if (!addr) ++ return 1; + +- if (register_shutdown(nicintel_shutdown, NULL)) ++ nicintel_control_bar = rphysmap("Intel NIC control/status reg", addr, NICINTEL_CONTROL_MEMMAP_SIZE); ++ if (nicintel_control_bar == ERROR_PTR) + return 1; + + /* FIXME: This register is pretty undocumented in all publicly available +@@ -112,11 +106,6 @@ int nicintel_init(void) + register_par_programmer(&par_programmer_nicintel, BUS_PARALLEL); + + return 0; +- +-error_out_unmap: +- physunmap(nicintel_bar, NICINTEL_MEMMAP_SIZE); +-error_out: +- return 1; + } + + static void nicintel_chip_writeb(const struct flashctx *flash, uint8_t val, +diff --git a/nicintel_spi.c b/nicintel_spi.c +index 0045c09..1522c9b 100644 +--- a/nicintel_spi.c ++++ b/nicintel_spi.c +@@ -19,10 +19,16 @@ + */ + + /* +- * Datasheet: ++ * Datasheets: + * PCI/PCI-X Family of Gigabit Ethernet Controllers Software Developer's Manual + * 82540EP/EM, 82541xx, 82544GC/EI, 82545GM/EM, 82546GB/EB, and 82547xx +- * http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf ++ * http://www.intel.com/content/www/us/en/ethernet-controllers/pci-pci-x-family-gbe-controllers-software-dev-manual.html ++ * ++ * PCIe GbE Controllers Open Source Software Developer's Manual ++ * http://www.intel.com/content/www/us/en/ethernet-controllers/pcie-gbe-controllers-open-source-manual.html ++ * ++ * Intel 82574 Gigabit Ethernet Controller Family Datasheet ++ * http://www.intel.com/content/www/us/en/ethernet-controllers/82574l-gbe-controller-datasheet.html + */ + + #include +@@ -72,6 +78,7 @@ const struct dev_entry nics_intel_spi[] = { + {PCI_VENDOR_ID_INTEL, 0x1076, OK, "Intel", "82541GI Gigabit Ethernet Controller"}, + {PCI_VENDOR_ID_INTEL, 0x107c, OK, "Intel", "82541PI Gigabit Ethernet Controller"}, + {PCI_VENDOR_ID_INTEL, 0x10b9, OK, "Intel", "82572EI Gigabit Ethernet Controller"}, ++ {PCI_VENDOR_ID_INTEL, 0x10d3, OK, "Intel", "82574L Gigabit Ethernet Controller"}, + + {0}, + }; +@@ -151,16 +158,12 @@ static int nicintel_spi_shutdown(void *data) + { + uint32_t tmp; + +- /* Disable writes manually. See the comment about EECD in +- * nicintel_spi_init() for details. +- */ ++ /* Disable writes manually. See the comment about EECD in nicintel_spi_init() for details. */ + tmp = pci_mmio_readl(nicintel_spibar + EECD); + tmp &= ~FLASH_WRITES_ENABLED; + tmp |= FLASH_WRITES_DISABLED; + pci_mmio_writel(tmp, nicintel_spibar + EECD); + +- physunmap(nicintel_spibar, MEMMAP_SIZE); +- + return 0; + } + +@@ -177,8 +180,13 @@ int nicintel_spi_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); +- nicintel_spibar = physmap("Intel Gigabit NIC w/ SPI flash", +- io_base_addr, MEMMAP_SIZE); ++ if (!io_base_addr) ++ return 1; ++ ++ nicintel_spibar = rphysmap("Intel Gigabit NIC w/ SPI flash", io_base_addr, MEMMAP_SIZE); ++ if (nicintel_spibar == ERROR_PTR) ++ return 1; ++ + /* Automatic restore of EECD on shutdown is not possible because EECD + * does not only contain FLASH_WRITES_DISABLED|FLASH_WRITES_ENABLED, + * but other bits with side effects as well. Those other bits must be +diff --git a/nicnatsemi.c b/nicnatsemi.c +index d62a73f..cb8da6d 100644 +--- a/nicnatsemi.c ++++ b/nicnatsemi.c +@@ -64,6 +64,8 @@ int nicnatsemi_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); ++ if (!io_base_addr) ++ return 1; + + /* The datasheet shows address lines MA0-MA16 in one place and MA0-MA15 + * in another. My NIC has MA16 connected to A16 on the boot ROM socket +diff --git a/nicrealtek.c b/nicrealtek.c +index fb8e9e1..02fbd39 100644 +--- a/nicrealtek.c ++++ b/nicrealtek.c +@@ -69,6 +69,8 @@ int nicrealtek_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); ++ if (!io_base_addr) ++ return 1; + + /* Beware, this ignores the vendor ID! */ + switch (dev->device_id) { +diff --git a/ogp_spi.c b/ogp_spi.c +index 0c09d6a..23431d1 100644 +--- a/ogp_spi.c ++++ b/ogp_spi.c +@@ -97,12 +97,6 @@ static const struct bitbang_spi_master bitbang_spi_master_ogp = { + .half_period = 0, + }; + +-static int ogp_spi_shutdown(void *data) +-{ +- physunmap(ogp_spibar, 4096); +- return 0; +-} +- + int ogp_spi_init(void) + { + struct pci_dev *dev = NULL; +@@ -126,8 +120,10 @@ int ogp_spi_init(void) + ogp_reg_sck = OGA1_XP10_CPROM_SCK; + } else { + msg_perr("Invalid or missing rom= parameter.\n"); ++ free(type); + return 1; + } ++ free(type); + + if (rget_io_perms()) + return 1; +@@ -137,9 +133,11 @@ int ogp_spi_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); +- ogp_spibar = physmap("OGP registers", io_base_addr, 4096); ++ if (!io_base_addr) ++ return 1; + +- if (register_shutdown(ogp_spi_shutdown, NULL)) ++ ogp_spibar = rphysmap("OGP registers", io_base_addr, 4096); ++ if (ogp_spibar == ERROR_PTR) + return 1; + + if (bitbang_spi_init(&bitbang_spi_master_ogp)) +diff --git a/pcidev.c b/pcidev.c +index c7e9d78..3a3f77c 100644 +--- a/pcidev.c ++++ b/pcidev.c +@@ -94,7 +94,7 @@ uintptr_t pcidev_readbar(struct pci_dev *dev, int bar) + + supported_cycles = pci_read_word(dev, PCI_COMMAND); + +- msg_pdbg("Requested BAR is "); ++ msg_pdbg("Requested BAR is of type "); + switch (bartype) { + case TYPE_MEMBAR: + msg_pdbg("MEM"); +diff --git a/physmap.c b/physmap.c +index 932fe75..150c44a 100644 +--- a/physmap.c ++++ b/physmap.c +@@ -21,11 +21,13 @@ + */ + + #include ++#include + #include + #include + #include + #include + #include "flash.h" ++#include "programmer.h" + #include "hwaccess.h" + + #if !defined(__DJGPP__) && !defined(__LIBPAYLOAD__) +@@ -88,7 +90,7 @@ static void *sys_physmap(uintptr_t phys_addr, size_t len) + #define sys_physmap_rw_uncached sys_physmap + #define sys_physmap_ro_cached sys_physmap + +-void physunmap(void *virt_addr, size_t len) ++void sys_physunmap_unaligned(void *virt_addr, size_t len) + { + __dpmi_meminfo mi; + +@@ -117,7 +119,7 @@ void *sys_physmap(uintptr_t phys_addr, size_t len) + #define sys_physmap_rw_uncached sys_physmap + #define sys_physmap_ro_cached sys_physmap + +-void physunmap(void *virt_addr, size_t len) ++void sys_physunmap_unaligned(void *virt_addr, size_t len) + { + } + #elif defined(__MACH__) && defined(__APPLE__) +@@ -138,7 +140,7 @@ static void *sys_physmap(uintptr_t phys_addr, size_t len) + #define sys_physmap_rw_uncached sys_physmap + #define sys_physmap_ro_cached sys_physmap + +-void physunmap(void *virt_addr, size_t len) ++void sys_physunmap_unaligned(void *virt_addr, size_t len) + { + unmap_physical(virt_addr, len); + } +@@ -164,12 +166,11 @@ static void *sys_physmap_rw_uncached(uintptr_t phys_addr, size_t len) + /* Open the memory device UNCACHED. Important for MMIO. */ + if (-1 == (fd_mem = open(MEM_DEV, O_RDWR | O_SYNC))) { + msg_perr("Critical error: open(" MEM_DEV "): %s\n", strerror(errno)); +- exit(2); ++ return ERROR_PTR; + } + } + +- virt_addr = mmap(NULL, len, PROT_WRITE | PROT_READ, MAP_SHARED, +- fd_mem, (off_t)phys_addr); ++ virt_addr = mmap(NULL, len, PROT_WRITE | PROT_READ, MAP_SHARED, fd_mem, (off_t)phys_addr); + return MAP_FAILED == virt_addr ? ERROR_PTR : virt_addr; + } + +@@ -184,50 +185,77 @@ static void *sys_physmap_ro_cached(uintptr_t phys_addr, size_t len) + /* Open the memory device CACHED. */ + if (-1 == (fd_mem_cached = open(MEM_DEV, O_RDWR))) { + msg_perr("Critical error: open(" MEM_DEV "): %s\n", strerror(errno)); +- exit(2); ++ return ERROR_PTR; + } + } + +- virt_addr = mmap(NULL, len, PROT_READ, MAP_SHARED, +- fd_mem_cached, (off_t)phys_addr); ++ virt_addr = mmap(NULL, len, PROT_READ, MAP_SHARED, fd_mem_cached, (off_t)phys_addr); + return MAP_FAILED == virt_addr ? ERROR_PTR : virt_addr; + } + +-void physunmap(void *virt_addr, size_t len) ++void sys_physunmap_unaligned(void *virt_addr, size_t len) + { +- if (len == 0) { +- msg_pspew("Not unmapping zero size at %p\n", virt_addr); +- return; +- } +- + munmap(virt_addr, len); + } + #endif + +-#define PHYSMAP_NOFAIL 0 +-#define PHYSMAP_MAYFAIL 1 +-#define PHYSMAP_RW 0 +-#define PHYSMAP_RO 1 ++#define PHYSM_RW 0 ++#define PHYSM_RO 1 ++#define PHYSM_NOCLEANUP 0 ++#define PHYSM_CLEANUP 1 ++#define PHYSM_EXACT 0 ++#define PHYSM_ROUND 1 ++ ++/* Round start to nearest page boundary below and set len so that the resulting address range ends at the lowest ++ * possible page boundary where the original address range is still entirely contained. It returns the ++ * difference between the rounded start address and the original start address. */ ++static uintptr_t round_to_page_boundaries(uintptr_t *start, size_t *len) ++{ ++ uintptr_t page_size = getpagesize(); ++ uintptr_t page_mask = ~(page_size-1); ++ uintptr_t end = *start + *len; ++ uintptr_t old_start = *start; ++ msg_gspew("page_size=%" PRIxPTR "\n", page_size); ++ msg_gspew("pre-rounding: start=0x%0*" PRIxPTR ", len=0x%zx, end=0x%0*" PRIxPTR "\n", ++ PRIxPTR_WIDTH, *start, *len, PRIxPTR_WIDTH, end); ++ *start = *start & page_mask; ++ end = (end + page_size - 1) & page_mask; ++ *len = end - *start; ++ msg_gspew("post-rounding: start=0x%0*" PRIxPTR ", len=0x%zx, end=0x%0*" PRIxPTR "\n", ++ PRIxPTR_WIDTH, *start, *len, PRIxPTR_WIDTH, *start + *len); ++ return old_start - *start; ++} ++ ++struct undo_physmap_data { ++ void *virt_addr; ++ size_t len; ++}; ++ ++static int undo_physmap(void *data) ++{ ++ if (data == NULL) { ++ msg_perr("%s: tried to physunmap without valid data!\n", __func__); ++ return 1; ++ } ++ struct undo_physmap_data *d = data; ++ physunmap_unaligned(d->virt_addr, d->len); ++ free(data); ++ return 0; ++} + +-static void *physmap_common(const char *descr, uintptr_t phys_addr, +- size_t len, int mayfail, int readonly) ++static void *physmap_common(const char *descr, uintptr_t phys_addr, size_t len, bool readonly, bool autocleanup, ++ bool round) + { + void *virt_addr; ++ uintptr_t offset = 0; + + if (len == 0) { + msg_pspew("Not mapping %s, zero size at 0x%0*" PRIxPTR ".\n", descr, PRIxPTR_WIDTH, phys_addr); + return ERROR_PTR; + } + +- if ((getpagesize() - 1) & len) { +- msg_perr("Mapping %s at 0x%0*" PRIxPTR ", unaligned size 0x%zx.\n", +- descr, PRIxPTR_WIDTH, phys_addr, len); +- } +- +- if ((getpagesize() - 1) & phys_addr) { +- msg_perr("Mapping %s, 0x%zx bytes at unaligned 0x%0*" PRIxPTR ".\n", +- descr, len, PRIxPTR_WIDTH, phys_addr); +- } ++ if (round) ++ offset = round_to_page_boundaries(&phys_addr, &len); + + if (readonly) + virt_addr = sys_physmap_ro_cached(phys_addr, len); +@@ -253,23 +281,89 @@ static void *physmap_common(const char *descr, uintptr_t phys_addr, + "and reboot, or reboot into\n" + "single user mode.\n"); + #endif +- if (!mayfail) +- exit(3); ++ return ERROR_PTR; + } + +- return virt_addr; ++ if (autocleanup) { ++ struct undo_physmap_data *d = malloc(sizeof(struct undo_physmap_data)); ++ if (d == NULL) { ++ msg_perr("%s: Out of memory!\n", __func__); ++ physunmap_unaligned(virt_addr, len); ++ return ERROR_PTR; ++ } ++ ++ d->virt_addr = virt_addr; ++ d->len = len; ++ if (register_shutdown(undo_physmap, d) != 0) { ++ msg_perr("%s: Could not register shutdown function!\n", __func__); ++ physunmap_unaligned(virt_addr, len); ++ return ERROR_PTR; ++ } ++ } ++ ++ return virt_addr + offset; ++} ++ ++void physunmap_unaligned(void *virt_addr, size_t len) ++{ ++ /* No need to check for zero size, such mappings would have yielded ERROR_PTR. */ ++ if (virt_addr == ERROR_PTR) { ++#ifndef FORCE10_SPI_CHANGE ++ msg_perr("Trying to unmap a nonexisting mapping!\n" ++ "Please report a bug at flashrom@flashrom.org\n"); ++#else ++ msg_pdbg("Trying to unmap a nonexisting mapping!\n" ++ "Please report a bug at flashrom@flashrom.org\n"); ++#endif ++ return; ++ } ++ ++ sys_physunmap_unaligned(virt_addr, len); ++} ++ ++void physunmap(void *virt_addr, size_t len) ++{ ++ uintptr_t tmp; ++ ++ /* No need to check for zero size, such mappings would have yielded ERROR_PTR. */ ++ if (virt_addr == ERROR_PTR) { ++#ifndef FORCE10_SPI_CHANGE ++ msg_perr("Trying to unmap a nonexisting mapping!\n" ++ "Please report a bug at flashrom@flashrom.org\n"); ++#else ++ msg_pdbg("Trying to unmap a nonexisting mapping!\n" ++ "Please report a bug at flashrom@flashrom.org\n"); ++#endif ++ return; ++ } ++ tmp = (uintptr_t)virt_addr; ++ /* We assume that the virtual address of a page-aligned physical address is page-aligned as well. By ++ * extension, rounding a virtual unaligned address as returned by physmap should yield the same offset ++ * between rounded and original virtual address as between rounded and original physical address. ++ */ ++ round_to_page_boundaries(&tmp, &len); ++ virt_addr = (void *)tmp; ++ physunmap_unaligned(virt_addr, len); + } + + void *physmap(const char *descr, uintptr_t phys_addr, size_t len) + { +- return physmap_common(descr, phys_addr, len, PHYSMAP_NOFAIL, +- PHYSMAP_RW); ++ return physmap_common(descr, phys_addr, len, PHYSM_RW, PHYSM_NOCLEANUP, PHYSM_ROUND); ++} ++ ++void *rphysmap(const char *descr, uintptr_t phys_addr, size_t len) ++{ ++ return physmap_common(descr, phys_addr, len, PHYSM_RW, PHYSM_CLEANUP, PHYSM_ROUND); ++} ++ ++void *physmap_ro(const char *descr, uintptr_t phys_addr, size_t len) ++{ ++ return physmap_common(descr, phys_addr, len, PHYSM_RO, PHYSM_NOCLEANUP, PHYSM_ROUND); + } + +-void *physmap_try_ro(const char *descr, uintptr_t phys_addr, size_t len) ++void *physmap_ro_unaligned(const char *descr, uintptr_t phys_addr, size_t len) + { +- return physmap_common(descr, phys_addr, len, PHYSMAP_MAYFAIL, +- PHYSMAP_RO); ++ return physmap_common(descr, phys_addr, len, PHYSM_RO, PHYSM_NOCLEANUP, PHYSM_EXACT); + } + + /* MSR abstraction implementations for Linux, OpenBSD, FreeBSD/Dragonfly, OSX, libpayload +diff --git a/pony_spi.c b/pony_spi.c +index 101751f..2a3666f 100644 +--- a/pony_spi.c ++++ b/pony_spi.c +@@ -140,6 +140,7 @@ int pony_spi_init(void) + } else if (arg && !strlen(arg)) { + msg_perr("Error: Missing argument for programmer type.\n"); + free(arg); ++ return 1; + } else if (arg){ + msg_perr("Error: Invalid programmer type specified.\n"); + free(arg); +diff --git a/print.c b/print.c +index 6766eeb..6d2921b 100644 +--- a/print.c ++++ b/print.c +@@ -436,12 +436,13 @@ static void print_supported_boards_helper(const struct board_info *boards, + msg_ginfo("%s", b->name); + for (i = 0; i < maxboardlen - strlen(b->name); i++) + msg_ginfo(" "); +- if (b->working == OK) +- msg_ginfo("OK "); +- else if (b->working == NT) +- msg_ginfo("NT "); +- else +- msg_ginfo("BAD "); ++ ++ if (b->working == OK) ++ msg_ginfo("OK "); ++ else if (b->working == NT) ++ msg_ginfo("NT "); ++ else ++ msg_ginfo("BAD "); + + for (e = board_matches; e->vendor_name != NULL; e++) { + if (strcmp(e->vendor_name, b->vendor) +@@ -530,6 +531,7 @@ const struct board_info boards_known[] = { + B("abit", "AN-M2", OK, NULL, NULL), + B("abit", "AV8", OK, NULL, NULL), + B("abit", "AX8", OK, NULL, NULL), ++ B("abit", "BF6", OK, NULL, NULL), + B("abit", "BM6", OK, NULL, NULL), + B("abit", "Fatal1ty F-I90HD", OK, NULL, NULL), + B("abit", "IC7", OK, NULL, NULL), +@@ -695,6 +697,7 @@ const struct board_info boards_known[] = { + B("ASUS", "P5L-VM 1394", OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5LVM_1394/", NULL), + B("ASUS", "P5LD2", NT, NULL, "Untested board enable."), + B("ASUS", "P5LD2-VM", NT, "http://www.asus.com/Motherboards/Intel_Socket_775/P5LD2VM/", "Untested board enable."), ++ B("ASUS", "P5LD2-VM DH", OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5LD2VM_DH/", NULL), + B("ASUS", "P5LP-LE (Lithium-UL8E)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c00379616&tmp_task=prodinfoCategory&cc=us&dlc=en&lc=en&product=1159887", "This is an OEM board from HP."), + B("ASUS", "P5LP-LE (Epson OEM)", OK, NULL, "This is an OEM board from Epson (e.g. Endeavor MT7700)."), + B("ASUS", "P5LP-LE", NT, NULL, "This designation is used for OEM boards from HP, Epson and maybe others. The HP names vary and not all of them have been tested yet. Please report any success or failure, thanks."), +diff --git a/programmer.h b/programmer.h +index 4db8d58..d3cc557 100644 +--- a/programmer.h ++++ b/programmer.h +@@ -276,8 +276,11 @@ int processor_flash_enable(void); + + /* physmap.c */ + void *physmap(const char *descr, uintptr_t phys_addr, size_t len); +-void *physmap_try_ro(const char *descr, uintptr_t phys_addr, size_t len); ++void *rphysmap(const char *descr, uintptr_t phys_addr, size_t len); ++void *physmap_ro(const char *descr, uintptr_t phys_addr, size_t len); ++void *physmap_ro_unaligned(const char *descr, uintptr_t phys_addr, size_t len); + void physunmap(void *virt_addr, size_t len); ++void physunmap_unaligned(void *virt_addr, size_t len); + #if CONFIG_INTERNAL == 1 + int setup_cpu_msr(int cpu); + void cleanup_cpu_msr(void); +@@ -287,9 +290,11 @@ int cb_parse_table(const char **vendor, const char **model); + int cb_check_image(uint8_t *bios, int size); + + /* dmi.c */ ++#if defined(__i386__) || defined(__x86_64__) + extern int has_dmi_support; + void dmi_init(void); + int dmi_match(const char *pattern); ++#endif // defined(__i386__) || defined(__x86_64__) + + /* internal.c */ + struct superio { +@@ -550,10 +555,19 @@ int default_spi_write_256(struct flashctx *flash, uint8_t *buf, unsigned int sta + int default_spi_write_aai(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); + int register_spi_programmer(const struct spi_programmer *programmer); + +-/* The following enum is needed by ich_descriptor_tool and ich* code. */ ++/* The following enum is needed by ich_descriptor_tool and ich* code as well as in chipset_enable.c. */ + enum ich_chipset { + CHIPSET_ICH_UNKNOWN, +- CHIPSET_ICH7 = 7, ++#ifdef DELL_AVOTON_SUPPORT ++ CHIPSET_AVOTON, ++#endif ++ CHIPSET_ICH, ++ CHIPSET_ICH2345, ++ CHIPSET_ICH6, ++ CHIPSET_POULSBO, /* SCH U* */ ++ CHIPSET_TUNNEL_CREEK, /* Atom E6xx */ ++ CHIPSET_CENTERTON, /* Atom S1220 S1240 S1260 */ ++ CHIPSET_ICH7, + CHIPSET_ICH8, + CHIPSET_ICH9, + CHIPSET_ICH10, +@@ -563,13 +577,15 @@ enum ich_chipset { + CHIPSET_8_SERIES_LYNX_POINT, + CHIPSET_8_SERIES_LYNX_POINT_LP, + CHIPSET_8_SERIES_WELLSBURG, ++#if DELL_DENVERTON_SUPPORT == 1 ++ CHIPSET_DENVERTON, ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + }; + + /* ichspi.c */ + #if CONFIG_INTERNAL == 1 + extern uint32_t ichspi_bbar; +-int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, +- enum ich_chipset ich_generation); ++int ich_init_spi(struct pci_dev *dev, void *spibar, enum ich_chipset ich_generation); + int via_init_spi(struct pci_dev *dev, uint32_t mmio_base); + + /* amd_imc.c */ +@@ -659,7 +675,7 @@ typedef int fdtype; + + void sp_flush_incoming(void); + fdtype sp_openserport(char *dev, unsigned int baud); +-void __attribute__((noreturn)) sp_die(char *msg); ++int serialport_config(fdtype fd, unsigned int baud); + extern fdtype sp_fd; + /* expose serialport_shutdown as it's currently used by buspirate */ + int serialport_shutdown(void *data); +diff --git a/rayer_spi.c b/rayer_spi.c +index b312610..189341a 100644 +--- a/rayer_spi.c ++++ b/rayer_spi.c +@@ -17,11 +17,9 @@ + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-/* Driver for the SPIPGM hardware by "RayeR" Martin Rehak. +- * See http://rayer.ic.cz/elektro/spipgm.htm for schematics and instructions. +- */ +- +-/* This driver uses non-portable direct I/O port accesses which won't work on ++/* Driver for various LPT adapters. ++ * ++ * This driver uses non-portable direct I/O port accesses which won't work on + * any non-x86 platform, and even on x86 there is a high chance there will be + * collisions with any loaded parallel port drivers. + * The big advantage of direct port I/O is OS independence and speed because +@@ -37,21 +35,87 @@ + #include "programmer.h" + #include "hwaccess.h" + +-enum rayer_type { +- TYPE_RAYER, +- TYPE_XILINX_DLC5, +-}; +- + /* We have two sets of pins, out and in. The numbers for both sets are + * independent and are bitshift values, not real pin numbers. + * Default settings are for the RayeR hardware. + */ +-/* Pins for master->slave direction */ +-static int rayer_cs_bit = 5; +-static int rayer_sck_bit = 6; +-static int rayer_mosi_bit = 7; +-/* Pins for slave->master direction */ +-static int rayer_miso_bit = 6; ++ ++struct rayer_programmer { ++ const char *type; ++ const enum test_state status; ++ const char *description; ++ const void *dev_data; ++}; ++ ++struct rayer_pinout { ++ uint8_t cs_bit; ++ uint8_t sck_bit; ++ uint8_t mosi_bit; ++ uint8_t miso_bit; ++ void (*preinit)(const void *); ++ int (*shutdown)(void *); ++}; ++ ++static const struct rayer_pinout rayer_spipgm = { ++ .cs_bit = 5, ++ .sck_bit = 6, ++ .mosi_bit = 7, ++ .miso_bit = 6, ++}; ++ ++static void dlc5_preinit(const void *); ++static int dlc5_shutdown(void *); ++ ++static const struct rayer_pinout xilinx_dlc5 = { ++ .cs_bit = 2, ++ .sck_bit = 1, ++ .mosi_bit = 0, ++ .miso_bit = 4, ++ .preinit = dlc5_preinit, ++ .shutdown = dlc5_shutdown, ++}; ++ ++static void byteblaster_preinit(const void *); ++static int byteblaster_shutdown(void *); ++ ++static const struct rayer_pinout altera_byteblastermv = { ++ .cs_bit = 1, ++ .sck_bit = 0, ++ .mosi_bit = 6, ++ .miso_bit = 7, ++ .preinit = byteblaster_preinit, ++ .shutdown = byteblaster_shutdown, ++}; ++ ++static void stk200_preinit(const void *); ++static int stk200_shutdown(void *); ++ ++static const struct rayer_pinout atmel_stk200 = { ++ .cs_bit = 7, ++ .sck_bit = 4, ++ .mosi_bit = 5, ++ .miso_bit = 6, ++ .preinit = stk200_preinit, ++ .shutdown = stk200_shutdown, ++}; ++ ++static const struct rayer_pinout wiggler_lpt = { ++ .cs_bit = 1, ++ .sck_bit = 2, ++ .mosi_bit = 3, ++ .miso_bit = 7, ++}; ++ ++static const struct rayer_programmer rayer_spi_types[] = { ++ {"rayer", NT, "RayeR SPIPGM", &rayer_spipgm}, ++ {"xilinx", NT, "Xilinx Parallel Cable III (DLC 5)", &xilinx_dlc5}, ++ {"byteblastermv", OK, "Altera ByteBlasterMV", &altera_byteblastermv}, ++ {"stk200", NT, "Atmel STK200/300 adapter", &atmel_stk200}, ++ {"wiggler", OK, "Wiggler LPT", &wiggler_lpt}, ++ {0}, ++}; ++ ++static const struct rayer_pinout *pinout = NULL; + + static uint16_t lpt_iobase; + +@@ -60,22 +124,22 @@ static uint8_t lpt_outbyte; + + static void rayer_bitbang_set_cs(int val) + { +- lpt_outbyte &= ~(1 << rayer_cs_bit); +- lpt_outbyte |= (val << rayer_cs_bit); ++ lpt_outbyte &= ~(1 << pinout->cs_bit); ++ lpt_outbyte |= (val << pinout->cs_bit); + OUTB(lpt_outbyte, lpt_iobase); + } + + static void rayer_bitbang_set_sck(int val) + { +- lpt_outbyte &= ~(1 << rayer_sck_bit); +- lpt_outbyte |= (val << rayer_sck_bit); ++ lpt_outbyte &= ~(1 << pinout->sck_bit); ++ lpt_outbyte |= (val << pinout->sck_bit); + OUTB(lpt_outbyte, lpt_iobase); + } + + static void rayer_bitbang_set_mosi(int val) + { +- lpt_outbyte &= ~(1 << rayer_mosi_bit); +- lpt_outbyte |= (val << rayer_mosi_bit); ++ lpt_outbyte &= ~(1 << pinout->mosi_bit); ++ lpt_outbyte |= (val << pinout->mosi_bit); + OUTB(lpt_outbyte, lpt_iobase); + } + +@@ -83,8 +147,8 @@ static int rayer_bitbang_get_miso(void) + { + uint8_t tmp; + +- tmp = INB(lpt_iobase + 1); +- tmp = (tmp >> rayer_miso_bit) & 0x1; ++ tmp = INB(lpt_iobase + 1) ^ 0x80; // bit.7 inverted ++ tmp = (tmp >> pinout->miso_bit) & 0x1; + return tmp; + } + +@@ -99,8 +163,8 @@ static const struct bitbang_spi_master bitbang_spi_master_rayer = { + + int rayer_spi_init(void) + { ++ const struct rayer_programmer *prog = rayer_spi_types; + char *arg = NULL; +- enum rayer_type rayer_type = TYPE_RAYER; + + /* Non-default port requested? */ + arg = extract_programmer_param("iobase"); +@@ -138,36 +202,20 @@ int rayer_spi_init(void) + + arg = extract_programmer_param("type"); + if (arg) { +- if (!strcasecmp(arg, "rayer")) { +- rayer_type = TYPE_RAYER; +- } else if (!strcasecmp(arg, "xilinx")) { +- rayer_type = TYPE_XILINX_DLC5; +- } else { ++ for (; prog->type != NULL; prog++) { ++ if (strcasecmp(arg, prog->type) == 0) { ++ break; ++ } ++ } ++ if (prog->type == NULL) { + msg_perr("Error: Invalid device type specified.\n"); + free(arg); + return 1; + } ++ free(arg); + } +- free(arg); +- switch (rayer_type) { +- case TYPE_RAYER: +- msg_pdbg("Using RayeR SPIPGM pinout.\n"); +- /* Bits for master->slave direction */ +- rayer_cs_bit = 5; +- rayer_sck_bit = 6; +- rayer_mosi_bit = 7; +- /* Bits for slave->master direction */ +- rayer_miso_bit = 6; +- break; +- case TYPE_XILINX_DLC5: +- msg_pdbg("Using Xilinx Parallel Cable III (DLC 5) pinout.\n"); +- /* Bits for master->slave direction */ +- rayer_cs_bit = 2; +- rayer_sck_bit = 1; +- rayer_mosi_bit = 0; +- /* Bits for slave->master direction */ +- rayer_miso_bit = 4; +- } ++ msg_pinfo("Using %s pinout.\n", prog->description); ++ pinout = (struct rayer_pinout *)prog->dev_data; + + if (rget_io_perms()) + return 1; +@@ -175,12 +223,60 @@ int rayer_spi_init(void) + /* Get the initial value before writing to any line. */ + lpt_outbyte = INB(lpt_iobase); + ++ if (pinout->shutdown) ++ register_shutdown(pinout->shutdown, (void*)pinout); ++ if (pinout->preinit) ++ pinout->preinit(pinout); ++ + if (bitbang_spi_init(&bitbang_spi_master_rayer)) + return 1; + + return 0; + } + ++static void byteblaster_preinit(const void *data){ ++ msg_pdbg("byteblaster_preinit\n"); ++ /* Assert #EN signal. */ ++ OUTB(2, lpt_iobase + 2 ); ++} ++ ++static int byteblaster_shutdown(void *data){ ++ msg_pdbg("byteblaster_shutdown\n"); ++ /* De-Assert #EN signal. */ ++ OUTB(0, lpt_iobase + 2 ); ++ return 0; ++} ++ ++static void stk200_preinit(const void *data) { ++ msg_pdbg("stk200_init\n"); ++ /* Assert #EN signals, set LED signal. */ ++ lpt_outbyte = (1 << 6) ; ++ OUTB(lpt_outbyte, lpt_iobase); ++} ++ ++static int stk200_shutdown(void *data) { ++ msg_pdbg("stk200_shutdown\n"); ++ /* Assert #EN signals, clear LED signal. */ ++ lpt_outbyte = (1 << 2) | (1 << 3); ++ OUTB(lpt_outbyte, lpt_iobase); ++ return 0; ++} ++ ++static void dlc5_preinit(const void *data) { ++ msg_pdbg("dlc5_preinit\n"); ++ /* Assert pin 6 to receive MISO. */ ++ lpt_outbyte |= (1<<4); ++ OUTB(lpt_outbyte, lpt_iobase); ++} ++ ++static int dlc5_shutdown(void *data) { ++ msg_pdbg("dlc5_shutdown\n"); ++ /* De-assert pin 6 to force MISO low. */ ++ lpt_outbyte &= ~(1<<4); ++ OUTB(lpt_outbyte, lpt_iobase); ++ return 0; ++} ++ + #else + #error PCI port I/O access is not supported on this architecture yet. + #endif +diff --git a/satamv.c b/satamv.c +index c3f27e7..e03508e 100644 +--- a/satamv.c ++++ b/satamv.c +@@ -57,12 +57,6 @@ static const struct par_programmer par_programmer_satamv = { + .chip_writen = fallback_chip_writen, + }; + +-static int satamv_shutdown(void *data) +-{ +- physunmap(mv_bar, 0x20000); +- return 0; +-} +- + /* + * Random notes: + * FCE# Flash Chip Enable +@@ -94,11 +88,11 @@ int satamv_init(void) + return 1; + + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); +- mv_bar = physmap("Marvell 88SX7042 registers", addr, 0x20000); +- if (mv_bar == ERROR_PTR) ++ if (!addr) + return 1; + +- if (register_shutdown(satamv_shutdown, NULL)) ++ mv_bar = rphysmap("Marvell 88SX7042 registers", addr, 0x20000); ++ if (mv_bar == ERROR_PTR) + return 1; + + tmp = pci_mmio_readl(mv_bar + FLASH_PARAM); +@@ -144,12 +138,15 @@ int satamv_init(void) + pci_rmmio_writel(tmp, mv_bar + GPIO_PORT_CONTROL); + + /* Get I/O BAR location. */ +- tmp = pcidev_readbar(dev, PCI_BASE_ADDRESS_2); ++ addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_2); ++ if (!addr) ++ return 1; ++ + /* Truncate to reachable range. + * FIXME: Check if the I/O BAR is actually reachable. + * This is an arch specific check. + */ +- mv_iobar = tmp & 0xffff; ++ mv_iobar = addr & 0xffff; + msg_pspew("Activating I/O BAR at 0x%04x\n", mv_iobar); + + /* 512 kByte with two 8-bit latches, and +diff --git a/satasii.c b/satasii.c +index 72e35e5..83dc62c 100644 +--- a/satasii.c ++++ b/satasii.c +@@ -54,12 +54,6 @@ static const struct par_programmer par_programmer_satasii = { + .chip_writen = fallback_chip_writen, + }; + +-static int satasii_shutdown(void *data) +-{ +- physunmap(sii_bar, SATASII_MEMMAP_SIZE); +- return 0; +-} +- + static uint32_t satasii_wait_done(void) + { + uint32_t ctrl_reg; +@@ -91,21 +85,25 @@ int satasii_init(void) + + if ((id == 0x3132) || (id == 0x3124)) { + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); ++ if (!addr) ++ return 1; + reg_offset = 0x70; + } else { + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_5); ++ if (!addr) ++ return 1; + reg_offset = 0x50; + } + +- sii_bar = physmap("SATA SiI registers", addr, SATASII_MEMMAP_SIZE) + reg_offset; ++ sii_bar = rphysmap("SATA SiI registers", addr, SATASII_MEMMAP_SIZE); ++ if (sii_bar == ERROR_PTR) ++ return 1; ++ sii_bar += reg_offset; + + /* Check if ROM cycle are OK. */ + if ((id != 0x0680) && (!(pci_mmio_readl(sii_bar) & (1 << 26)))) + msg_pwarn("Warning: Flash seems unconnected.\n"); + +- if (register_shutdown(satasii_shutdown, NULL)) +- return 1; +- + register_par_programmer(&par_programmer_satasii, BUS_PARALLEL); + + return 0; +diff --git a/sb600spi.c b/sb600spi.c +index cb7c4ac..9523591 100644 +--- a/sb600spi.c ++++ b/sb600spi.c +@@ -57,7 +57,28 @@ static enum amd_chipset amd_gen = CHIPSET_AMD_UNKNOWN; + static void determine_generation(struct pci_dev *dev) + { + amd_gen = CHIPSET_AMD_UNKNOWN; +- if (dev->device_id == 0x780e) { ++ msg_pdbg2("Trying to determine the generation of the SPI interface... "); ++ if (dev->device_id == 0x438d) { ++ amd_gen = CHIPSET_SB6XX; ++ msg_pdbg("SB6xx detected.\n"); ++ } else if (dev->device_id == 0x439d) { ++ struct pci_dev *smbus_dev = pci_dev_find(0x1002, 0x4385); ++ if (smbus_dev == NULL) ++ return; ++ uint8_t rev = pci_read_byte(smbus_dev, PCI_REVISION_ID); ++ if (rev >= 0x39 && rev <= 0x3D) { ++ amd_gen = CHIPSET_SB7XX; ++ msg_pdbg("SB7xx/SP5100 detected.\n"); ++ } else if (rev >= 0x40 && rev <= 0x42) { ++ amd_gen = CHIPSET_SB89XX; ++ msg_pdbg("SB8xx/SB9xx/Hudson-1 detected.\n"); ++ } else { ++ msg_pwarn("SB device found but SMBus revision 0x%02x does not match known values.\n" ++ "Assuming SB8xx/SB9xx/Hudson-1. Please send a log to flashrom@flashrom.org\n", ++ rev); ++ amd_gen = CHIPSET_SB89XX; ++ } ++ } else if (dev->device_id == 0x780e) { + /* The PCI ID of the LPC bridge doesn't change between Hudson-2/3/4 and Yangtze (Kabini/Temash) + * although they use different SPI interfaces. */ + #ifdef USE_YANGTZE_HEURISTICS +@@ -94,7 +115,11 @@ static void determine_generation(struct pci_dev *dev) + "the output of lspci -nnvx, thanks!.\n", rev); + } + #endif +- } ++ } else ++ msg_pwarn("%s: Unknown LPC device %" PRIx16 ":%" PRIx16 ".\n" ++ "Please report this to flashrom@flashrom.org and include this log and\n" ++ "the output of lspci -nnvx, thanks!\n", ++ __func__, dev->vendor_id, dev->device_id); + } + + static void reset_internal_fifo_pointer(void) +@@ -247,10 +272,66 @@ static int sb600_spi_send_command(struct flashctx *flash, unsigned int writecnt, + return 0; + } + ++struct spispeed { ++ const char *const name; ++ const uint8_t speed; ++}; ++ ++static const struct spispeed spispeeds[] = { ++ { "66 MHz", 0x00 }, ++ { "33 MHz", 0x01 }, ++ { "22 MHz", 0x02 }, ++ { "16.5 MHz", 0x03 }, ++}; ++ ++static int set_speed(struct pci_dev *dev, const struct spispeed *spispeed) ++{ ++ bool success = false; ++ uint8_t speed = spispeed->speed; ++ ++ msg_pdbg("Setting SPI clock to %s (0x%x).\n", spispeed->name, speed); ++ if (amd_gen != CHIPSET_YANGTZE) { ++ rmmio_writeb((mmio_readb(sb600_spibar + 0xd) & ~(0x3 << 4)) | (speed << 4), sb600_spibar + 0xd); ++ success = (speed == ((mmio_readb(sb600_spibar + 0xd) >> 4) & 0x3)); ++ } ++ ++ if (!success) { ++ msg_perr("Setting SPI clock failed.\n"); ++ return 1; ++ } ++ return 0; ++} ++ ++static int handle_speed(struct pci_dev *dev) ++{ ++ uint32_t tmp; ++ int8_t spispeed_idx = 3; /* Default to 16.5 MHz */ ++ ++ /* See the chipset support matrix for SPI Base_Addr below for an explanation of the symbols used. ++ * bit 6xx 7xx/SP5100 8xx 9xx hudson1 hudson234 yangtze ++ * 18 rsvd <- fastReadEnable ? <- ? SpiReadMode[0] ++ * 29:30 rsvd <- <- ? <- ? SpiReadMode[2:1] ++ */ ++ if (amd_gen != CHIPSET_YANGTZE) { ++ if (amd_gen >= CHIPSET_SB89XX && amd_gen <= CHIPSET_HUDSON234) { ++ bool fast_read = (mmio_readl(sb600_spibar + 0x00) >> 18) & 0x1; ++ msg_pdbg("Fast Reads are %sabled\n", fast_read ? "en" : "dis"); ++ if (fast_read) { ++ msg_pdbg("Disabling them temporarily.\n"); ++ rmmio_writel(mmio_readl(sb600_spibar + 0x00) & ~(0x1 << 18), ++ sb600_spibar + 0x00); ++ } ++ } ++ tmp = (mmio_readb(sb600_spibar + 0xd) >> 4) & 0x3; ++ msg_pdbg("NormSpeed is %s\n", spispeeds[tmp].name); ++ } ++ return set_speed(dev, &spispeeds[spispeed_idx]); ++} ++ + static int sb600_handle_imc(struct pci_dev *dev, bool amd_imc_force) + { + /* Handle IMC everywhere but sb600 which does not have one. */ +- if (dev->device_id == 0x438d) ++ if (amd_gen == CHIPSET_SB6XX) + return 0; + + /* TODO: we should not only look at IntegratedImcPresent (LPC Dev 20, Func 3, 40h) but also at +@@ -297,9 +378,6 @@ int sb600_probe_spi(struct pci_dev *dev) + uint32_t tmp; + uint8_t reg; + bool amd_imc_force = false; +- static const char *const speed_names[4] = { +- "66/reserved", "33", "22", "16.5" +- }; + + char *arg = extract_programmer_param("amd_imc_force"); + if (arg && !strcmp(arg, "yes")) { +@@ -326,14 +404,20 @@ int sb600_probe_spi(struct pci_dev *dev) + return 0; + + /* Physical memory has to be mapped at page (4k) boundaries. */ +- sb600_spibar = physmap("SB600 SPI registers", tmp & 0xfffff000, +- 0x1000); ++ sb600_spibar = rphysmap("SB600 SPI registers", tmp & 0xfffff000, 0x1000); ++ if (sb600_spibar == ERROR_PTR) ++ return ERROR_FATAL; ++ + /* The low bits of the SPI base address are used as offset into + * the mapped page. + */ + sb600_spibar += tmp & 0xfff; + + determine_generation(dev); ++ if (amd_gen == CHIPSET_AMD_UNKNOWN) { ++ msg_perr("Could not determine chipset generation."); ++ return ERROR_NONFATAL; ++ } + + if (amd_gen == CHIPSET_YANGTZE) { + msg_perr("SPI on Kabini/Temash and newer chipsets are not yet supported.\n" +@@ -341,34 +425,87 @@ int sb600_probe_spi(struct pci_dev *dev) + return ERROR_NONFATAL; + } + +- tmp = pci_read_long(dev, 0xa0); +- msg_pdbg("AltSpiCSEnable=%i, SpiRomEnable=%i, " +- "AbortEnable=%i\n", tmp & 0x1, (tmp & 0x2) >> 1, +- (tmp & 0x4) >> 2); +- tmp = (pci_read_byte(dev, 0xba) & 0x4) >> 2; +- msg_pdbg("PrefetchEnSPIFromIMC=%i, ", tmp); +- +- tmp = pci_read_byte(dev, 0xbb); +- /* FIXME: Set bit 3,6,7 if not already set. +- * Set bit 5, otherwise SPI accesses are pointless in LPC mode. +- * See doc 42413 AMD SB700/710/750 RPR. ++ /* How to read the following table and similar ones in this file: ++ * "?" means we have no datasheet for this chipset generation or it doesn't have any relevant info. ++ * "<-" means the bit/register meaning is identical to the next non-"?" chipset to the left. "<-" thus ++ * never refers to another "?". ++ * If a "?" chipset is between two chipsets with identical meaning, we assume the meaning didn't change ++ * twice in between, i.e. the meaning is unchanged for the "?" chipset. Usually we assume that ++ * succeeding hardware supports the same functionality as its predecessor unless proven different by ++ * tests or documentation, hence "?" will often be implemented equally to "<-". ++ * ++ * Chipset support matrix for SPI Base_Addr (LPC PCI reg 0xa0) ++ * bit 6xx 7xx/SP5100 8xx 9xx hudson1 hudson2+ yangtze ++ * 3 rsvd <- <- ? <- ? RouteTpm2Spi ++ * 2 rsvd AbortEnable rsvd ? <- ? <- ++ * 1 rsvd SpiRomEnable <- ? <- ? <- ++ * 0 rsvd AltSpiCSEnable rsvd ? <- ? <- + */ +- msg_pdbg("PrefetchEnSPIFromHost=%i, SpiOpEnInLpcMode=%i\n", +- tmp & 0x1, (tmp & 0x20) >> 5); +- tmp = mmio_readl(sb600_spibar); +- /* FIXME: If SpiAccessMacRomEn or SpiHostAccessRomEn are zero on +- * SB700 or later, reads and writes will be corrupted. Abort in this +- * case. Make sure to avoid this check on SB600. ++ if (amd_gen >= CHIPSET_SB7XX) { ++ tmp = pci_read_long(dev, 0xa0); ++ msg_pdbg("SpiRomEnable=%i", (tmp >> 1) & 0x1); ++ if (amd_gen == CHIPSET_SB7XX) ++ msg_pdbg(", AltSpiCSEnable=%i, AbortEnable=%i", tmp & 0x1, (tmp >> 2) & 0x1); ++ ++ tmp = pci_read_byte(dev, 0xba); ++ msg_pdbg(", PrefetchEnSPIFromIMC=%i", (tmp & 0x4) >> 2); ++ ++ tmp = pci_read_byte(dev, 0xbb); ++ /* FIXME: Set bit 3,6,7 if not already set. ++ * Set bit 5, otherwise SPI accesses are pointless in LPC mode. ++ * See doc 42413 AMD SB700/710/750 RPR. ++ */ ++ if (amd_gen == CHIPSET_SB7XX) ++ msg_pdbg(", SpiOpEnInLpcMode=%i", (tmp >> 5) & 0x1); ++ msg_pdbg(", PrefetchEnSPIFromHost=%i\n", tmp & 0x1); ++ } ++ ++ /* Chipset support matrix for SPI_Cntrl0 (spibar + 0x0) ++ * See the chipset support matrix for SPI Base_Addr above for an explanation of the symbols used. ++ * bit 6xx 7xx/SP5100 8xx 9xx hudson1 hudson2+ yangtze ++ * 17 rsvd <- <- ? <- ? <- ++ * 18 rsvd <- fastReadEnable<1> ? <- ? SpiReadMode[0]<1> ++ * 19 SpiArbEnable <- <- ? <- ? <- ++ * 20 (FifoPtrClr) <- <- ? <- ? <- ++ * 21 (FifoPtrInc) <- <- ? <- ? IllegalAccess ++ * 22 SpiAccessMacRomEn <- <- ? <- ? <- ++ * 23 SpiHostAccessRomEn <- <- ? <- ? <- ++ * 24:26 ArbWaitCount <- <- ? <- ? <- ++ * 27 SpiBridgeDisable <- <- ? <- ? rsvd ++ * 28 rsvd DropOneClkOnRd = SPIClkGate ? <- ? <- ++ * 29:30 rsvd <- <- ? <- ? SpiReadMode[2:1]<1> ++ * 31 rsvd <- SpiBusy ? <- ? <- ++ * ++ * <1> see handle_speed + */ +- msg_pdbg("(0x%08" PRIx32 ") fastReadEnable=%u, SpiArbEnable=%i, SpiAccessMacRomEn=%i, " +- "SpiHostAccessRomEn=%i, ArbWaitCount=%i, " +- "SpiBridgeDisable=%i, DropOneClkOnRd=%i\n", +- tmp, (tmp >> 18) & 0x1, +- (tmp >> 19) & 0x1, (tmp >> 22) & 0x1, +- (tmp >> 23) & 0x1, (tmp >> 24) & 0x7, +- (tmp >> 27) & 0x1, (tmp >> 28) & 0x1); +- tmp = (mmio_readb(sb600_spibar + 0xd) >> 4) & 0x3; +- msg_pdbg("NormSpeed is %s MHz\n", speed_names[tmp]); ++ tmp = mmio_readl(sb600_spibar + 0x00); ++ msg_pdbg("(0x%08" PRIx32 ") SpiArbEnable=%i", tmp, (tmp >> 19) & 0x1); ++ ++ msg_pdbg(", SpiAccessMacRomEn=%i, SpiHostAccessRomEn=%i, ArbWaitCount=%i", ++ (tmp >> 22) & 0x1, (tmp >> 23) & 0x1, (tmp >> 24) & 0x7); ++ ++ if (amd_gen != CHIPSET_YANGTZE) ++ msg_pdbg(", SpiBridgeDisable=%i", (tmp >> 27) & 0x1); ++ ++ switch (amd_gen) { ++ case CHIPSET_SB7XX: ++ msg_pdbg(", DropOneClkOnRd/SpiClkGate=%i", (tmp >> 28) & 0x1); ++ case CHIPSET_SB89XX: ++ case CHIPSET_HUDSON234: ++ msg_pdbg(", SpiBusy=%i", (tmp >> 31) & 0x1); ++ default: break; ++ } ++ msg_pdbg("\n"); ++ ++ if (((tmp >> 22) & 0x1) == 0 || ((tmp >> 23) & 0x1) == 0) { ++ msg_perr("ERROR: State of SpiAccessMacRomEn or SpiHostAccessRomEn prohibits full access.\n"); ++ return ERROR_NONFATAL; ++ } ++ ++ if (amd_gen >= CHIPSET_SB89XX) { ++ tmp = mmio_readb(sb600_spibar + 0x1D); ++ msg_pdbg("Using SPI_CS%d\n", tmp & 0x3); ++ } + + /* Look for the SMBus device. */ + smbus_dev = pci_dev_find(0x1002, 0x4385); +@@ -409,6 +546,9 @@ int sb600_probe_spi(struct pci_dev *dev) + return 0; + } + ++ if (handle_speed(dev) != 0) ++ return ERROR_FATAL; ++ + if (sb600_handle_imc(dev, amd_imc_force) != 0) + return ERROR_FATAL; + +diff --git a/serial.c b/serial.c +index 1b394cd..126079a 100644 +--- a/serial.c ++++ b/serial.c +@@ -41,12 +41,6 @@ + + fdtype sp_fd = SER_INV_FD; + +-void __attribute__((noreturn)) sp_die(char *msg) +-{ +- perror(msg); +- exit(1); +-} +- + #ifdef _WIN32 + struct baudentry { + DWORD flag; +@@ -158,35 +152,18 @@ static void msg_perr_strerror(const char *msg) + #endif + } + +-fdtype sp_openserport(char *dev, unsigned int baud) ++int serialport_config(fdtype fd, unsigned int baud) + { +-#ifdef _WIN32 +- HANDLE fd; +- char *dev2 = dev; +- if ((strlen(dev) > 3) && +- (tolower((unsigned char)dev[0]) == 'c') && +- (tolower((unsigned char)dev[1]) == 'o') && +- (tolower((unsigned char)dev[2]) == 'm')) { +- dev2 = malloc(strlen(dev) + 5); +- if (!dev2) { +- msg_perr_strerror("Out of memory: "); +- return SER_INV_FD; +- } +- strcpy(dev2, "\\\\.\\"); +- strcpy(dev2 + 4, dev); +- } +- fd = CreateFile(dev2, GENERIC_READ | GENERIC_WRITE, 0, NULL, +- OPEN_EXISTING, 0, NULL); +- if (dev2 != dev) +- free(dev2); +- if (fd == INVALID_HANDLE_VALUE) { +- msg_perr_strerror("Cannot open serial port: "); +- return SER_INV_FD; ++ if (fd == SER_INV_FD) { ++ msg_perr("%s: File descriptor is invalid.\n", __func__); ++ return 1; + } ++ ++#ifdef _WIN32 + DCB dcb; + if (!GetCommState(fd, &dcb)) { + msg_perr_strerror("Could not fetch original serial port configuration: "); +- goto out_close; ++ return 1; + } + const struct baudentry *entry = round_baud(baud); + dcb.BaudRate = entry->flag; +@@ -195,35 +172,25 @@ fdtype sp_openserport(char *dev, unsigned int baud) + dcb.StopBits = ONESTOPBIT; + if (!SetCommState(fd, &dcb)) { + msg_perr_strerror("Could not change serial port configuration: "); +- goto out_close; ++ return 1; + } + if (!GetCommState(fd, &dcb)) { + msg_perr_strerror("Could not fetch new serial port configuration: "); +- goto out_close; ++ return 1; + } + msg_pdbg("Baud rate is %ld.\n", dcb.BaudRate); +- return fd; +-out_close: +- CloseHandle(sp_fd); +- return SER_INV_FD; + #else + struct termios wanted, observed; +- int fd; +- fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY); +- if (fd < 0) { +- msg_perr_strerror("Cannot open serial port: "); +- return SER_INV_FD; +- } + fcntl(fd, F_SETFL, 0); + if (tcgetattr(fd, &observed) != 0) { + msg_perr_strerror("Could not fetch original serial port configuration: "); +- goto out_close; ++ return 1; + } + wanted = observed; + const struct baudentry *entry = round_baud(baud); + if (cfsetispeed(&wanted, entry->flag) != 0 || cfsetospeed(&wanted, entry->flag) != 0) { + msg_perr_strerror("Could not set serial baud rate: "); +- goto out_close; ++ return 1; + } + wanted.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS); + wanted.c_cflag |= (CS8 | CLOCAL | CREAD); +@@ -232,11 +199,11 @@ out_close: + wanted.c_oflag &= ~OPOST; + if (tcsetattr(fd, TCSANOW, &wanted) != 0) { + msg_perr_strerror("Could not change serial port configuration: "); +- goto out_close; ++ return 1; + } + if (tcgetattr(fd, &observed) != 0) { + msg_perr_strerror("Could not fetch new serial port configuration: "); +- goto out_close; ++ return 1; + } + if (observed.c_cflag != wanted.c_cflag || + observed.c_lflag != wanted.c_lflag || +@@ -244,14 +211,54 @@ out_close: + observed.c_oflag != wanted.c_oflag || + cfgetispeed(&observed) != cfgetispeed(&wanted)) { + msg_perr("%s: Some requested options did not stick.\n", __func__); +- goto out_close; ++ return 1; + } +- msg_pdbg("Baud rate is %d.\n", entry->baud); +- return fd; ++ msg_pdbg("Baud rate is %d now.\n", entry->baud); ++#endif ++ return 0; ++} + +-out_close: +- close(sp_fd); +- return SER_INV_FD; ++fdtype sp_openserport(char *dev, unsigned int baud) ++{ ++ fdtype fd; ++#ifdef _WIN32 ++ char *dev2 = dev; ++ if ((strlen(dev) > 3) && ++ (tolower((unsigned char)dev[0]) == 'c') && ++ (tolower((unsigned char)dev[1]) == 'o') && ++ (tolower((unsigned char)dev[2]) == 'm')) { ++ dev2 = malloc(strlen(dev) + 5); ++ if (!dev2) { ++ msg_perr_strerror("Out of memory: "); ++ return SER_INV_FD; ++ } ++ strcpy(dev2, "\\\\.\\"); ++ strcpy(dev2 + 4, dev); ++ } ++ fd = CreateFile(dev2, GENERIC_READ | GENERIC_WRITE, 0, NULL, ++ OPEN_EXISTING, 0, NULL); ++ if (dev2 != dev) ++ free(dev2); ++ if (fd == INVALID_HANDLE_VALUE) { ++ msg_perr_strerror("Cannot open serial port: "); ++ return SER_INV_FD; ++ } ++ if (serialport_config(fd, baud) != 0) { ++ CloseHandle(fd); ++ return SER_INV_FD; ++ } ++ return fd; ++#else ++ fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY); ++ if (fd < 0) { ++ msg_perr_strerror("Cannot open serial port: "); ++ return SER_INV_FD; ++ } ++ if (serialport_config(fd, baud) != 0) { ++ close(fd); ++ return SER_INV_FD; ++ } ++ return fd; + #endif + } + +@@ -350,7 +357,7 @@ int serialport_write(unsigned char *buf, unsigned int writecnt) + if (!tmp) { + msg_pdbg2("Empty write\n"); + empty_writes--; +- programmer_delay(500); ++ internal_delay(500); + if (empty_writes == 0) { + msg_perr("Serial port is unresponsive!\n"); + return 1; +diff --git a/serprog.c b/serprog.c +index 3476315..35c4f32 100644 +--- a/serprog.c ++++ b/serprog.c +@@ -100,6 +100,7 @@ static int sp_opensocket(char *ip, unsigned int port) + if (NULL == hostPtr) { + hostPtr = gethostbyaddr(ip, strlen(ip), AF_INET); + if (NULL == hostPtr) { ++ close(sock); + msg_perr("Error: cannot resolve %s\n", ip); + return -1; + } +@@ -114,7 +115,11 @@ static int sp_opensocket(char *ip, unsigned int port) + } + /* We are latency limited, and sometimes do write-write-read * + * (write-n) - so enable TCP_NODELAY. */ +- setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); ++ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int))) { ++ close(sock); ++ msg_perr("Error: serprog cannot set socket options: %s\n", strerror(errno)); ++ return -1; ++ } + return sock; + } + #endif +@@ -237,43 +242,58 @@ static int sp_docommand(uint8_t command, uint32_t parmlen, + return 0; + } + +-static void sp_flush_stream(void) ++static int sp_flush_stream(void) + { + if (sp_streamed_transmit_ops) + do { + unsigned char c; + if (serialport_read(&c, 1) != 0) { +- sp_die("Error: cannot read from device (flushing stream)"); ++ msg_perr("Error: cannot read from device (flushing stream)"); ++ return 1; + } + if (c == S_NAK) { + msg_perr("Error: NAK to a stream buffer operation\n"); +- exit(1); ++ return 1; + } + if (c != S_ACK) { + msg_perr("Error: Invalid reply 0x%02X from device\n", c); +- exit(1); ++ return 1; + } + } while (--sp_streamed_transmit_ops); + sp_streamed_transmit_ops = 0; + sp_streamed_transmit_bytes = 0; ++ return 0; + } + +-static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t * parms) ++static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t *parms) + { + uint8_t *sp; + if (sp_automatic_cmdcheck(cmd)) + return 1; ++ + sp = malloc(1 + parmlen); +- if (!sp) sp_die("Error: cannot malloc command buffer"); ++ if (!sp) { ++ msg_perr("Error: cannot malloc command buffer\n"); ++ return 1; ++ } + sp[0] = cmd; + memcpy(&(sp[1]), parms, parmlen); +- if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) +- sp_flush_stream(); +- if (serialport_write(sp, 1 + parmlen) != 0) +- sp_die("Error: cannot write command"); +- free(sp); ++ ++ if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) { ++ if (sp_flush_stream() != 0) { ++ free(sp); ++ return 1; ++ } ++ } ++ if (serialport_write(sp, 1 + parmlen) != 0) { ++ msg_perr("Error: cannot write command\n"); ++ free(sp); ++ return 1; ++ } + sp_streamed_transmit_ops += 1; + sp_streamed_transmit_bytes += 1 + parmlen; ++ ++ free(sp); + return 0; + } + +@@ -656,16 +676,16 @@ int serprog_init(void) + return 0; + } + +-/* Move an in flashrom buffer existing write-n operation to * +- * the on-device operation buffer. */ +-static void sp_pass_writen(void) ++/* Move an in flashrom buffer existing write-n operation to the on-device operation buffer. */ ++static int sp_pass_writen(void) + { + unsigned char header[7]; +- msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", +- sp_write_n_bytes, sp_write_n_addr); +- if (sp_streamed_transmit_bytes >= +- (7 + sp_write_n_bytes + sp_device_serbuf_size)) +- sp_flush_stream(); ++ msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", sp_write_n_bytes, sp_write_n_addr); ++ if (sp_streamed_transmit_bytes >= (7 + sp_write_n_bytes + sp_device_serbuf_size)) { ++ if (sp_flush_stream() != 0) { ++ return 1; ++ } ++ } + /* In case it's just a single byte send it as a single write. */ + if (sp_write_n_bytes == 1) { + sp_write_n_bytes = 0; +@@ -673,9 +693,10 @@ static void sp_pass_writen(void) + header[1] = (sp_write_n_addr >> 8) & 0xFF; + header[2] = (sp_write_n_addr >> 16) & 0xFF; + header[3] = sp_write_n_buf[0]; +- sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header); ++ if (sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header) != 0) ++ return 1; + sp_opbuf_usage += 5; +- return; ++ return 0; + } + header[0] = S_CMD_O_WRITEN; + header[1] = (sp_write_n_bytes >> 0) & 0xFF; +@@ -684,39 +705,55 @@ static void sp_pass_writen(void) + header[4] = (sp_write_n_addr >> 0) & 0xFF; + header[5] = (sp_write_n_addr >> 8) & 0xFF; + header[6] = (sp_write_n_addr >> 16) & 0xFF; +- if (serialport_write(header, 7) != 0) +- sp_die("Error: cannot write write-n command\n"); +- if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) +- sp_die("Error: cannot write write-n data"); ++ if (serialport_write(header, 7) != 0) { ++ msg_perr(MSGHEADER "Error: cannot write write-n command\n"); ++ return 1; ++ } ++ if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) { ++ msg_perr(MSGHEADER "Error: cannot write write-n data"); ++ return 1; ++ } + sp_streamed_transmit_bytes += 7 + sp_write_n_bytes; + sp_streamed_transmit_ops += 1; + sp_opbuf_usage += 7 + sp_write_n_bytes; + sp_write_n_bytes = 0; + sp_prev_was_write = 0; ++ return 0; + } + +-static void sp_execute_opbuf_noflush(void) ++static int sp_execute_opbuf_noflush(void) + { +- if ((sp_max_write_n) && (sp_write_n_bytes)) +- sp_pass_writen(); +- sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL); +- msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", +- sp_opbuf_usage); ++ if ((sp_max_write_n) && (sp_write_n_bytes)) { ++ if (sp_pass_writen() != 0) { ++ msg_perr("Error: could not transfer write buffer\n"); ++ return 1; ++ } ++ } ++ if (sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL) != 0) { ++ msg_perr("Error: could not execute command buffer\n"); ++ return 1; ++ } ++ msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", sp_opbuf_usage); + sp_opbuf_usage = 0; + sp_prev_was_write = 0; +- return; ++ return 0; + } + +-static void sp_execute_opbuf(void) ++static int sp_execute_opbuf(void) + { +- sp_execute_opbuf_noflush(); +- sp_flush_stream(); ++ if (sp_execute_opbuf_noflush() != 0) ++ return 1; ++ if (sp_flush_stream() != 0) ++ return 1; ++ ++ return 0; + } + + static int serprog_shutdown(void *data) + { + if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) +- sp_execute_opbuf(); ++ if (sp_execute_opbuf() != 0) ++ msg_pwarn("Could not flush command buffer.\n"); + if (sp_check_commandavail(S_CMD_S_PIN_STATE)) { + uint8_t dis = 0; + if (sp_docommand(S_CMD_S_PIN_STATE, 1, &dis, 0, NULL) == 0) +@@ -731,14 +768,15 @@ static int serprog_shutdown(void *data) + return 0; + } + +-static void sp_check_opbuf_usage(int bytes_to_be_added) ++static int sp_check_opbuf_usage(int bytes_to_be_added) + { + if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) { +- sp_execute_opbuf(); +- /* If this happens in the mid of an page load the page load * +- * will probably fail. */ +- msg_pdbg(MSGHEADER "Warning: executed operation buffer due to size reasons\n"); ++ /* If this happens in the middle of a page load the page load will probably fail. */ ++ msg_pwarn(MSGHEADER "Warning: executed operation buffer due to size reasons\n"); ++ if (sp_execute_opbuf() != 0) ++ return 1; + } ++ return 0; + } + + static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val, +@@ -768,7 +806,7 @@ static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val, + writeb_parm[1] = (addr >> 8) & 0xFF; + writeb_parm[2] = (addr >> 16) & 0xFF; + writeb_parm[3] = val; +- sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); ++ sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); // FIXME: return error + sp_opbuf_usage += 5; + } + } +@@ -785,16 +823,16 @@ static uint8_t serprog_chip_readb(const struct flashctx *flash, + buf[0] = ((addr >> 0) & 0xFF); + buf[1] = ((addr >> 8) & 0xFF); + buf[2] = ((addr >> 16) & 0xFF); +- sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); +- sp_flush_stream(); ++ sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); // FIXME: return error ++ sp_flush_stream(); // FIXME: return error + if (serialport_read(&c, 1) != 0) +- sp_die("readb byteread"); ++ msg_perr(MSGHEADER "readb byteread"); // FIXME: return error + msg_pspew("%s addr=0x%" PRIxPTR " returning 0x%02X\n", __func__, addr, c); + return c; + } + + /* Local version that really does the job, doesn't care of max_read_n. */ +-static void sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len) ++static int sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len) + { + unsigned char sbuf[6]; + msg_pspew("%s: addr=0x%" PRIxPTR " len=%zu\n", __func__, addr, len); +@@ -808,10 +846,13 @@ static void sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len) + sbuf[4] = ((len >> 8) & 0xFF); + sbuf[5] = ((len >> 16) & 0xFF); + sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf); +- sp_flush_stream(); +- if (serialport_read(buf, len) != 0) +- sp_die("Error: cannot read read-n data"); +- return; ++ if (sp_flush_stream() != 0) ++ return 1; ++ if (serialport_read(buf, len) != 0) { ++ msg_perr(MSGHEADER "Error: cannot read read-n data"); ++ return 1; ++ } ++ return 0; + } + + /* The externally called version that makes sure that max_read_n is obeyed. */ +@@ -821,12 +862,12 @@ static void serprog_chip_readn(const struct flashctx *flash, uint8_t * buf, + size_t lenm = len; + chipaddr addrm = addr; + while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) { +- sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); ++ sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); // FIXME: return error + addrm += sp_max_read_n; + lenm -= sp_max_read_n; + } + if (lenm) +- sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); ++ sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); // FIXME: return error + } + + void serprog_delay(int usecs) +@@ -858,11 +899,18 @@ static int serprog_spi_send_command(struct flashctx *flash, + unsigned char *parmbuf; + int ret; + msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt); +- if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) +- sp_execute_opbuf(); ++ if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) { ++ if (sp_execute_opbuf() != 0) { ++ msg_perr("Error: could not execute command buffer before sending SPI commands.\n"); ++ return 1; ++ } ++ } ++ + parmbuf = malloc(writecnt + 6); +- if (!parmbuf) +- sp_die("Error: cannot malloc SPI send param buffer"); ++ if (!parmbuf) { ++ msg_perr("Error: could not allocate SPI send param buffer.\n"); ++ return 1; ++ } + parmbuf[0] = (writecnt >> 0) & 0xFF; + parmbuf[1] = (writecnt >> 8) & 0xFF; + parmbuf[2] = (writecnt >> 16) & 0xFF; +@@ -879,8 +927,7 @@ static int serprog_spi_send_command(struct flashctx *flash, + /* FIXME: This function is optimized so that it does not split each transaction + * into chip page_size long blocks unnecessarily like spi_read_chunked. This has + * the advantage that it is much faster for most chips, but breaks those with +- * non-contiguous address space (like AT45DB161D). When spi_read_chunked is +- * fixed this method can be removed. */ ++ * non-continuous reads. When spi_read_chunked is fixed this method can be removed. */ + static int serprog_spi_read(struct flashctx *flash, uint8_t *buf, + unsigned int start, unsigned int len) + { +diff --git a/spi25.c b/spi25.c +index e001196..862a865 100644 +--- a/spi25.c ++++ b/spi25.c +@@ -679,7 +679,7 @@ int spi_block_erase_20(struct flashctx *flash, unsigned int addr, + + result = spi_send_multicommand(flash, cmds); + if (result) { +- msg_cerr("%s failed during command execution at address 0x%x\n", ++ msg_pdbg("%s failed during command execution at address 0x%x\n", + __func__, addr); + return result; + } +@@ -1128,13 +1128,9 @@ int default_spi_write_aai(struct flashctx *flash, uint8_t *buf, unsigned int sta + + + result = spi_send_multicommand(flash, cmds); +- if (result) { +- msg_cerr("%s failed during start command execution\n", +- __func__); +- /* FIXME: Should we send WRDI here as well to make sure the chip +- * is not in AAI mode? +- */ +- return result; ++ if (result != 0) { ++ msg_cerr("%s failed during start command execution: %d\n", __func__, result); ++ goto bailout; + } + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(10); +@@ -1146,16 +1142,21 @@ int default_spi_write_aai(struct flashctx *flash, uint8_t *buf, unsigned int sta + while (pos < start + len - 1) { + cmd[1] = buf[pos++ - start]; + cmd[2] = buf[pos++ - start]; +- spi_send_command(flash, JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE, 0, +- cmd, NULL); ++ result = spi_send_command(flash, JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE, 0, cmd, NULL); ++ if (result != 0) { ++ msg_cerr("%s failed during followup AAI command execution: %d\n", __func__, result); ++ goto bailout; ++ } + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(10); + } + +- /* Use WRDI to exit AAI mode. This needs to be done before issuing any +- * other non-AAI command. +- */ +- spi_write_disable(flash); ++ /* Use WRDI to exit AAI mode. This needs to be done before issuing any other non-AAI command. */ ++ result = spi_write_disable(flash); ++ if (result != 0) { ++ msg_cerr("%s failed to disable AAI mode.\n", __func__); ++ return SPI_GENERIC_ERROR; ++ } + + /* Write remaining byte (if any). */ + if (pos < start + len) { +@@ -1165,4 +1166,10 @@ int default_spi_write_aai(struct flashctx *flash, uint8_t *buf, unsigned int sta + } + + return 0; ++ ++bailout: ++ result = spi_write_disable(flash); ++ if (result != 0) ++ msg_cerr("%s failed to disable AAI mode.\n", __func__); ++ return SPI_GENERIC_ERROR; + } +diff --git a/spi25_statusreg.c b/spi25_statusreg.c +index 8fb7f2d..48fceb0 100644 +--- a/spi25_statusreg.c ++++ b/spi25_statusreg.c +@@ -270,7 +270,7 @@ static void spi_prettyprint_status_register_bp(uint8_t status, int bp) + } + + /* Unnamed bits. */ +-static void spi_prettyprint_status_register_bit(uint8_t status, int bit) ++void spi_prettyprint_status_register_bit(uint8_t status, int bit) + { + msg_cdbg("Chip status register: Bit %i is %sset\n", bit, (status & (1 << bit)) ? "" : "not "); + } +diff --git a/stm50.c b/stm50.c +new file mode 100644 +index 0000000..edcfdd2 +--- /dev/null ++++ b/stm50.c +@@ -0,0 +1,115 @@ ++/* ++ * This file is part of the flashrom project. ++ * ++ * Copyright (C) 2008 Claus Gindhart ++ * Copyright (C) 2009 Sean Nelson ++ * Copyright (C) 2013 Stefan Tauner ++ * ++ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * All ST M50 chips are locked on startup. Most of them have a uniform 64 kB block layout, but some have ++ * a non-uniform block/sector segmentation which has to be handled with more care. Some of the non-uniform ++ * chips support erasing of the 4 kB sectors with another command. ++ */ ++ ++#include "flash.h" ++#include "flashchips.h" ++#include "chipdrivers.h" ++ ++static int stm50_unlock_address(struct flashctx *flash, int offset) ++{ ++ chipaddr wrprotect = flash->virtual_registers + 2; ++ static const uint8_t unlock_sector = 0x00; ++ msg_cdbg("unlocking at 0x%x\n", offset); ++ chip_writeb(flash, unlock_sector, wrprotect + offset); ++ if (chip_readb(flash, wrprotect + offset) != unlock_sector) { ++ msg_cerr("Cannot unlock address 0x%x\n", offset); ++ return -1; ++ } ++ return 0; ++} ++ ++/* Chips known to use a non-uniform block and sector layout for locking (as well as for erasing): ++ * Name Size Address range of lock registers ++ * M50FLW080A 1MB FFB00002 - FFBFF002 ++ * M50FLW080B 1MB FFB00002 - FFBFF002 ++ * M50FW002 256k FFBC0002 - FFBFC002 ++ * M50LPW116 2MB FFA00002 - FFBFC002 ++ */ ++int unlock_stm50_nonuniform(struct flashctx *flash) ++{ ++ int i; ++ struct eraseblock *eraseblocks = flash->chip->block_erasers[0].eraseblocks; ++ unsigned int done = 0; ++ for (i = 0; i < NUM_ERASEREGIONS && eraseblocks[i].count != 0; i++) { ++ unsigned int block_size = eraseblocks[i].size; ++ unsigned int block_count = eraseblocks[i].count; ++ ++ int j; ++ for (j = 0; j < block_count; j++) { ++ if (stm50_unlock_address(flash, done)) { ++ msg_cerr("UNLOCK FAILED!\n"); ++ return -1; ++ } ++ done += block_count * block_size; ++ } ++ } ++ return 0; ++} ++ ++/* Unlocking for uniform 64 kB blocks starting at offset 2 of the feature registers. */ ++int unlock_stm50_uniform(struct flashctx *flash) ++{ ++ int i; ++ for (i = 0; i < flash->chip->total_size * 1024; i+= 64 * 1024) { ++ if (stm50_unlock_address(flash, i)) { ++ msg_cerr("UNLOCK FAILED!\n"); ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++static int stm50_erase_sector(struct flashctx *flash, unsigned int addr) ++{ ++ chipaddr bios = flash->virtual_memory + addr; ++ ++ // clear status register ++ chip_writeb(flash, 0x50, bios); ++ // now start it ++ chip_writeb(flash, 0x32, bios); ++ chip_writeb(flash, 0xd0, bios); ++ programmer_delay(10); ++ ++ uint8_t status = wait_82802ab(flash); ++ print_status_82802ab(status); ++ ++ return status == 0x80; ++} ++ ++/* Some ST M50* chips do support erasing of sectors. This function will derive the erase function to use from ++ * the length of the of the block. For calls that apparently do not address a sector (but a block) we just call ++ * the block erase function instead. FIXME: This duplicates the behavior of the remaining erasers for blocks and ++ * might be fixed when flashrom supports multiple functions per eraser or erasers that do erase parts of the ++ * chip only. */ ++int erase_sector_stm50(struct flashctx *flash, unsigned int addr, unsigned int len) ++{ ++ if (len == 4096) ++ return stm50_erase_sector(flash, addr); ++ else ++ return erase_block_82802ab(flash, addr, len); ++} +diff --git a/udelay.c b/udelay.c +index e3cf3e3..9d3bfc2 100644 +--- a/udelay.c ++++ b/udelay.c +@@ -90,7 +90,11 @@ void myusec_calibrate_delay(void) + unsigned long timeusec, resolution; + int i, tries = 0; + ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("Calibrating delay loop... "); ++#else + msg_pinfo("Calibrating delay loop... "); ++#endif + resolution = measure_os_delay_resolution(); + if (resolution) { + msg_pdbg("OS timer resolution is %lu usecs, ", resolution); +@@ -151,7 +155,7 @@ recalibrate: + } + } + } else { +- msg_perr("delay loop is unreliable, trying to continue "); ++ msg_pdbg("delay loop is unreliable, trying to continue "); + } + + /* We're interested in the actual precision. */ +@@ -166,7 +170,11 @@ recalibrate: + timeusec = measure_delay(resolution * 4); + msg_pdbg("%ld myus = %ld us, ", resolution * 4, timeusec); + ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("OK.\n"); ++#else + msg_pinfo("OK.\n"); ++#endif + } + + /* Not very precise sleep. */ +diff --git a/util/getrevision.sh b/util/getrevision.sh +new file mode 100755 +index 0000000..709e45f +--- /dev/null ++++ b/util/getrevision.sh +@@ -0,0 +1,311 @@ ++#!/bin/sh ++# ++# This file is part of the flashrom project. ++# ++# Copyright (C) 2005 coresystems GmbH ++# Copyright (C) 2009,2010 Carl-Daniel Hailfinger ++# Copyright (C) 2010 Chromium OS Authors ++# Copyright (C) 2013 Stefan Tauner ++# ++# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++# ++ ++EXIT_SUCCESS=0 ++EXIT_FAILURE=1 ++ ++# Make sure we don't get translated output ++export LC_ALL=C ++# nor local times or dates ++export TZ=UTC0 ++ ++# Helper functions ++# First argument is the path to inspect (usually optional; w/o it the whole repository will be considered) ++svn_has_local_changes() { ++ svn status "$1" | egrep '^ *[ADMR] *' >/dev/null ++} ++ ++git_has_local_changes() { ++ git update-index -q --refresh >/dev/null ++ ! git diff-index --quiet HEAD -- "$1" ++} ++ ++git_last_commit() { ++ git log --pretty=format:"%h" -1 -- "$1" ++} ++ ++svn_is_file_tracked() { ++ svn info "$1" >/dev/null 2>&1 ++} ++ ++git_is_file_tracked() { ++ git ls-files --error-unmatch -- "$1" >/dev/null 2>&1 ++} ++ ++is_file_tracked() { ++ svn_is_file_tracked "$1" || git_is_file_tracked "$1" ++} ++ ++# Tries to find a remote source for the changes committed locally. ++# This includes the URL of the remote repository including the last commit and a suitable branch name. ++# Takes one optional argument: the path to inspect ++git_url() { ++ last_commit=$(git_last_commit "$1") ++ # get all remote branches containing the last commit (excluding origin/HEAD and git-svn branches/tags) ++ branches=$(git branch -r --contains $last_commit | sed '/\//!d;/.*->.*/d;s/[\t ]*//') ++ if [ -z "$branches" ] ; then ++ echo "No remote branch contains a suitable commit">&2 ++ return ++ fi ++ ++ # find "nearest" branch ++ local mindiff=9000 ++ local target= ++ for branch in $branches ; do ++ curdiff=$(git rev-list --count $last_commit..$branch) ++ if [ $curdiff -ge $mindiff ] ; then ++ continue ++ fi ++ mindiff=$curdiff ++ target=$branch ++ done ++ ++ echo "$(git ls-remote --exit-code --get-url ${target%/*}) ${target#*/}" ++} ++ ++# Returns a string indicating where others can get the current source code (excluding uncommitted changes) ++# Takes one optional argument: the path to inspect ++scm_url() { ++ local url= ++ ++ # for a primitive VCS like subversion finding the URL is easy: there is only one upstream host ++ if svn_is_file_tracked "$1" ; then ++ url="$(svn info "$1" 2>/dev/null | ++ grep URL: | ++ sed 's/.*URL:[[:blank:]]*//;s/:\/\/.*@/:\/\//' | ++ grep ^.)" ++ elif git_is_file_tracked "$1" ; then ++ url="$(git_url "$1")" ++ else ++ return ${EXIT_FAILURE} ++ fi ++ ++ echo "${url}" ++} ++ ++# Retrieve timestamp since last modification. If the sources are pristine, ++# then the timestamp will match that of the SCM's most recent modification ++# date. ++timestamp() { ++ local t ++ ++ # date syntaxes are manifold: ++ # gnu date [-d input]... [+FORMAT] ++ # netbsd date [-ajnu] [-d date] [-r seconds] [+format] [[[[[[CC]yy]mm]dd]HH]MM[.SS]] ++ # freebsd date [-jnu] [-d dst] [-r seconds] [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] [...] ++ # dragonflybsd date [-jnu] [-d dst] [-r seconds] [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] [...] ++ # openbsd date [-aju] [-d dst] [-r seconds] [+format] [[[[[[cc]yy]mm]dd]HH]MM[.SS]] [...] ++ if svn_is_file_tracked "$2" ; then ++ if svn_has_local_changes "$2"; then ++ t=$(date -u "$1") ++ else ++ # No local changes, get date of the last log record. Subversion provides that in ++ # ISO 8601 format when using the --xml switch. The sed call extracts that ignoring any ++ # fractional parts started by a comma or a dot. ++ local last_commit_date="$(svn info --xml "$2"| \ ++ sed -n -e 's/\([^,\.]*\)\([\.,].*\)*Z<\/date>/\1Z/p')" ++ ++ case $(uname) in ++ # Most BSD dates do not support parsing date values from user input with -d but all of ++ # them support parsing the syntax with [[[[[[cc]yy]mm]dd]HH]MM[.ss]]. We have to ++ # transform the ISO8601 date first though. ++ NetBSD|OpenBSD|DragonFly|FreeBSD) ++ last_commit_date="$(echo ${last_commit_date} | \ ++ sed -n -e 's/\(....\)-\(..\)-\(..\)T\(..\):\(..\):\(..\)Z/\1\2\3\4\5\.\6/p')" ++ t=$(date -u -j "${last_commit_date}" "$1" 2>/dev/null);; ++ *) ++ t=$(date -u -d "${last_commit_date}" "$1" 2>/dev/null);; ++ esac ++ fi ++ elif git_is_file_tracked "$2" ; then ++ # are there local changes? ++ if git_has_local_changes "$2" ; then ++ t=$(date -u "${1}") ++ else ++ # No local changes, get date of the last commit ++ case $(uname) in ++ # Most BSD dates do not support parsing date values from user input with -d but all of ++ # them support parsing epoch seconds with -r. Thanks to git we can easily use that: ++ NetBSD|OpenBSD|DragonFly|FreeBSD) ++ t=$(date -u -r "$(git log --pretty=format:%ct -1 -- $2)" "$1" 2>/dev/null);; ++ *) ++ t=$(date -d "$(git log --pretty=format:%cD -1 -- $2)" -u "$1" 2>/dev/null);; ++ esac ++ fi ++ else ++ t=$(date -u "$1") ++ fi ++ ++ if [ -z "$t" ]; then ++ echo "Warning: Could not determine timestamp." 2>/dev/null ++ fi ++ echo "${t}" ++} ++ ++# Retrieve local SCM revision info. This is useful if we're working in a different SCM than upstream and/or ++# have local changes. ++local_revision() { ++ local r= ++ ++ if svn_is_file_tracked "$1" ; then ++ r=$(svn_has_local_changes "$1" && echo "dirty") ++ elif git_is_file_tracked "$1" ; then ++ r=$(git_last_commit "$1") ++ ++ local svn_base=$(git log --grep git-svn-id -1 --format='%h') ++ if [ "$svn_base" != "" ] ; then ++ local diff_to_svn=$(git rev-list --count ${svn_base}..${r}) ++ if [ "$diff_to_svn" -gt 0 ] ; then ++ r="$r-$diff_to_svn" ++ fi ++ fi ++ ++ if git_has_local_changes "$1" ; then ++ r="$r-dirty" ++ fi ++ else ++ return ${EXIT_FAILURE} ++ fi ++ ++ echo "${r}" ++} ++ ++# Get the upstream flashrom revision stored in SVN metadata. ++upstream_revision() { ++ local r= ++ ++ if svn_is_file_tracked "$1" ; then ++ r=$(svn info "$1" 2>/dev/null | \ ++ grep "Last Changed Rev:" | \ ++ sed -e "s/^Last Changed Rev: *//" -e "s/\([0-9]*\).*/r\1/" | \ ++ grep "r[0-9]") ++ elif git_is_file_tracked "$1" ; then ++ # If this is a "native" git-svn clone we could use git svn log: ++ # git svn log --oneline -1 | sed 's/^r//;s/[[:blank:]].*//' or even git svn find-rev ++ # but it is easier to just grep for the git-svn-id unconditionally ++ r=$(git log --grep git-svn-id -1 -- "$1" | \ ++ grep git-svn-id | \ ++ sed 's/.*@/r/;s/[[:blank:]].*//') ++ fi ++ ++ if [ -z "$r" ]; then ++ r="unknown" # default to unknown ++ fi ++ echo "${r}" ++} ++ ++show_help() { ++ echo "Usage: ++ ${0} [path] ++ ++Commands ++ -h or --help ++ this message ++ -l or --local ++ local revision information including an indicator for uncommitted changes ++ -u or --upstream ++ upstream revision ++ -U or --url ++ URL associated with the latest commit ++ -d or --date ++ date of most recent modification ++ -t or --timestamp ++ timestamp of most recent modification ++" ++ return ++} ++ ++check_action() { ++ if [ -n "$action" ]; then ++ echo "Error: Multiple actions given.">&2 ++ exit ${EXIT_FAILURE} ++ fi ++} ++ ++main() { ++ local query_path= ++ local action= ++ ++ # The is the main loop ++ while [ $# -gt 0 ]; ++ do ++ case ${1} in ++ -h|--help) ++ action=show_help; ++ shift;; ++ -l|--local) ++ check_action $1 ++ action=local_revision ++ shift;; ++ -u|--upstream) ++ check_action $1 ++ action=upstream_revision ++ shift;; ++ -U|--url) ++ check_action $1 ++ action=scm_url ++ shift;; ++ -d|--date) ++ check_action $1 ++ action="timestamp +%Y-%m-%d" # refrain from suffixing 'Z' to indicate it's UTC ++ shift;; ++ -t|--timestamp) ++ check_action $1 ++ action="timestamp +%Y-%m-%dT%H:%M:%SZ" # There is only one valid time format! ISO 8601 ++ shift;; ++ -*) ++ show_help; ++ echo "Error: Invalid option: ${1}" ++ exit ${EXIT_FAILURE};; ++ *) ++ if [ -z "$query_path" ] ; then ++ if [ ! -e "$1" ] ; then ++ echo "Error: Path \"${1}\" does not exist.">&2 ++ exit ${EXIT_FAILURE} ++ fi ++ query_path=$1 ++ else ++ echo "Warning: Ignoring over-abundant paramter: \"${1}\"">&2 ++ fi ++ shift;; ++ esac; ++ done ++ ++ # default to current directory (usually equals the whole repository) ++ if [ -z "$query_path" ] ; then ++ query_path=. ++ fi ++ if ! is_file_tracked "$query_path" ; then ++ echo "Warning: Path \"${query_path}\" is not under version control.">&2 ++ fi ++ if [ -z "$action" ] ; then ++ show_help ++ echo "Error: No actions specified" ++ exit ${EXIT_FAILURE} ++ fi ++ ++ $action "$query_path" ++} ++ ++main $@ +diff --git a/util/ich_descriptors_tool/ich_descriptors_tool.c b/util/ich_descriptors_tool/ich_descriptors_tool.c +index c359913..dd35860 100644 +--- a/util/ich_descriptors_tool/ich_descriptors_tool.c ++++ b/util/ich_descriptors_tool/ich_descriptors_tool.c +@@ -77,12 +77,13 @@ static void dump_file(const char *prefix, const uint32_t *dump, unsigned int len + printf("Dumping %u bytes of the %s region from 0x%08x-0x%08x to %s... ", + file_len, region_names[i], base, limit, fn); + int fh = open(fn, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); +- free(fn); + if (fh < 0) { + fprintf(stderr, + "ERROR: couldn't open(%s): %s\n", fn, strerror(errno)); ++ free(fn); + exit(1); + } ++ free(fn); + + ret = write(fh, &dump[base >> 2], file_len); + if (ret != file_len) { +@@ -120,6 +121,7 @@ static void usage(char *argv[], char *error) + "\t- \"5\" or \"ibex\" for Intel's 5 series chipsets,\n" + "\t- \"6\" or \"cougar\" for Intel's 6 series chipsets,\n" + "\t- \"7\" or \"panther\" for Intel's 7 series chipsets.\n" ++"\t- \"avoton\",\n" + "If '-d' is specified some regions such as the BIOS image as seen by the CPU or\n" + "the GbE blob that is required to initialize the GbE are also dumped to files.\n", + argv[0], argv[0]); +@@ -197,6 +199,10 @@ int main(int argc, char *argv[]) + else if ((strcmp(csn, "7") == 0) || + (strcmp(csn, "panther") == 0)) + cs = CHIPSET_7_SERIES_PANTHER_POINT; ++#ifdef DELL_AVOTON_SUPPORT ++ else if (strcmp(csn, "avoton") == 0) ++ cs = CHIPSET_AVOTON; ++#endif + } + + ret = read_ich_descriptors_from_dump(buf, len, &desc); +diff --git a/util/z60_flashrom.rules b/util/z60_flashrom.rules +index 8456a04..948563c 100644 +--- a/util/z60_flashrom.rules ++++ b/util/z60_flashrom.rules +@@ -80,4 +80,8 @@ ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="664", GROUP="plugdev" + # http://www.diygadget.com/tiao-usb-multi-protocol-adapter-jtag-spi-i2c-serial.html + ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", MODE="664", GROUP="plugdev" + ++# TIAO/DIYGADGET USB Multi-Protocol Adapter (TUMPA) Lite ++# http://www.tiaowiki.com/w/TIAO_USB_Multi_Protocol_Adapter_Lite_User's_Manual ++ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a99", MODE="664", GROUP="plugdev" ++ + LABEL="flashrom_rules_end" +-- +2.7.4 + diff --git a/platform/broadcom/sonic-platform-modules-dell/tools/flashrom.sh b/platform/broadcom/sonic-platform-modules-dell/tools/flashrom.sh new file mode 100755 index 00000000000..c3af65fd6d8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/tools/flashrom.sh @@ -0,0 +1,10 @@ +#!/bin/bash +export DELL_TOOLS_DIR="platform/broadcom/sonic-platform-modules-dell/tools" + +cd $DELL_TOOLS_DIR +rm -rf $DELL_TOOLS_DIR/flashrom +git clone https://github.com/flashrom/flashrom.git +cd flashrom +git checkout tags/0.9.7 +git apply ../0002-Flashrom-support-for-Intel-Rangeley-and-Denverton-CP.patch +make diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/systemd/z9100-lpc-monitor.service b/platform/broadcom/sonic-platform-modules-dell/z9100/systemd/z9100-lpc-monitor.service new file mode 100644 index 00000000000..136081a63f3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/systemd/z9100-lpc-monitor.service @@ -0,0 +1,12 @@ +[Unit] +Description=Dell Z9100 LPC bus monitoring poller +DefaultDependencies=no + +[Service] +User=root +ExecStart=/usr/local/bin/dell_lpc_mon.sh +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target + diff --git a/platform/cavium/docker-syncd-cavm.mk b/platform/cavium/docker-syncd-cavm.mk index 52f81e1b9b2..2ae78a07d25 100644 --- a/platform/cavium/docker-syncd-cavm.mk +++ b/platform/cavium/docker-syncd-cavm.mk @@ -10,3 +10,4 @@ $(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $(SYNCD_DBG) \ $(LIBSAIMETADATA_DBG) \ $(LIBSAIREDIS_DBG) +$(DOCKER_SYNCD_CAVM)_BASE_IMAGE_FILES += monit_syncd:/etc/monit/conf.d diff --git a/platform/cavium/docker-syncd-cavm/base_image_files/monit_syncd b/platform/cavium/docker-syncd-cavm/base_image_files/monit_syncd new file mode 100644 index 00000000000..3079618990e --- /dev/null +++ b/platform/cavium/docker-syncd-cavm/base_image_files/monit_syncd @@ -0,0 +1,7 @@ +############################################################################### +## Monit configuration for syncd container +## process list: +## syncd +############################################################################### +check process syncd matching "/usr/bin/syncd" + if does not exist for 5 times within 5 cycles then alert diff --git a/platform/centec/docker-syncd-centec.mk b/platform/centec/docker-syncd-centec.mk index 9e1fbef160f..6dd58354d64 100644 --- a/platform/centec/docker-syncd-centec.mk +++ b/platform/centec/docker-syncd-centec.mk @@ -11,3 +11,4 @@ $(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $(SYNCD_DBG) \ $(LIBSAIREDIS_DBG) $(DOCKER_SYNCD_CENTEC)_RUN_OPT += -v /var/run/docker-syncd:/var/run/sswsyncd +$(DOCKER_SYNCD_CENTEC)_BASE_IMAGE_FILES += monit_syncd:/etc/monit/conf.d diff --git a/platform/centec/docker-syncd-centec/base_image_files/monit_syncd b/platform/centec/docker-syncd-centec/base_image_files/monit_syncd new file mode 100644 index 00000000000..3079618990e --- /dev/null +++ b/platform/centec/docker-syncd-centec/base_image_files/monit_syncd @@ -0,0 +1,7 @@ +############################################################################### +## Monit configuration for syncd container +## process list: +## syncd +############################################################################### +check process syncd matching "/usr/bin/syncd" + if does not exist for 5 times within 5 cycles then alert diff --git a/platform/marvell-arm64/docker-syncd-mrvl/base_image_files/monit_syncd b/platform/marvell-arm64/docker-syncd-mrvl/base_image_files/monit_syncd new file mode 100644 index 00000000000..3079618990e --- /dev/null +++ b/platform/marvell-arm64/docker-syncd-mrvl/base_image_files/monit_syncd @@ -0,0 +1,7 @@ +############################################################################### +## Monit configuration for syncd container +## process list: +## syncd +############################################################################### +check process syncd matching "/usr/bin/syncd" + if does not exist for 5 times within 5 cycles then alert diff --git a/platform/marvell-armhf/docker-syncd-mrvl/base_image_files/monit_syncd b/platform/marvell-armhf/docker-syncd-mrvl/base_image_files/monit_syncd new file mode 100644 index 00000000000..3079618990e --- /dev/null +++ b/platform/marvell-armhf/docker-syncd-mrvl/base_image_files/monit_syncd @@ -0,0 +1,7 @@ +############################################################################### +## Monit configuration for syncd container +## process list: +## syncd +############################################################################### +check process syncd matching "/usr/bin/syncd" + if does not exist for 5 times within 5 cycles then alert diff --git a/platform/marvell/docker-syncd-mrvl.mk b/platform/marvell/docker-syncd-mrvl.mk index a3f6017c012..a1808c04c0e 100644 --- a/platform/marvell/docker-syncd-mrvl.mk +++ b/platform/marvell/docker-syncd-mrvl.mk @@ -13,3 +13,4 @@ $(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $(SYNCD_DBG) \ $(LIBSAIREDIS_DBG) +$(DOCKER_SYNCD_BASE)_BASE_IMAGE_FILES += monit_syncd:/etc/monit/conf.d diff --git a/platform/marvell/docker-syncd-mrvl/base_image_files/monit_syncd b/platform/marvell/docker-syncd-mrvl/base_image_files/monit_syncd new file mode 100644 index 00000000000..3079618990e --- /dev/null +++ b/platform/marvell/docker-syncd-mrvl/base_image_files/monit_syncd @@ -0,0 +1,7 @@ +############################################################################### +## Monit configuration for syncd container +## process list: +## syncd +############################################################################### +check process syncd matching "/usr/bin/syncd" + if does not exist for 5 times within 5 cycles then alert diff --git a/platform/mellanox/cpld.mk b/platform/mellanox/cpld.mk index 0a03b3c54a9..385308e0043 100644 --- a/platform/mellanox/cpld.mk +++ b/platform/mellanox/cpld.mk @@ -4,6 +4,7 @@ MLNX_SN2700_CPLD_ARCHIVE = msn2700_cpld.tar.gz $(MLNX_SN2700_CPLD_ARCHIVE)_PATH = platform/mellanox/cpld/ SONIC_COPY_FILES += $(MLNX_SN2700_CPLD_ARCHIVE) -MLNX_CPLD_ARCHIVES += $(MLNX_SN2700_CPLD_ARCHIVE) +MLNX_CPLD_ARCHIVES = $(MLNX_SN2700_CPLD_ARCHIVE) +MLNX_FILES += $(MLNX_CPLD_ARCHIVES) export MLNX_CPLD_ARCHIVES diff --git a/platform/mellanox/cpld/msn2700_cpld.tar.gz b/platform/mellanox/cpld/msn2700_cpld.tar.gz index 81d99d04dda..0af78f26437 100644 Binary files a/platform/mellanox/cpld/msn2700_cpld.tar.gz and b/platform/mellanox/cpld/msn2700_cpld.tar.gz differ diff --git a/platform/mellanox/docker-syncd-mlnx.mk b/platform/mellanox/docker-syncd-mlnx.mk index a4eac46d48a..57a625aac36 100644 --- a/platform/mellanox/docker-syncd-mlnx.mk +++ b/platform/mellanox/docker-syncd-mlnx.mk @@ -6,3 +6,4 @@ include $(PLATFORM_PATH)/../template/docker-syncd-base.mk $(DOCKER_SYNCD_BASE)_DEPENDS += $(SYNCD) $(PYTHON_SDK_API) $(MLNX_SFPD) $(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $(SYNCD_DBG) $(LIBSWSSCOMMON_DBG) $(LIBSAIMETADATA_DBG) $(LIBSAIREDIS_DBG) $(DOCKER_SYNCD_BASE)_RUN_OPT += -v /host/warmboot:/var/warmboot +$(DOCKER_SYNCD_BASE)_BASE_IMAGE_FILES += monit_syncd:/etc/monit/conf.d diff --git a/platform/mellanox/docker-syncd-mlnx/base_image_files/monit_syncd b/platform/mellanox/docker-syncd-mlnx/base_image_files/monit_syncd new file mode 100644 index 00000000000..3079618990e --- /dev/null +++ b/platform/mellanox/docker-syncd-mlnx/base_image_files/monit_syncd @@ -0,0 +1,7 @@ +############################################################################### +## Monit configuration for syncd container +## process list: +## syncd +############################################################################### +check process syncd matching "/usr/bin/syncd" + if does not exist for 5 times within 5 cycles then alert diff --git a/platform/mellanox/fw.mk b/platform/mellanox/fw.mk index 18b2d2dd54c..63659060163 100644 --- a/platform/mellanox/fw.mk +++ b/platform/mellanox/fw.mk @@ -1,9 +1,12 @@ -# mellanox firmware +# mellanox asic firmware -MLNX_FW_VERSION = 13.2000.1636 -MLNX_FW_FILE = fw-SPC-rel-$(subst .,_,$(MLNX_FW_VERSION))-EVB.mfa -$(MLNX_FW_FILE)_URL = $(MLNX_SDK_BASE_URL)/$(MLNX_FW_FILE) -SONIC_ONLINE_FILES += $(MLNX_FW_FILE) +MLNX_SPC_FW_VERSION = 13.2000.1658 +MLNX_SPC_FW_FILE = fw-SPC-rel-$(subst .,_,$(MLNX_SPC_FW_VERSION))-EVB.mfa +$(MLNX_SPC_FW_FILE)_URL = $(MLNX_SDK_BASE_URL)/$(MLNX_SPC_FW_FILE) +SONIC_ONLINE_FILES += $(MLNX_SPC_FW_FILE) -export MLNX_FW_VERSION -export MLNX_FW_FILE +MLNX_FW_FILES = $(MLNX_SPC_FW_FILE) +MLNX_FILES += $(MLNX_FW_FILES) + +export MLNX_SPC_FW_VERSION +export MLNX_SPC_FW_FILE diff --git a/platform/mellanox/hw-management-wd.mk b/platform/mellanox/hw-management-wd.mk new file mode 100644 index 00000000000..a0f3271fa79 --- /dev/null +++ b/platform/mellanox/hw-management-wd.mk @@ -0,0 +1,9 @@ +# Mellanox script for enabling/disabling hardware watchdog + +HW_MANAGEMENT_WD_SCRIPT = hw-management-wd.sh +$(HW_MANAGEMENT_WD_SCRIPT)_PATH = platform/mellanox/ +SONIC_COPY_FILES += $(HW_MANAGEMENT_WD_SCRIPT) + +MLNX_FILES += $(HW_MANAGEMENT_WD_SCRIPT) + +export HW_MANAGEMENT_WD_SCRIPT diff --git a/platform/mellanox/hw-management-wd.sh b/platform/mellanox/hw-management-wd.sh new file mode 100755 index 00000000000..75a467f4cf3 --- /dev/null +++ b/platform/mellanox/hw-management-wd.sh @@ -0,0 +1,182 @@ +#!/bin/sh +######################################################################## +# Copyright (c) 2020 Mellanox Technologies. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the names of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# Alternatively, this software may be distributed under the terms of the +# GNU General Public License ("GPL") version 2 as published by the Free +# Software Foundation. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +# Description: hw-management watchdog actions script. +# It uses direct access to CPLD watchdog mechanism. +# 1. Start watchdog to provided timeout or default timeout. +# 2. Stop watchdog. +# 3. Check if previous reset was caused by watchdog. +# 4. Check watchdog timeleft. + +CPLD_LPC_BASE=0x2500 +CPLD_LPC_CPBLT_REG=0xf9 +CPLD_LPC_RESET_CAUSE_REG=0x1d +CPLD_LPC_WD2_TMR_REG=0xcd +CPLD_LPC_WD2_ACT_REG=0xcf +CPLD_LPC_WD_CPBLT_BIT=6 +CPLD_LPC_WD_RESET_CAUSE_BIT=6 +CPLD_LPC_WD_RESET=1 +WD3_DFLT_TO=600 +WD_TYPE3_MAX_TO=65535 + +wd_max_to= +wd_act_reg= +wd_tmr_reg= +wd_tleft_reg= +wd_tmr_reg_len= +wd_to= + +action=$1 +param_num=$# + +usage() +{ + echo "Usage: $(basename "$0") start [timeout] | stop | tleft | check_reset | help" + echo "start - start watchdog" + echo " timeout is optional. Default value will be used in case if it's omitted" + echo " timeout provided in seconds" + echo "stop - stop watchdog" + echo "tleft - check watchdog timeout left" + echo "check_reset - check if previous reset was caused by watchdog" + echo " Prints only in case of watchdog reset" + echo "help -this help" +} + +check_watchdog_type() +{ + reg=$((CPLD_LPC_BASE+CPLD_LPC_CPBLT_REG)) + wd_cpblt=$(iorw -r -b $reg -l 1 | awk '{print $5}') + wd_cpblt=$((wd_cpblt>>=CPLD_LPC_WD_CPBLT_BIT)) + wd_cpblt=$((wd_cpblt&=1)) + + if [ $wd_cpblt -eq 0 ]; then + wd_type=3 + wd_to=$WD3_DFLT_TO + wd_max_to=$WD_TYPE3_MAX_TO + wd_act_reg=$CPLD_LPC_WD2_ACT_REG + wd_tmr_reg=$CPLD_LPC_WD2_TMR_REG + wd_tleft_reg=$CPLD_LPC_WD2_TMR_REG + wd_tmr_reg_len=2 + else + board=$(cat /sys/devices/virtual/dmi/id/board_name) + case $board in + VMOD0001|VMOD0003) + wd_type=1 + ;; + *) + wd_type=2 + ;; + esac + echo "Watchdog type ${wd_type} isn't supported by this script." + exit 1 + fi +} + +check_watchdog_timeout() +{ + if [ $param_num -ge 2 ]; then + wd_to=$2 + fi + if [ $wd_to -gt $wd_max_to ]; then + echo "Error: Watchdog timeout ${wd_to} exceeds max timeout ${wd_max_to}" + exit 1 + fi +} + +start_watchdog() +{ + reg=$((CPLD_LPC_BASE+wd_tmr_reg)) + iorw -w -b $reg -v $wd_to -l $wd_tmr_reg_len + reg=$((CPLD_LPC_BASE+wd_act_reg)) + val=$CPLD_LPC_WD_RESET + iorw -w -b $reg -v $val -l 1 + echo "Watchdog is started, timeout ${wd_to} sec." +} + +stop_watchdog() +{ + reg=$((CPLD_LPC_BASE+wd_act_reg)) + iorw -w -b $reg -v 0 -l 1 + reg=$((CPLD_LPC_BASE+wd_tmr_reg)) + iorw -w -b $reg -v 0 -l 1 + reg=$((reg+1)) + iorw -w -b $reg -v 0 -l 1 + echo "Watchdog is stopped" +} + +time_left() +{ + reg=$((CPLD_LPC_BASE+wd_tleft_reg)) + val=$(iorw -r -b $reg -l 2 | awk '{print $3 $2}') + val=$(printf "0x%s" ${val}) + printf "Watchdog timeleft: %d sec.\n" ${val} +} + +check_reset() +{ + reg=$((CPLD_LPC_BASE+CPLD_LPC_RESET_CAUSE_REG)) + val=$(iorw -r -b $reg -l 1 | awk '{print $5}') + val=$((val>>=CPLD_LPC_WD_RESET_CAUSE_BIT)) + val=$((val&=1)) + if [ $val -eq 1 ]; then + echo "Watchdog was caused reset in previous boot" + fi +} + +check_watchdog_type + +case $action in + start) + check_watchdog_timeout "$@" + start_watchdog + ;; + stop) + stop_watchdog + ;; + tleft) + time_left + ;; + check_reset) + check_reset + ;; + help) + usage + ;; + *) + usage + exit 1 + ;; +esac + +exit 0 + diff --git a/platform/mellanox/issu-version.mk b/platform/mellanox/issu-version.mk index c7ae4296ab7..db368ffd8c1 100644 --- a/platform/mellanox/issu-version.mk +++ b/platform/mellanox/issu-version.mk @@ -5,5 +5,6 @@ $(ISSU_VERSION_FILE)_SRC_PATH = $(PLATFORM_PATH)/issu-version $(ISSU_VERSION_FILE)_DEPENDS += $(APPLIBS) SONIC_MAKE_FILES += $(ISSU_VERSION_FILE) -export ISSU_VERSION_FILE +MLNX_FILES += $(ISSU_VERSION_FILE) +export ISSU_VERSION_FILE diff --git a/platform/mellanox/mft.mk b/platform/mellanox/mft.mk index ae2c92e0ac1..e6c9d9ba0ea 100644 --- a/platform/mellanox/mft.mk +++ b/platform/mellanox/mft.mk @@ -1,7 +1,7 @@ # Mellanox SAI -MFT_VERSION = 4.12.0 -MFT_REVISION = 104 +MFT_VERSION = 4.13.5 +MFT_REVISION = 1 export MFT_VERSION MFT_REVISION diff --git a/platform/mellanox/mlnx-ffb.mk b/platform/mellanox/mlnx-ffb.mk index dabb995a365..82d50b7ae3e 100755 --- a/platform/mellanox/mlnx-ffb.mk +++ b/platform/mellanox/mlnx-ffb.mk @@ -4,4 +4,6 @@ MLNX_FFB_SCRIPT = mlnx-ffb.sh $(MLNX_FFB_SCRIPT)_PATH = platform/mellanox/ SONIC_COPY_FILES += $(MLNX_FFB_SCRIPT) +MLNX_FILES += $(MLNX_FFB_SCRIPT) + export MLNX_FFB_SCRIPT diff --git a/platform/mellanox/mlnx-fw-upgrade.j2 b/platform/mellanox/mlnx-fw-upgrade.j2 index efe2728afe1..599fc7bcab6 100755 --- a/platform/mellanox/mlnx-fw-upgrade.j2 +++ b/platform/mellanox/mlnx-fw-upgrade.j2 @@ -24,7 +24,7 @@ declare -r BURN_CMD="mlxfwmanager -u -f -y" declare -r FW_FILE="/etc/mlnx/fw-SPC.mfa" declare -r QUERY_FILE="/tmp/mlxfwmanager-query.txt" -declare -r FW_REQUIRED="{{ MLNX_FW_VERSION }}" +declare -r FW_REQUIRED="{{ MLNX_SPC_FW_VERSION }}" IMAGE_UPGRADE="${NO_PARAM}" CPLD_UPGRADE="${NO_PARAM}" diff --git a/platform/mellanox/mlnx-sai.mk b/platform/mellanox/mlnx-sai.mk index 199624c4858..7f13dc2fabd 100644 --- a/platform/mellanox/mlnx-sai.mk +++ b/platform/mellanox/mlnx-sai.mk @@ -1,7 +1,7 @@ # Mellanox SAI MLNX_SAI_VERSION = SAIRel1.14.2-master -MLNX_SAI_REVISION = d5810ae692f47898bbf6e093875c89b5f7e4ef19 +MLNX_SAI_REVISION = f55e6bf96e229a3e74c2e98fb25df5a21a3c46cc export MLNX_SAI_VERSION MLNX_SAI_REVISION diff --git a/platform/mellanox/mlnx-ssd-fw-update.mk b/platform/mellanox/mlnx-ssd-fw-update.mk new file mode 100644 index 00000000000..f932e57d252 --- /dev/null +++ b/platform/mellanox/mlnx-ssd-fw-update.mk @@ -0,0 +1,9 @@ +# ssd update tool + +MLNX_SSD_FW_UPDATE = mlnx-ssd-fw-update.sh +$(MLNX_SSD_FW_UPDATE)_PATH = platform/mellanox/ +SONIC_COPY_FILES += $(MLNX_SSD_FW_UPDATE) + +MLNX_FILES += $(MLNX_SSD_FW_UPDATE) + +export MLNX_SSD_FW_UPDATE diff --git a/platform/mellanox/mlnx-ssd-fw-update.sh b/platform/mellanox/mlnx-ssd-fw-update.sh new file mode 100755 index 00000000000..5163c8e7f8f --- /dev/null +++ b/platform/mellanox/mlnx-ssd-fw-update.sh @@ -0,0 +1,727 @@ +#!/bin/bash +######################################################################## +# Copyright (c) 2020 Mellanox Technologies. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the names of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# Alternatively, this software may be distributed under the terms of the +# GNU General Public License ("GPL") version 2 as published by the Free +# Software Foundation. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +#==============================================================================# +#= Global variable # +#= +#===== +VERSION="1.3" +#===== +SWITCH_SSD_DEV="/dev/sda" +UTIL_TITLE="This is MLNX SSD firmware update utility to read and write SSD FW. Version ${VERSION}" +DEPENDECIES=("smartctl" "sha256sum" "tar" "/bin/bash" "gpg" "sed" "realpath" "dirname") +TRUE="0" +FALSE="1" +ERR_MSG="ERR_MSG" +INI_PREFIX="ini_section_" +PUBLIC_CERT_NAME="trusted.gpg" +CHECKSUM_NAME="checksum" +SCRIPT_MODE="RELESE" # RELESE -or- DEBUG +DEBUG_MSG="DEBUG" # remove all instance after script is ready. +#===== +PKG_EXTRACTED=$FALSE +LOGGER_UTIL=$FALSE +SSD_FW_VER="" +SSD_DEVICE_MODEL="" +SSD_SERIAL="" +SSD_SIZE="" +SECTIONS=() +#===== +ARG_IMAGE_FLAG=$FALSE +ARG_IMAGE_VAL="" +ARG_QUERY_FLAG=$FALSE +ARG_YES_FLAG=$FALSE +ARG_POWER_CYCLE_FLAG=$FALSE +ARG_HELP_FLAG=$FALSE +ARG_VERSION_FLAG=$FALSE +ARG_PACKAGE_INFO_FLAG=$FALSE +ARG_UPDATE_FLAG=$FALSE + + + +#==============================================================================# +#= usage function. # +#= +function init_script() { +# check if logger utility supported + if [ -x "$(command -v logger)" ]; then + LOGGER_UTIL=$TRUE + else + LOGGER_UTIL=$FALSE + fi +} + +#==============================================================================# +#= usage function. # +#= +function usage() { + echo + echo -e "$UTIL_TITLE" + echo + echo -e "Usage:" + echo -e "\tmlnx_ssd_fw_update.sh [OPTION]" + echo -e "Commands:" + echo -e "\t-i, --image\t\t Path to SSD FW package" + echo -e "\t-q, --query\t\t Print SSD information (SSD model, serial number, version and size)" + echo -e "\t\t\t\t Combined with image, comparison is made if update is required" + echo -e "\t-p, --package-info\t Get package info" + echo -e "\t-u, --update\t\t Upgrade firmware" + echo -e "\t-y --yes\t\t Assume \"yes\" to all questions" + echo -e "\t-V, --version\t\t Print utility version" + echo -e "\t-h, --help\t\t Show this usage" + echo -e "\t --power-cycle\t Execute power cycle at completion, even if not required" + echo + echo -e "Example:" + echo -e "\tmlnx_ssd_fw_update.sh -q" + echo -e "\tmlnx_ssd_fw_update.sh -q -i mlnx_ssd_fw_package.pkg" + echo -e "\tmlnx_ssd_fw_update.sh -p -i mlnx_ssd_fw_package.pkg" + echo -e "\tmlnx_ssd_fw_update.sh -u -i mlnx_ssd_fw_package.pkg" + echo +} + +#==============================================================================# +#= Log function. # +#= +function LOG_MSG() { + if [ $# -gt 0 ]; then + LOG_STR=$1 + if [[ $# -eq 1 ]]; then + [[ "$LOGGER_UTIL" == "$TRUE" && "$LOG_STR" != "" ]] && logger -t mlnx_ssd_fw_update.sh -p user.notice $(echo "$LOG_STR" | sed 's/\\t//g') + echo -e "$LOG_STR" + elif [[ $# -eq 2 && "$2" == "$ERR_MSG" ]]; then + [[ "$LOGGER_UTIL" == "$TRUE" && "$LOG_STR" != "" ]] && logger -t mlnx_ssd_fw_update.sh -p user.err $(echo "$LOG_STR" | sed 's/\\t//g') + echo -e "$LOG_STR" + elif [[ $# -eq 2 && "$2" == "$SCRIPT_MODE" ]]; then + echo -e "DBG: $LOG_STR" + fi + fi +} + +#==============================================================================# +#= Log function. # +#= +function LOG_MSG_AND_EXIT() { + LOG_MSG "$@" "$ERR_MSG" + erase_extract_package "$extraction_path" + LOG_MSG "Exiting..." + exit 1 +} + +#==============================================================================# +#= This function check if given argument is valid and return boolean result. # +#= +function check_usage() { + local argument_count=$# + + LOG_MSG "Number of argument:$argument_count" ${DEBUG_MSG} + + if [ $# -eq 0 ]; then + LOG_MSG "Error: false usage given." + usage + exit 1 + fi + + while [[ $# -gt 0 ]] + do + key="$1" + + case $key in + -i|--image) + ARG_IMAGE_FLAG=$TRUE + ARG_IMAGE_VAL="$2" + shift # past argument + shift # past value + ;; + -q|--query) + ARG_QUERY_FLAG=$TRUE + shift # past argument + ;; + -y|--yes) + ARG_YES_FLAG=$TRUE + shift # past argument + ;; + -h|--help) + ARG_HELP_FLAG=$TRUE + shift # past argument + ;; + -V|--version) + ARG_VERSION_FLAG=$TRUE + shift # past argument + ;; + -u|--update) + ARG_UPDATE_FLAG=$TRUE + shift # past argument + ;; + -p|--package-info) + ARG_PACKAGE_INFO_FLAG=$TRUE + shift # past argument + ;; + --power-cycle) + ARG_POWER_CYCLE_FLAG=$TRUE + shift # past argument + ;; + *) + LOG_MSG "Error: false usage given." + usage + exit 1 + ;; + esac + done + + if [[ ("$ARG_IMAGE_FLAG" == "$TRUE" && ( $argument_count -lt 3 )) || + ("$ARG_IMAGE_FLAG" == "$TRUE" && ( $argument_count -gt 5 )) || + ("$ARG_PACKAGE_INFO_FLAG" == "$TRUE" && ( $argument_count -ne 3 )) || + ("$ARG_QUERY_FLAG" == "$TRUE" && ( $argument_count -lt 1 )) || + ("$ARG_QUERY_FLAG" == "$TRUE" && ( $argument_count -gt 3 )) || + ("$ARG_HELP_FLAG" == "$TRUE" && ( $argument_count -gt 1 )) || + ("$ARG_VERSION_FLAG" == "$TRUE" && ( $argument_count -gt 1 )) || + ("$ARG_IMAGE_FLAG" == "$TRUE" && "$ARG_IMAGE_VAL" == "") || + ("$ARG_UPDATE_FLAG" == "$TRUE" && "$ARG_IMAGE_FLAG" == "$FALSE") || + ("$ARG_PACKAGE_INFO_FLAG" == "$TRUE" && "$ARG_IMAGE_FLAG" == "$FALSE") || + ("$ARG_POWER_CYCLE_FLAG" == "$TRUE" && "$ARG_UPDATE_FLAG" == "$FALSE") || + ("$ARG_UPDATE_FLAG" == "$TRUE" && "$ARG_PACKAGE_INFO_FLAG" == "$TRUE") ]]; then + + LOG_MSG "Error: false usage given." + usage + exit 1 + fi + +### Debug message remove when script is done. + LOG_MSG "ARG_IMAGE_FLAG = ${ARG_IMAGE_FLAG}" ${DEBUG_MSG} + LOG_MSG "ARG_IMAGE_VAL = ${ARG_IMAGE_VAL}" ${DEBUG_MSG} + LOG_MSG "ARG_QUERY_FLAG = ${ARG_QUERY_FLAG}" ${DEBUG_MSG} + LOG_MSG "ARG_YES_FLAG = ${ARG_YES_FLAG}" ${DEBUG_MSG} + LOG_MSG "ARG_HELP_FLAG = ${ARG_HELP_FLAG}" ${DEBUG_MSG} + LOG_MSG "ARG_VERSION_FLAG = ${ARG_VERSION_FLAG}" ${DEBUG_MSG} + LOG_MSG "ARG_PACKAGE_INFO_FLAG = ${ARG_PACKAGE_INFO_FLAG}" ${DEBUG_MSG} + LOG_MSG "ARG_POWER_CYCLE_FLAG = ${ARG_POWER_CYCLE_FLAG}" ${DEBUG_MSG} + +} + +#==============================================================================# +# This function return SSD fw version using hdparm utility # +# +function get_ssd_fw_version() { + [ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; } + + local device_fw_version + device_fw_version=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "Firmware Version: +\K[^,]+") + LOG_MSG "device_fw_version: $device_fw_version" ${DEBUG_MSG} + eval $1='$device_fw_version' +} + +#==============================================================================# +# This function return SSD device model using hdparm utility # +# +function get_ssd_device_model() { + [ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; } + + local device_model_name + device_model_name=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "Device Model: +\K[^,]+") + LOG_MSG "device_model_name: $device_model_name" ${DEBUG_MSG} + eval $1='$device_model_name' +} + +#==============================================================================# +# This function return SSD size using hdparm utility # +# +function get_ssd_size() { + [ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; } + + local device_size + device_size=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "User Capacity:.+bytes \[\K[^ ]+") + LOG_MSG "device_size: $device_size" ${DEBUG_MSG} + eval $1='$device_size' +} + +#==============================================================================# +# This function return SSD serial using hdparm utility # +# +function get_ssd_serial() { + [ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; } + + local device_serial + device_serial=$(smartctl -i $SWITCH_SSD_DEV | grep -Po "Serial Number: +\K[^,]+") + LOG_MSG "device_serial: $device_serial" ${DEBUG_MSG} + eval $1='$device_serial' +} + +#==============================================================================# +#= This function check if given argument is valid and return boolean result. # +#= +function get_ssd_info() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + get_ssd_fw_version SSD_FW_VER + get_ssd_device_model SSD_DEVICE_MODEL + get_ssd_serial SSD_SERIAL + get_ssd_size SSD_SIZE +} + +#==============================================================================# +#= This function check if given argument is valid and return boolean result. # +#= +function check_tool_dependencies() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + for i in "${!DEPENDECIES[@]}" + do + if [ ! -x "$(command -v ${DEPENDECIES[$i]})" ]; then + LOG_MSG_AND_EXIT "Error: This tool require the following utils to be installed ${DEPENDECIES[$i]}" + fi + done +} + +#==============================================================================# +#= This function parse package ini file and declare it attributes # +#= +function ini_parser { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + + local filename="$1" + LOG_MSG "filename:$filename" ${DEBUG_MSG} + + shopt -p extglob &> /dev/null + CHANGE_EXTGLOB=$? + if [ $CHANGE_EXTGLOB = 1 ] + then + shopt -s extglob + fi + ini="$(<$filename)" # read the file + ini=${ini//$'\r'/} # remove linefeed i.e dos2unix + ini="${ini//[/\\[}" + ini="${ini//]/\\]}" + IFS=$'\n' && ini=( ${ini} ) # convert to line-array + ini=( ${ini[*]//\)/\\\)} ) # append / before any parenthesis + ini=( ${ini[*]//\(/\\\(} ) # append / before any parenthesis + ini=( ${ini[*]/#*([[:space:]]);*/} ) + ini=( ${ini[*]/#*([[:space:]])\#*/} ) + ini=( ${ini[*]/#+([[:space:]])/} ) # remove init whitespace + ini=( ${ini[*]/%+([[:space:]])/} ) # remove ending whitespace + ini=( ${ini[*]/*([[:space:]])=*([[:space:]])/=} ) # remove whitespace around = + ini=( ${ini[*]/#\\[/\}$'\n'"$INI_PREFIX"} ) # set section prefix + ini=( ${ini[*]/%\\]/ \(} ) # convert text2function (1) + ini=( ${ini[*]/=/=\( } ) # convert item to array + ini=( ${ini[*]/%/ \)} ) # close array parenthesis + ini=( ${ini[*]/%\\ \)/ \\} ) # the multiline trick + ini=( ${ini[*]/%\( \)/\(\) \{} ) # convert text2function (2) + ini=( ${ini[*]/%\} \)/\}} ) # remove extra parenthesis + ini=( ${ini[*]/%\{/\{$'\n''ini_unset ${FUNCNAME/#'$INI_PREFIX'}'$'\n'} ) # clean previous definition of section + ini[0]="" # remove first element + ini[${#ini[*]} + 1]='}' # add the last brace + eval "$(echo "${ini[*]}")" # eval the result + [ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: failed to parse package content." + SECTIONS="$(echo ${ini[*]} | grep -Po "$INI_PREFIX+\K[\w]+")" + if [ $CHANGE_EXTGLOB = 1 ] + then + shopt -u extglob + fi +} + +#==============================================================================# +#= This function unset parse ini section and variables # +#= +function ini_unset { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + SECTION=$1 + OLDIFS="$IFS" + IFS=' '$'\n' + if [ -z "$SECTION" ] + then + fun="$(declare -F)" + else + fun="$(declare -F $INI_PREFIX$SECTION)" + if [ -z "$fun" ] + then + echo "section $SECTION not found" 1>&2 + return + fi + fi + fun="${fun//declare -f/}" + for f in $fun; do + [ "${f#$INI_PREFIX}" == "${f}" ] && continue + item="$(declare -f ${f})" + item="${item##*\{}" # remove function definition + item="${item##*FUNCNAME*$INI_PREFIX\};}" # remove clear section + item="${item/\}}" # remove function close + item="${item%)*}" # remove everything after parenthesis + item="${item});" # add close parenthesis + vars="" + while [ "$item" != "" ] + do + newvar="${item%%=*}" # get item name + vars="$vars $newvar" # add name to collection + item="${item#*;}" # remove readed line + done + for var in $vars; do + unset $var + done + done + IFS="$OLDIFS" +} + +#==============================================================================# +#= This function check package signing and returns back true or false # +#= +function check_package_signing() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + + [ $1 ] || { LOG_MSG_AND_EXIT "Wrong usage - ${FUNCNAME[0]}()"; } + + local package_path=$1 + local checksum_unsigned_file="$package_path/$CHECKSUM_NAME" + local checksum_signed_file="$package_path/$CHECKSUM_NAME.sig" + local public_cert_file="$package_path/$PUBLIC_CERT_NAME" + +### Check if unsigned checksum file exists + [ ! -f "$checksum_unsigned_file" ] && LOG_MSG_AND_EXIT "Error: fail to find unsigned checksum file to verify package signing." + +### Check if signed checksum file exists + [ ! -f "$checksum_signed_file" ] && LOG_MSG_AND_EXIT "Error: fail to find sign checksum file to verify package signing." + +### Check if public key exists + [ ! -f "$public_cert_file" ] && LOG_MSG_AND_EXIT "Error: fail to find public certificate to verify package signing." + + + LOG_MSG "public_cert_file: ${public_cert_file}" ${DEBUG_MSG} + LOG_MSG "checksum_signed_file: ${checksum_signed_file}" ${DEBUG_MSG} + LOG_MSG "checksum_unsigned_file: ${checksum_unsigned_file}" ${DEBUG_MSG} + + gpg --keyring "$public_cert_file" --verify "$checksum_signed_file" "$checksum_unsigned_file" > /dev/null 2>&1 + [ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: fault package signing." + + LOG_MSG "cd into: ${package_path}" ${DEBUG_MSG} + cd $package_path > /dev/null 2>&1 + sha256sum -c $CHECKSUM_NAME > /dev/null 2>&1 + [ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: fault package SHA signing, file has been compromised" + LOG_MSG "backing back:" ${DEBUG_MSG} + cd - > /dev/null 2>&1 + LOG_MSG "exiting:" ${DEBUG_MSG} + +} + +#==============================================================================# +#= This function prints supported SSD from package ini # +#= +function string_supported_model() { + + local section=$1 + + if [[ ! -z "${Vendor[*]}" ]] && [[ ! -z "${SSD_FW_Model[*]}" ]] && [[ ! -z "${SSD_FW_Version[*]}" ]] \ + && [[ ! -z "${SSD_Size[*]}" ]] && [[ ! -z ${Shutdown_Policy[*]} ]]; then + printf 'o %-10s | %-30s | %-12s | %-6sGB | %-7s |\n' \ + "$( IFS=$'\n'; echo "${Vendor[@]}" )" "$( IFS=$'\n'; echo "${SSD_FW_Model[@]}" )" \ + "${SSD_FW_Version[@]}" "${SSD_Size[@]}" "${Shutdown_Policy[@],,}" + fi + +} + +#==============================================================================# +#= This function extract SSD FW package into /tmp # +#= +function extract_package() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + + local filename=$1 + LOG_MSG "filename:$filename" ${DEBUG_MSG} +### Check if file exists + [ ! -f $filename ] && LOG_MSG_AND_EXIT "Error: given file ($filename) not found." +### Check if tmp available + [ ! -d "/tmp" ] && LOG_MSG_AND_EXIT "Error: directory /tmp DOES NOT exists." + + local base_filename="${filename##*/}" + local folder_name="/tmp/""${base_filename%%.*}" + +### Check if full path available + if [ -d $folder_name ]; then + LOG_MSG "Path:$folder_name already exists, removing folder." ${DEBUG_MSG} + rm -rf ${folder_name} + [ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: folder:$folder_name is already in use and can't be overwrite, please remove it and retry." + fi + + mkdir ${folder_name} && tar xf ${filename} -C ${folder_name} --strip-components 1 --warning=no-timestamp > /dev/null 2>&1 + #tar -xf $filename --directory /tmp/ --warning=no-timestamp > /dev/null 2>&1 +### Check if untar succeed. + [ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: fail to extract given package ($filename)." + +### return the path file extraction is + # local base_filename="${filename##*/}" + # local folder_name="/tmp/""${base_filename%%.*}" + eval $2="$folder_name" + + PKG_EXTRACTED=$TRUE + + check_package_signing $folder_name + + LOG_MSG "successfully untar file." ${DEBUG_MSG} +} + +#==============================================================================# +#= This function extract SSD FW package into /tmp # +#= +function erase_extract_package() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + + [[ "$PKG_EXTRACTED" == "$FALSE" ]] && return + + local folder_name=$1 + + LOG_MSG "folder_name: $folder_name" ${DEBUG_MSG} + +### Check if folder exists + if [ ! -d "$folder_name" ]; then + LOG_MSG "Error: directory $folder_name DOES NOT exists." "$ERR_MSG" + LOG_MSG "Exiting..." + exit 1 + fi + rm -rf $folder_name +### Check if untar succeed. + if [ $? -ne 0 ]; then + LOG_MSG "Error: fail to delete $folder_name folder." "$ERR_MSG" + LOG_MSG "Exiting..." + exit 1 + fi + + PKG_EXTRACTED=$FALSE + LOG_MSG "successfully removed folder:$folder_name" ${DEBUG_MSG} +} + + +#==============================================================================# +#= This function returns back ini section array. +#= +function call_ini_section() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + + local ini_section=$1 + LOG_MSG "ini_section:$ini_section" ${DEBUG_MSG} + + [[ -z "$ini_section" ]] && LOG_MSG_AND_EXIT "Error: given INI section is null." + [[ -z "$(declare -F "$INI_PREFIX$ini_section")" ]] && LOG_MSG_AND_EXIT "Error: $ini_section section is missing in INI file." + + eval "$(echo "$INI_PREFIX$ini_section")" # call given section function. +} + +#==============================================================================# +#= This function prints ssd info +#= +function print_ssd_info() { + LOG_MSG "func: ${FUNCNAME[0]}()" ${DEBUG_MSG} + + local argument_count=$# + + if [ $argument_count -eq 2 ]; then + local newer_fw_version=$1 + local power_policy=$2 + LOG_MSG "Device Model\t\t : $SSD_DEVICE_MODEL" + LOG_MSG "Serial Number\t\t : $SSD_SERIAL" + LOG_MSG "User Capacity\t\t : $SSD_SIZE GB" + LOG_MSG "Current Firmware Version : $SSD_FW_VER" + LOG_MSG "Available Firmware Version : $Newer_FW_Version" + LOG_MSG "Power Cycle Required\t : $power_policy" + LOG_MSG "Upgrade Required\t : yes" + elif [ $argument_count -eq 1 ]; then + local _upgrade_require=$1 + LOG_MSG "Device Model\t : $SSD_DEVICE_MODEL" + LOG_MSG "Serial Number\t : $SSD_SERIAL" + LOG_MSG "User Capacity\t : $SSD_SIZE GB" + LOG_MSG "Firmware Version : $SSD_FW_VER" + LOG_MSG "Upgrade Required : $_upgrade_require" + else + LOG_MSG "Device Model\t : $SSD_DEVICE_MODEL" + LOG_MSG "Serial Number\t : $SSD_SERIAL" + LOG_MSG "User Capacity\t : $SSD_SIZE GB" + LOG_MSG "Firmware Version : $SSD_FW_VER" + fi +} + +# Main +# ------------------------------------------------------------------------------ +init_script +check_usage "$@" + +# show help +if [ $ARG_HELP_FLAG == $TRUE ]; then + usage + exit 0 +# show version +elif [ $ARG_VERSION_FLAG == $TRUE ]; then + echo $UTIL_TITLE + exit 0 +# show SSD info +elif [ $ARG_QUERY_FLAG == $TRUE ]; then + match_found=$FALSE + check_tool_dependencies + get_ssd_info + + if [ $ARG_IMAGE_FLAG == $TRUE ]; then + extract_package $ARG_IMAGE_VAL extraction_path + ini_parser "$extraction_path/list.ini" + + for section in $SECTIONS; do + if [[ $section != "main" ]]; then + call_ini_section $section + if [[ "$SSD_DEVICE_MODEL" == "$( IFS=$'\n'; echo "${SSD_FW_Model[@]}" )" ]] && \ + [[ "$SSD_FW_VER" == "${SSD_FW_Version[@]}" ]] && \ + [[ "$SSD_SIZE" == "${SSD_Size[@]}" ]]; then + + match_found=$TRUE + break + fi + ini_unset $section + fi + done + + erase_extract_package "$extraction_path" + if [[ "$match_found" == "$FALSE" ]]; then + #LOG_MSG "SSD FW upgrade not require, based on given package latest version is in used." + print_ssd_info "no" + echo -e "" + exit 0 + fi + fi + + if [[ "$match_found" == "$TRUE" ]]; then + print_ssd_info $Newer_FW_Version ${Shutdown_Policy[0],,} + erase_extract_package "$extraction_path" + else + print_ssd_info + fi + + echo -e "" + + exit 0 +# show package version +elif [ $ARG_PACKAGE_INFO_FLAG == $TRUE ]; then + check_tool_dependencies + extract_package $ARG_IMAGE_VAL extraction_path + # 2. check signing + ini_parser "$extraction_path/list.ini" + + call_ini_section "main" + LOG_MSG "Package Name: $ARG_IMAGE_VAL" + [[ ! -z ${description[@]} ]] && LOG_MSG "Description: ${description[@]}" + [[ ! -z ${version[@]} ]] && LOG_MSG "Version: ${version[@]}" + [[ ! -z ${release_date[@]} ]] && LOG_MSG "Release Date: ${release_date[@]}" + LOG_MSG "Supported SSDs:" + LOG_MSG " Vendor | Model | FW ver | Size | Pwr Cyc Req |" + LOG_MSG "=============|================================|==============|==========|=============|" + for section in $SECTIONS; do + if [[ "$section" != "main" ]]; then + call_ini_section $section + supported_model=$(string_supported_model $section) + LOG_MSG "$supported_model" + ini_unset $section + fi + done + echo -e "" + erase_extract_package "$extraction_path" + exit 0 +# operate SSD fw update +elif [ $ARG_UPDATE_FLAG == $TRUE ]; then + check_tool_dependencies + get_ssd_info + extract_package $ARG_IMAGE_VAL extraction_path + # 2. check signing + UPDATE_DONE=$FALSE + ini_parser "$extraction_path/list.ini" + for section in $SECTIONS; do + if [[ $section != "main" ]]; then + call_ini_section $section + if [[ "$SSD_DEVICE_MODEL" == "$( IFS=$'\n'; echo "${SSD_FW_Model[@]}" )" ]] && \ + [[ "$SSD_FW_VER" == "${SSD_FW_Version[@]}" ]] && \ + [[ "$SSD_SIZE" == "${SSD_Size[@]}" ]]; then + UPDATE_DONE=$TRUE + + power_policy=${Shutdown_Policy[0],,} + LOG_MSG "Power policy:$power_policy" ${DEBUG_MSG} + print_ssd_info $Newer_FW_Version ${Shutdown_Policy[0],,} + echo -e "" + #[[ "yes" == "$power_policy" ]] && LOG_MSG "PLEASE NOTE: System will power-cycle automatically once SSD FW Update complete!" + [[ "yes" == "$power_policy" || "$ARG_POWER_CYCLE_FLAG" == "$TRUE" ]] && LOG_MSG "Please note: Once SSD FW Update process ends, system will power-cycle automaticly and it will take up to 1 minute to access it back." + + # Prompt approval for FW update if ignore in case "yes" flag is on. + if [[ "$ARG_YES_FLAG" == "$FALSE" ]]; then + read -p "Do you want to continue? [Y/N]" -n 1 -r + echo # (optional) move to a new line + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + LOG_MSG_AND_EXIT "Aborting..." + exit 0 + fi + fi + + # Check FWUpgrade scripts exists & if so call it. + ssd_script_name=$Update_Script + ssd_script_path="${extraction_path}/${section}/${ssd_script_name}" + LOG_MSG "ssd_script_path: $ssd_script_path" ${DEBUG_MSG} + if [ ! -f $ssd_script_path ]; then + LOG_MSG_AND_EXIT "Error: fail to call upgrade script ($ssd_script_path)!" + fi + ( + cd "${extraction_path}/${section}" > /dev/null 2>&1 || exit + /bin/bash "$ssd_script_path" "${extraction_path}/${section}" + #cd - > /dev/null 2>&1 || exit + ) + if [ $? -ne 0 ]; then + LOG_MSG_AND_EXIT "Error: SSD FW update failed." + else + LOG_MSG "SSD FW update completed successfully." + + if [ $ARG_POWER_CYCLE_FLAG == $TRUE ]; then + LOG_MSG "Execute power cycle..." + sleep 1 + sync + power_cycle_script="${extraction_path}/common/mlnx_shutdown.sh" + [ ! -f $power_cycle_script ]&& LOG_MSG_AND_EXIT "Error: failed to initiate power cycle." + ($power_cycle_script "-s") + [ $? -ne 0 ] && LOG_MSG_AND_EXIT "Error: failed to power cycle the system automatically." + erase_extract_package "$extraction_path" + + fi + + fi + + break # Exit the for loop + fi + ini_unset $section + fi + done + if [ $UPDATE_DONE == $FALSE ]; then + LOG_MSG "SSD FW upgrade not require, based on given package latest version is in used." + print_ssd_info "no" + fi + + echo -e "" + erase_extract_package "$extraction_path" + exit 0 +fi + +exit 0 diff --git a/platform/mellanox/one-image.mk b/platform/mellanox/one-image.mk index d930850b7ac..89f203defe9 100644 --- a/platform/mellanox/one-image.mk +++ b/platform/mellanox/one-image.mk @@ -5,5 +5,5 @@ $(SONIC_ONE_IMAGE)_MACHINE = mellanox $(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie $(SONIC_ONE_IMAGE)_INSTALLS += $(SX_KERNEL) $(KERNEL_MFT) $(MFT_OEM) $(MFT) $(MLNX_HW_MANAGEMENT) $(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES) -$(SONIC_ONE_IMAGE)_FILES += $(MLNX_FW_FILE) $(MLNX_CPLD_ARCHIVES) $(MLNX_FFB_SCRIPT) $(ISSU_VERSION_FILE) +$(SONIC_ONE_IMAGE)_FILES += $(MLNX_FILES) SONIC_INSTALLERS += $(SONIC_ONE_IMAGE) diff --git a/platform/mellanox/rules.mk b/platform/mellanox/rules.mk index 3ed1f1bae04..56e27bb4779 100644 --- a/platform/mellanox/rules.mk +++ b/platform/mellanox/rules.mk @@ -4,6 +4,7 @@ include $(PLATFORM_PATH)/fw.mk include $(PLATFORM_PATH)/mft.mk include $(PLATFORM_PATH)/mlnx-sai.mk include $(PLATFORM_PATH)/hw-management.mk +include $(PLATFORM_PATH)/hw-management-wd.mk include $(PLATFORM_PATH)/mlnx-platform-api.mk include $(PLATFORM_PATH)/docker-syncd-mlnx.mk include $(PLATFORM_PATH)/docker-syncd-mlnx-rpc.mk @@ -15,6 +16,7 @@ include $(PLATFORM_PATH)/docker-ptf-mlnx.mk include $(PLATFORM_PATH)/mlnx-sfpd.mk include $(PLATFORM_PATH)/mlnx-ffb.mk include $(PLATFORM_PATH)/issu-version.mk +include $(PLATFORM_PATH)/mlnx-ssd-fw-update.mk SONIC_ALL += $(SONIC_ONE_IMAGE) \ $(DOCKER_FPM) diff --git a/platform/mellanox/sdk-src/applibs/Makefile b/platform/mellanox/sdk-src/applibs/Makefile new file mode 100644 index 00000000000..767012410f9 --- /dev/null +++ b/platform/mellanox/sdk-src/applibs/Makefile @@ -0,0 +1,30 @@ +.ONESHELL: +SHELL = /bin/bash + +MAIN_TARGET = applibs_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +DERIVED_TARGETS = applibs-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +PACKAGE_NAME = applibs + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # get sources + rm -rf $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + wget -c $(MLNX_SDK_SOURCE_BASE_URL)/$(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION).tar.gz -O - | tar -xz + + # build + pushd $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + sed -i "s/sx-libnl/$(LIBNL3)/g" ./debian/control + sed -i "s/-Werror//g" ./configure.in + + if [ -f autogen.sh ]; then + ./autogen.sh + fi + + debuild -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + + popd + + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/platform/mellanox/sdk-src/iproute2/Makefile b/platform/mellanox/sdk-src/iproute2/Makefile new file mode 100644 index 00000000000..fad46e62533 --- /dev/null +++ b/platform/mellanox/sdk-src/iproute2/Makefile @@ -0,0 +1,27 @@ +.ONESHELL: +SHELL = /bin/bash + +MAIN_TARGET = iproute2_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +DERIVED_TARGETS = iproute2-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +PACKAGE_NAME = iproute2-3.19.0 + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # get sources + rm -rf $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + wget -c $(MLNX_SDK_SOURCE_BASE_URL)/$(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION).tar.gz -O - | tar -xz + + # build + pushd $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + if [ -f autogen.sh ]; then + ./autogen.sh + fi + + debuild -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + + popd + + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/platform/mellanox/sdk-src/python-sdk-api/Makefile b/platform/mellanox/sdk-src/python-sdk-api/Makefile new file mode 100644 index 00000000000..2ea14cd9d62 --- /dev/null +++ b/platform/mellanox/sdk-src/python-sdk-api/Makefile @@ -0,0 +1,27 @@ +.ONESHELL: +SHELL = /bin/bash + +MAIN_TARGET = python-sdk-api_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +DERIVED_TARGETS = +PACKAGE_NAME = python_sdk_api + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # get sources + rm -rf $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + wget -c $(MLNX_SDK_SOURCE_BASE_URL)/$(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION).tar.gz -O - | tar -xz + + # build + pushd $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + if [ -f autogen.sh ]; then + ./autogen.sh + fi + + debuild -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + + popd + + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/platform/mellanox/sdk-src/sx-complib/Makefile b/platform/mellanox/sdk-src/sx-complib/Makefile new file mode 100644 index 00000000000..aae38a6439e --- /dev/null +++ b/platform/mellanox/sdk-src/sx-complib/Makefile @@ -0,0 +1,28 @@ +.ONESHELL: +SHELL = /bin/bash + +MAIN_TARGET = sx-complib_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +DERIVED_TARGETS = sx-complib-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb \ + sx-complib-dev-static_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +PACKAGE_NAME = sx_complib + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # get sources + rm -rf $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + wget -c $(MLNX_SDK_SOURCE_BASE_URL)/$(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION).tar.gz -O - | tar -xz + + # build + pushd $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + if [ -f autogen.sh ]; then + ./autogen.sh + fi + + debuild -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + + popd + + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/platform/mellanox/sdk-src/sx-examples/Makefile b/platform/mellanox/sdk-src/sx-examples/Makefile new file mode 100644 index 00000000000..4368a43f68d --- /dev/null +++ b/platform/mellanox/sdk-src/sx-examples/Makefile @@ -0,0 +1,27 @@ +.ONESHELL: +SHELL = /bin/bash + +MAIN_TARGET = sx-examples_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +DERIVED_TARGETS = sx-examples-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +PACKAGE_NAME = sx_examples + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # get sources + rm -rf $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + wget -c $(MLNX_SDK_SOURCE_BASE_URL)/$(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION).tar.gz -O - | tar -xz + + # build + pushd $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + if [ -f autogen.sh ]; then + ./autogen.sh + fi + + debuild -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + + popd + + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/platform/mellanox/sdk-src/sx-gen-utils/Makefile b/platform/mellanox/sdk-src/sx-gen-utils/Makefile new file mode 100644 index 00000000000..b5814b5bc6d --- /dev/null +++ b/platform/mellanox/sdk-src/sx-gen-utils/Makefile @@ -0,0 +1,27 @@ +.ONESHELL: +SHELL = /bin/bash + +MAIN_TARGET = sx-gen-utils_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +DERIVED_TARGETS = sx-gen-utils-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +PACKAGE_NAME = sx_gen_utils + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # get sources + rm -rf $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + wget -c $(MLNX_SDK_SOURCE_BASE_URL)/$(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION).tar.gz -O - | tar -xz + + # build + pushd $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + if [ -f autogen.sh ]; then + ./autogen.sh + fi + + debuild -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + + popd + + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/platform/mellanox/sdk-src/sx-kernel/Makefile b/platform/mellanox/sdk-src/sx-kernel/Makefile new file mode 100644 index 00000000000..422f2ae95aa --- /dev/null +++ b/platform/mellanox/sdk-src/sx-kernel/Makefile @@ -0,0 +1,29 @@ +.ONESHELL: +SHELL = /bin/bash + +MAIN_TARGET = sx-kernel_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +DERIVED_TARGETS = sx-kernel-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +PACKAGE_NAME = sx_kernel + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # get sources + + if [ ! -z "$(MLNX_SDK_SOURCE_BASE_URL)" ]; then + rm -rf sx_kernel-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + wget -c $(MLNX_SDK_SOURCE_BASE_URL)/$(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION).tar.gz -O - | tar -xz + pushd sx_kernel-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + else + pushd Switch-SDK-drivers + git reset --hard + git clean -xfd + fi + + # build + + debuild -e KVERSION=$(KVERSION) -e KSRC_EXT=/lib/modules/$(KVERSION)/source/ -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + + popd + + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/platform/mellanox/sdk-src/sx-scew/Makefile b/platform/mellanox/sdk-src/sx-scew/Makefile new file mode 100644 index 00000000000..b0679fa9c8b --- /dev/null +++ b/platform/mellanox/sdk-src/sx-scew/Makefile @@ -0,0 +1,28 @@ +.ONESHELL: +SHELL = /bin/bash + +MAIN_TARGET = sx-scew_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +DERIVED_TARGETS = sx-scew-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb \ + sx-scew-dev-static_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +PACKAGE_NAME = sx_scew + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # get sources + rm -rf $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + wget -c $(MLNX_SDK_SOURCE_BASE_URL)/$(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION).tar.gz -O - | tar -xz + + # build + pushd $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + if [ -f autogen.sh ]; then + ./autogen.sh + fi + + debuild -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + + popd + + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/platform/mellanox/sdk-src/sxd-libs/Makefile b/platform/mellanox/sdk-src/sxd-libs/Makefile new file mode 100644 index 00000000000..82cedb3bd13 --- /dev/null +++ b/platform/mellanox/sdk-src/sxd-libs/Makefile @@ -0,0 +1,28 @@ +.ONESHELL: +SHELL = /bin/bash + +MAIN_TARGET = sxd-libs_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +DERIVED_TARGETS = sxd-libs-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb \ + sxd-libs-dev-static_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +PACKAGE_NAME = sxd_libs + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # get sources + rm -rf $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + wget -c $(MLNX_SDK_SOURCE_BASE_URL)/$(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION).tar.gz -O - | tar -xz + + # build + pushd $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + if [ -f autogen.sh ]; then + ./autogen.sh + fi + + debuild -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + + popd + + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/platform/mellanox/sdk-src/wjh-libs/Makefile b/platform/mellanox/sdk-src/wjh-libs/Makefile new file mode 100644 index 00000000000..fd1e53168ea --- /dev/null +++ b/platform/mellanox/sdk-src/wjh-libs/Makefile @@ -0,0 +1,28 @@ +.ONESHELL: +SHELL = /bin/bash + +MAIN_TARGET = wjh-libs_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +DERIVED_TARGETS = wjh-libs-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb \ + wjh-libs-dev-static_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +PACKAGE_NAME = wjh_libs + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # get sources + rm -rf $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + wget -c $(MLNX_SDK_SOURCE_BASE_URL)/$(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION).tar.gz -O - | tar -xz + + # build + pushd $(PACKAGE_NAME)-$(MLNX_SDK_VERSION)-$(MLNX_SDK_ISSU_VERSION) + + if [ -f autogen.sh ]; then + ./autogen.sh + fi + + debuild -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + + popd + + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/platform/mellanox/sdk.mk b/platform/mellanox/sdk.mk index a00069a0199..70263ea94dc 100644 --- a/platform/mellanox/sdk.mk +++ b/platform/mellanox/sdk.mk @@ -1,5 +1,8 @@ -MLNX_SDK_BASE_URL = https://github.com/Mellanox/SAI-Implementation/raw/d5810ae692f47898bbf6e093875c89b5f7e4ef19/sdk -MLNX_SDK_VERSION = 4.3.1634 +MLNX_SDK_BASE_URL = https://github.com/Mellanox/SAI-Implementation/raw/7b12396d53e6c2dcd3e8610afc146141ef51d831/sdk +MLNX_SDK_VERSION = 4.3.1646 +MLNX_SDK_DEB_VERSION = $(subst _,.,$(MLNX_SDK_VERSION)) +MLNX_SDK_ISSU_VERSION = 101 + MLNX_SDK_RDEBS += $(APPLIBS) $(IPROUTE2_MLNX) $(SX_ACL_RM) $(SX_COMPLIB) \ $(SX_EXAMPLES) $(SX_GEN_UTILS) $(SX_SCEW) $(SX_SDN_HAL) \ $(SXD_LIBS) $(TESTX) $(WJH_LIBS) @@ -10,46 +13,68 @@ MLNX_SDK_DEBS += $(APPLIBS_DEV) $(IPROUTE2_MLNX_DEV) $(SX_ACL_RM_DEV) \ $(SX_SDN_HAL_DEV) $(SX_SDN_HAL_DEV_STATIC) $(SXD_LIBS_DEV) \ $(SXD_LIBS_DEV_STATIC) $(TESTX_DEV) $(WJH_LIBS_DEV) -APPLIBS = applibs_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb +# Place here URL where SDK sources exist +MLNX_SDK_SOURCE_BASE_URL = + +ifneq ($(MLNX_SDK_SOURCE_BASE_URL), ) +SDK_FROM_SRC = y +else +SDK_FROM_SRC = n +endif + +export MLNX_SDK_SOURCE_BASE_URL MLNX_SDK_VERSION MLNX_SDK_ISSU_VERSION MLNX_SDK_DEB_VERSION + +APPLIBS = applibs_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +$(APPLIBS)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/applibs $(APPLIBS)_DEPENDS += $(SX_COMPLIB) $(SX_GEN_UTILS) $(SXD_LIBS) $(LIBNL3) $(LIBNL_GENL3) $(APPLIBS)_RDEPENDS += $(SX_COMPLIB) $(SX_GEN_UTILS) $(SXD_LIBS) $(LIBNL3) $(LIBNL_GENL3) -APPLIBS_DEV = applibs-dev_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb +APPLIBS_DEV = applibs-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(eval $(call add_derived_package,$(APPLIBS),$(APPLIBS_DEV))) -IPROUTE2_MLNX = iproute2_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb -IPROUTE2_MLNX_DEV = iproute2-dev_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb +IPROUTE2_MLNX = iproute2_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +$(IPROUTE2_MLNX)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/iproute2 +IPROUTE2_MLNX_DEV = iproute2-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(eval $(call add_derived_package,$(IPROUTE2_MLNX),$(IPROUTE2_MLNX_DEV))) -SX_COMPLIB = sx-complib_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb -SX_COMPLIB_DEV = sx-complib-dev_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb +SX_COMPLIB = sx-complib_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +$(SX_COMPLIB)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/sx-complib +SX_COMPLIB_DEV = sx-complib-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(eval $(call add_derived_package,$(SX_COMPLIB),$(SX_COMPLIB_DEV))) -SX_EXAMPLES = sx-examples_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb +SX_EXAMPLES = sx-examples_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +$(SX_EXAMPLES)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/sx-examples $(SX_EXAMPLES)_DEPENDS += $(APPLIBS) $(SX_SCEW) $(SXD_LIBS) $(SX_EXAMPLES)_RDEPENDS += $(APPLIBS) $(SX_SCEW) $(SXD_LIBS) -SX_EXAMPLES_DEV = sx-examples-dev_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb +SX_EXAMPLES_DEV = sx-examples-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(eval $(call add_derived_package,$(SX_EXAMPLES),$(SX_EXAMPLES_DEV))) -SX_GEN_UTILS = sx-gen-utils_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb -$(SX_GEN_UTILS)_DEPENDS += $(SX_COMPLIB) +SX_GEN_UTILS = sx-gen-utils_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +$(SX_GEN_UTILS)_SRC_PATH += $(PLATFORM_PATH)/sdk-src/sx-gen-utils +$(SX_GEN_UTILS)_DEPENDS += $(SX_COMPLIB) $(SXD_LIBS) $(SX_GEN_UTILS)_RDEPENDS += $(SX_COMPLIB) -SX_GEN_UTILS_DEV = sx-gen-utils-dev_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb +SX_GEN_UTILS_DEV = sx-gen-utils-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(eval $(call add_derived_package,$(SX_GEN_UTILS),$(SX_GEN_UTILS_DEV))) -SX_SCEW = sx-scew_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb -SX_SCEW_DEV = sx-scew-dev_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb +SX_SCEW = sx-scew_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +$(SX_SCEW)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/sx-scew +SX_SCEW_DEV = sx-scew-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(eval $(call add_derived_package,$(SX_SCEW),$(SX_SCEW_DEV))) -SXD_LIBS = sxd-libs_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb -SXD_LIBS_DEV = sxd-libs-dev_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb +SXD_LIBS = sxd-libs_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +$(SXD_LIBS)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/sxd-libs +$(SXD_LIBS)_DEPENDS += $(SX_COMPLIB_DEV) +SXD_LIBS_DEV = sxd-libs-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(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_VERSION)_amd64.deb +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) $(SXD_LIBS) $(PYTHON_SDK_API)_RDEPENDS += $(APPLIBS) $(SXD_LIBS) -SX_KERNEL = sx-kernel_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb -SX_KERNEL_DEV = sx-kernel-dev_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb +SX_KERNEL = sx-kernel_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +$(SX_KERNEL)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/sx-kernel +$(SX_KERNEL)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) +SX_KERNEL_DEV = sx-kernel-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(eval $(call add_derived_package,$(SX_KERNEL),$(SX_KERNEL_DEV))) -WJH_LIBS = wjh-libs_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb -#$(WJH_LIBS)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/wjh-libs +WJH_LIBS = wjh-libs_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb +$(WJH_LIBS)_SRC_PATH = $(PLATFORM_PATH)/sdk-src/wjh-libs $(WJH_LIBS)_DEPENDS += $(SX_COMPLIB_DEV) $(SXD_LIBS_DEV) $(APPLIBS_DEV) $(WJH_LIBS)_RDEPENDS += $(SX_COMPLIB) $(PYTHON_SDK_API) -WJH_LIBS_DEV = wjh-libs-dev_1.mlnx.$(MLNX_SDK_VERSION)_amd64.deb +WJH_LIBS_DEV = wjh-libs-dev_1.mlnx.$(MLNX_SDK_DEB_VERSION)_amd64.deb $(eval $(call add_derived_package,$(WJH_LIBS),$(WJH_LIBS_DEV))) define make_url @@ -61,5 +86,11 @@ $(eval $(foreach deb,$(MLNX_SDK_DEBS),$(call make_url,$(deb)))) $(eval $(foreach deb,$(MLNX_SDK_RDEBS),$(call make_url,$(deb)))) $(eval $(foreach deb,$(PYTHON_SDK_API) $(SX_KERNEL) $(SX_KERNEL_DEV),$(call make_url,$(deb)))) +ifeq ($(SDK_FROM_SRC), y) +SONIC_MAKE_DEBS += $(MLNX_SDK_RDEBS) $(PYTHON_SDK_API) $(SX_KERNEL) +else SONIC_ONLINE_DEBS += $(MLNX_SDK_RDEBS) $(PYTHON_SDK_API) $(SX_KERNEL) +endif + +SONIC_STRETCH_DEBS += $(SX_KERNEL) diff --git a/platform/nephos/docker-syncd-nephos.mk b/platform/nephos/docker-syncd-nephos.mk index bbfd1cba413..4929f77981b 100644 --- a/platform/nephos/docker-syncd-nephos.mk +++ b/platform/nephos/docker-syncd-nephos.mk @@ -15,3 +15,4 @@ $(DOCKER_SYNCD_BASE)_RUN_OPT += -v /var/run/docker-syncd:/var/run/sswsyncd $(DOCKER_SYNCD_BASE)_RUN_OPT += -v /host/warmboot:/var/warmboot $(DOCKER_SYNCD_BASE)_BASE_IMAGE_FILES += npx_diag:/usr/bin/npx_diag +$(DOCKER_SYNCD_BASE)_BASE_IMAGE_FILES += monit_syncd:/etc/monit/conf.d diff --git a/platform/nephos/docker-syncd-nephos/base_image_files/monit_syncd b/platform/nephos/docker-syncd-nephos/base_image_files/monit_syncd new file mode 100644 index 00000000000..0b9ec741cd5 --- /dev/null +++ b/platform/nephos/docker-syncd-nephos/base_image_files/monit_syncd @@ -0,0 +1,11 @@ +############################################################################### +## Monit configuration for syncd container +## process list: +## syncd +## dsserve +############################################################################### +check process syncd matching "/usr/bin/syncd" + if does not exist for 5 times within 5 cycles then alert + +check process dsserve matching "/usr/bin/dsserve /usr/bin/syncd" + if does not exist for 5 times within 5 cycles then alert diff --git a/platform/nephos/one-image.mk b/platform/nephos/one-image.mk index d29d0e8c935..60320f795b3 100644 --- a/platform/nephos/one-image.mk +++ b/platform/nephos/one-image.mk @@ -7,6 +7,9 @@ $(SONIC_ONE_IMAGE)_INSTALLS += $(NEPHOS_NPS_KERNEL) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(INGRASYS_S9130_32X_PLATFORM_MODULE) \ $(INGRASYS_S9230_64X_PLATFORM_MODULE) \ $(ACCTON_AS7116_54X_PLATFORM_MODULE) \ - $(CIG_CS6436_56P_PLATFORM_MODULE) + $(CIG_CS6436_56P_PLATFORM_MODULE) \ + $(CIG_CS6436_54P_PLATFORM_MODULE) \ + $(CIG_CS5435_54P_PLATFORM_MODULE) + $(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES) SONIC_INSTALLERS += $(SONIC_ONE_IMAGE) diff --git a/platform/nephos/platform-modules-cig.mk b/platform/nephos/platform-modules-cig.mk index 98bbadf9ce3..5cccf169255 100644 --- a/platform/nephos/platform-modules-cig.mk +++ b/platform/nephos/platform-modules-cig.mk @@ -1,12 +1,26 @@ -# Cig CS6436 56P Platform modules +# Cig Nephos Switch Platform modules -CIG_CS6436_56P_PLATFORM_MODULE_VERSION = 1.0.0 +CIG_MTK_PLATFORM_MODULE_VERSION = 1.0.0 -export CIG_CS6436_56P_PLATFORM_MODULE_VERSION +export CIG_MTK_PLATFORM_MODULE_VERSION -CIG_CS6436_56P_PLATFORM_MODULE = sonic-platform-cig-cs6436-56p_$(CIG_CS6436_56P_PLATFORM_MODULE_VERSION)_amd64.deb +CIG_CS6436_56P_PLATFORM_MODULE = sonic-platform-cig-cs6436-56p_$(CIG_MTK_PLATFORM_MODULE_VERSION)_amd64.deb $(CIG_CS6436_56P_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-cig $(CIG_CS6436_56P_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) $(CIG_CS6436_56P_PLATFORM_MODULE)_PLATFORM = x86_64-cig_cs6436_56p-r0 SONIC_DPKG_DEBS += $(CIG_CS6436_56P_PLATFORM_MODULE) -SONIC_STRETCH_DEBS += $(CIG_CS6436_56P_PLATFORM_MODULE) \ No newline at end of file +SONIC_STRETCH_DEBS += $(CIG_CS6436_56P_PLATFORM_MODULE) + +CIG_CS6436_54P_PLATFORM_MODULE = sonic-platform-cig-cs6436-54p_$(CIG_MTK_PLATFORM_MODULE_VERSION)_amd64.deb +$(CIG_CS6436_54P_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-cig +$(CIG_CS6436_54P_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) +$(CIG_CS6436_54P_PLATFORM_MODULE)_PLATFORM = x86_64-cig_cs6436_54p-r0 +SONIC_DPKG_DEBS += $(CIG_CS6436_54P_PLATFORM_MODULE) +SONIC_STRETCH_DEBS += $(CIG_CS6436_54P_PLATFORM_MODULE) + +CIG_CS5435_54P_PLATFORM_MODULE = sonic-platform-cig-cs5435-54p_$(CIG_MTK_PLATFORM_MODULE_VERSION)_amd64.deb +$(CIG_CS5435_54P_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-cig +$(CIG_CS5435_54P_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) +$(CIG_CS5435_54P_PLATFORM_MODULE)_PLATFORM = x86_64-cig_cs5435_54p-r0 +SONIC_DPKG_DEBS += $(CIG_CS5435_54P_PLATFORM_MODULE) +SONIC_STRETCH_DEBS += $(CIG_CS5435_54P_PLATFORM_MODULE) diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/classes/__init__.py b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/classes/__init__.py new file mode 100755 index 00000000000..e69de29bb2d diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/classes/fanutil.py b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/classes/fanutil.py new file mode 100755 index 00000000000..e69de29bb2d diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/classes/thermalutil.py b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/classes/thermalutil.py new file mode 100755 index 00000000000..e69de29bb2d diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/Makefile b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/Makefile new file mode 100644 index 00000000000..446fde4b0a7 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/Makefile @@ -0,0 +1,6 @@ +obj-m :=x86-64-cig-cs5435-54p-sysfs.o \ + x86-64-cig-cs5435-54p-cpld.o \ + x86-64-cig-cs5435-54p-fan.o \ + x86-64-cig-cs5435-54p-led.o \ + x86-64-cig-cs5435-54p-psu.o \ + x86-64-cig-cs5435-54p-sfp.o diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/i2c-algo-lpc.h b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/i2c-algo-lpc.h new file mode 100644 index 00000000000..dc9e30d16dd --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/i2c-algo-lpc.h @@ -0,0 +1,222 @@ +/* -------------------------------------------------------------------- + + * A hwmon driver for the CIG cs5435-54P + * + * Copyright (C) 2018 Cambridge, 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 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 I2C_LPC_H +#define I2C_LPC_H 1 + +/* ----- Control register bits ---------------------------------------- */ +#define I2C_LPC_PIN 0x80 +#define I2C_LPC_ESO 0x40 +#define I2C_LPC_ES1 0x20 +#define I2C_LPC_ES2 0x10 +#define I2C_LPC_ENI 0x08 + +#define I2C_LPC_STO 0x40 +#define I2C_LPC_ACK 0x01 + +/*command register*/ +#define I2C_LPC_STA 0x80 +#define I2C_LPC_ABT 0x40 + +/*status register*/ +#define I2C_LPC_TBE 0x02 +#define I2C_LPC_IBB 0x80 +#define I2C_LPC_RBF 0x01 +#define I2C_LPC_TD 0x08 + +#define I2C_LPC_START I2C_LPC_STA +#define I2C_LPC_STOP I2C_LPC_STO +#define I2C_LPC_REPSTART I2C_LPC_STA +#define I2C_LPC_IDLE + +/* ----- Status register bits ----------------------------------------- */ +/*#define I2C_LPC_PIN 0x80 as above*/ + +#define I2C_LPC_INI 0x40 /* 1 if not initialized */ +#define I2C_LPC_STS 0x20 +#define I2C_LPC_BER 0x10 +#define I2C_LPC_AD0 0x08 +#define I2C_LPC_LRB 0x08 +#define I2C_LPC_AAS 0x04 +#define I2C_LPC_LAB 0x02 +#define I2C_LPC_BB 0x80 + +/* ----- Chip clock frequencies --------------------------------------- */ +#define I2C_LPC_CLK3 0x00 +#define I2C_LPC_CLK443 0x10 +#define I2C_LPC_CLK6 0x14 +#define I2C_LPC_CLK 0x18 +#define I2C_LPC_CLK12 0x1c + +/* ----- transmission frequencies ------------------------------------- */ +#define I2C_LPC_TRNS90 0x00 /* 90 kHz */ +#define I2C_LPC_TRNS45 0x01 /* 45 kHz */ +#define I2C_LPC_TRNS11 0x02 /* 11 kHz */ +#define I2C_LPC_TRNS15 0x03 /* 1.5 kHz */ + + +#define I2C_LPC_OWNADR 0 +#define I2C_LPC_INTREG I2C_LPC_ES2 +#define I2C_LPC_CLKREG I2C_LPC_ES1 + +#define I2C_LPC_REG_TEST 0x01 +#define I2C_LPC_REG_BUS_SEL 0x80 +#define I2C_LPC_REG_DEVICE_ADDR 0x81 +#define I2C_LPC_REG_BYTE_COUNT 0x83 +#define I2C_LPC_REG_COMMAND 0x84 +#define I2C_LPC_REG_STATUS 0x85 +#define I2C_LPC_REG_DATA_RX1 0x86 +#define I2C_LPC_REG_DATA_RX2 0x87 +#define I2C_LPC_REG_DATA_RX3 0x88 +#define I2C_LPC_REG_DATA_RX4 0x89 +#define I2C_LPC_REG_DATA_TX1 0x8a +#define I2C_LPC_REG_DATA_TX2 0x8b +#define I2C_LPC_REG_DATA_TX3 0x8c +#define I2C_LPC_REG_DATA_TX4 0x8d + + +#define ADDR_REG_SFP_STATUS_ADDR 0X62 //reg addr +R/W# //1031 +#define ADDR_REG_SFP_STATUS_TX 0X63 // write data +#define ADDR_REG_SFP_STATUS_RX 0X64 //read data +#define ADDR_REG_SFP_STATUS_COMMAND 0X65 //cmd bit7=1,go +#define ADDR_REG_SFP_STATUS_STATUS 0X66 //status + +#define CPLD_MASTER_INTERRUPT_STATUS_REG 0x20 +#define CPLD_MASTER_INTERRUPT_MASK_REG 0x21 +#define CPLD_MASTER_INTERRUPT_ALL 0x3f +#define CPLD_MASTER_INTERRUPT_CPLD2 0x20 +#define CPLD_MASTER_INTERRUPT_CPLD1 0x10 +#define CPLD_MASTER_INTERRUPT_PSU2 0x08 +#define CPLD_MASTER_INTERRUPT_PSU1 0x04 +#define CPLD_MASTER_INTERRUPT_6320 0x02 +#define CPLD_MASTER_INTERRUPT_LSW 0x01 + + + +#define CPLD_SLAVE1_INTERRUPT_STATUS_L_REG 0x20 +#define CPLD_SLAVE1_INTERRUPT_STATUS_H_REG 0x21 +#define CPLD_SLAVE2_INTERRUPT_STATUS_L_REG 0x22 +#define CPLD_SLAVE2_INTERRUPT_STATUS_H_REG 0x23 +#define CPLD_SLAVE1_INTERRUPT_MASK_REG 0x24 +#define CPLD_SLAVE2_INTERRUPT_MASK_REG 0x25 + + +#define CPLD_SLAVE1_PRESENT08_REG 0x01 +#define CPLD_SLAVE1_PRESENT16_REG 0x02 +#define CPLD_SLAVE1_PRESENT24_REG 0x03 +#define CPLD_SLAVE2_PRESENT32_REG 0x04 +#define CPLD_SLAVE2_PRESENT40_REG 0x05 +#define CPLD_SLAVE2_PRESENT48_REG 0x06 + +#define CPLD_SLAVE1_RX_LOST08_REG 0x07 +#define CPLD_SLAVE1_RX_LOST16_REG 0x08 +#define CPLD_SLAVE1_RX_LOST24_REG 0x09 +#define CPLD_SLAVE2_RX_LOST32_REG 0x0a +#define CPLD_SLAVE2_RX_LOST40_REG 0x0b +#define CPLD_SLAVE2_RX_LOST48_REG 0x0c + +#define CPLD_SLAVE1_TX_FAULT08_REG 0x0d +#define CPLD_SLAVE1_TX_FAULT16_REG 0x0e +#define CPLD_SLAVE1_TX_FAULT24_REG 0x0f +#define CPLD_SLAVE2_TX_FAULT32_REG 0x10 +#define CPLD_SLAVE2_TX_FAULT40_REG 0x11 +#define CPLD_SLAVE2_TX_FAULT48_REG 0x12 + +#define CPLD_SLAVE2_PRESENT56_REG 0x19 +#define CPLD_SLAVE2_QSFP_CR56_REG 0x1a + + +#define CPLD_SLAVE1_INTERRUPT_PRESENT08 0x0001 +#define CPLD_SLAVE1_INTERRUPT_PRESENT16 0x0002 +#define CPLD_SLAVE1_INTERRUPT_PRESENT24 0x0004 +#define CPLD_SLAVE2_INTERRUPT_PRESENT32 0x0001 +#define CPLD_SLAVE2_INTERRUPT_PRESENT40 0x0002 +#define CPLD_SLAVE2_INTERRUPT_PRESENT48 0x0004 + +#define CPLD_SLAVE2_INTERRUPT_QSFP_CR56 0x0200 +#define CPLD_SLAVE2_INTERRUPT_PRESENT56 0x0400 + +#define CPLD_SLAVE1_INTERRUPT_RX_LOST08 0x0008 +#define CPLD_SLAVE1_INTERRUPT_RX_LOST16 0x0010 +#define CPLD_SLAVE1_INTERRUPT_RX_LOST24 0x0020 +#define CPLD_SLAVE2_INTERRUPT_RX_LOST32 0x0008 +#define CPLD_SLAVE2_INTERRUPT_RX_LOST40 0x0010 +#define CPLD_SLAVE2_INTERRUPT_RX_LOST48 0x0020 + +#define CPLD_SLAVE1_INTERRUPT_TX_FAULT08 0x0040 +#define CPLD_SLAVE1_INTERRUPT_TX_FAULT16 0x0080 +#define CPLD_SLAVE1_INTERRUPT_TX_FAULT24 0x0100 +#define CPLD_SLAVE2_INTERRUPT_TX_FAULT32 0x0040 +#define CPLD_SLAVE2_INTERRUPT_TX_FAULT40 0x0080 +#define CPLD_SLAVE2_INTERRUPT_TX_FAULT48 0x0100 + + + + + + + +#define WAIT_TIME_OUT_COUNT 100 + + +struct i2c_algo_lpc_data { + void *data; /* private data for lolevel routines */ + void (*setlpc) (void *data, int ctl, int val); + int (*getlpc) (void *data, int ctl); + int (*getown) (void *data); + int (*getclock) (void *data); + void (*waitforpin) (void *data); + + int (*xfer_begin) (void *data); + int (*xfer_end) (void *data); + + /* Multi-master lost arbitration back-off delay (msecs) + * This should be set by the bus adapter or knowledgable client + * if bus is multi-mastered, else zero + */ + unsigned long lab_mdelay; +}; + + +struct subsys_private { + struct kset subsys; + struct kset *devices_kset; + struct list_head interfaces; + struct mutex mutex; + + struct kset *drivers_kset; + struct klist klist_devices; + struct klist klist_drivers; + struct blocking_notifier_head bus_notifier; + unsigned int drivers_autoprobe:1; + struct bus_type *bus; + + struct kset glue_dirs; + struct class *class; +}; + +void cs5435_54p_sysfs_add_client(struct i2c_client *client); +void cs5435_54p_sysfs_remove_client(struct i2c_client *client); + + +#endif /* I2C_LPC8584_H */ diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-cpld.c b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-cpld.c new file mode 100644 index 00000000000..68f1192e58b --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-cpld.c @@ -0,0 +1,2209 @@ +/* + * A hwmon driver for the CIG cs5435-54P CPLD + * + * Copyright (C) 2018 Cambridge, 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 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 "i2c-algo-lpc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CPLD_USER +# include +#else +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + + + + + +/********************************************** Start ********************************************************/ + +/* + * ISA bus. + */ + +static void platform_isa_bus_release(struct device * dev) +{ + return ; +} + + +static struct device isa_bus = { + .init_name = "lpc-isa", + .release = platform_isa_bus_release, +}; + +struct isa_dev { + struct device dev; + struct device *next; + unsigned int id; +}; + +#define to_isa_dev(x) container_of((x), struct isa_dev, dev) + +static int isa_bus_match(struct device *dev, struct device_driver *driver) +{ + struct isa_driver *isa_driver = to_isa_driver(driver); + + if (dev->platform_data == isa_driver) { + if (!isa_driver->match || + isa_driver->match(dev, to_isa_dev(dev)->id)) + return 1; + dev->platform_data = NULL; + } + return 0; +} + +static int isa_bus_probe(struct device *dev) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->probe) + return isa_driver->probe(dev, to_isa_dev(dev)->id); + + return 0; +} + +static int isa_bus_remove(struct device *dev) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->remove) + return isa_driver->remove(dev, to_isa_dev(dev)->id); + + return 0; +} + +static void isa_bus_shutdown(struct device *dev) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->shutdown) + isa_driver->shutdown(dev, to_isa_dev(dev)->id); +} + +static int isa_bus_suspend(struct device *dev, pm_message_t state) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->suspend) + return isa_driver->suspend(dev, to_isa_dev(dev)->id, state); + + return 0; +} + +static int isa_bus_resume(struct device *dev) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->resume) + return isa_driver->resume(dev, to_isa_dev(dev)->id); + + return 0; +} + +static struct bus_type isa_bus_type = { + .name = "lpc-isa", + .match = isa_bus_match, + .probe = isa_bus_probe, + .remove = isa_bus_remove, + .shutdown = isa_bus_shutdown, + .suspend = isa_bus_suspend, + .resume = isa_bus_resume +}; + +static void isa_dev_release(struct device *dev) +{ + kfree(to_isa_dev(dev)); +} + +void lpc_unregister_driver(struct isa_driver *isa_driver) +{ + struct device *dev = isa_driver->devices; + + while (dev) { + struct device *tmp = to_isa_dev(dev)->next; + device_unregister(dev); + dev = tmp; + } + driver_unregister(&isa_driver->driver); +} + + +int lpc_register_driver(struct isa_driver *isa_driver, unsigned int ndev) +{ + int error; + unsigned int id; + + isa_driver->driver.bus = &isa_bus_type; + isa_driver->devices = NULL; + + error = driver_register(&isa_driver->driver); + if (error) + return error; + + for (id = 0; id < ndev; id++) { + struct isa_dev *isa_dev; + + isa_dev = kzalloc(sizeof *isa_dev, GFP_KERNEL); + if (!isa_dev) { + error = -ENOMEM; + break; + } + + isa_dev->dev.parent = &isa_bus; + isa_dev->dev.bus = &isa_bus_type; + + dev_set_name(&isa_dev->dev, "%s.%u", + isa_driver->driver.name, id); + isa_dev->dev.platform_data = isa_driver; + isa_dev->dev.release = isa_dev_release; + isa_dev->id = id; + + isa_dev->dev.coherent_dma_mask = DMA_BIT_MASK(24); + isa_dev->dev.dma_mask = &isa_dev->dev.coherent_dma_mask; + + error = device_register(&isa_dev->dev); + if (error) { + put_device(&isa_dev->dev); + break; + } + + if (isa_dev->dev.platform_data) { + isa_dev->next = isa_driver->devices; + isa_driver->devices = &isa_dev->dev; + } else + device_unregister(&isa_dev->dev); + } + + if (!error && !isa_driver->devices) + error = -ENODEV; + + if (error) + isa_unregister_driver(isa_driver); + + return error; +} + + +int lpc_bus_init(void) +{ + int error; + + error = bus_register(&isa_bus_type); + if (!error) { + error = device_register(&isa_bus); + if (error) + bus_unregister(&isa_bus_type); + } + return error; +} + +void lpc_bus_exit(void) +{ + + device_unregister(&isa_bus); + + bus_unregister(&isa_bus_type); +} + + +/********************************************** End ********************************************************/ + + + + + + +/********************************************** Start ********************************************************/ +/* + * module parameters: + */ +static int i2c_debug = 0; +static struct mutex lpc_lock; + + +#define DEB2(x) if (i2c_debug == 2) x +#define DEB3(x) if (i2c_debug == 3) x + /* print several statistical values */ +#define DEBPROTO(x) if (i2c_debug == 9) x; + /* debug the protocol by showing transferred bits */ +#define DEF_TIMEOUT 160 + + + +/* setting states on the bus with the right timing: */ + +#define set_lpc(adap, ctl, val) adap->setlpc(adap->data, ctl, val) +#define get_lpc(adap, ctl) adap->getlpc(adap->data, ctl) +#define get_own(adap) adap->getown(adap->data) +#define get_clock(adap) adap->getclock(adap->data) +#define i2c_outaddr(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DEVICE_ADDR, val) + +#define i2c_outbyte1(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DATA_TX1, val) +#define i2c_outbyte2(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DATA_TX2, val) +#define i2c_outbyte3(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DATA_TX3, val) +#define i2c_outbyte4(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DATA_TX4, val) +#define i2c_inbyte1(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX1) +#define i2c_inbyte2(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX2) +#define i2c_inbyte3(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX3) +#define i2c_inbyte4(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX4) + + + +#define LPC_FPRINTF_LOG_PATH "/tmp/file.log" +struct file *lpc_fprintf_file = NULL; + +static int lpc_fprintf_debug(const char *fmt, ...) +{ + char lpc_fprintf_buf[256]={0}; + struct va_format vaf; + va_list args; + int r; + mm_segment_t old_fs; + struct timeval tv; + struct rtc_time tm; + + do_gettimeofday(&tv); + + rtc_time_to_tm(tv.tv_sec,&tm); + + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + r=snprintf(lpc_fprintf_buf,sizeof(lpc_fprintf_buf),"[%04d.%08d] %pV\n",tm.tm_sec, (int)tv.tv_usec, &vaf); + va_end(args); + old_fs = get_fs(); + set_fs(KERNEL_DS); + vfs_write(lpc_fprintf_file, (char *)&lpc_fprintf_buf, strlen(lpc_fprintf_buf), &lpc_fprintf_file->f_pos); + set_fs(old_fs); + memset(lpc_fprintf_buf,0x0,sizeof(lpc_fprintf_buf)); + return r; + +} + + + +static int lpc_fprintf_init(void) +{ + printk("lpc_fprintf_init.\n"); + + if(lpc_fprintf_file == NULL) + lpc_fprintf_file = filp_open(LPC_FPRINTF_LOG_PATH, O_RDWR | O_APPEND | O_CREAT, 0644); + + if (IS_ERR(lpc_fprintf_file)) { + printk("Error occured while opening file %s, exiting...\n", LPC_FPRINTF_LOG_PATH); + return -1; + } + + return 0; +} + +static int lpc_fprintf_exit(void) +{ + printk("lpc_fprintf_exit.\n"); + + if(lpc_fprintf_file != NULL) + filp_close(lpc_fprintf_file, NULL); + + return 0; +} + + +/* other auxiliary functions */ + + +void print_reg(struct i2c_algo_lpc_data *adap) +{ + unsigned char status; + DEBPROTO(lpc_fprintf_debug("================================================\n");) + status = get_lpc(adap, I2C_LPC_REG_BUS_SEL); + DEBPROTO(lpc_fprintf_debug("%s select reg %x : %x\n",__func__,I2C_LPC_REG_BUS_SEL, status);) + status = get_lpc(adap, I2C_LPC_REG_BYTE_COUNT); + DEBPROTO(lpc_fprintf_debug("%s count reg %x : %x\n",__func__,I2C_LPC_REG_BYTE_COUNT, status);) + + status = get_lpc(adap, I2C_LPC_REG_COMMAND); + DEBPROTO(lpc_fprintf_debug("%s command reg %x : %x\n",__func__,I2C_LPC_REG_COMMAND, status);) + status = get_lpc(adap, I2C_LPC_REG_DEVICE_ADDR); + DEBPROTO(lpc_fprintf_debug("%s address reg %x : %x\n",__func__,I2C_LPC_REG_DEVICE_ADDR, status);) + + status = get_lpc(adap, I2C_LPC_REG_STATUS); + DEBPROTO(lpc_fprintf_debug("%s status reg %x : %x\n",__func__,I2C_LPC_REG_STATUS, status);) +} + + + +static void i2c_repstart(struct i2c_algo_lpc_data *adap) +{ + DEBPROTO(lpc_fprintf_debug("%s :\n",__func__);) + set_lpc(adap, I2C_LPC_REG_COMMAND, I2C_LPC_REPSTART); +} + +static void i2c_stop(struct i2c_algo_lpc_data *adap) +{ + DEBPROTO(lpc_fprintf_debug("%s :\n",__func__);) + set_lpc(adap, I2C_LPC_REG_COMMAND, I2C_LPC_STOP); + udelay(60); + set_lpc(adap, I2C_LPC_REG_COMMAND, 0x00); +} + + + + +static void i2c_start(struct i2c_algo_lpc_data *adap) +{ + print_reg(adap); + + set_lpc(adap, I2C_LPC_REG_COMMAND, I2C_LPC_START); + + print_reg(adap); +} + + + + +static int wait_for_bb(struct i2c_algo_lpc_data *adap) +{ + + int timeout = DEF_TIMEOUT; + int status; + + while (--timeout) { + status = get_lpc(adap, I2C_LPC_REG_STATUS); + + DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus free status : %x\n",__func__,status);) + + if(status == I2C_LPC_TD) + { + DEBPROTO(lpc_fprintf_debug("%s : Bus is free status : %x\n",__func__,status);) + break; + } + } + + if (timeout == 0) { + DEBPROTO(lpc_fprintf_debug("%s : Timeout for free busy status : %x\n",__func__,status);) + return -ETIMEDOUT; + } + + + + return 0; +} + + +static int wait_for_be(int mode,struct i2c_algo_lpc_data *adap) +{ + + int timeout = DEF_TIMEOUT; + unsigned char status; + + + while (--timeout) { + + status = get_lpc(adap, I2C_LPC_REG_STATUS); + + DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus empty status : %x\n",__func__,status);) + + if(mode == 1) + { + if((status & I2C_LPC_IBB) && (status & I2C_LPC_TBE)) + { + DEBPROTO(lpc_fprintf_debug("%s : Bus is empty status : %x\n",__func__,status);) + break; + } + } + else + { + if(status & I2C_LPC_TD) + { + DEBPROTO(lpc_fprintf_debug("%s : Bus is empty status : %x\n",__func__,status);) + break; + } + } + + status = get_lpc(adap, I2C_LPC_REG_TEST); + + DEBPROTO(lpc_fprintf_debug("%s : The test register data : %x\n",__func__,status);) + udelay(1); /* wait for 100 us */ + } + + if (timeout == 0) { + DEBPROTO(lpc_fprintf_debug("%s : Timeout waiting for Bus Empty\n",__func__);) + return -ETIMEDOUT; + } + + return 0; +} + + +static int wait_for_bf(struct i2c_algo_lpc_data *adap) +{ + + int timeout = DEF_TIMEOUT; + int status; + + + while (--timeout) { + status = get_lpc(adap, I2C_LPC_REG_STATUS); + + DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus full status : %x\n",__func__,status);) + + if(status & I2C_LPC_RBF) + { + DEBPROTO(lpc_fprintf_debug("%s : Bus is full status : %x\n",__func__,status);) + break; + } + + status = get_lpc(adap, I2C_LPC_REG_TEST); + + DEBPROTO(lpc_fprintf_debug("%s : The test register data : %x\n",__func__,status);) + udelay(1); /* wait for 100 us */ + } + + if (timeout == 0) { + DEBPROTO(lpc_fprintf_debug("%s : Timeout waiting for Bus Full\n",__func__);) + return -ETIMEDOUT; + } + + return 0; +} + +static int wait_for_td(struct i2c_algo_lpc_data *adap) +{ + + int timeout = DEF_TIMEOUT; + int status=0; + + while (--timeout) { + udelay(4); + status = get_lpc(adap, I2C_LPC_REG_STATUS); + + DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus done status : %x\n",__func__,status);) + + if(status == I2C_LPC_TD) + { + DEBPROTO(lpc_fprintf_debug("%s : Bus is done status : %x\n",__func__,status);) + break; + } + } + + if (timeout == 0) { + DEBPROTO(lpc_fprintf_debug("%s : Timeout waiting for Bus Done\n",__func__);) + return -ETIMEDOUT; + } + + return 0; +} + + + +static int wait_for_pin(struct i2c_algo_lpc_data *adap, int *status) +{ + int timeout = DEF_TIMEOUT; + *status = get_lpc(adap, I2C_LPC_REG_STATUS); + + while ((*status & I2C_LPC_TBE) && --timeout) { + *status = get_lpc(adap, I2C_LPC_REG_STATUS); + } + + if (timeout == 0) + return -ETIMEDOUT; + + + return 0; +} + + +static int lpc_doAddress(struct i2c_algo_lpc_data *adap,struct i2c_msg *msg) +{ + unsigned short flags = msg->flags; + unsigned char addr; + + addr = msg->addr << 1; + if (flags & I2C_M_RD) + { + addr |= 1; + DEBPROTO(lpc_fprintf_debug("step 7 : read mode then write device address 0x%x\n",addr);) + } + else + { + DEBPROTO(lpc_fprintf_debug("step 2 : write mode then write device address 0x%x\n",addr);) + } + + if (flags & I2C_M_REV_DIR_ADDR) + { + addr ^= 1; + + } + i2c_outaddr(adap, addr); + return 0; + +} + + +static int lpc_sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) +{ + struct i2c_algo_lpc_data *adap = i2c_adap->algo_data; + int i = 0,timeout=0; + + unsigned int count = msg->len; + unsigned char *buf = msg->buf; + + do{ + lpc_doAddress(adap,msg); + set_lpc(adap, I2C_LPC_REG_BYTE_COUNT, (count-i) >= 4 ? 4:(count - i)); + DEBPROTO(lpc_fprintf_debug("step 3 : write register count %x\n",count);) + + if((count -i) >= 4) + { + i2c_outbyte1(adap, buf[i+0] & 0xff); + i2c_outbyte2(adap, buf[i+1] & 0xff); + i2c_outbyte3(adap, buf[i+2] & 0xff); + i2c_outbyte4(adap, buf[i+3] & 0xff); + + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+0,buf[i+0]);) + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+1,buf[i+1]);) + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+2,buf[i+2]);) + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+3,buf[i+3]);) + i += 4; + } + else if((count -i) == 3) + { + i2c_outbyte1(adap, buf[i+0] & 0xff); + i2c_outbyte2(adap, buf[i+1] & 0xff); + i2c_outbyte3(adap, buf[i+2] & 0xff); + + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+0,buf[i+0]);) + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+1,buf[i+1]);) + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+2,buf[i+2]);) + + i += 3; + } + else if((count -i) == 2) + { + i2c_outbyte1(adap, buf[i+0] & 0xff); + i2c_outbyte2(adap, buf[i+1] & 0xff); + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+0,buf[i+0]);) + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+1,buf[i+1]);) + i += 2; + } + else if((count -i) == 1) + { + i2c_outbyte1(adap, buf[i+0] & 0xff); + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+0,buf[i+0]);) + i += 1; + } + + /* Send START */ + DEBPROTO(lpc_fprintf_debug("step 5-1 : Delay 6mS \n");) + udelay(6000); + DEBPROTO(lpc_fprintf_debug("step 5-2 : Start to transfrom \n");) + i2c_stop(adap); + i2c_start(adap); + DEBPROTO(lpc_fprintf_debug("step 5-3 : Start done\n");) + + udelay(400); + DEBPROTO(lpc_fprintf_debug("step 6 : Waiting for BE\n");) + timeout = wait_for_td(adap); + if (timeout) { + DEBPROTO(lpc_fprintf_debug("step 6 : Timeout waiting for BE \n");) + return -EREMOTEIO; + } + }while (i < count); + + if(i == count) + { + DEBPROTO(lpc_fprintf_debug("Writen %d bytes successd !\n",count);) + return i; + } + else + { + DEBPROTO(lpc_fprintf_debug("Writen %d bytes failed \n",count);) + return -EIO; + } +} + +static int lpc_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) +{ + int i=0,timeout=0; + struct i2c_algo_lpc_data *adap = i2c_adap->algo_data; + + unsigned int count = msg->len; + unsigned char *buf = msg->buf; + + do{ + lpc_doAddress(adap,msg); + set_lpc(adap, I2C_LPC_REG_BYTE_COUNT, (count-i) >= 4 ? 4:(count - i)); + DEBPROTO(lpc_fprintf_debug("step 8 : write register count %d\n",count);) + + /* Send START */ + DEBPROTO(lpc_fprintf_debug("step 9-1 : Delay 6mS\n");) + udelay(6000); + DEBPROTO(lpc_fprintf_debug("step 9-2 : Start to receive data\n");) + i2c_stop(adap); + i2c_start(adap); + DEBPROTO(lpc_fprintf_debug("step 9-3 : Start done\n");) + + udelay(400); + DEBPROTO(lpc_fprintf_debug("step 10 : Waiting for TD\n");) + timeout = wait_for_td(adap); + if (timeout) { + DEBPROTO(lpc_fprintf_debug("step 10 : Timeout waiting for TD \n");) + return -EREMOTEIO; + } + + if((count -i) >= 4) + { + buf[i+0] = 0xff & i2c_inbyte1(adap); + buf[i+1] = 0xff & i2c_inbyte2(adap); + buf[i+2] = 0xff & i2c_inbyte3(adap); + buf[i+3] = 0xff & i2c_inbyte4(adap); + + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+0,buf[i+0]);) + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+1,buf[i+1]);) + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+2,buf[i+2]);) + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+3,buf[i+3]);) + + i += 4; + } + else if((count -i) == 3) + { + buf[i+0] = 0xff & i2c_inbyte1(adap); + buf[i+1] = 0xff & i2c_inbyte2(adap); + buf[i+2] = 0xff & i2c_inbyte3(adap); + + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+0,buf[i+0]);) + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+1,buf[i+1]);) + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+2,buf[i+2]);) + + i += 3; + } + else if((count -i) == 2) + { + buf[i+0] = 0xff & i2c_inbyte1(adap); + buf[i+1] = 0xff & i2c_inbyte2(adap); + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+0,buf[i+0]);) + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+1,buf[i+1]);) + i += 2; + } + else if((count -i) == 1) + { + buf[i+0] = 0xff & i2c_inbyte1(adap); + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+0,buf[i+0]);) + i += 1; + } + + + }while(i < count); + + if(i == count) + { + DEBPROTO(lpc_fprintf_debug("Read %d bytes successd !\n",count);) + return i; + } + else + { + DEBPROTO(lpc_fprintf_debug("Read %d bytes failed \n",count);) + return -EIO; + } +} + + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; +#define LPC_I2C_MAX_NCHANS 6 + + +struct lpc_iic { + struct i2c_adapter *virt_adaps[LPC_I2C_MAX_NCHANS]; + u8 last_chan; /* last register value */ +}; + + +static int lpc_master_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, + int num) +{ + struct i2c_algo_lpc_data *adap = i2c_adap->algo_data; + struct i2c_msg *pmsg; + int i; + int ret=0; + + mutex_lock(&lpc_lock); + + if (adap->xfer_begin) + adap->xfer_begin(&i2c_adap->nr); + + + for (i = 0;ret >= 0 && i < num; i++) { + pmsg = &msgs[i]; + + DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n", + pmsg->flags & I2C_M_RD ? "read" : "write", + pmsg->len, pmsg->addr, i + 1, num);) + + DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n", + i, msgs[i].addr, msgs[i].flags, msgs[i].len);) + + if (pmsg->flags & I2C_M_RD) { + ret = lpc_readbytes(i2c_adap, pmsg); + + if (ret != pmsg->len) { + DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: fail: " + "only read %d bytes.\n",ret)); + } else { + DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: read %d bytes.\n",ret)); + } + } else { + + ret = lpc_sendbytes(i2c_adap, pmsg); + + if (ret != pmsg->len) { + DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: fail: " + "only wrote %d bytes.\n",ret)); + } else { + DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: wrote %d bytes.\n",ret)); + } + } + } + + if (adap->xfer_end) + adap->xfer_end(&i2c_adap->nr); + + mutex_unlock(&lpc_lock); + + DEBPROTO(lpc_fprintf_debug("ret = 0x%x num = 0x%x i = 0x%x.\n",ret,num,i)); + + return ret = (ret < 0) ? ret : num; +} + + +static u32 lpc_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_QUICK; +} + +/* exported algorithm data: */ +static const struct i2c_algorithm lpc_algo = { + .master_xfer = lpc_master_xfer, + //.smbus_xfer = lpc_smbus_xfer, + .functionality = lpc_func, +}; + + +/********************************************** End ********************************************************/ + + + + + + +/********************************************** Start ********************************************************/ +#define DEFAULT_BASE 0x0a00 + +static int lpc_base= 0x0a00; +static u8 __iomem *lpc_base_iomem; + +static int lpc_irq; +static int lpc_clock = 0x1c; +static int lpc_own = 0x55; +static int lpc_mmapped; + +static unsigned long lpc_base_addr = 0x0a00; +static unsigned int lpc_io_space_size = 2; + +static unsigned long LPC_INDEX_REG; +static unsigned long LPC_DATA_REG; + + +/* notice : removed static struct i2c_lpc_iic gpi; code - + this module in real supports only one device, due to missing arguments + in some functions, called from the algo-lpc module. Sometimes it's + need to be rewriten - but for now just remove this for simpler reading */ + +static wait_queue_head_t lpc_wait; +static int lpc_pending; +static spinlock_t lock; +static spinlock_t lpc_slock; + +static struct i2c_adapter lpc_iic_ops; + +struct cpld_dev_type { + struct resource *io_resource; + struct semaphore sem; + struct cdev cdev; +}; + +struct cpld_dev_type *cpld_device; + + +/* ----- local functions ---------------------------------------------- */ + +static void lpc_cpld_setbyte(void *data, int ctl, int val) +{ + outb(ctl, LPC_INDEX_REG); + mb(); + + outb(val, LPC_DATA_REG); + mb(); +} + +static int lpc_cpld_getbyte(void *data, int ctl) +{ + u8 val = 0; + + outb(ctl, LPC_INDEX_REG); + mb(); + + val = inb(LPC_DATA_REG); + mb(); + + return val; +} + +static void lpc_iic_setbyte(void *data, int ctl, int val) +{ + if (!cpld_device) + { + return ; + } + + if (down_interruptible(&cpld_device->sem)) + { + return ; + } + + + lpc_cpld_setbyte(data,ctl,val); + + up(&cpld_device->sem); + DEBPROTO(lpc_fprintf_debug("%s REG[%x] = %x\n",__func__,ctl,val);) +} + + +static int lpc_iic_getbyte(void *data, int ctl) +{ + u8 val = 0; + if (!cpld_device) + return -ENOTTY; + + if (down_interruptible(&cpld_device->sem)) + return -ERESTARTSYS; + + val = lpc_cpld_getbyte(data,ctl); + + up(&cpld_device->sem); + DEBPROTO(lpc_fprintf_debug("%s REG[%x] = %x\n",__func__,ctl,val);) + return val; +} + +int cig_cpld_read_register(u8 reg_off, u8 *val) +{ + if (!cpld_device) + return -ENOTTY; + + if (down_interruptible(&cpld_device->sem)) + return -ERESTARTSYS; + + *val = lpc_cpld_getbyte(cpld_device, reg_off); + + up(&cpld_device->sem); + + return 0; +} +EXPORT_SYMBOL(cig_cpld_read_register); + +int cig_cpld_write_register(u8 reg_off, u8 val) +{ + if (!cpld_device) + return -ENOTTY; + + if (down_interruptible(&cpld_device->sem)) + return -ERESTARTSYS; + + lpc_cpld_setbyte(cpld_device, reg_off, val); + up(&cpld_device->sem); + return 0; +} +EXPORT_SYMBOL(cig_cpld_write_register); + + + +static int lpc_iic_getown(void *data) +{ + return (lpc_own); +} + + +static int lpc_iic_getclock(void *data) +{ + return (lpc_clock); +} + +static void lpc_iic_waitforpin(void *data) +{ + DEFINE_WAIT(wait); + int timeout = 2; + unsigned long flags; + + if (lpc_irq > 0) { + spin_lock_irqsave(&lock, flags); + if (lpc_pending == 0) { + spin_unlock_irqrestore(&lock, flags); + prepare_to_wait(&lpc_wait, &wait, TASK_INTERRUPTIBLE); + if (schedule_timeout(timeout*HZ)) { + spin_lock_irqsave(&lock, flags); + if (lpc_pending == 1) { + lpc_pending = 0; + } + spin_unlock_irqrestore(&lock, flags); + } + finish_wait(&lpc_wait, &wait); + } else { + lpc_pending = 0; + spin_unlock_irqrestore(&lock, flags); + } + } else { + udelay(100); + } +} + + +static irqreturn_t lpc_iic_handler(int this_irq, void *dev_id) { + spin_lock(&lock); + lpc_pending = 1; + spin_unlock(&lock); + wake_up_interruptible(&lpc_wait); + return IRQ_HANDLED; +} + +static int board_id = 0; + + +static int lpc_iic_select(void *data) +{ + unsigned int chan_id=0; + chan_id = *(unsigned int *)data; + chan_id -= 2; + DEBPROTO(lpc_fprintf_debug("step 1 : selest channel id = %d\n",chan_id);) + lpc_iic_setbyte(data,I2C_LPC_REG_BUS_SEL,chan_id); + + return 0; +} + +static int lpc_iic_deselect(void *data) +{ + + unsigned int chan_id=0; + chan_id = *(unsigned int *)data; + chan_id -= 2; + DEBPROTO(lpc_fprintf_debug("step last :deselect channel id = %d\n",chan_id);) + + return 0; +} + + +/* ------------------------------------------------------------------------ + * Encapsulate the above functions in the correct operations structure. + * This is only done when more than one hardware adapter is supported. + */ +static struct i2c_algo_lpc_data lpc_iic_data = { + .setlpc = lpc_iic_setbyte, + .getlpc = lpc_iic_getbyte, + .getown = lpc_iic_getown, + .getclock = lpc_iic_getclock, + .waitforpin = lpc_iic_waitforpin, + .xfer_begin = lpc_iic_select, + .xfer_end = lpc_iic_deselect, +}; + +#include + +static struct i2c_adapter lpc_iic_arr_ops[LPC_I2C_MAX_NCHANS] = {0}; + +static void dummy_setscl(void *data, int state) +{ + return; +} + +static void dummy_setsda(void *data, int state) +{ + return; + +} + +static int dummy_getscl(void *data) +{ + return 1; + +} + +static int dummy_getsda(void *data) +{ + return 1; +} + + +static struct i2c_algo_bit_data dummy_algo_data = { + .setsda = dummy_setsda, + .setscl = dummy_setscl, + .getsda = dummy_getsda, + .getscl = dummy_getscl, + .udelay = 50, + .timeout = HZ, +}; + + +static int dummy_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, + int num) +{ + return 1; +} + +static u32 dummy_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_QUICK; +} + + +static const struct i2c_algorithm dummy_algo = { + .master_xfer = dummy_xfer, + .functionality = dummy_func, +}; + + + +static struct i2c_adapter i2c_dummy = { + .owner = THIS_MODULE, + .class = I2C_CLASS_HWMON, + .algo_data = &dummy_algo_data, + .algo = &dummy_algo, + .name = "i2c_dummy", +}; + + +static int lpc_iic_match(struct device *dev, unsigned int id) +{ + /* sanity checks for lpc_mmapped I/O */ + + DEB2(printk("lpc_iic_match\n");) + + + if (lpc_base < DEFAULT_BASE) { + dev_err(dev, "incorrect lpc_base address (%#x) specified " + "for lpc_mmapped I/O\n", lpc_base); + return 0; + } + + if (lpc_base == 0) { + lpc_base = DEFAULT_BASE; + } + return 1; +} + +static int lpc_iic_probe(struct device *dev, unsigned int id) +{ + int rval,num; + + lpc_fprintf_init(); + + DEB2(printk("lpc_iic_probe\n");) + + mutex_init(&lpc_lock); + + for(num = 0; num < LPC_I2C_MAX_NCHANS;num++) + { + lpc_iic_arr_ops[num].dev.parent = dev; + lpc_iic_arr_ops[num].owner = THIS_MODULE; + lpc_iic_arr_ops[num].class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + lpc_iic_arr_ops[num].algo = &lpc_algo; + lpc_iic_arr_ops[num].algo_data = &lpc_iic_data, + lpc_iic_arr_ops[num].nr=num; + snprintf(lpc_iic_arr_ops[num].name, sizeof(lpc_iic_arr_ops[num].name), "i2c-%d-lpc", i2c_adapter_id(&lpc_iic_arr_ops[num])); + rval |= i2c_add_adapter(&lpc_iic_arr_ops[num]); + DEB2(printk("%s\n",lpc_iic_arr_ops[num].name);) + } + + return 0; +} + +static int lpc_iic_remove(struct device *dev, unsigned int id) +{ + int num; + DEB2(printk("lpc_iic_remove\n")); + + lpc_fprintf_exit(); + for(num = LPC_I2C_MAX_NCHANS - 1; num >= 0 ;num--) + i2c_del_adapter(&lpc_iic_arr_ops[num]); + + + return 0; +} + +static struct isa_driver i2c_lpc_driver = { + .match = lpc_iic_match, + .probe = lpc_iic_probe, + .remove = lpc_iic_remove, + .driver = { + .owner = THIS_MODULE, + .name = "lpc-iic", + }, +}; + +/********************************************** End ********************************************************/ + + + + + + +/********************************************** Start ********************************************************/ + +static int cpld_major = 0; +static int cpld_minor = 0; + +struct cpld_rw_msg { + unsigned char addr; + unsigned char data; +}; + + +static struct cpld_rw_msg param_read = {-1}; +static struct cpld_rw_msg param_write = {-1}; +static struct cpld_rw_msg param_reads = {-1}; +static struct cpld_rw_msg param_writes = {-1}; + +void cpld_sysfs_kobj_release(struct kobject *kobj) +{ + return; +} + +int cpld_sysfs_add_attr(struct kobject* kobj, char* attr_name) +{ + + struct attribute *attr; + + attr = kmalloc(sizeof(struct attribute), GFP_KERNEL); + attr->name = attr_name; + attr->mode = 0644; + + return sysfs_create_file(kobj, attr); +} + +static int cig_cpld_write_slave_cpld_register(u8 reg_addr, u8 reg_data); +static int cig_cpld_read_slave_cpld_register(u8 reg_addr, u8 *reg_data); + + +static ssize_t cpld_sysfs_show(struct kobject *kobj, struct attribute *attr, char *buffer) +{ + u8 val=0,ret=0,year=0,month=0,day=0,cpld_m=0,cpld_1=0,cpld_2=0; + + if (0 == strcmp(attr->name, "read")) + { + val = lpc_iic_getbyte(NULL,param_read.addr); + ret = sprintf(buffer,"read : addr = 0x%x val = 0x%x\n",param_read.addr, val); + + } + else if (0 == strcmp(attr->name, "write")) + { + lpc_iic_setbyte(NULL, param_write.addr,param_write.data); + ret = sprintf(buffer,"write : addr = 0x%x val = 0x%x\n",param_write.addr, param_write.data); + } + else if (0 == strcmp(attr->name, "version")) + { + cpld_m = lpc_iic_getbyte(NULL, 0x02); + year = lpc_iic_getbyte(NULL, 0x03); + month = lpc_iic_getbyte(NULL, 0x04); + day = lpc_iic_getbyte(NULL, 0x05); + + cig_cpld_read_slave_cpld_register(0x1d,&cpld_1); + cig_cpld_read_slave_cpld_register(0x1e,&cpld_2); + + ret = sprintf(buffer,"Main CPLD version : V%02x\n"\ + "Main CPLD date : 20%02x-%02x-%02x\n"\ + "Slave 1 CPLD version : V%02x\n"\ + "Slave 2 CPLD version : V%02x\n",cpld_m,year,month,day,cpld_1,cpld_2); + } + if (0 == strcmp(attr->name, "reads")) + { + ret = cig_cpld_read_slave_cpld_register(param_reads.addr,&val); + if (ret < 0) + printk("ERROR:Failed to read slave cpld.\n"); + ret = sprintf(buffer,"reads : addr = 0x%x val = 0x%x\n",param_reads.addr, val); + + } + else if (0 == strcmp(attr->name, "writes")) + { + ret = cig_cpld_write_slave_cpld_register(param_writes.addr,param_writes.data); + if (ret < 0) + printk("ERROR:Failed to read slave cpld.\n"); + ret = sprintf(buffer,"writes : addr = 0x%x val = 0x%x\n",param_writes.addr, param_writes.data); + } + + + return ret; + +} + +static ssize_t cpld_sysfs_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) +{ + int param[3]; + + if (0 == strcmp(attr->name, "read")) + { + sscanf(buffer, "0x%02x", ¶m[0]); + param_read.addr = param[0]; + } + else if (0 == strcmp(attr->name, "write")) + { + sscanf(buffer, "0x%2x 0x%02x", ¶m[0], ¶m[1]); + param_write.addr = param[0]; + param_write.data = param[1]; + } + if (0 == strcmp(attr->name, "reads")) + { + sscanf(buffer, "0x%02x", ¶m[0]); + param_reads.addr = param[0]; + } + else if (0 == strcmp(attr->name, "writes")) + { + sscanf(buffer, "0x%2x 0x%02x", ¶m[0], ¶m[1]); + param_writes.addr = param[0]; + param_writes.data = param[1]; + } + return count; +} + + + +static struct sysfs_ops cpld_sysfs_ops = +{ + .show = cpld_sysfs_show, + .store = cpld_sysfs_store, +}; + +static struct kobj_type cpld_kobj_type = +{ + .release = cpld_sysfs_kobj_release, + .sysfs_ops = &cpld_sysfs_ops, + .default_attrs = NULL, +}; + + +static const char driver_name[] = "cpld_drv"; +static atomic_t cpld_available = ATOMIC_INIT(1); +static struct class *cpld_class; +static struct device *cpld_dev; + + + +#define CPLD_IOC_MAGIC '[' + +#define CPLD_IOC_RDREG _IOR(CPLD_IOC_MAGIC, 0, struct cpld_rw_msg) +#define CPLD_IOC_WRREG _IOW(CPLD_IOC_MAGIC, 1, struct cpld_rw_msg) + +#define CPLD_IOC_MAXNR 2 + + +int cpld_open(struct inode *inode, struct file *filp) +{ + struct cpld_dev_type *dev; + + if (! atomic_dec_and_test(&cpld_available)) { + atomic_inc(&cpld_available); + return -EBUSY; + } + + dev = container_of(inode->i_cdev, struct cpld_dev_type, cdev); + filp->private_data = dev; + + return 0; +} + +int cpld_release(struct inode *inode, struct file *flip) +{ + atomic_inc(&cpld_available); + return 0; +} + + +long cpld_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int rc = 0; + int err = 0; + struct cpld_dev_type *dev = (struct cpld_dev_type *)filp->private_data; + struct cpld_rw_msg msg; + + if (_IOC_TYPE(cmd) != CPLD_IOC_MAGIC) + return -ENOTTY; + if (_IOC_NR(cmd) > CPLD_IOC_MAXNR) + return -ENOTTY; + + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (err) + return -EFAULT; + + if (down_interruptible(&dev->sem)) + return -ERESTARTSYS; + + switch(cmd){ + case CPLD_IOC_RDREG: + rc = copy_from_user(&msg, (void __user *)arg, sizeof(msg)); + if (!rc) { + msg.data = lpc_cpld_getbyte(dev, msg.addr); + rc = copy_to_user((void __user *)arg, &msg, sizeof(msg)); + } + break; + + case CPLD_IOC_WRREG: + rc = copy_from_user(&msg, (void __user *)arg, sizeof(msg)); + if (!rc) { + lpc_cpld_setbyte(dev, msg.addr, msg.data); + } + break; + default: + rc = -ENOTTY; + break; + } + up(&dev->sem); + + return rc; +} + +struct file_operations cpld_fops = { + .owner = THIS_MODULE, + .open = cpld_open, + .unlocked_ioctl = cpld_ioctl, + .release = cpld_release, +}; + + +static void cpld_setup_cdev(struct cpld_dev_type *dev) +{ + int err, devno = MKDEV(cpld_major, cpld_minor); + + cdev_init(&dev->cdev, &cpld_fops); + dev->cdev.owner = THIS_MODULE; + dev->cdev.ops = &cpld_fops; + err = cdev_add(&dev->cdev, devno, 1); + + if (err) + DEB2(printk(KERN_NOTICE "Error %d adding cpld", err);) +} +/********************************************** End ********************************************************/ + + + + +/********************************************** Start ********************************************************/ +#include +#include +#include + +static spinlock_t irq_inter_lock; +static struct delayed_work irq_inter_work; +static unsigned long irq_inter_delay; + + +static int cig_cpld_write_slave_cpld_register(u8 reg_addr, u8 reg_data) +{ + u8 read_status = 0; + u8 wait_time_out = WAIT_TIME_OUT_COUNT; + DEB2(printk("<=======write=========>")); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_ADDR, reg_addr << 1); + DEB2(printk("[62]=%x\n",reg_addr << 1)); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_TX, reg_data); + DEB2(printk("[63]=%x\n",reg_data)); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_COMMAND, 0x80); + DEB2(printk("[65]=%x\n",0x80)); + do{ + cig_cpld_read_register(ADDR_REG_SFP_STATUS_STATUS, &read_status); + DEB2(printk("[66]=%x\n",read_status)); + udelay(60); + wait_time_out--; + if(wait_time_out == 0) + break; + }while(read_status != 0x02); + DEB2(printk("<=======write=========>")); + + + if(wait_time_out == 0) + return -1; + + return 1; +} + + +static int cig_cpld_read_slave_cpld_register(u8 reg_addr, u8 *reg_data) +{ + u8 read_status = 0; + u8 wait_time_out = WAIT_TIME_OUT_COUNT; + DEB2(printk("<========read=========>")); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_ADDR, reg_addr << 1 | 1); + DEB2(printk("[62]=%x\n",reg_addr << 1 | 1)); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_COMMAND, 0x80); + DEB2(printk("[65]=%x\n",0x80)); + do{ + udelay(60); + cig_cpld_read_register(ADDR_REG_SFP_STATUS_STATUS, &read_status); + DEB2(printk("[66]=%x\n",read_status)); + wait_time_out--; + if(wait_time_out == 0) + break; + }while(read_status != 0x01); + + cig_cpld_read_register(ADDR_REG_SFP_STATUS_RX,reg_data); + DEB2(printk("[64]=%x\n",*reg_data)); + DEB2(printk("<========read=========>")); + + if(wait_time_out == 0) + return -1; + + return 1; +} + + + +struct sock *nlsk = NULL; +extern struct net init_net; +#define NETLINK_TEST 26 +#define MSG_LEN 125 +#define USER_PORT 100 +static u32 irq_present_status_low_current,irq_present_status_low_next; +static u32 irq_present_status_high_current,irq_present_status_high_next; +static u32 irq_tx_fault_status_low_current,irq_tx_fault_status_low_next; +static u32 irq_tx_fault_status_high_current,irq_tx_fault_status_high_next; +static u32 irq_rx_lost_status_low_current,irq_rx_lost_status_low_next; +static u32 irq_rx_lost_status_high_current,irq_rx_lost_status_high_next; + +static u8 irq_present_qsfp_current,irq_present_qsfp_next; +static u8 irq_interrupt_qsfp_current,irq_interrupt_qsfp_next; + +struct input_dev *cpld_input_dev; + + + +int send_usrmsg(char *pbuf, uint16_t len) +{ + struct sk_buff *nl_skb; + struct nlmsghdr *nlh; + + int ret; + + + nl_skb = nlmsg_new(len, GFP_ATOMIC); + if(!nl_skb) + { + printk("netlink alloc failure\n"); + return -1; + } + + + nlh = nlmsg_put(nl_skb, 0, 0, NETLINK_TEST, len, 0); + if(nlh == NULL) + { + printk("nlmsg_put failaure \n"); + nlmsg_free(nl_skb); + return -1; + } + + memcpy(nlmsg_data(nlh), pbuf, len); + ret = netlink_unicast(nlsk, nl_skb, USER_PORT, MSG_DONTWAIT); + + return ret; +} + +static void netlink_rcv_msg(struct sk_buff *skb) +{ + + struct nlmsghdr *nlh = NULL; + char *umsg = NULL; + char kmsg[1024] = {0}; + char kmsg_tmp[16] = {0}; + u8 i = 0; + u8 tmp[3]={0}; + + if(skb->len >= nlmsg_total_size(0)) + { + nlh = nlmsg_hdr(skb); + umsg = NLMSG_DATA(nlh); + if(umsg) + { + for(i = 0;i < 24;i++) + { + if(!(irq_present_status_low_current & (0x1 << i))) + { + tmp[0] = 1; + } + else + { + tmp[0] = 0; + } + + if(!(irq_rx_lost_status_low_current & (0x1 << i))) + { + tmp[1] = 1; + } + else + { + tmp[1] = 0; + } + + if(!(irq_tx_fault_status_low_current & (0x1 << i))) + { + tmp[2] = 1; + } + else + { + tmp[2] = 0; + } + memset(kmsg_tmp,0xff,sizeof(kmsg_tmp)); + sprintf(kmsg_tmp,"sfp%02d:%1d:%1d:%1d ",i+1,tmp[0],tmp[1],tmp[2]); + strcat(kmsg,kmsg_tmp); + } + + for(i = 0;i < 24;i++) + { + if(!(irq_present_status_high_current & (0x1 << i))) + { + tmp[0] = 1; + } + else + { + tmp[0] = 0; + } + + if(!(irq_rx_lost_status_high_current & (0x1 << i))) + { + tmp[1] = 1; + } + else + { + tmp[1] = 0; + } + + if(!(irq_tx_fault_status_high_current & (0x1 << i))) + { + tmp[2] = 1; + } + else + { + tmp[2] = 0; + } + memset(kmsg_tmp,0xff,sizeof(kmsg_tmp)); + sprintf(kmsg_tmp,"sfp%02d:%1d:%1d:%1d ",i+25,tmp[0],tmp[1],tmp[2]); + strcat(kmsg,kmsg_tmp); + } + + + for(i = 0;i < 8;i++) + { + if(!(irq_present_qsfp_current & (0x1 << i))) + { + tmp[0] = 1; + } + else + { + tmp[0] = 0; + } + + if(!(irq_interrupt_qsfp_current & (0x1 << i))) + { + tmp[1] = 1; + } + else + { + tmp[1] = 0; + } + + memset(kmsg_tmp,0xff,sizeof(kmsg_tmp)); + sprintf(kmsg_tmp,"qsfp%02d:%1d:%1d:%1d ",i+49,tmp[0],tmp[1],0); + strcat(kmsg,kmsg_tmp); + } + + printk("kernel recv from user: %s\n", umsg); + send_usrmsg(kmsg, strlen(kmsg)); + } + } + + return ; +} + + + +struct netlink_kernel_cfg cfg = { + .input = netlink_rcv_msg, /* set recv callback */ +}; + + + +#define RANGE_OF_BYTE_SHIFT(to_arg,shift,from_arg) {to_arg &= ~(0xff << shift); to_arg |= from_arg << shift;} + + +static void irq_inter_wapper(struct work_struct * work) +{ + + u8 m_data = 0; + u8 data_high8 = 0,data_low8 = 0; + u16 data_16 = 0; + u8 status = 0; + u8 i = 0; + char kmsg[64]={0}; + u8 tmp[3] = {0}; + + DEB2(printk("CPLD_MASTER_INTERRUPT\r\n")); + + m_data = lpc_iic_getbyte(NULL,CPLD_MASTER_INTERRUPT_STATUS_REG); + lpc_iic_setbyte(NULL,CPLD_MASTER_INTERRUPT_STATUS_REG,0xff); + + cig_cpld_write_slave_cpld_register(CPLD_SLAVE1_INTERRUPT_MASK_REG,0xff); + cig_cpld_write_slave_cpld_register(CPLD_SLAVE2_INTERRUPT_MASK_REG,0xff); + if(!(m_data & CPLD_MASTER_INTERRUPT_CPLD1)) + { + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_INTERRUPT_STATUS_H_REG,&data_high8); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_INTERRUPT_STATUS_L_REG,&data_low8); + data_16 = data_low8 | data_high8 << 8; + if( + !(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT08) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT16) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT24) + ) + { + if(!(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT08)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT08\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_PRESENT08_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_low_current,0,status); + + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT16)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT16\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_PRESENT16_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_low_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT24)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT24\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_PRESENT24_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_low_current,16,status); + } + DEB2(printk("irq_present_status_low_next = %08x irq_present_status_low_current = %08x \n",irq_present_status_low_next,irq_present_status_low_current)); + } + + if( + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST08) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST16) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST24) + ) + { + if(!(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST08)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_RX_LOST08\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_RX_LOST08_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_low_current,0,status); + + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST16)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT16\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_RX_LOST16_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_low_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST24)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT24\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_RX_LOST24_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_low_current,16,status); + } + DEB2(printk("irq_rx_lost_status_low_next = %08x irq_rx_lost_status_low_current = %08x \n",irq_rx_lost_status_low_next,irq_rx_lost_status_low_current)); + } + + if( + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST08) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST16) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST24) + ) + { + if(!(data_16 & CPLD_SLAVE1_INTERRUPT_TX_FAULT08)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_TX_FAULT08\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_TX_FAULT08_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_low_current,0,status); + + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_TX_FAULT16)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_TX_FAULT16\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_TX_FAULT16_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_low_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_TX_FAULT24)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_TX_FAULT24\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_TX_FAULT24_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_low_current,16,status); + } + DEB2(printk("irq_tx_fault_status_low_next = %08x irq_tx_fault_status_low_current = %08x \n",irq_tx_fault_status_low_next,irq_tx_fault_status_low_current)); + + } + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_CPLD2)) + { + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_INTERRUPT_STATUS_H_REG,&data_high8); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_INTERRUPT_STATUS_L_REG,&data_low8); + data_16 = data_low8 | data_high8 << 8; + if( + !(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT32) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT40) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT48) + ) + { + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT32)) + { + DEB2(printk("CPLD_SLAVE2_PRESENT32_REG\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_PRESENT32_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_high_current,0,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT40)) + { + DEB2(printk("CPLD_SLAVE2_PRESENT40_REG\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_PRESENT40_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_high_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT48)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT48\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_PRESENT48_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_high_current,16,status); + } + } + + if( + !(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST32) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST40) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST48) + ) + { + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST32)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_RX_LOST32\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_RX_LOST32_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_high_current,0,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST40)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT40\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_RX_LOST40_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_high_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST48)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT48\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_RX_LOST48_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_high_current,16,status); + } + + } + + if( + !(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT32) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT40) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT48) + ) + { + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT32)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_RX_LOST32\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_TX_FAULT32_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_high_current,0,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT40)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT40\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_TX_FAULT40_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_high_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT48)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT48\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_TX_FAULT48_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_high_current,16,status); + } + } + + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT56)) + { + DEB2(printk("CPLD_SLAVE2_PRESENT56_REG\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_PRESENT56_REG,&status); + irq_present_qsfp_current = status; + } + + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_QSFP_CR56)) + { + DEB2(printk("CPLD_SLAVE2_QSFP_CR56_REG\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_QSFP_CR56_REG,&status); + irq_interrupt_qsfp_current = status; + } + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_LSW)) + { + DEB2(printk("CPLD_MASTER_INTERRUPT_LSW\r\n")); + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_PSU1)) + { + DEB2(printk("CPLD_MASTER_INTERRUPT_PSU1\r\n")); + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_PSU2)) + { + DEB2(printk("CPLD_MASTER_INTERRUPT_PSU2\r\n")); + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_6320)) + { + DEB2(printk("CPLD_MASTER_INTERRUPT_6320\r\n")); + } + cig_cpld_write_slave_cpld_register(CPLD_SLAVE1_INTERRUPT_MASK_REG,0x0); + cig_cpld_write_slave_cpld_register(CPLD_SLAVE2_INTERRUPT_MASK_REG,0x0); + + memset(tmp,0xff,sizeof(tmp)); + + for(i = 0;i < 24;i++) + { + if(!(irq_present_status_low_current & (0x1 << i)) && (irq_present_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d is present\r\n",i+1)); + tmp[0] = 1; + } + else if((irq_present_status_low_current & (0x1 << i)) && !(irq_present_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d is absent\r\n",i+1)); + tmp[0] = 0; + } + + if(!(irq_tx_fault_status_low_current & (0x1 << i)) && (irq_tx_fault_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d transmission is right\r\n",i+1)); + tmp[1] = 1; + } + else if((irq_tx_fault_status_low_current & (0x1 << i)) && !(irq_tx_fault_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d transmission is fault\r\n",i+1)); + tmp[1] = 0; + } + + if(!(irq_rx_lost_status_low_current & (0x1 << i)) && (irq_rx_lost_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d optical is meet\r\n",i+1)); + tmp[2] = 1; + } + else if((irq_rx_lost_status_low_current & (0x1 << i)) && !(irq_rx_lost_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d optical is lost\r\n",i+1)); + tmp[2] = 0; + } + + if((tmp[0] != 0xff) || (tmp[1] != 0xff) || (tmp[2] != 0xff)) + { + memset(kmsg,0xff,sizeof(kmsg)); + snprintf(kmsg,sizeof(kmsg),"sfp%02d:%1d:%1d:%1d ",i+1,(tmp[0] == 0xff) ? 0:tmp[0],(tmp[1] == 0xff) ? 0:tmp[1],(tmp[2] == 0xff) ? 0:tmp[2]); + break; + } + } + + memset(tmp,0xff,sizeof(tmp)); + for(i = 0;i < 24;i++) + { + if(!(irq_present_status_high_current & (0x1 << i)) && (irq_present_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d is present\r\n",i+25)); + tmp[0] = 1; + } + else if((irq_present_status_high_current & (0x1 << i)) && !(irq_present_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d is absent\r\n",i+25)); + tmp[0] = 0; + + } + + if(!(irq_rx_lost_status_high_current & (0x1 << i)) && (irq_rx_lost_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d optical is meet\r\n",i+25)); + tmp[1] = 1; + } + else if((irq_rx_lost_status_high_current & (0x1 << i)) && !(irq_rx_lost_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d optical is lost\r\n",i+25)); + tmp[1] = 0; + } + + if(!(irq_tx_fault_status_high_current & (0x1 << i)) && (irq_tx_fault_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d transmission is right\r\n",i+25)); + tmp[2] = 1; + } + else if((irq_tx_fault_status_high_current & (0x1 << i)) && !(irq_tx_fault_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d transmission is fault\r\n",i+25)); + tmp[2] = 0; + } + + if((tmp[0] != 0xff) || (tmp[1] != 0xff) || (tmp[2] != 0xff)) + { + memset(kmsg,0xff,sizeof(kmsg)); + snprintf(kmsg,sizeof(kmsg),"sfp%02d:%1d:%1d:%1d ",i+25,(tmp[0] == 0xff) ? 0:tmp[0],(tmp[1] == 0xff) ? 0:tmp[1],(tmp[2] == 0xff) ? 0:tmp[2]); + break; + } + } + + memset(tmp,0xff,sizeof(tmp)); + for(i = 0 ; i < 8; i++) + { + if(!(irq_present_qsfp_current & (0x1 << i)) && (irq_present_qsfp_next & (0x1 << i))) + { + DEB2(printk("SFP%d is present\r\n",i+49)); + tmp[0] = 1; + } + else if((irq_present_qsfp_current & (0x1 << i)) && !(irq_present_qsfp_next & (0x1 << i))) + { + DEB2(printk("SFP%d is absent\r\n",i+49)); + tmp[0] = 0; + } + + if(!(irq_interrupt_qsfp_current & (0x1 << i)) && (irq_interrupt_qsfp_next & (0x1 << i))) + { + DEB2(printk("SFP%d interrupt is occured \r\n",i+49)); + tmp[1] = 1; + } + else if((irq_interrupt_qsfp_current & (0x1 << i)) && !(irq_interrupt_qsfp_next & (0x1 << i))) + { + DEB2(printk("SFP%d interrupt is cleaned\r\n",i+49)); + tmp[1] = 0; + } + + if((tmp[0] != 0xff) || (tmp[1] != 0xff)) + { + memset(kmsg,0xff,sizeof(kmsg)); + snprintf(kmsg,sizeof(kmsg),"qsfp%02d:%1d:%1d:%1d ",i+49,(tmp[0] == 0xff) ? 0:tmp[0],(tmp[1] == 0xff) ? 0:tmp[1],0); + break; + } + } + + + irq_present_status_low_next = irq_present_status_low_current; + irq_rx_lost_status_low_next = irq_rx_lost_status_low_current; + irq_tx_fault_status_low_next = irq_tx_fault_status_low_current; + irq_present_status_high_next = irq_present_status_high_current; + irq_rx_lost_status_high_next = irq_rx_lost_status_high_current; + irq_tx_fault_status_high_next = irq_tx_fault_status_high_current; + irq_present_qsfp_next = irq_present_qsfp_current; + irq_interrupt_qsfp_next = irq_interrupt_qsfp_current; + + send_usrmsg(kmsg, strlen(kmsg)); +} + +static void disableIrq(unsigned short maskReg, unsigned short mask) +{ + u8 data = 0; + + data = lpc_iic_getbyte(NULL,maskReg); + data |= mask; + lpc_iic_setbyte(NULL,maskReg, data); +} + +static void enableIrq(unsigned short maskReg, unsigned short mask) +{ + unsigned short data; + + data = lpc_iic_getbyte(NULL,maskReg); + data &= ~mask; + lpc_iic_setbyte(NULL,maskReg, data); +} + + +static irqreturn_t irq_inter_isr(int irq, void *handle) +{ + + /* + * use keventd context to read the event fifo registers + * Schedule readout at least 25ms after notification for + * REVID < 4 + */ + + schedule_delayed_work(&irq_inter_work, irq_inter_delay); + + return IRQ_HANDLED; +} + + +#define CIG_CPLD_CHR_NAME "cpld" + + +static int __init cpld_init(void) +{ + int rval,rc=0; + dev_t dev; + u8 s_data; + int isr_GPIO_num = 289; + + DEB2(printk("cpld_init\n");) + +/**************************************************************************************/ + + LPC_INDEX_REG = lpc_base_addr; + LPC_DATA_REG = lpc_base_addr + 1; + + cpld_device = kzalloc(sizeof(struct cpld_dev_type), GFP_KERNEL); + if (!cpld_device) + goto error3; + cpld_device->io_resource = request_region(lpc_base_addr, + lpc_io_space_size, "lpc-i2c"); + if (!cpld_device->io_resource) { + printk("lpc: claim I/O resource fail\n"); + goto error2; + } + sema_init(&cpld_device->sem, 1); + + if (cpld_major) { + dev = MKDEV(cpld_major, cpld_minor); + rc = register_chrdev_region(dev, 1, CIG_CPLD_CHR_NAME); + } else { + rc = alloc_chrdev_region(&dev, cpld_major, 1, CIG_CPLD_CHR_NAME); + cpld_major = MAJOR(dev); + } + + cpld_setup_cdev(cpld_device); + + cpld_class = class_create(THIS_MODULE,CIG_CPLD_CHR_NAME); + if (!cpld_class) { + DEB2(printk("failed to create class\n");) + goto error1; + } + + cpld_class->p->subsys.kobj.ktype= &cpld_kobj_type; + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "read"); + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "write"); + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "reads"); + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "writes"); + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "version"); + + cpld_dev = device_create(cpld_class, NULL, dev, NULL, CIG_CPLD_CHR_NAME); + +/**************************************************************************************/ + + rval = lpc_bus_init(); + rval = lpc_register_driver(&i2c_lpc_driver, 1); + +/**************************************************************************************/ + return 0; +error1: + cdev_del(&cpld_device->cdev); + unregister_chrdev_region(dev, 1); +error2: + release_resource(cpld_device->io_resource); +error3: + kfree(cpld_device); + + return rc; +} + +static void __exit cpld_exit(void) +{ + DEB2(printk("cpld_exit\n")); + + if (nlsk){ + netlink_kernel_release(nlsk); /* release ..*/ + nlsk = NULL; + } + + + lpc_unregister_driver(&i2c_lpc_driver); + lpc_bus_exit(); + dev_t devno = MKDEV(cpld_major, cpld_minor); + + cdev_del(&cpld_device->cdev); + if (cpld_class) { + device_destroy(cpld_class, devno); + class_destroy(cpld_class); + } + + if (cpld_device) { + if (cpld_device->io_resource) + release_resource(cpld_device->io_resource); + + kfree(cpld_device); + } + unregister_chrdev_region(devno, 1); + + +} + +module_param(cpld_major, int, S_IRUGO); +module_param(cpld_minor, int, S_IRUGO); +module_param(i2c_debug, int, S_IRUGO); +module_param(board_id, int, S_IRUGO); + +module_init(cpld_init); +module_exit(cpld_exit); + +MODULE_AUTHOR("Zhang Peng "); +MODULE_DESCRIPTION("cs5435-54p-cpld driver"); +MODULE_LICENSE("GPL"); + + +/********************************************** End ********************************************************/ + + + diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-fan.c b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-fan.c new file mode 100644 index 00000000000..a254dae33c2 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-fan.c @@ -0,0 +1,521 @@ +/* + * A hwmon driver for the CIG cs5435-54p fan + * + * Copyright (C) 2018 Cambridge, 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 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 +#include +#include +#include +#include + + + +#define FAN_SPEED_DUTY_TO_CPLD_STEP 10 + +static struct cs5435_54p_fan_data *cs5435_54p_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 set_fan_direction(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); + + +extern int cig_cpld_write_register(u8 reg_off, u8 val); +extern int cig_cpld_read_register(u8 reg_off, u8 *val); + +/* fan related data, the index should match sysfs_fan_attributes + */ +static const u8 fan_reg[] = { + 0x41, /* fan enable/disable */ + 0x40, /* fan PWM(for all fan) */ + 0x42, /* front fan 1 speed(rpm) */ + 0x44, /* front fan 2 speed(rpm) */ + 0x46, /* front fan 3 speed(rpm) */ + 0x48, /* front fan 4 speed(rpm) */ + 0x4a, /* front fan 5 speed(rpm) */ + 0x43, /* rear fan 1 speed(rpm) */ + 0x45, /* rear fan 2 speed(rpm) */ + 0x47, /* rear fan 3 speed(rpm) */ + 0x49, /* rear fan 4 speed(rpm) */ + 0x4b, /* rear fan 5 speed(rpm) */ + 0x4c, /* fan direction rear to front or front to rear */ +}; + + +/* Each client has this additional data */ +struct cs5435_54p_fan_data { + 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 reg_val[ARRAY_SIZE(fan_reg)]; /* Register value */ +}; + +static struct cs5435_54p_fan_data *fan_data = NULL; + +enum fan_id { + FAN1_ID, + FAN2_ID, + FAN3_ID, + FAN4_ID, + FAN5_ID, +}; + +enum sysfs_fan_attributes { + FAN_STATE_REG, + FAN_DUTY_CYCLE_PERCENTAGE, /* Only one CPLD register to control duty cycle for all fans */ + FAN1_FRONT_SPEED_RPM, + FAN2_FRONT_SPEED_RPM, + FAN3_FRONT_SPEED_RPM, + FAN4_FRONT_SPEED_RPM, + FAN5_FRONT_SPEED_RPM, + FAN1_REAR_SPEED_RPM, + FAN2_REAR_SPEED_RPM, + FAN3_REAR_SPEED_RPM, + FAN4_REAR_SPEED_RPM, + FAN5_REAR_SPEED_RPM, + FAN_DIRECTION, + FAN1_STATE, + FAN2_STATE, + FAN3_STATE, + FAN4_STATE, + FAN5_STATE, + FAN1_FAULT, + FAN2_FAULT, + FAN3_FAULT, + FAN4_FAULT, + FAN5_FAULT, + FAN1_DIRECTION, + FAN2_DIRECTION, + FAN3_DIRECTION, + FAN4_DIRECTION, + FAN5_DIRECTION, +}; + +/* Define attributes + */ +#define DECLARE_FAN_STATE_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_state, S_IRUGO, fan_show_value, NULL, FAN##index##_STATE) +#define DECLARE_FAN_STATE_ATTR(index) &sensor_dev_attr_fan##index##_state.dev_attr.attr + +#define DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FAULT) +#define DECLARE_FAN_FAULT_ATTR(index) &sensor_dev_attr_fan##index##_fault.dev_attr.attr + +#define DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN##index##_DUTY_CYCLE_PERCENTAGE) +#define DECLARE_FAN_DUTY_CYCLE_ATTR(index) &sensor_dev_attr_fan##index##_duty_cycle_percentage.dev_attr.attr + +#define DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_front_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_FRONT_SPEED_RPM);\ + static SENSOR_DEVICE_ATTR(fan##index##_rear_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_REAR_SPEED_RPM) +#define DECLARE_FAN_SPEED_RPM_ATTR(index) &sensor_dev_attr_fan##index##_front_speed_rpm.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_rear_speed_rpm.dev_attr.attr + +#define DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_direction, S_IWUSR | S_IRUGO, fan_show_value, set_fan_direction, FAN##index##_DIRECTION) +#define DECLARE_FAN_DIRECTION_ATTR(index) &sensor_dev_attr_fan##index##_direction.dev_attr.attr + + +/* 5 fan state attributes in this platform */ +DECLARE_FAN_STATE_SENSOR_DEV_ATTR(1); +DECLARE_FAN_STATE_SENSOR_DEV_ATTR(2); +DECLARE_FAN_STATE_SENSOR_DEV_ATTR(3); +DECLARE_FAN_STATE_SENSOR_DEV_ATTR(4); +DECLARE_FAN_STATE_SENSOR_DEV_ATTR(5); + + +/* 5 fan fault attributes in this platform */ +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(1); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(2); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(3); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(4); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(5); + +/* 5 fan speed(rpm) attributes in this platform */ +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(1); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(2); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(3); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(4); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(5); + +/* 1 fan duty cycle attribute in this platform */ +DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(); + +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(1); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(2); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(3); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(4); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(5); + + +static struct attribute *cs5435_54p_fan_attributes[] = { + /* fan related attributes */ + DECLARE_FAN_STATE_ATTR(1), + DECLARE_FAN_STATE_ATTR(2), + DECLARE_FAN_STATE_ATTR(3), + DECLARE_FAN_STATE_ATTR(4), + DECLARE_FAN_STATE_ATTR(5), + DECLARE_FAN_FAULT_ATTR(1), + DECLARE_FAN_FAULT_ATTR(2), + DECLARE_FAN_FAULT_ATTR(3), + DECLARE_FAN_FAULT_ATTR(4), + DECLARE_FAN_FAULT_ATTR(5), + DECLARE_FAN_SPEED_RPM_ATTR(1), + DECLARE_FAN_SPEED_RPM_ATTR(2), + DECLARE_FAN_SPEED_RPM_ATTR(3), + DECLARE_FAN_SPEED_RPM_ATTR(4), + DECLARE_FAN_SPEED_RPM_ATTR(5), + DECLARE_FAN_DUTY_CYCLE_ATTR(), + DECLARE_FAN_DIRECTION_ATTR(1), + DECLARE_FAN_DIRECTION_ATTR(2), + DECLARE_FAN_DIRECTION_ATTR(3), + DECLARE_FAN_DIRECTION_ATTR(4), + DECLARE_FAN_DIRECTION_ATTR(5), + NULL +}; + +#define FAN_MAX_DUTY_CYCLE 100 +#define FAN_REG_VAL_TO_SPEED_RPM_STEP 100 + +/* fan utility functions + */ +static u32 reg_val_to_duty_cycle(u8 reg_val) +{ + if (reg_val +== 0xFF) { + return 100; + } + return ((u32)(reg_val) * 100)/ 255; +} + +static u8 duty_cycle_to_reg_val(u8 duty_cycle) +{ + if (duty_cycle >= FAN_MAX_DUTY_CYCLE) { + return 0xFF; + } + + return 255 / 10 * (duty_cycle / 10); +} + +static u32 reg_val_to_speed_rpm(u8 reg_val) +{ + return (u32)reg_val * FAN_REG_VAL_TO_SPEED_RPM_STEP; +} + +static u8 reg_val_to_is_state(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 cs5435_54p_fan_data *data, enum fan_id id) +{ + u8 ret = 1; + int front_fan_index = FAN1_FRONT_SPEED_RPM + id; + int rear_fan_index = FAN1_REAR_SPEED_RPM + id; + + /* Check if the speed of front or rear fan is ZERO, + */ + if (reg_val_to_speed_rpm(data->reg_val[front_fan_index]) && + reg_val_to_speed_rpm(data->reg_val[rear_fan_index])) { + ret = 0; + } + + return ret; +} + + +static ssize_t 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 <= 0 || value > FAN_MAX_DUTY_CYCLE) + return -EINVAL; + + cig_cpld_write_register(fan_reg[FAN_DUTY_CYCLE_PERCENTAGE], duty_cycle_to_reg_val(value)); + + return count; +} + +static ssize_t set_fan_direction(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value,fan_index; + u8 mask,reg_val; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + fan_index = attr->index - FAN1_DIRECTION; + error = kstrtoint(buf, 10, &value); + if (error) + return error; + + if (!(value == 0 || value == 1)) + return -EINVAL; + + + cig_cpld_read_register(fan_reg[FAN_DIRECTION],®_val); + + if(value == 1) + { + reg_val |= (1 << fan_index); + } + else + { + reg_val &= ~(1 << fan_index); + } + + cig_cpld_write_register(fan_reg[FAN_DIRECTION], reg_val); + + return count; +} + + + + + +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); + + cs5435_54p_fan_update_device(dev); + + struct cs5435_54p_fan_data *data = fan_data; + + ssize_t ret = 0; + + if (data->valid) { + switch (attr->index) { + + case FAN1_STATE: + case FAN2_STATE: + case FAN3_STATE: + case FAN4_STATE: + case FAN5_STATE: + //printk("FAN_STATE_REG: 0x%x\n", data->reg_val[FAN_STATE_REG]); + //printk("index: %d\n", attr->index); + ret = sprintf(buf, "%d\n", + reg_val_to_is_state(data->reg_val[FAN_STATE_REG], + attr->index - FAN1_STATE)); + break; + case FAN_DUTY_CYCLE_PERCENTAGE: + { + u32 duty_cycle = reg_val_to_duty_cycle(data->reg_val[FAN_DUTY_CYCLE_PERCENTAGE]); + ret = sprintf(buf, "%u\n", duty_cycle); + break; + } + case FAN1_FRONT_SPEED_RPM: + case FAN2_FRONT_SPEED_RPM: + case FAN3_FRONT_SPEED_RPM: + case FAN4_FRONT_SPEED_RPM: + case FAN5_FRONT_SPEED_RPM: + case FAN1_REAR_SPEED_RPM: + case FAN2_REAR_SPEED_RPM: + case FAN3_REAR_SPEED_RPM: + case FAN4_REAR_SPEED_RPM: + case FAN5_REAR_SPEED_RPM: +// printk("FAN_seed_REG: 0x%x\n", data->reg_val[attr->index]); +// printk("index: %d\n", attr->index); + ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_val[attr->index])); + break; + + case FAN1_FAULT: + case FAN2_FAULT: + case FAN3_FAULT: + case FAN4_FAULT: + case FAN5_FAULT: + ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN1_FAULT)); + break; + case FAN1_DIRECTION: + case FAN2_DIRECTION: + case FAN3_DIRECTION: + case FAN4_DIRECTION: + case FAN5_DIRECTION: + ret = sprintf(buf, "%d\n",reg_val_to_is_state(data->reg_val[FAN_DIRECTION],attr->index - FAN1_DIRECTION)); + break; + default: + break; + } + } + + return ret; +} + +static const struct attribute_group cs5435_54p_fan_group = { + .attrs = cs5435_54p_fan_attributes, +}; + +static struct cs5435_54p_fan_data *cs5435_54p_fan_update_device(struct device *dev) +{ + struct cs5435_54p_fan_data *data = fan_data; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || + !data->valid) { + int i; + + data->valid = 0; + + /* Update fan data + */ + for (i = 0; i < ARRAY_SIZE(data->reg_val); i++) { + u8 status; + (void)cig_cpld_read_register(fan_reg[i], &status); + + if (status < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + return data; + } + else { + data->reg_val[i] = status; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int cs5435_54p_fan_probe(struct platform_device *pdev) +{ + int status = -1; + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &cs5435_54p_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, "cs5435_54p_fan\n"); + + return 0; + +exit_remove: + sysfs_remove_group(&pdev->dev.kobj, &cs5435_54p_fan_group); +exit: + return status; +} + +static int cs5435_54p_fan_remove(struct platform_device *pdev) +{ + hwmon_device_unregister(fan_data->hwmon_dev); + sysfs_remove_group(&fan_data->pdev->dev.kobj, &cs5435_54p_fan_group); + + return 0; +} + +#define DRVNAME "cs5435_54p_fan" + +static struct platform_driver cs5435_54p_fan_driver = { + .probe = cs5435_54p_fan_probe, + .remove = cs5435_54p_fan_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + + + + + +static int __init cs5435_54p_fan_init(void) +{ + int ret; + + cig_cpld_write_register(0x40, duty_cycle_to_reg_val(50)); + + ret = platform_driver_register(&cs5435_54p_fan_driver); + if (ret < 0) { + goto exit; + } + + fan_data = kzalloc(sizeof(struct cs5435_54p_fan_data), GFP_KERNEL); + if (!fan_data) { + ret = -ENOMEM; + platform_driver_unregister(&cs5435_54p_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(&cs5435_54p_fan_driver); + kfree(fan_data); + goto exit; + } + +exit: + return ret; +} + +static void __exit cs5435_54p_fan_exit(void) +{ + platform_device_unregister(fan_data->pdev); + platform_driver_unregister(&cs5435_54p_fan_driver); + kfree(fan_data); +} + +MODULE_AUTHOR("CIG"); +MODULE_DESCRIPTION("cs5435_54p_fan driver"); +MODULE_LICENSE("GPL"); + +module_init(cs5435_54p_fan_init); +module_exit(cs5435_54p_fan_exit); + +MODULE_AUTHOR("Zhang Peng "); +MODULE_DESCRIPTION("cs5435_54p_fan driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-led.c b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-led.c new file mode 100644 index 00000000000..dae49967592 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-led.c @@ -0,0 +1,594 @@ +/* + * A hwmon driver for the CIG cs5435-54P LED + * + * Copyright (C) 2018 Cambridge, 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 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 cig_cpld_write_register(u8 reg_off, u8 val); + +extern int cig_cpld_read_register(u8 reg_off, u8 *val); + +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 "cs5435_54p_led" + +struct cs5435_54p_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[6]; /* 0: system & location + 1: PSU1 &PSU12 + 2: fan & management + 3: console & ToD + 4-5 : fan1-fan5*/ +}; + +static struct cs5435_54p_led_data *ledctl = NULL; + +/* LED related data + */ +#define LED_TYPE_PSU1_REG_MASK 0x0C +#define LED_MODE_PSU1_GREEN_MASK 0x08 +#define LED_MODE_PSU1_RED_MASK 0x04 +#define LED_MODE_PSU1_AMBER_MASK 0x0C +#define LED_MODE_PSU1_OFF_MASK 0x00 + +#define LED_TYPE_PSU2_REG_MASK 0x30 +#define LED_MODE_PSU2_GREEN_MASK 0x20 +#define LED_MODE_PSU2_RED_MASK 0x10 +#define LED_MODE_PSU2_AMBER_MASK 0x30 +#define LED_MODE_PSU2_OFF_MASK 0x00 + +#define LED_TYPE_SYS_REG_MASK 0xF0 +#define LED_MODE_SYS_GREEN_MASK 0x40 +#define LED_MODE_SYS_RED_MASK 0x20 +#define LED_MODE_SYS_AMBER_MASK 0x60 +#define LED_MODE_SYS_AMBER_FLASHING_MASK 0x70 +#define LED_MODE_SYS_OFF_MASK 0x00 + +#define LED_TYPE_RES_REG_MASK 0x0F +#define LED_MODE_RES_GREEN_MASK 0x04 +#define LED_MODE_RES_RED_MASK 0x02 +#define LED_MODE_RES_AMBER_MASK 0x06 +#define LED_MODE_RES_AMBER_FLASHING_MASK 0x07 +#define LED_MODE_RES_OFF_MASK 0x00 + +#define LED_TYPE_FAN_REG_MASK 0x03 +#define LED_MODE_FAN_GREEN_MASK 0x02 +#define LED_MODE_FAN_RED_MASK 0x01 +#define LED_MODE_FAN_AMBER_MASK 0x03 +#define LED_MODE_FAN_OFF_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_MODE_FANX_GREEN_MASK 0x02 +#define LED_MODE_FANX_RED_MASK 0x01 +#define LED_MODE_FANX_AMBER_MASK 0x03 +#define LED_MODE_FANX_OFF_MASK 0x00 + +enum led_type { + LED_TYPE_SYS, + LED_TYPE_PSU2, + LED_TYPE_PSU1, + LED_TYPE_FAN, + LED_TYPE_FAN1, + LED_TYPE_FAN2, + LED_TYPE_FAN3, + LED_TYPE_FAN4, + LED_TYPE_FAN5, +}; + +static const u8 led_reg[] = { + 0x30, /* system & reserved*/ + 0x31, /* fan & PSU1 & PSU2 */ + 0x32, /* FAN5 LED */ + 0x33, /* FAN1-4 LED */ +}; + + +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_GREEN_FLASHING, + LED_MODE_AMBER_FLASHING, + LED_MODE_RED_FLASHING, + LED_MODE_AUTO, + LED_MODE_UNKNOWN +}; + +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_RED, LED_MODE_PSU1_RED_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_RED, LED_MODE_PSU2_RED_MASK}, +{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_OFF, LED_MODE_PSU2_OFF_MASK}, + +{LED_TYPE_SYS, LED_TYPE_SYS_REG_MASK, LED_MODE_GREEN, LED_MODE_SYS_GREEN_MASK}, +{LED_TYPE_SYS, LED_TYPE_SYS_REG_MASK, LED_MODE_AMBER, LED_MODE_SYS_AMBER_MASK}, +{LED_TYPE_SYS, LED_TYPE_SYS_REG_MASK, LED_MODE_RED, LED_MODE_SYS_RED_MASK}, +{LED_TYPE_SYS, LED_TYPE_SYS_REG_MASK, LED_MODE_AMBER_FLASHING, LED_MODE_SYS_AMBER_FLASHING_MASK}, +{LED_TYPE_SYS, LED_TYPE_SYS_REG_MASK, LED_MODE_OFF, LED_MODE_SYS_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_RED, LED_MODE_FAN_RED_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_AMBER, LED_MODE_FANX_AMBER_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_AMBER, LED_MODE_FANX_AMBER_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_AMBER, LED_MODE_FANX_AMBER_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_AMBER, LED_MODE_FANX_AMBER_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_AMBER, LED_MODE_FANX_AMBER_MASK << 0}, +{LED_TYPE_FAN5, LED_TYPE_FAN5_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 0}, +}; + +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, 3}, + {'2', LED_TYPE_FAN2, 3}, + {'3', LED_TYPE_FAN3, 3}, + {'4', LED_TYPE_FAN4, 3}, + {'5', LED_TYPE_FAN5, 2}, +}; + + +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)); + break; + } + + return reg_val; +} + +static void cs5435_54p_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 cs5435_54p_led update\n"); + + /* Update LED data + */ + for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) { + u8 status; + cig_cpld_read_register(led_reg[i], &status); + + 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 cs5435_54p_led_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode, + u8 reg, enum led_type type) +{ + u8 reg_val; + mutex_lock(&ledctl->update_lock); + + cig_cpld_read_register(reg, ®_val); + 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); + + cig_cpld_write_register(reg, reg_val); + + /* to prevent the slow-update issue */ + ledctl->valid = 0; + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void cs5435_54p_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; + + cs5435_54p_led_set(led_cdev, led_light_mode, led_reg[reg_id], led_type1); + return; + } + } +} + + +static enum led_brightness cs5435_54p_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; + cs5435_54p_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[5]); +} + + +static void cs5435_54p_led_psu1_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + cs5435_54p_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU1); +} + +static enum led_brightness cs5435_54p_led_psu1_get(struct led_classdev *cdev) +{ + cs5435_54p_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU1, ledctl->reg_val[1]); +} + +static void cs5435_54p_led_psu2_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + cs5435_54p_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU2); +} + +static enum led_brightness cs5435_54p_led_psu2_get(struct led_classdev *cdev) +{ + cs5435_54p_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]); +} + +static void cs5435_54p_led_sys_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + cs5435_54p_led_set(led_cdev, led_light_mode,led_reg[0], LED_TYPE_SYS); +} + +static enum led_brightness cs5435_54p_led_sys_get(struct led_classdev *cdev) +{ + cs5435_54p_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_SYS, ledctl->reg_val[0]); +} + + +static enum led_brightness cs5435_54p_led_fan_get(struct led_classdev *cdev) +{ + cs5435_54p_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[1]); +} + +static void cs5435_54p_led_fan_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + cs5435_54p_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_FAN); +} + + +static struct led_classdev cs5435_54p_leds[] = { + [LED_TYPE_SYS] = { + .name = "cs5435_54p_led::sys", + .default_trigger = "unused", + .brightness_set = cs5435_54p_led_sys_set, + .brightness_get = cs5435_54p_led_sys_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN] = { + .name = "cs5435_54p_led::fan", + .default_trigger = "unused", + .brightness_set = cs5435_54p_led_fan_set, + .brightness_get = cs5435_54p_led_fan_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + + [LED_TYPE_PSU1] = { + .name = "cs5435_54p_led::psu1", + .default_trigger = "unused", + .brightness_set = cs5435_54p_led_psu1_set, + .brightness_get = cs5435_54p_led_psu1_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_PSU2] = { + .name = "cs5435_54p_led::psu2", + .default_trigger = "unused", + .brightness_set = cs5435_54p_led_psu2_set, + .brightness_get = cs5435_54p_led_psu2_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + + [LED_TYPE_FAN1] = { + .name = "cs5435_54p_led::fan1", + .default_trigger = "unused", + .brightness_set = cs5435_54p_led_fanx_set, + .brightness_get = cs5435_54p_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN2] = { + .name = "cs5435_54p_led::fan2", + .default_trigger = "unused", + .brightness_set = cs5435_54p_led_fanx_set, + .brightness_get = cs5435_54p_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN3] = { + .name = "cs5435_54p_led::fan3", + .default_trigger = "unused", + .brightness_set = cs5435_54p_led_fanx_set, + .brightness_get = cs5435_54p_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN4] = { + .name = "cs5435_54p_led::fan4", + .default_trigger = "unused", + .brightness_set = cs5435_54p_led_fanx_set, + .brightness_get = cs5435_54p_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN5] = { + .name = "cs5435_54p_led::fan5", + .default_trigger = "unused", + .brightness_set = cs5435_54p_led_fanx_set, + .brightness_get = cs5435_54p_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + } +}; + +static int cs5435_54p_led_suspend(struct platform_device *dev, + pm_message_t state) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(cs5435_54p_leds); i++) { + led_classdev_suspend(&cs5435_54p_leds[i]); + } + + return 0; +} + +static int cs5435_54p_led_resume(struct platform_device *dev) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(cs5435_54p_leds); i++) { + led_classdev_resume(&cs5435_54p_leds[i]); + } + + return 0; +} + +static int cs5435_54p_led_probe(struct platform_device *pdev) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(cs5435_54p_leds); i++) { + ret = led_classdev_register(&pdev->dev, &cs5435_54p_leds[i]); + + if (ret < 0) + break; + } + + /* Check if all LEDs were successfully registered */ + if (i != ARRAY_SIZE(cs5435_54p_leds)) { + int j; + + /* only unregister the LEDs that were successfully registered */ + for (j = 0; j < i; j++) { + led_classdev_unregister(&cs5435_54p_leds[i]); + } + } + + return ret; +} + +static int cs5435_54p_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs5435_54p_leds); i++) { + led_classdev_unregister(&cs5435_54p_leds[i]); + } + + return 0; +} + +static struct platform_driver cs5435_54p_led_driver = { + .probe = cs5435_54p_led_probe, + .remove = cs5435_54p_led_remove, + .suspend = cs5435_54p_led_suspend, + .resume = cs5435_54p_led_resume, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int cs5435_54p_led_default(void) +{ + cig_cpld_write_register(0x30, 0x40);// system green led solid on +} + +static int __init cs5435_54p_led_init(void) +{ + int ret; + + ret = platform_driver_register(&cs5435_54p_led_driver); + if (ret < 0) { + goto exit; + } + + ledctl = kzalloc(sizeof(struct cs5435_54p_led_data), GFP_KERNEL); + if (!ledctl) { + ret = -ENOMEM; + platform_driver_unregister(&cs5435_54p_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(&cs5435_54p_led_driver); + kfree(ledctl); + goto exit; + } + + cs5435_54p_led_default(); + +exit: + return ret; +} + +static void __exit cs5435_54p_led_exit(void) +{ + platform_device_unregister(ledctl->pdev); + platform_driver_unregister(&cs5435_54p_led_driver); + kfree(ledctl); +} + +module_init(cs5435_54p_led_init); +module_exit(cs5435_54p_led_exit); + +MODULE_AUTHOR("Zhang Peng "); +MODULE_DESCRIPTION("cs5435_54p_led driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-psu.c b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-psu.c new file mode 100644 index 00000000000..5a7942653fc --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-psu.c @@ -0,0 +1,946 @@ +/* + * A hwmon driver for the CIG cs5435-54P Power Module + * + * Copyright (C) 2018 Cambridge, 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 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 +#include +#include +#include +#include +#include "i2c-algo-lpc.h" + + + +#define MAX_FAN_DUTY_CYCLE 100 + +/* Address scanned */ +static const unsigned short normal_i2c[] = {I2C_CLIENT_END }; + +/* This is additional data */ +struct cs5435_54p_psu_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; + unsigned long last_updated; /* In jiffies */ + + /* Registers value */ + u8 vout_mode; + u16 v_in; + u16 v_out; + u16 i_in; + u16 i_out; + u16 p_in; + u16 p_out; + u16 temp_input[3]; + u8 temp_fault; + u8 fan_fault; + u16 fan_duty_cycle[2]; + u16 fan_speed[2]; + u8 mfr_id[8]; + u8 mfr_model[20]; + u8 mfr_serial[20]; + u8 psu_is_present; + u8 psu_is_good; + struct i2c_client *client; + struct bin_attribute *bin; /* eeprom data */ +}; + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask); +static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count); +static ssize_t for_linear_data(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_fan_fault(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_fan_warning(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_temp_fault(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_temp_warning(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_vout_data(struct device *dev, struct device_attribute *dev_attr, char *buf); +static int cs5435_54p_psu_read_byte(struct i2c_client *client, u8 reg); +static int cs5435_54p_psu_read_word(struct i2c_client *client, u8 reg); +static int cs5435_54p_psu_write_word(struct i2c_client *client, u8 reg, u16 value); +static int cs5435_54p_psu_read_block(struct i2c_client *client, u8 command, u8 *data, int data_len); +static struct cs5435_54p_psu_data *cs5435_54p_psu_update_device(struct device *dev); +static ssize_t for_ascii(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_status(struct device *dev, struct device_attribute *dev_attr, char *buf); + +enum cs5435_54p_psu_sysfs_attributes { + PSU_V_IN, + PSU_V_OUT, + PSU_I_IN, + PSU_I_OUT, + PSU_P_IN, + PSU_P_OUT, + PSU_TEMP1_INPUT, + PSU_TEMP2_INPUT, + PSU_TEMP3_INPUT, + PSU_TEMP_FAULT, + PSU_TEMP_WARN, + PSU_FAN1_FAULT, + PSU_FAN1_WARN, + PSU_FAN1_DUTY_CYCLE, + PSU_FAN1_SPEED, + PSU_MFR_ID, + PSU_MFR_MODEL, + PSU_MFR_SERIAL, + PSU_PRESENT, + PSU_P_GOOD, +}; + +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 \ + *dev_attr, const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct i2c_client *client = to_i2c_client(dev); + struct cs5435_54p_psu_data *data = i2c_get_clientdata(client); + int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1; + long speed; + int error; + + if (data->valid != 1) + { + return -ENODEV; + } + + 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; + cs5435_54p_psu_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t for_linear_data(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs5435_54p_psu_data *data = cs5435_54p_psu_update_device(dev); + + u16 value = 0; + int exponent, mantissa; + int multiplier = 1000; + + if (data->valid != 1) + { + return -ENODEV; + } + + 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_TEMP2_INPUT: + value = data->temp_input[1]; + break; + case PSU_TEMP3_INPUT: + value = data->temp_input[2]; + 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 for_fan_fault(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs5435_54p_psu_data *data = cs5435_54p_psu_update_device(dev); + + if (data->valid != 1) + { + return -ENODEV; + } + + u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; + + return sprintf(buf, "%d\n", data->fan_fault >> shift); +} + +static ssize_t for_fan_warning(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs5435_54p_psu_data *data = cs5435_54p_psu_update_device(dev); + + if (data->valid != 1) + { + return -ENODEV; + } + + u8 shift = (attr->index == PSU_FAN1_WARN) ? 5 : 4; + + return sprintf(buf, "%d\n", data->fan_fault >> shift); +} + +static ssize_t for_temp_fault(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs5435_54p_psu_data *data = cs5435_54p_psu_update_device(dev); + + if (data->valid != 1) + { + return -ENODEV; + } + + + + return sprintf(buf, "%d\n", data->temp_fault >> 7); +} + +static ssize_t for_temp_warning(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs5435_54p_psu_data *data = cs5435_54p_psu_update_device(dev); + if (data->valid != 1) + { + return -ENODEV; + } + + + return sprintf(buf, "%d\n", data->temp_fault >> 6); +} +static ssize_t for_vout_data(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct cs5435_54p_psu_data *data = cs5435_54p_psu_update_device(dev); + int exponent, mantissa; + int multiplier = 1000; + if (data->valid != 1) + { + return -ENODEV; + } + + + 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) >> (-exponent))); +} + +static ssize_t for_ascii(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs5435_54p_psu_data *data = cs5435_54p_psu_update_device(dev); + u8 *ptr = NULL; + + if (data->valid != 1) + { + return -ENODEV; + } + + switch (attr->index) { + case PSU_MFR_ID: + ptr = data->mfr_id + 1; + break; + case PSU_MFR_MODEL: + ptr = data->mfr_model + 1; + break; + case PSU_MFR_SERIAL: + ptr = data->mfr_serial + 1; + break; + default: + return 0; + } + return sprintf(buf, "%s\n", ptr); +} + + +static ssize_t for_status(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs5435_54p_psu_data *data = cs5435_54p_psu_update_device(dev); + u8 *ptr = NULL; + + u8 status = 0; + + if (attr->index == PSU_PRESENT) { + status = data->psu_is_present; + } + else { /* PSU_POWER_GOOD */ + if (!data->valid) { + return -ENODEV; + } + + status = data->psu_is_good; + } + + return sprintf(buf, "%d\n", status); +} + + +static int cs5435_54p_psu_read_byte(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int cs5435_54p_psu_read_word(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_word_data(client, reg); +} + +static int cs5435_54p_psu_write_word(struct i2c_client *client, u8 reg, \ + u16 value) +{ + union i2c_smbus_data data; + data.word = value; + return i2c_smbus_xfer(client->adapter, client->addr, + client->flags |= I2C_CLIENT_PEC, + I2C_SMBUS_WRITE, reg, + I2C_SMBUS_WORD_DATA, &data); + +} + +static int cs5435_54p_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; + +} + +struct reg_data_byte { + u8 reg; + u8 *value; +}; + +struct reg_data_word { + u8 reg; + u16 *value; +}; + + + +#define EEPROM_NAME "psu_eeprom" +#define EEPROM_SIZE 256 /* 256 byte eeprom */ + +/* Platform dependent --- */ +static ssize_t psu_eeprom_write(struct i2c_client *client, u8 command, const char *data, + int data_len) +{ + int status, retry = 3; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_write_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(100); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + return status; + } + + return data_len; + +} + + +static ssize_t psu_page_write(struct i2c_client *client,const char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + return count; + } + + /* + * Write data to chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + + + while (count) { + ssize_t status; + + status = psu_eeprom_write(client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + buf += status; + off += status; + count -= status; + retval += status; + } + + + return retval; +} + + + +static ssize_t psu_bin_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct cs5435_54p_psu_data *data; + ssize_t retval = 0; + struct i2c_client *client; + + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + client = to_i2c_client(container_of(kobj, struct device, kobj)); + + mutex_lock(&data->update_lock); + retval = psu_page_write(client, buf, off, count); + mutex_unlock(&data->update_lock); + return retval; +} + + +static ssize_t psu_eeprom_read(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int status, retry = 3; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(100); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + goto abort; + } + if (unlikely(status != data_len)) { + status = -EIO; + goto abort; + } + +abort: + return status; +} + + + +static ssize_t psu_page_read(struct i2c_client *client,char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + printk("Count = 0, return"); + return count; + } + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + + + while (count) { + ssize_t status; + + status = psu_eeprom_read(client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + + buf += status; + off += status; + count -= status; + retval += status; + } + + + return retval; + +} + + +static ssize_t psu_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct cs5435_54p_psu_data *data; + struct i2c_client *client; + ssize_t retval = 0; + + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + client = to_i2c_client(container_of(kobj, struct device, kobj)); + mutex_lock(&data->update_lock); + retval = psu_page_read(client, buf, off, count); + mutex_unlock(&data->update_lock); + + return retval; +} + + + +static int psu_sysfs_eeprom_init(struct kobject *kobj, struct bin_attribute *eeprom) +{ + int err; + + sysfs_bin_attr_init(eeprom); + eeprom->attr.name = EEPROM_NAME; + eeprom->attr.mode = S_IWUSR | S_IRUGO; + eeprom->read = psu_bin_read; + eeprom->write = psu_bin_write; + eeprom->size = EEPROM_SIZE; + + /* Create eeprom file */ + err = sysfs_create_bin_file(kobj, eeprom); + if (err) { + return err; + } + + return 0; +} + + +static int psu_sysfs_eeprom_cleanup(struct kobject *kobj, struct bin_attribute *eeprom) +{ + sysfs_remove_bin_file(kobj, eeprom); + return 0; +} + + +static int psu_i2c_check_functionality(struct i2c_client *client) +{ + return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK); +} + + + +static int psu_eeprom_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) +{ + int status; + + struct cs5435_54p_psu_data *data; + + if (!psu_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + mutex_init(&data->update_lock); + + data->bin = kzalloc(sizeof(struct bin_attribute), GFP_KERNEL); + if (!data->bin) { + status = -ENOMEM; + goto eeprom_bin_error; + } + + /* init eeprom */ + status = psu_sysfs_eeprom_init(&client->dev.kobj, data->bin); + if (status) { + status = -ENOMEM; + goto sys_init_error; + } + + dev_info(&client->dev, "psu eeprom '%s'\n", client->name); + + return 0; + + sys_init_error: + kfree(data->bin); + + eeprom_bin_error: + kfree(data); + + exit: + return status; +} + + + + +static struct cs5435_54p_psu_data *cs5435_54p_psu_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cs5435_54p_psu_data *data = i2c_get_clientdata(client); + + + mutex_lock(&data->update_lock); + + + if (time_after(jiffies, data->last_updated)) { + int i, status; + u8 command; + struct reg_data_byte regs_byte[] = { + {0x20, &data->vout_mode}, + {0x81, &data->fan_fault}, + {0x7d, &data->temp_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])}, + {0x90, &(data->fan_speed[0])}, + }; + data->valid = 1; + + dev_dbg(&client->dev, "start data update\n"); + + /* one milliseconds from now */ + data->last_updated = jiffies + HZ / 1000; + + for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { + status = cs5435_54p_psu_read_byte(client, + regs_byte[i].reg); + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_byte[i].reg, status); + *(regs_byte[i].value) = 0; + data->valid = 0; + } else { + *(regs_byte[i].value) = status; + } + } + + for (i = 0; i < ARRAY_SIZE(regs_word); i++) + { + status = cs5435_54p_psu_read_word(client,regs_word[i].reg); + if (status < 0) + { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_word[i].reg, status); + *(regs_word[i].value) = 0; + data->valid = 0; + } + else + { + *(regs_word[i].value) = status; + } + } + + command = 0x99; /* PSU mfr_id */ + status = cs5435_54p_psu_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); + memset(data->mfr_id, 0, sizeof(data->mfr_id)); + data->valid = 0; + } + + command = 0x9a; /* PSU mfr_model */ + status = cs5435_54p_psu_read_block(client, command, + data->mfr_model, ARRAY_SIZE(data->mfr_model) - 1); + data->mfr_model[ARRAY_SIZE(data->mfr_model) - 1] = '\0'; + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + memset(data->mfr_model, 0, sizeof(data->mfr_id)); + data->valid = 0; + } + + command = 0x9e; /* PSU mfr_serial */ + status = cs5435_54p_psu_read_block(client, command, + data->mfr_serial, ARRAY_SIZE(data->mfr_serial) - 1); + data->mfr_serial[ARRAY_SIZE(data->mfr_serial) - 1] = '\0'; + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + memset(data->mfr_serial, 0, sizeof(data->mfr_id)); + data->valid = 0; + } + + data->psu_is_present = strlen(data->mfr_id) > 1 ? 1:0; + if(data->psu_is_present) + { + data->psu_is_good = ((data->fan_fault) || (data->temp_fault))? 0:1; + } + else + { + data->valid = 0; + data->psu_is_good = 0; + } + } + + mutex_unlock(&data->update_lock); + + return data; + +} + +/* sysfs attributes for hwmon */ +static SENSOR_DEVICE_ATTR(psu_v_in, S_IRUGO, for_linear_data, NULL, PSU_V_IN); +static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, for_vout_data, NULL, PSU_V_OUT); +static SENSOR_DEVICE_ATTR(psu_i_in, S_IRUGO, for_linear_data, NULL, PSU_I_IN); +static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, for_linear_data, NULL, PSU_I_OUT); +static SENSOR_DEVICE_ATTR(psu_p_in, S_IRUGO, for_linear_data, NULL, PSU_P_IN); +static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, for_linear_data, NULL, PSU_P_OUT); +static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, for_linear_data, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp2_input, S_IRUGO, for_linear_data, NULL, PSU_TEMP2_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp3_input, S_IRUGO, for_linear_data, NULL, PSU_TEMP3_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp_fault, S_IRUGO, for_temp_fault, NULL, PSU_TEMP_FAULT); +static SENSOR_DEVICE_ATTR(psu_temp_warning, S_IRUGO, for_temp_warning, NULL, PSU_TEMP_WARN); +static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, for_fan_fault, NULL, PSU_FAN1_FAULT); +static SENSOR_DEVICE_ATTR(psu_fan1_warning, S_IRUGO, for_fan_warning, NULL, PSU_FAN1_WARN); +static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, for_linear_data, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE); +static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, for_linear_data, NULL, PSU_FAN1_SPEED); +static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, for_ascii, NULL, PSU_MFR_ID); +static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, for_ascii, NULL, PSU_MFR_MODEL); +static SENSOR_DEVICE_ATTR(psu_mfr_serial, S_IRUGO, for_ascii, NULL, PSU_MFR_SERIAL); +static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, for_status, NULL, PSU_PRESENT); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, for_status, NULL, PSU_P_GOOD); + + + +static struct attribute *cs5435_54p_psu_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_temp2_input.dev_attr.attr, + &sensor_dev_attr_psu_temp3_input.dev_attr.attr, + &sensor_dev_attr_psu_temp_fault.dev_attr.attr, + &sensor_dev_attr_psu_temp_warning.dev_attr.attr, + &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, + &sensor_dev_attr_psu_fan1_warning.dev_attr.attr, + &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, + &sensor_dev_attr_psu_fan1_speed_rpm.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_serial.dev_attr.attr, + &sensor_dev_attr_psu_present.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + NULL +}; + +static const struct attribute_group cs5435_54p_psu_group = { + .attrs = cs5435_54p_psu_attributes, +}; + + +static int psu_register_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int status; + + + struct cs5435_54p_psu_data *data; + + if (!psu_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + mutex_init(&data->update_lock); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &cs5435_54p_psu_group); + if (status) + goto exit_sysfs_create_group; + + cs5435_54p_sysfs_add_client(client); + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_hwmon_device_register; + } + + /* init eeprom */ + + return 0; + + exit_hwmon_device_register: + sysfs_remove_group(&client->dev.kobj, &cs5435_54p_psu_group); + exit_sysfs_create_group: + kfree(data); + exit: + return status; + +} + + +static int cs5435_54p_psu_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int status; + + if((client->addr == 0x52) ||(client->addr == 0x53)) + { + status = psu_eeprom_probe(client, id); + } + else if((client->addr == 0x5a) ||(client->addr == 0x5b)) + { + status = psu_register_probe(client, id); + } + return status; +} + +static int cs5435_54p_psu_remove(struct i2c_client *client) +{ + cs5435_54p_sysfs_remove_client(client); + + if((client->addr == 0x52) ||(client->addr == 0x53)) + { + struct cs5435_54p_psu_data *data; + data = i2c_get_clientdata(client); + psu_sysfs_eeprom_cleanup(&client->dev.kobj,data->bin); + kfree(data); + } + else if((client->addr == 0x5a) ||(client->addr == 0x5b)) + { + struct cs5435_54p_psu_data *data; + data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &cs5435_54p_psu_group); + kfree(data); + } + + return 0; +} + +enum psu_index +{ + cs5435_54p_psu1, + cs5435_54p_psu2 +}; + +static const struct i2c_device_id cs5435_54p_psu_id[] = { + { "cs5435_54p_psu1", cs5435_54p_psu1 }, + { "cs5435_54p_psu2", cs5435_54p_psu2 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, cs5435_54p_psu_id); + +static struct i2c_driver cs5435_54p_psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "cs5435_54p_psu", + }, + .probe = cs5435_54p_psu_probe, + .remove = cs5435_54p_psu_remove, + .id_table = cs5435_54p_psu_id, + .address_list = normal_i2c, +}; + +module_i2c_driver(cs5435_54p_psu_driver); + +MODULE_AUTHOR("Zhang Peng "); +MODULE_DESCRIPTION("cs5435_54p_psu driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-sfp.c b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-sfp.c new file mode 100644 index 00000000000..3bdb3d2de79 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-sfp.c @@ -0,0 +1,1713 @@ +/* + * A hwmon driver for the CIG cs5435-54P SFP Module + * + * Copyright (C) 2018 Cambridge, 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 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 "i2c-algo-lpc.h" + +#define DRIVER_NAME "cs5435_54p_sfp" /* Platform dependent */ + +#define DEBUG_MODE 0 + +#if (DEBUG_MODE == 1) + #define DEBUG_PRINT(fmt, args...) \ + printk (KERN_INFO "%s:%s[%d]: " fmt "\r\n", __FILE__, __FUNCTION__, __LINE__, ##args) +#else + #define DEBUG_PRINT(fmt, args...) +#endif + +#define EEPROM_NAME "sfp_eeprom" +#define EEPROM_SIZE 256 /* 256 byte eeprom */ +#define BIT_INDEX(i) (1ULL << (i)) +#define USE_I2C_BLOCK_READ 1 /* Platform dependent */ +#define I2C_RW_RETRY_COUNT 3 +#define I2C_RW_RETRY_INTERVAL 100 /* ms */ + +#define SFP_EEPROM_A0_I2C_ADDR (0xA0 >> 1) +#define SFP_EEPROM_A2_I2C_ADDR (0xA2 >> 1) + +#define SFF8024_PHYSICAL_DEVICE_ID_ADDR 0x0 +#define SFF8024_DEVICE_ID_SFP 0x3 +#define SFF8024_DEVICE_ID_QSFP 0xC +#define SFF8024_DEVICE_ID_QSFP_PLUS 0xD +#define SFF8024_DEVICE_ID_QSFP28 0x11 + +#define SFF8472_DIAG_MON_TYPE_ADDR 92 +#define SFF8472_DIAG_MON_TYPE_DDM_MASK 0x40 +#define SFF8472_10G_ETH_COMPLIANCE_ADDR 0x3 +#define SFF8472_10G_BASE_MASK 0xF0 + +#define SFF8436_RX_LOS_ADDR 3 +#define SFF8436_TX_FAULT_ADDR 4 +#define SFF8436_TX_DISABLE_ADDR 86 +#define QSFP_RESET_ADDR 0x1b +#define QSFP_INTER_ADDR 0x1a +#define QSFP_LPMODE_ADDR 0x1c + +static ssize_t show_port_number(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_port_type(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_present(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t sfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t sfp_set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t qsfp_set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count);; +static ssize_t sfp_show_ddm_implemented(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t sfp_eeprom_read(struct i2c_client *, u8, u8 *,int); +static ssize_t sfp_eeprom_write(struct i2c_client *, u8 , const char *,int); +extern int cig_cpld_read_register(u8 reg_off, u8 *val); +extern int cig_cpld_write_register(u8 reg_off, u8 val); + +static ssize_t qsfp_reset_read(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_reset_write(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t qsfp_inter_read(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_lpmode_read(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_lpmode_write(struct device *dev, struct device_attribute *da, const char *buf, size_t count); + +enum sfp_sysfs_attributes { + PRESENT, + PRESENT_ALL, + PORT_NUMBER, + PORT_TYPE, + DDM_IMPLEMENTED, + TX_FAULT, + TX_FAULT1, + TX_FAULT2, + TX_FAULT3, + TX_FAULT4, + TX_DISABLE, + TX_DISABLE1, + TX_DISABLE2, + TX_DISABLE3, + TX_DISABLE4, + RX_LOS, + RX_LOS1, + RX_LOS2, + RX_LOS3, + RX_LOS4, + RX_LOS_ALL, + QSFPRESET, + QSFPINT, + QSFPLPMODE +}; + +/* SFP/QSFP common attributes for sysfs */ +static SENSOR_DEVICE_ATTR(sfp_port_number, S_IRUGO, show_port_number, NULL, PORT_NUMBER); +static SENSOR_DEVICE_ATTR(sfp_port_type, S_IRUGO, show_port_type, NULL, PORT_TYPE); +static SENSOR_DEVICE_ATTR(sfp_is_present, S_IRUGO, show_present, NULL, PRESENT); +static SENSOR_DEVICE_ATTR(sfp_is_present_all, S_IRUGO, show_present, NULL, PRESENT_ALL); +static SENSOR_DEVICE_ATTR(sfp_rx_los, S_IRUGO, sfp_show_tx_rx_status, NULL, RX_LOS); +static SENSOR_DEVICE_ATTR(sfp_tx_disable, S_IWUSR | S_IRUGO, sfp_show_tx_rx_status, sfp_set_tx_disable, TX_DISABLE); +static SENSOR_DEVICE_ATTR(sfp_tx_fault, S_IRUGO, sfp_show_tx_rx_status, NULL, TX_FAULT); + +/* QSFP attributes for sysfs */ +static SENSOR_DEVICE_ATTR(sfp_rx_los1, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS1); +static SENSOR_DEVICE_ATTR(sfp_rx_los2, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS2); +static SENSOR_DEVICE_ATTR(sfp_rx_los3, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS3); +static SENSOR_DEVICE_ATTR(sfp_rx_los4, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS4); +static SENSOR_DEVICE_ATTR(sfp_tx_disable1, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE1); +static SENSOR_DEVICE_ATTR(sfp_tx_disable2, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE2); +static SENSOR_DEVICE_ATTR(sfp_tx_disable3, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE3); +static SENSOR_DEVICE_ATTR(sfp_tx_disable4, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE4); +static SENSOR_DEVICE_ATTR(sfp_tx_fault1, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT1); +static SENSOR_DEVICE_ATTR(sfp_tx_fault2, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT2); +static SENSOR_DEVICE_ATTR(sfp_tx_fault3, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT3); +static SENSOR_DEVICE_ATTR(sfp_tx_fault4, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT4); +static SENSOR_DEVICE_ATTR(sfp_reset, S_IWUSR | S_IRUGO, qsfp_reset_read, qsfp_reset_write, QSFPRESET); +static SENSOR_DEVICE_ATTR(sfp_inter, S_IRUGO, qsfp_inter_read, NULL, QSFPINT); +static SENSOR_DEVICE_ATTR(sfp_lpmode, S_IWUSR | S_IRUGO, qsfp_lpmode_read, qsfp_lpmode_write, QSFPLPMODE); +static struct attribute *qsfp_attributes[] = { + &sensor_dev_attr_sfp_port_number.dev_attr.attr, + &sensor_dev_attr_sfp_port_type.dev_attr.attr, + &sensor_dev_attr_sfp_is_present.dev_attr.attr, + &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los1.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los2.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los3.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los4.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable1.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable2.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable3.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable4.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault1.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault2.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault3.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault4.dev_attr.attr, + &sensor_dev_attr_sfp_reset.dev_attr.attr, + &sensor_dev_attr_sfp_inter.dev_attr.attr, + &sensor_dev_attr_sfp_lpmode.dev_attr.attr, + NULL +}; + +/* SFP msa attributes for sysfs */ +static SENSOR_DEVICE_ATTR(sfp_ddm_implemented, S_IRUGO, sfp_show_ddm_implemented, NULL, DDM_IMPLEMENTED); +static SENSOR_DEVICE_ATTR(sfp_rx_los_all, S_IRUGO, sfp_show_tx_rx_status, NULL, RX_LOS_ALL); +static struct attribute *sfp_msa_attributes[] = { + &sensor_dev_attr_sfp_port_number.dev_attr.attr, + &sensor_dev_attr_sfp_port_type.dev_attr.attr, + &sensor_dev_attr_sfp_is_present.dev_attr.attr, + &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, + &sensor_dev_attr_sfp_ddm_implemented.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los_all.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable.dev_attr.attr, + NULL +}; + +/* SFP ddm attributes for sysfs */ +static struct attribute *sfp_ddm_attributes[] = { + NULL +}; + +/* Platform dependent +++ */ +#define CPLD_PORT_TO_FRONT_PORT(port) (port+1) + +enum port_numbers { +cs5435_54p_sfp1, cs5435_54p_sfp2, cs5435_54p_sfp3, cs5435_54p_sfp4, +cs5435_54p_sfp5, cs5435_54p_sfp6, cs5435_54p_sfp7, cs5435_54p_sfp8, +cs5435_54p_sfp9, cs5435_54p_sfp10, cs5435_54p_sfp11, cs5435_54p_sfp12, +cs5435_54p_sfp13, cs5435_54p_sfp14, cs5435_54p_sfp15, cs5435_54p_sfp16, +cs5435_54p_sfp17, cs5435_54p_sfp18, cs5435_54p_sfp19, cs5435_54p_sfp20, +cs5435_54p_sfp21, cs5435_54p_sfp22, cs5435_54p_sfp23, cs5435_54p_sfp24, +cs5435_54p_sfp25, cs5435_54p_sfp26, cs5435_54p_sfp27, cs5435_54p_sfp28, +cs5435_54p_sfp29, cs5435_54p_sfp30, cs5435_54p_sfp31, cs5435_54p_sfp32, +cs5435_54p_sfp33, cs5435_54p_sfp34, cs5435_54p_sfp35, cs5435_54p_sfp36, +cs5435_54p_sfp37, cs5435_54p_sfp38, cs5435_54p_sfp39, cs5435_54p_sfp40, +cs5435_54p_sfp41, cs5435_54p_sfp42, cs5435_54p_sfp43, cs5435_54p_sfp44, +cs5435_54p_sfp45, cs5435_54p_sfp46, cs5435_54p_sfp47, cs5435_54p_sfp48, +cs5435_54p_sfp49, cs5435_54p_sfp50, cs5435_54p_sfp51, cs5435_54p_sfp52, +cs5435_54p_sfp53, cs5435_54p_sfp54, cs5435_54p_sfp55, cs5435_54p_sfp56 +}; + +#define I2C_DEV_ID(x) { #x, x} + +static const struct i2c_device_id sfp_device_id[] = { +I2C_DEV_ID(cs5435_54p_sfp1), +I2C_DEV_ID(cs5435_54p_sfp2), +I2C_DEV_ID(cs5435_54p_sfp3), +I2C_DEV_ID(cs5435_54p_sfp4), +I2C_DEV_ID(cs5435_54p_sfp5), +I2C_DEV_ID(cs5435_54p_sfp6), +I2C_DEV_ID(cs5435_54p_sfp7), +I2C_DEV_ID(cs5435_54p_sfp8), +I2C_DEV_ID(cs5435_54p_sfp9), +I2C_DEV_ID(cs5435_54p_sfp10), +I2C_DEV_ID(cs5435_54p_sfp11), +I2C_DEV_ID(cs5435_54p_sfp12), +I2C_DEV_ID(cs5435_54p_sfp13), +I2C_DEV_ID(cs5435_54p_sfp14), +I2C_DEV_ID(cs5435_54p_sfp15), +I2C_DEV_ID(cs5435_54p_sfp16), +I2C_DEV_ID(cs5435_54p_sfp17), +I2C_DEV_ID(cs5435_54p_sfp18), +I2C_DEV_ID(cs5435_54p_sfp19), +I2C_DEV_ID(cs5435_54p_sfp20), +I2C_DEV_ID(cs5435_54p_sfp21), +I2C_DEV_ID(cs5435_54p_sfp22), +I2C_DEV_ID(cs5435_54p_sfp23), +I2C_DEV_ID(cs5435_54p_sfp24), +I2C_DEV_ID(cs5435_54p_sfp25), +I2C_DEV_ID(cs5435_54p_sfp26), +I2C_DEV_ID(cs5435_54p_sfp27), +I2C_DEV_ID(cs5435_54p_sfp28), +I2C_DEV_ID(cs5435_54p_sfp29), +I2C_DEV_ID(cs5435_54p_sfp30), +I2C_DEV_ID(cs5435_54p_sfp31), +I2C_DEV_ID(cs5435_54p_sfp32), +I2C_DEV_ID(cs5435_54p_sfp33), +I2C_DEV_ID(cs5435_54p_sfp34), +I2C_DEV_ID(cs5435_54p_sfp35), +I2C_DEV_ID(cs5435_54p_sfp36), +I2C_DEV_ID(cs5435_54p_sfp37), +I2C_DEV_ID(cs5435_54p_sfp38), +I2C_DEV_ID(cs5435_54p_sfp39), +I2C_DEV_ID(cs5435_54p_sfp40), +I2C_DEV_ID(cs5435_54p_sfp41), +I2C_DEV_ID(cs5435_54p_sfp42), +I2C_DEV_ID(cs5435_54p_sfp43), +I2C_DEV_ID(cs5435_54p_sfp44), +I2C_DEV_ID(cs5435_54p_sfp45), +I2C_DEV_ID(cs5435_54p_sfp46), +I2C_DEV_ID(cs5435_54p_sfp47), +I2C_DEV_ID(cs5435_54p_sfp48), +I2C_DEV_ID(cs5435_54p_sfp49), +I2C_DEV_ID(cs5435_54p_sfp50), +I2C_DEV_ID(cs5435_54p_sfp51), +I2C_DEV_ID(cs5435_54p_sfp52), +I2C_DEV_ID(cs5435_54p_sfp53), +I2C_DEV_ID(cs5435_54p_sfp54), +I2C_DEV_ID(cs5435_54p_sfp55), +I2C_DEV_ID(cs5435_54p_sfp56), +{ /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i2c, sfp_device_id); + +/* + * list of valid port types + * note OOM_PORT_TYPE_NOT_PRESENT to indicate no + * module is present in this port + */ +typedef enum oom_driver_port_type_e { + OOM_DRIVER_PORT_TYPE_INVALID, + OOM_DRIVER_PORT_TYPE_NOT_PRESENT, + OOM_DRIVER_PORT_TYPE_SFP, + OOM_DRIVER_PORT_TYPE_SFP_PLUS, + OOM_DRIVER_PORT_TYPE_QSFP, + OOM_DRIVER_PORT_TYPE_QSFP_PLUS, + OOM_DRIVER_PORT_TYPE_QSFP28 +} oom_driver_port_type_t; + +enum driver_type_e { + DRIVER_TYPE_SFP_MSA, + DRIVER_TYPE_SFP_DDM, + DRIVER_TYPE_QSFP +}; + +/* Each client has this additional data + */ +struct eeprom_data { + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + struct bin_attribute bin; /* eeprom data */ +}; + +struct sfp_msa_data { + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u64 status[6]; /* bit0:port0, bit1:port1 and so on */ + /* index 0 => tx_fail + 1 => tx_disable + 2 => rx_loss + 3 => device id + 4 => 10G Ethernet Compliance Codes + to distinguish SFP or SFP+ + 5 => DIAGNOSTIC MONITORING TYPE */ + struct eeprom_data eeprom; +}; + +struct sfp_ddm_data { + struct eeprom_data eeprom; +}; + +struct qsfp_data { + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 status[3]; /* bit0:port0, bit1:port1 and so on */ + /* index 0 => tx_fail + 1 => tx_disable + 2 => rx_loss */ + + u8 device_id; + struct eeprom_data eeprom; +}; + +struct sfp_port_data { + struct mutex update_lock; + enum driver_type_e driver_type; + int port; /* CPLD port index */ + oom_driver_port_type_t port_type; + u64 present; /* present status, bit0:port0, bit1:port1 and so on */ + + struct sfp_msa_data *msa; + struct sfp_ddm_data *ddm; + struct qsfp_data *qsfp; + + struct i2c_client *client; +}; + +static ssize_t show_port_number(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + return sprintf(buf, "%d\n", CPLD_PORT_TO_FRONT_PORT(data->port)); +} + + + +static int cig_cpld_write_sfp_register(u8 sfp_reg_addr, u8 sfp_write_reg_data) +{ + u8 sfp_read_status = 0; + u8 wait_time_out = WAIT_TIME_OUT_COUNT; + + cig_cpld_write_register(ADDR_REG_SFP_STATUS_ADDR, sfp_reg_addr << 1); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_TX, sfp_write_reg_data); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_COMMAND, 0x80); + do{ + cig_cpld_read_register(ADDR_REG_SFP_STATUS_STATUS, &sfp_read_status); + udelay(60); + wait_time_out--; + if(wait_time_out == 0) + break; + }while(sfp_read_status != 0x02); + + if(wait_time_out == 0) + return -1; + + return 1; +} + + +static int cig_cpld_read_sfp_register(u8 sfp_reg_addr, u8 *sfp_read_reg_data) +{ + u8 sfp_read_status = 0; + u8 wait_time_out = WAIT_TIME_OUT_COUNT; + + cig_cpld_write_register(ADDR_REG_SFP_STATUS_ADDR, sfp_reg_addr << 1 | 1); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_COMMAND, 0x80); + do{ + udelay(60); + cig_cpld_read_register(ADDR_REG_SFP_STATUS_STATUS, &sfp_read_status); + wait_time_out--; + if(wait_time_out == 0) + break; + }while(sfp_read_status != 0x01); + + cig_cpld_read_register(ADDR_REG_SFP_STATUS_RX,sfp_read_reg_data); + + if(wait_time_out == 0) + return -1; + + return 1; +} + + + + + + +/* Platform dependent +++ */ +static struct sfp_port_data *sfp_update_present(struct i2c_client *client) +{ + int i = 0, j = 0, status = -1; + unsigned char cpld_reg_data = 0,cpld_reg_addr = 0; + struct sfp_port_data *data = i2c_get_clientdata(client); + + DEBUG_PRINT("Starting sfp present status update"); + mutex_lock(&data->update_lock); + data->present = 0; + + udelay(6000); + + /* Read present status of port 1~48(SFP port) */ + for (i = 0; i < 6; i++) { + cpld_reg_addr = 1 + i; + + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); + + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_reg_addr, cpld_reg_data, status); + goto exit; + } + + data->present |= (u64)cpld_reg_data << (i*8); + + DEBUG_PRINT("Present status = 0x%lx\r\n", data->present); + } + + /* Read present status of port 49-56(QSFP port) */ + cpld_reg_addr = 25; + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_reg_addr, cpld_reg_data, status); + goto exit; + } + else { + data->present |= (u64)cpld_reg_data << 48; + } + + DEBUG_PRINT("Present status = 0x%lx", data->present); +exit: + mutex_unlock(&data->update_lock); + return (status < 0) ? ERR_PTR(status) : data; +} + +static struct sfp_port_data *sfp_update_tx_rx_status(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + int i = 0, j = 0; + int status = -1; + unsigned char cpld_reg_data = 0,cpld_reg_addr = 0; + + if (time_before(jiffies, data->msa->last_updated + HZ + HZ / 2) && data->msa->valid) { + return data; + } + + DEBUG_PRINT("Starting cs5435_54p sfp tx rx status update"); + mutex_lock(&data->update_lock); + data->msa->valid = 0; + memset(data->msa->status, 0, sizeof(data->msa->status)); + + udelay(6000); + + /* Read status of port 1~48(SFP port) */ + for (i = 0; i < 6; i++) { + cpld_reg_addr = 13+i; + + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_reg_addr, cpld_reg_data, status); + goto exit; + } + + data->msa->status[0] |= (u64)cpld_reg_data << (i * 8); + + DEBUG_PRINT("tx rx status[0] = 0x%lx\r\n", data->msa->status[0]); + } + + + for (i = 0; i < 6; i++) { + cpld_reg_addr = 19+i; + + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_reg_addr, cpld_reg_data, status); + goto exit; + } + + data->msa->status[1] |= (u64)cpld_reg_data << (i * 8); + + DEBUG_PRINT("tx rx status[1] = 0x%lx\r\n", data->msa->status[1]); + } + + for (i = 0; i < 6; i++) { + cpld_reg_addr = 7+i; + + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_reg_addr, cpld_reg_data, status); + goto exit; + } + + data->msa->status[2] |= (u64)cpld_reg_data << (i * 8); + + DEBUG_PRINT("tx rx status[2] = 0x%lx\r\n", data->msa->status[2]); + } + + data->msa->valid = 1; + data->msa->last_updated = jiffies; + +exit: + mutex_unlock(&data->update_lock); + return (status < 0) ? ERR_PTR(status) : data; +} + +static ssize_t sfp_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 sfp_port_data *data = i2c_get_clientdata(client); + unsigned char cpld_reg_data = 0,cpld_reg_addr = 0,cpld_reg_bit = 0,cpld_reg_val = 0; + long disable; + int error; + + if (data->driver_type == DRIVER_TYPE_QSFP) { + return qsfp_set_tx_disable(dev, da, buf, count); + } + + error = kstrtol(buf, 10, &disable); + if (error) { + return error; + } + + mutex_lock(&data->update_lock); + + udelay(6000); + + if(data->port <= 48) { + cpld_reg_addr = 19 + data->port / 8; + cpld_reg_bit = 1 << ((data->port) % 8); + } + + /* Read current status */ + error = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); + + /* Update tx_disable status */ + if (disable) { + data->msa->status[1] |= BIT_INDEX(data->port); + cpld_reg_data |= cpld_reg_bit; + } + else { + data->msa->status[1] &= ~ BIT_INDEX(data->port); + cpld_reg_data &= ~cpld_reg_bit; + } + + error = cig_cpld_write_sfp_register(cpld_reg_addr,cpld_reg_data); + + mutex_unlock(&data->update_lock); + return count; +} +/* Platform dependent --- */ + +static int sfp_is_port_present(struct i2c_client *client, int port) +{ + struct sfp_port_data *data = i2c_get_clientdata(client); + + data = sfp_update_present(client); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + return !(data->present & BIT_INDEX(data->port)); /* Platform dependent */ +} + +/* Platform dependent +++ */ +static ssize_t show_present(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); + + if (PRESENT_ALL == attr->index) { + int i; + u8 values[7] = {0}; + struct sfp_port_data *data = sfp_update_present(client); + + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + for (i = 0; i < ARRAY_SIZE(values); i++) { + values[i] = ~(u8)(data->present >> (i * 8)); + } + + /* Return values 1 -> 56 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]); + } + else { + struct sfp_port_data *data = i2c_get_clientdata(client); + int present = sfp_is_port_present(client, data->port); + + if (IS_ERR_VALUE(present)) { + return present; + } + + /* PRESENT */ + return sprintf(buf, "%d\n", present); + } +} +/* Platform dependent --- */ + +static struct sfp_port_data *sfp_update_port_type(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + u8 buf = 0; + int status; + + mutex_lock(&data->update_lock); + + switch (data->driver_type) { + case DRIVER_TYPE_SFP_MSA: + { + status = sfp_eeprom_read(client, SFF8024_PHYSICAL_DEVICE_ID_ADDR, &buf, sizeof(buf)); + if (unlikely(status < 0)) { + data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; + break; + } + + if (buf != SFF8024_DEVICE_ID_SFP) { + data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; + break; + } + + status = sfp_eeprom_read(client, SFF8472_10G_ETH_COMPLIANCE_ADDR, &buf, sizeof(buf)); + if (unlikely(status < 0)) { + data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; + break; + } + + DEBUG_PRINT("sfp port type (0x3) data = (0x%x)", buf); + data->port_type = buf & SFF8472_10G_BASE_MASK ? OOM_DRIVER_PORT_TYPE_SFP_PLUS : OOM_DRIVER_PORT_TYPE_SFP; + break; + } + case DRIVER_TYPE_QSFP: + { + status = sfp_eeprom_read(client, SFF8024_PHYSICAL_DEVICE_ID_ADDR, &buf, sizeof(buf)); + if (unlikely(status < 0)) { + data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; + break; + } + + DEBUG_PRINT("qsfp port type (0x0) buf = (0x%x)", buf); + switch (buf) { + case SFF8024_DEVICE_ID_QSFP: + data->port_type = OOM_DRIVER_PORT_TYPE_QSFP; + break; + case SFF8024_DEVICE_ID_QSFP_PLUS: + data->port_type = OOM_DRIVER_PORT_TYPE_QSFP_PLUS; + break; + case SFF8024_DEVICE_ID_QSFP28: + data->port_type = OOM_DRIVER_PORT_TYPE_QSFP_PLUS; + break; + default: + data->port_type = buf; + break; + } + + break; + } + default: + break; + } + + mutex_unlock(&data->update_lock); + return data; +} + +static ssize_t show_port_type(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + int present = sfp_is_port_present(client, data->port); + + if (IS_ERR_VALUE(present)) { + return present; + } + + if (!present) { + /* port is not present */ + return sprintf(buf, "%d\n", OOM_DRIVER_PORT_TYPE_NOT_PRESENT); + } + + sfp_update_port_type(dev); + return sprintf(buf, "%d\n", data->port_type); +} + +static struct sfp_port_data *qsfp_update_tx_rx_status(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + int i, status = -1; + u8 buf = 0; + u8 reg[] = {SFF8436_TX_FAULT_ADDR, SFF8436_TX_DISABLE_ADDR, SFF8436_RX_LOS_ADDR}; + + DEBUG_PRINT(""); + if (time_before(jiffies, data->qsfp->last_updated + HZ + HZ / 2) && data->qsfp->valid) { + return data; + } + + DEBUG_PRINT("Starting sfp tx rx status update"); + mutex_lock(&data->update_lock); + data->qsfp->valid = 0; + memset(data->qsfp->status, 0, sizeof(data->qsfp->status)); + + DEBUG_PRINT(""); + /* Notify device to update tx fault/ tx disable/ rx los status */ + for (i = 0; i < ARRAY_SIZE(reg); i++) { + status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); + if (unlikely(status < 0)) { + DEBUG_PRINT(""); + goto exit; + } + } + msleep(200); + DEBUG_PRINT(""); + + /* Read actual tx fault/ tx disable/ rx los status */ + for (i = 0; i < ARRAY_SIZE(reg); i++) { + status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); + if (unlikely(status < 0)) { + DEBUG_PRINT(""); + goto exit; + } + + DEBUG_PRINT("qsfp reg(0x%x) status = (0x%x)", reg[i], data->qsfp->status[i]); + data->qsfp->status[i] = (buf & 0xF); + } + + DEBUG_PRINT(""); + data->qsfp->valid = 1; + data->qsfp->last_updated = jiffies; + +exit: + DEBUG_PRINT(""); + mutex_unlock(&data->update_lock); + return (status < 0) ? ERR_PTR(status) : data; +} + +static ssize_t qsfp_inter_read(struct device *dev, struct device_attribute *da, char *buf) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_INTER_ADDR, &cpld_reg_data); + index = data->port - 48; + index = 1 << index; + val = (cpld_reg_data & index) > 0 ? 1 : 0; + + printk("inter read:data->port = %d, index = %hhu, cpld_reg_data = %hhu\n", data->port, index, cpld_reg_data); + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", val); +} + + +static ssize_t qsfp_reset_read(struct device *dev, struct device_attribute *da, char *buf) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_RESET_ADDR, &cpld_reg_data); + index = data->port - 48; + index = 1 << index; + val = (cpld_reg_data & index) > 0 ? 1 : 0; + + printk("reset read:data->port = %d, index = %hhu, cpld_reg_data = %hhu\n", data->port, index, cpld_reg_data); + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t qsfp_reset_write(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + long usrdata; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + ret = kstrtol(buf, 10, &usrdata); + if (ret) { + return ret; + } + + usrdata = usrdata > 0 ? 1 : 0; + index = data->port - 48; + + DEBUG_PRINT("usrdata = %u, index = %hhu\n", usrdata, index); + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_RESET_ADDR, &cpld_reg_data); + if (ret == 1) + { + + DEBUG_PRINT("cpld_reg_data = %x\n", cpld_reg_data); + cpld_reg_data &= ~(1 << index); + cpld_reg_data |= usrdata << index; + + DEBUG_PRINT("cpld_reg_data = %x\n", cpld_reg_data); + ret = cig_cpld_write_sfp_register(QSFP_RESET_ADDR, cpld_reg_data); + if (1 != ret) + { + DEBUG_PRINT("write failed\n"); + } + } + else + { + DEBUG_PRINT("read failed\n"); + } + + mutex_unlock(&data->update_lock); + + if (ret != 1) + return -1; + + return count; +} + + + + +static ssize_t qsfp_lpmode_read(struct device *dev, struct device_attribute *da, char *buf) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_LPMODE_ADDR, &cpld_reg_data); + index = data->port - 48; + index = 1 << index; + val = (cpld_reg_data & index) > 0 ? 1 : 0; + + printk("lpmode read:data->port = %d, index = %hhu, cpld_reg_data = %hhu\n", data->port, index, cpld_reg_data); + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t qsfp_lpmode_write(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + long usrdata; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + ret = kstrtol(buf, 10, &usrdata); + if (ret) { + return ret; + } + + usrdata = usrdata > 0 ? 1 : 0; + index = data->port - 48; + + DEBUG_PRINT("usrdata = %u, index = %hhu\n", usrdata, index); + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_LPMODE_ADDR, &cpld_reg_data); + if (ret == 1) + { + + DEBUG_PRINT("cpld_reg_data = %x\n", cpld_reg_data); + cpld_reg_data &= ~(1 << index); + cpld_reg_data |= usrdata << index; + + DEBUG_PRINT("cpld_reg_data = %x\n", cpld_reg_data); + ret = cig_cpld_write_sfp_register(QSFP_LPMODE_ADDR, cpld_reg_data); + if (1 != ret) + { + DEBUG_PRINT("write failed\n"); + } + } + else + { + DEBUG_PRINT("read failed\n"); + } + + mutex_unlock(&data->update_lock); + + if (ret != 1) + return -1; + + return count; +} + + + +static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + int present; + u8 val = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + DEBUG_PRINT(""); + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + DEBUG_PRINT(""); + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + DEBUG_PRINT(""); + data = qsfp_update_tx_rx_status(dev); + DEBUG_PRINT(""); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + DEBUG_PRINT(""); + switch (attr->index) { + case TX_FAULT: + val = !!(data->qsfp->status[2] & 0xF); + break; + case TX_FAULT1: + case TX_FAULT2: + case TX_FAULT3: + case TX_FAULT4: + val = !!(data->qsfp->status[2] & BIT_INDEX(attr->index - TX_FAULT1)); + break; + case TX_DISABLE: + val = data->qsfp->status[1] & 0xF; + break; + case TX_DISABLE1: + case TX_DISABLE2: + case TX_DISABLE3: + case TX_DISABLE4: + val = !!(data->qsfp->status[1] & BIT_INDEX(attr->index - TX_DISABLE1)); + break; + case RX_LOS: + val = !!(data->qsfp->status[0] & 0xF); + break; + case RX_LOS1: + case RX_LOS2: + case RX_LOS3: + case RX_LOS4: + val = !!(data->qsfp->status[0] & BIT_INDEX(attr->index - RX_LOS1)); + break; + default: + break; + } + + DEBUG_PRINT(""); + return sprintf(buf, "%d\n", val); +} + +static ssize_t qsfp_set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long disable; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + status = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(status)) { + return status; + } + + if (!status) { + /* port is not present */ + return -ENXIO; + } + + status = kstrtol(buf, 10, &disable); + if (status) { + return status; + } + + data = qsfp_update_tx_rx_status(dev); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + mutex_lock(&data->update_lock); + + if (attr->index == TX_DISABLE) { + data->qsfp->status[1] = disable & 0xF; + } + else {/* TX_DISABLE1 ~ TX_DISABLE4*/ + if (disable) { + data->qsfp->status[1] |= (1 << (attr->index - TX_DISABLE1)); + } + else { + data->qsfp->status[1] &= ~(1 << (attr->index - TX_DISABLE1)); + } + } + + DEBUG_PRINT("index = (%d), status = (0x%x)", attr->index, data->qsfp->status[1]); + status = sfp_eeprom_write(data->client, SFF8436_TX_DISABLE_ADDR, &data->qsfp->status[1], sizeof(data->qsfp->status[1])); + if (unlikely(status < 0)) { + count = status; + } + + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t sfp_show_ddm_implemented(struct device *dev, struct device_attribute *da, + char *buf) +{ + int status; + char ddm; + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + status = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(status)) { + return status; + } + + if (status == 0) { + /* port is not present */ + return -ENODEV; + } + + status = sfp_eeprom_read(client, SFF8472_DIAG_MON_TYPE_ADDR, &ddm, sizeof(ddm)); + if (unlikely(status < 0)) { + return status; + } + + return sprintf(buf, "%d\n", !!(ddm & SFF8472_DIAG_MON_TYPE_DDM_MASK)); +} + +/* Platform dependent +++ */ +static ssize_t sfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + u8 val = 0, index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + DEBUG_PRINT("driver type = (%d)", data->driver_type); + if (data->driver_type == DRIVER_TYPE_QSFP) { + DEBUG_PRINT(""); + return qsfp_show_tx_rx_status(dev, da, buf); + } + + DEBUG_PRINT(""); + data = sfp_update_tx_rx_status(dev); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + if(attr->index == RX_LOS_ALL) { + int i = 0; + u8 values[6] = {0}; + + for (i = 0; i < ARRAY_SIZE(values); i++) { + values[i] = (u8)(data->msa->status[2] >> (i * 8)); + } + + /** 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]); + } + + switch (attr->index) { + case TX_FAULT: + index = 0; + break; + case TX_DISABLE: + index = 1; + break; + case RX_LOS: + index = 2; + break; + default: + break; + } + + val = !!(data->msa->status[index] & BIT_INDEX(data->port)); + return sprintf(buf, "%d\n", val); +} +/* Platform dependent --- */ +static ssize_t sfp_eeprom_write(struct i2c_client *client, u8 command, const char *data, + int data_len) +{ +#if USE_I2C_BLOCK_READ + int status, retry = I2C_RW_RETRY_COUNT; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_write_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + return status; + } + + return data_len; +#else + int status, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, command, *data); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + return status; + } + + return 1; +#endif + + +} + +static ssize_t sfp_port_write(struct sfp_port_data *data, + const char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + return count; + } + + /* + * Write data to chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&data->update_lock); + + while (count) { + ssize_t status; + + status = sfp_eeprom_write(data->client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + buf += status; + off += status; + count -= status; + retval += status; + } + + mutex_unlock(&data->update_lock); + return retval; +} + + +static ssize_t sfp_bin_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct sfp_port_data *data; + DEBUG_PRINT("%s(%d) offset = (%d), count = (%d)", off, count); + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + + present = sfp_is_port_present(data->client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + return sfp_port_write(data, buf, off, count); +} + +static ssize_t sfp_eeprom_read(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ +#if USE_I2C_BLOCK_READ + int status, retry = I2C_RW_RETRY_COUNT; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + goto abort; + } + if (unlikely(status != data_len)) { + status = -EIO; + goto abort; + } + + //result = data_len; + +abort: + return status; +#else + int status, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, command); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "sfp read byte data failed, command(0x%2x), data(0x%2x)\r\n", command, status); + goto abort; + } + + *data = (u8)status; + status = 1; + +abort: + return status; +#endif +} + +static ssize_t sfp_port_read(struct sfp_port_data *data, + char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + DEBUG_PRINT("Count = 0, return"); + return count; + } + + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&data->update_lock); + + while (count) { + ssize_t status; + + status = sfp_eeprom_read(data->client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + + buf += status; + off += status; + count -= status; + retval += status; + } + + mutex_unlock(&data->update_lock); + return retval; + +} + +static ssize_t sfp_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct sfp_port_data *data; + DEBUG_PRINT("offset = (%d), count = (%d)", off, count); + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + + present = sfp_is_port_present(data->client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + return sfp_port_read(data, buf, off, count); +} + +static int sfp_sysfs_eeprom_init(struct kobject *kobj, struct bin_attribute *eeprom) +{ + int err; + + sysfs_bin_attr_init(eeprom); + eeprom->attr.name = EEPROM_NAME; + eeprom->attr.mode = S_IWUSR | S_IRUGO; + eeprom->read = sfp_bin_read; + eeprom->write = sfp_bin_write; + eeprom->size = EEPROM_SIZE; + + /* Create eeprom file */ + err = sysfs_create_bin_file(kobj, eeprom); + if (err) { + return err; + } + + return 0; +} + +static int sfp_sysfs_eeprom_cleanup(struct kobject *kobj, struct bin_attribute *eeprom) +{ + sysfs_remove_bin_file(kobj, eeprom); + return 0; +} + +static const struct attribute_group sfp_msa_group = { + .attrs = sfp_msa_attributes, +}; + +static int sfp_i2c_check_functionality(struct i2c_client *client) +{ +#if USE_I2C_BLOCK_READ + return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK); +#else + return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA); +#endif +} + +static int sfp_msa_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, + struct sfp_msa_data **data) +{ + int status; + struct sfp_msa_data *msa; + + if (!sfp_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + msa = kzalloc(sizeof(struct sfp_msa_data), GFP_KERNEL); + if (!msa) { + status = -ENOMEM; + goto exit; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &sfp_msa_group); + if (status) { + goto exit_free; + } + + /* init eeprom */ + status = sfp_sysfs_eeprom_init(&client->dev.kobj, &msa->eeprom.bin); + if (status) { + goto exit_remove; + } + + *data = msa; + dev_info(&client->dev, "sfp msa '%s'\n", client->name); + + cs5435_54p_sysfs_add_client(client); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &sfp_msa_group); +exit_free: + kfree(msa); +exit: + + return status; +} + +static const struct attribute_group sfp_ddm_group = { + .attrs = sfp_ddm_attributes, +}; + +static int sfp_ddm_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, + struct sfp_ddm_data **data) +{ + int status; + struct sfp_ddm_data *ddm; + + if (!sfp_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + ddm = kzalloc(sizeof(struct sfp_ddm_data), GFP_KERNEL); + if (!ddm) { + status = -ENOMEM; + goto exit; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &sfp_ddm_group); + if (status) { + goto exit_free; + } + + /* init eeprom */ + status = sfp_sysfs_eeprom_init(&client->dev.kobj, &ddm->eeprom.bin); + if (status) { + goto exit_remove; + } + + *data = ddm; + dev_info(&client->dev, "sfp ddm '%s'\n", client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &sfp_ddm_group); +exit_free: + kfree(ddm); +exit: + + return status; +} + +static const struct attribute_group qsfp_group = { + .attrs = qsfp_attributes, +}; + +static int qsfp_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, + struct qsfp_data **data) +{ + int status; + struct qsfp_data *qsfp; + + if (!sfp_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + qsfp = kzalloc(sizeof(struct qsfp_data), GFP_KERNEL); + if (!qsfp) { + status = -ENOMEM; + goto exit; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &qsfp_group); + if (status) { + goto exit_free; + } + + /* init eeprom */ + status = sfp_sysfs_eeprom_init(&client->dev.kobj, &qsfp->eeprom.bin); + if (status) { + goto exit_remove; + } + + /* Bring QSFPs out of reset */ + //cig_lpc_write(0x62, 0x15, 0x3F); + + *data = qsfp; + dev_info(&client->dev, "qsfp '%s'\n", client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &qsfp_group); +exit_free: + kfree(qsfp); +exit: + + return status; +} + +/* Platform dependent +++ */ +static int sfp_device_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct sfp_port_data *data = NULL; + + data = kzalloc(sizeof(struct sfp_port_data), GFP_KERNEL); + if (!data) { + return -ENOMEM; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->port = dev_id->driver_data; + data->client = client; + + if (dev_id->driver_data >= cs5435_54p_sfp1 && dev_id->driver_data <= cs5435_54p_sfp48) { + if (client->addr == SFP_EEPROM_A0_I2C_ADDR) { + data->driver_type = DRIVER_TYPE_SFP_MSA; + return sfp_msa_probe(client, dev_id, &data->msa); + } + else if (client->addr == SFP_EEPROM_A2_I2C_ADDR) { + data->driver_type = DRIVER_TYPE_SFP_DDM; + return sfp_ddm_probe(client, dev_id, &data->ddm); + } + } + else { /* cs5435_54p_sfp49 ~ cs5435_54p_sfp56 */ + if (client->addr == SFP_EEPROM_A0_I2C_ADDR) { + data->driver_type = DRIVER_TYPE_QSFP; + return qsfp_probe(client, dev_id, &data->qsfp); + } + } + + return -ENODEV; +} +/* Platform dependent --- */ + +static int sfp_msa_remove(struct i2c_client *client, struct sfp_msa_data *data) +{ + sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); + sysfs_remove_group(&client->dev.kobj, &sfp_msa_group); + kfree(data); + return 0; +} + +static int sfp_ddm_remove(struct i2c_client *client, struct sfp_ddm_data *data) +{ + sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); + sysfs_remove_group(&client->dev.kobj, &sfp_ddm_group); + kfree(data); + return 0; +} + +static int qfp_remove(struct i2c_client *client, struct qsfp_data *data) +{ + sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); + sysfs_remove_group(&client->dev.kobj, &qsfp_group); + kfree(data); + return 0; +} + +static int sfp_device_remove(struct i2c_client *client) +{ + struct sfp_port_data *data = i2c_get_clientdata(client); + + cs5435_54p_sysfs_remove_client(client); + switch (data->driver_type) { + case DRIVER_TYPE_SFP_MSA: + return sfp_msa_remove(client, data->msa); + case DRIVER_TYPE_SFP_DDM: + return sfp_ddm_remove(client, data->ddm); + case DRIVER_TYPE_QSFP: + return qfp_remove(client, data->qsfp); + } + + return 0; +} + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static struct i2c_driver cs5435_54p_sfp_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .probe = sfp_device_probe, + .remove = sfp_device_remove, + .id_table = sfp_device_id, + .address_list = normal_i2c, +}; + +module_i2c_driver(cs5435_54p_sfp_driver); + + +MODULE_AUTHOR("Zhang Peng "); +MODULE_DESCRIPTION("cs5435_54p_sfp driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-sysfs.c b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-sysfs.c new file mode 100644 index 00000000000..0ba8836cf33 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/modules/x86-64-cig-cs5435-54p-sysfs.c @@ -0,0 +1,335 @@ +/* + * A hwmon driver for the CIG cs5435-54P sysfs Module + * + * Copyright (C) 2018 Cambridge, 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 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c-algo-lpc.h" + + +static LIST_HEAD(sysfs_client_list); +static struct mutex list_lock; + +struct sysfs_client_node { + struct i2c_client *client; + struct list_head list; +}; + +#define DEVICE_NAME "cigfs" +static int dev_major; +static struct class *dev_class; +static struct cdev *dev_cdev; +static struct device *dev_device; +static struct class *psu_class; +static struct class *sfp_class; + + +void cs5435_54p_sysfs_add_client(struct i2c_client *client) +{ + struct sysfs_client_node *node = kzalloc(sizeof(struct sysfs_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate sysfs_client_node (0x%x)\n", client->addr); + return; + } + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &sysfs_client_list); + mutex_unlock(&list_lock); +} + +EXPORT_SYMBOL(cs5435_54p_sysfs_add_client); + +void cs5435_54p_sysfs_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct sysfs_client_node *sysfs_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &sysfs_client_list) + { + sysfs_node = list_entry(list_node, struct sysfs_client_node, list); + if (IS_ERR(sysfs_node)) + { + break; + } + if (sysfs_node->client == client) { + found = 1; + break; + } + } + if (found) { + list_del(list_node); + kfree(sysfs_node); + } + + mutex_unlock(&list_lock); +} + +EXPORT_SYMBOL(cs5435_54p_sysfs_remove_client); + +struct class * cs5435_54p_sysfs_create_symclass(char *cls_name) +{ + int rc = 0; + struct class *my_class; +/**************************************************************************************/ + my_class = class_create(THIS_MODULE,cls_name); + if (IS_ERR(my_class)) { + pr_err("failed to create my class\n"); + } + return my_class; + +/**************************************************************************************/ +} + +void cs5435_54p_sysfs_delete_symclass(struct class *my_class) +{ +/**************************************************************************************/ + + if (IS_ERR(my_class)) { + pr_err("Pointer is invaild\n"); + } + class_destroy(my_class); + +/**************************************************************************************/ +} + + + + + +int cs5435_54p_sysfs_create_symlink(struct class *my_class,char * driver_name,char *device_name) +{ + struct list_head *list_node = NULL; + struct sysfs_client_node *sysfs_node = NULL; + int ret = -EPERM; + int rc = 0; + + mutex_lock(&list_lock); + list_for_each(list_node, &sysfs_client_list) + { + sysfs_node = list_entry(list_node, struct sysfs_client_node, list); + if (!strcmp(sysfs_node->client->name,driver_name)) { + rc = sysfs_create_link(&my_class->p->subsys.kobj, &sysfs_node->client->dev.kobj,device_name); + if(rc) + { + pr_err("failed to create symlink %d\n",rc); + } + break; + } + } + mutex_unlock(&list_lock); + return ret; +} + + +int cs5435_54p_sysfs_delete_symlink(struct class *my_class,char * driver_name,char *device_name) +{ + struct list_head *list_node = NULL; + struct sysfs_client_node *sysfs_node = NULL; + int ret = -EPERM; + int rc = 0; + + mutex_lock(&list_lock); + list_for_each(list_node, &sysfs_client_list) + { + sysfs_node = list_entry(list_node, struct sysfs_client_node, list); + if (!strcmp(sysfs_node->client->name,driver_name)) { + sysfs_remove_link(&my_class->p->subsys.kobj,device_name); + break; + } + } + mutex_unlock(&list_lock); + return ret; +} + + +static int cs5435_54p_sysfs_open(struct inode *inode, struct file *file) +{ + return 0; +} + + + +static ssize_t cs5435_54p_sysfs_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) +{ + char str[10],name[18],port[8]; + int ret; + int i; + memset(str, 0, sizeof(str)); + ret = copy_from_user(str, buf, count); + if (ret) + { + printk(KERN_ERR "copy_from_user fail\n"); + return -EINVAL; + } + + if(!strncmp(str,"start",5)) + { + psu_class = cs5435_54p_sysfs_create_symclass("psu"); + cs5435_54p_sysfs_create_symlink(psu_class,"cs5435_54p_psu1","psu1"); + cs5435_54p_sysfs_create_symlink(psu_class,"cs5435_54p_psu2","psu2"); + sfp_class = cs5435_54p_sysfs_create_symclass("swps"); + for(i = 1; i <= 48;i++) + { + memset(name,0xff,sizeof(name)); + memset(port,0xff,sizeof(port)); + snprintf(name,sizeof(name),"cs5435_54p_sfp%d",i); + snprintf(port,sizeof(port),"port%d",i); + cs5435_54p_sysfs_create_symlink(sfp_class,name,port); + } + } + else if(!strncmp(str,"stop",4)) + { + cs5435_54p_sysfs_delete_symlink(psu_class,"cs5435_54p_psu1","psu1"); + cs5435_54p_sysfs_delete_symlink(psu_class,"cs5435_54p_psu2","psu2"); + cs5435_54p_sysfs_delete_symclass(psu_class); + + for(i = 1; i <= 48;i++) + { + memset(name,0xff,sizeof(name)); + memset(port,0xff,sizeof(port)); + snprintf(name,sizeof(name),"cs5435_54p_sfp%d",i); + snprintf(port,sizeof(port),"port%d",i); + cs5435_54p_sysfs_delete_symlink(sfp_class,name,port); + } + cs5435_54p_sysfs_delete_symclass(sfp_class); + } + return count; +} + + +static struct file_operations cs5435_54p_sysfs_fops = { + .owner = THIS_MODULE, + .open = cs5435_54p_sysfs_open, + .write = cs5435_54p_sysfs_write, +}; + + +static int __init cs5435_54p_sysfs_init(void) +{ + int result = 0; + int err = 0; + dev_t dev = MKDEV(dev_major, 0); + + if (dev_major) + result = register_chrdev_region(dev, 1, DEVICE_NAME); + else { + result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME); + dev_major = MAJOR(dev); + } + if (result < 0) + { + printk("unable to get major %d\n", dev_major); + err= -EINVAL; + } + printk("get major is %d\n", dev_major); + if (dev_major == 0) + dev_major = result; + + dev_cdev= kmalloc(sizeof(struct cdev), GFP_KERNEL); + if(IS_ERR(dev_cdev)) { + err= -ENOMEM; + } + + cdev_init(dev_cdev, &cs5435_54p_sysfs_fops); + dev_cdev->owner = THIS_MODULE; + dev_cdev->ops = &cs5435_54p_sysfs_fops; + err = cdev_add(dev_cdev, dev, 1); + if (err) + { + printk("error %d add fpga ", err); + goto err_malloc; + } + + dev_class = class_create(THIS_MODULE, DEVICE_NAME); + if (IS_ERR(dev_class)) + { + printk("Err:failed in creating class.\n"); + goto err_cdev_add; + } + + dev_device = device_create(dev_class, NULL, MKDEV(dev_major, 0), NULL, DEVICE_NAME); + if (IS_ERR(dev_device)) + { + printk("Err:failed in creating device.\n"); + goto err_class_crt; + } + + mutex_init(&list_lock); + + return err; + + err_class_crt: + cdev_del(dev_cdev); + err_cdev_add: + kfree(dev_cdev); + err_malloc: + unregister_chrdev_region(MKDEV(dev_major,0), 1); + + return err; + +} + +static void __exit cs5435_54p_sysfs_exit(void) +{ + cdev_del(dev_cdev); + printk("cdev_del ok\n"); + device_destroy(dev_class, MKDEV(dev_major, 0)); + + class_destroy(dev_class); + + if(dev_cdev != NULL) + kfree(dev_cdev); + + unregister_chrdev_region(MKDEV(dev_major, 0), 1); + printk("cs5435_54p_sysfs_exit...\r\n"); +} + + +MODULE_AUTHOR("Zhang Peng "); +MODULE_DESCRIPTION("cs5435-54p-sysfs driver"); +MODULE_LICENSE("GPL"); + +module_init(cs5435_54p_sysfs_init); +module_exit(cs5435_54p_sysfs_exit); + + diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/service/cs5435-platform-init.service b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/service/cs5435-platform-init.service new file mode 100644 index 00000000000..b609a2be45c --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/service/cs5435-platform-init.service @@ -0,0 +1,13 @@ +[Unit] +Description=Cig CS5435-54P Platform initialization service +Before=pmon.service +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/cig_cs5435_util.py install +ExecStop=/usr/local/bin/cig_cs5435_util.py clean +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/service/cs5435-platform-misc.service b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/service/cs5435-platform-misc.service new file mode 100644 index 00000000000..852ab5689a7 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/service/cs5435-platform-misc.service @@ -0,0 +1,15 @@ +[Unit] +Description=Cig CS5435-54P Platform miscellaneous service +After=cs5435-platform-init.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/cig_cs5435_misc.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/setup.py b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/setup.py new file mode 100755 index 00000000000..1d4fa7f3645 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/setup.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +import os +import sys +from setuptools import setup +os.listdir + +setup( + name='cs5435-54p', + version='1.0.0', + description='Module to initialize Cig CS5435-54P platforms', + + packages=['cs5435-54p'], + package_dir={'cs5435-54p': 'cs5435-54p/classes'}, + ) diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/utils/cig_cs5435_misc.py b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/utils/cig_cs5435_misc.py new file mode 100755 index 00000000000..0a78085fd49 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/utils/cig_cs5435_misc.py @@ -0,0 +1,574 @@ +#!/usr/bin/env python +# +# Copyright (C) 2018 Cambridge, 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 . + +import os +import commands +import sys, getopt +import logging +import re +import time +import datetime +from collections import namedtuple +from threading import Thread + +DEBUG = False +i2c_prefix = '/sys/bus/i2c/devices/' +leds_prefix = '/sys/devices/platform/cs5435_54p_led/leds/' +fans_prefix = '/sys/devices/platform/cs5435_54p_fan/' +fansdir_prefix = fans_prefix + 'fan{}_direction' + +ageing_controlfile = '/etc/sonic/agcontrol' +AGFlag = 0 + + +platform_misc_log = '/var/log/platform_misc.log' +misclogger = logging.getLogger('platform_misc') +misclogger.setLevel(logging.INFO) +miscformatter = logging.Formatter('%(asctime)s-%(levelname)s-%(message)s') + +if not os.path.isfile(platform_misc_log): + try: + os.mknod(platform_misc_log) + except: + print 'Failed to creat platform_misc.log' + +fileHandler = logging.FileHandler(platform_misc_log) +fileHandler.setLevel(logging.INFO) +fileHandler.setFormatter(miscformatter) +misclogger.addHandler(fileHandler) + + +starttime = datetime.datetime.now() +IsGetlswt = 0 +coretemp_prefix = '/sys/class/hwmon/hwmon1/' +coretemp_ps = [] +psu1_p = '/sys/bus/i2c/devices/5-005a/psu_present' +psu2_p = '/sys/bus/i2c/devices/5-005b/psu_present' +psu1_d = '/sys/bus/i2c/devices/5-0052/psu_eeprom' +psu2_d = '/sys/bus/i2c/devices/5-0053/psu_eeprom' +psu1led_d = leds_prefix + 'cs5435_54p_led::psu1/brightness' +psu2led_d = leds_prefix + 'cs5435_54p_led::psu2/brightness' +cs5435_ledpath = {'fan':leds_prefix + 'cs5435_54p_led::fan/brightness', + 'fan1':leds_prefix + 'cs5435_54p_led::fan1/brightness', + 'fan2':leds_prefix + 'cs5435_54p_led::fan2/brightness', + 'fan3':leds_prefix + 'cs5435_54p_led::fan3/brightness', + 'fan4':leds_prefix + 'cs5435_54p_led::fan4/brightness', + 'fan5':leds_prefix + 'cs5435_54p_led::fan5/brightness', + 'psu1':leds_prefix + 'cs5435_54p_led::psu1/brightness', + 'psu2':leds_prefix + 'cs5435_54p_led::psu2/brightness', + 'sys':leds_prefix + 'cs5435_54p_led::sys/brightness'} + + +def system_read_filestr(node): + with open(node, 'r') as f: + try: + str = f.read() + except IOError as e: + misclogger.error('Failed to get node, str={}'.format(node)) + return "0" + return str + + +def system_bright_leds(dev, colour): + global AGFlag + + if AGFlag == 1: + return + + cmd = 'echo {} > {}'.format(colour, dev) + log_os_system(cmd, 1) + return + +''' +1: front in tail out +0: front out tail in +''' +def system_getpsu_direction(dev): + try: + with open(dev) as f: + f.seek(0x30) + str = f.read(2) + except IOError as e: + misclogger.error('Failed to get psu eep') + return 1 + if str == 'AA': ## front in tail out + return 1 + elif str == 'RA':## tail in front out + return 0 + else: + misclogger.error('Failed to get psu eep, str={}'.format(str)) + return -1 + + +def system_get_cputype(): + cmdretfd = os.popen("lscpu | grep 'Model name'") + retstring = cmdretfd.read() + endindex = retstring.find('@') - 1 + startindex = retstring[:endindex].rfind(' ') + 1 + cputype = retstring[startindex:endindex] + + return cputype + + +def system_init_coretemppath(): + global coretemp_ps + + cmdstr = "ls {} | grep 'input'".format(coretemp_prefix) + cmdretfd = os.popen(cmdstr) + + coretemppss = cmdretfd.read().splitlines() + if len(coretemppss) < 3: + cputype = system_get_cputype() + misclogger.error('Failed to init core temperature path.' + ' cpu type = {}, num thermal = {}'.format(cputype, len(coretemp_ps))) + return 1 + + for i in range(0,3): + coretemp_ps.append(coretemp_prefix + coretemppss[i]) + + print coretemp_ps + + return 0 + + +class cs5435_fanattr: + def __init__(self, name): + self.name = name + self.direction = 0 + self.direction_p = '' + self.rear = 0 + self.rear_p = '' + self.front = 0 + self.front_p = '' + self.fault = 0 + self.fault_p = '' + self.status = 0 + self.setpath() + self.updatedevice() + + return + + def setpath(self): + self.direction_p = fans_prefix + '{}_direction'.format(self.name) + self.rear_p = fans_prefix + '{}_rear_speed_rpm'.format(self.name) + self.front_p = fans_prefix + '{}_front_speed_rpm'.format(self.name) + self.fault_p = fans_prefix + '{}_fault'.format(self.name) + + return + + def updatedevice(self): + self.direction = int(system_read_filestr(self.direction_p)) + self.rear = int(system_read_filestr(self.rear_p)) + self.front = int(system_read_filestr(self.front_p)) + self.fault = int(system_read_filestr(self.fault_p)) + + return + + def checkspeedrpm(self, speedrpm): + frontrpmexp = speedrpm * 21000 / 100 + rearrpmexp = speedrpm * 19000 / 100 + deviationfront = abs(frontrpmexp - self.front) / float(frontrpmexp) + deviationrear = abs(rearrpmexp - self.rear) / float(rearrpmexp) + + if deviationfront < 0.3 and deviationrear < 0.3: + return 0 + else: + misclogger.error(':{} speed wrong. frontexp is {}, but rpm is {}.rearexp is {}, but rpm is {}'.format(self.name, frontrpmexp, self.front, rearrpmexp, self.rear)) + return 1 + + def checkstatus(self, speedrpm, totaldirct): + speedstatus = self.checkspeedrpm(speedrpm) + if self.direction != totaldirct: + self.status = 1 + misclogger.error(':{} direction = {}.fan direction is not ok.'.format(self.name, self.direction)) + elif speedstatus != 0: + self.status = 1 + elif self.fault != 0: + misclogger.error(':{} fault.'.format(self.name)) + self.status = 1 + else: + self.status = 0 + + if self.status == 1: + system_bright_leds(cs5435_ledpath[self.name], 3) + else: + system_bright_leds(cs5435_ledpath[self.name], 1) + + return self.status + +cs5435_fanattrnodes = [] + + +class cs5435_psuattr: + def __init__(self, name): + self.name = name + self.direction = 0 + self.direction_p = '' + self.present = 0 + self.present_p = '' + self.status = 0 + + self.setpath() + self.updatepresent() + self.updatedirection() + + return + + def setpath(self): + if self.name == 'psu1': + self.present_p = psu1_p + self.direction_p = psu1_d + if self.name == 'psu2': + self.present_p = psu2_p + self.direction_p = psu2_d + + return + + def updatepresent(self): + self.present = int(system_read_filestr(self.present_p)) + + return + + def updatedirection(self): + if self.present == 1: + self.direction = system_getpsu_direction(self.direction_p) + else: + self.direction = 2 + + return + + def checkstatus(self, totaldirct): + if self.present != 1: + self.status = 1 + misclogger.error(':{} not present.'.format(self.name)) + elif self.direction == 2: + self.status = 0 + misclogger.info(':{} direction need to be update.'.format(self.name)) + elif self.direction != totaldirct: + self.status = 1 + misclogger.info(':{} direction is wrong.'.format(self.name)) + else: + self.status = 0 + + if self.status == 1: + system_bright_leds(cs5435_ledpath[self.name], 3) + else: + system_bright_leds(cs5435_ledpath[self.name], 1) + + return self.status + +cs5435_psuattrnodes = [] + + + +def my_log(txt): + if DEBUG == True: + print "[ROY]"+txt + return + +def device_exist(): + ret1, log = log_os_system("ls "+i2c_prefix+"5-005a", 0) + ret2, log = log_os_system("ls "+i2c_prefix+"5-005b", 0) + ret3, log = log_os_system("ls "+leds_prefix+"cs5435_54p_led*", 0) + return not(ret1 or ret2 or ret3) + + +def log_os_system(cmd, show): + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) + my_log (cmd +"with result:" + str(status)) + my_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + + +def system_get_coretemp(): + temp1 = system_read_filestr(coretemp_ps[0]).strip() + temp2 = system_read_filestr(coretemp_ps[1]).strip() + temp3 = system_read_filestr(coretemp_ps[2]).strip() + + return int(temp1), int(temp2), int(temp3) + +def system_get_boardtemp(): + for i in range(0,16): + temp1path = "/sys/bus/i2c/devices/5-004a/hwmon/hwmon%d/temp1_input" % i + if os.access(temp1path, os.F_OK): + break + for i in range(0,16): + temp2path = "/sys/bus/i2c/devices/5-004b/hwmon/hwmon%d/temp1_input" % i + if os.access(temp2path, os.F_OK): + break + temp1 = system_read_filestr(temp1path).strip() + temp2 = system_read_filestr(temp2path).strip() + + return int(temp1), int(temp2) + + +def system_get_lswtemp(): + global IsGetlswt + global starttime + if IsGetlswt == 0: + now = datetime.datetime.now() + misclogger.info("time wait.") + misclogger.info("start = {}, now = {}.".format(starttime, now)) + if (now - starttime).seconds > 150: + misclogger.info("time = ".format((now - starttime).seconds)) + IsGetlswt = 1 + + return 25 + +# chp = subprocess.Popen("docker ps --filter name=syncd", shell=True, stdout=subprocess.PIPE) +# if chp.poll() == None: +# misclogger.info("No subp.") +# chp.kill() +# +# return 25 + +# retstring = chp.stdout.read() +# chp.kill() +# if 'Up' not in retstring: +# misclogger.info("lsw not up.") +# +# return 25 + + status, output = log_os_system('npx_diag swc show temperature', 1) + if status: + misclogger.error('failed to show lsw temperature') + + return 25 + + output = output.strip() + if output.find("it 0, temperature ") > 0: + startindex = output.find('temperature') + len('temperature') + 1 + endindex = output[startindex:].find(" ") + endindex = startindex + endindex + temp = output[startindex:endindex] + b = temp.find('.') + if b > 0: + temp=temp[:b] + temp = int(temp) + else: + misclogger.error("Failed to get temperature.") + temp = 0 + + return int(temp) + +def system_monitor_temperature(): + + ctemp1, ctemp2, ctemp3 = system_get_coretemp() + btemp1, btemp2 = system_get_boardtemp() + ltemp = system_get_lswtemp() + fan_speed_str = system_cs5435_getfanexspeed() + fan_speed = int(fan_speed_str) + policy = 'stay' + pos = 0 + #speed c1 c2 c3 b1 b2 lsw + fan_policy_up = ([30, 40000, 40000, 40000, 42000, 35000, 95], + [40, 44000, 44000, 44000, 44000, 39000, 96], + [50, 49000, 49000, 49000, 47000, 44000, 91], + [60, 52000, 52000, 52000, 51500, 47500, 92], + [70, 53000, 53000, 53000, 52000, 49000, 93], + [100,999999,999999,999999,999999,999999,999]) + + fan_policy_down=([30, 0, 0, 0, 0, 0, 0], + [40, 34000, 34000, 34000, 34000, 30000, 80], + [50, 38000, 38000, 38000, 37000, 33000, 81], + [60, 44000, 44000, 44000, 43000, 39000, 84], + [70, 44000, 44000, 44000, 43000, 40000, 84], + [100, 48000, 48000, 48000, 46000, 42000, 85],) + + for policytable in fan_policy_up: + if fan_speed <= policytable[0]: + break + pos = pos + 1 + fan_speed = policytable[0] + if (ctemp1 < policytable[1]) and (ctemp2 < policytable[2]) and (ctemp3 < policytable[3]) and (btemp1 < policytable[4]) and (btemp2 < policytable[5]) and (ltemp < policytable[6]): + policy = 'stay' + policytable = fan_policy_down[pos] + if (ctemp1 < policytable[1]) and (ctemp2 < policytable[2]) and (ctemp3 < policytable[3]) and (btemp1 < policytable[4]) and (btemp2 < policytable[5]) and (ltemp < policytable[6]): + policy = 'down' + else: + policy = 'up' + + if policy == 'up': + misclogger.info("speed = %d." % fan_speed) + misclogger.info("core1 = %d, core2 = %d, core3 = %d." % (ctemp1, ctemp2, ctemp3)) + misclogger.info("board1 = %d, board2 = %d." % (btemp1, btemp2)) + misclogger.info("lsw = %d" % ltemp) + fan_speed = fan_policy_down[pos + 1][0] + misclogger.info("fan policy: up. speedexp = {}".format(fan_speed)) + + if policy == 'stay': + fan_speed = fan_policy_down[pos] + return + + if policy == 'down': + misclogger.info("speed = %d." % fan_speed) + misclogger.info("core1 = %d, core2 = %d, core3 = %d." % (ctemp1, ctemp2, ctemp3)) + misclogger.info("board1 = %d, board2 = %d." % (btemp1, btemp2)) + misclogger.info("lsw = %d" % ltemp) + fan_speed = fan_policy_down[pos - 1][0] + misclogger.info("fan policy: down.speedexp = {}".format(fan_speed)) + + cmd = "echo %d > /sys/devices/platform/cs5435_54p_fan/fan_duty_cycle_percentage" % fan_speed + status, output = log_os_system(cmd, 1) + if status: + misclogger.error("set fan speed fault") + + return + + +def system_cs5435_setfanexspeed(num): + fanspeednode = fans_prefix + 'fan_duty_cycle_percentage' + numstr = str(num) + with open(fanspeednode, 'w') as f: + f.write(numstr) + + +def system_cs5435_getfanexspeed(): + fanspeednode = fans_prefix + 'fan_duty_cycle_percentage' + fanspeedstr = system_read_filestr(fanspeednode) + fanspeedexp = int(fanspeedstr) + + return fanspeedexp + + +def system_cs5435_getdirection(): + global cs5435_fanattrnodes + direction = 0 + + for fan in cs5435_fanattrnodes: + direction = direction + fan.direction + + if direction > 2: + direction = 1 + else: + direction = 0 + + return direction + + +def system_check_psusdirection(): + global cs5435_psuattrnodes + cs5435totaldirct = system_cs5435_getdirection() + psutatus = 0 + + for psu in cs5435_psuattrnodes: + psu.updatedirection() + psu.checkstatus(cs5435totaldirct) + psutatus = psu.status + psutatus + + return (psutatus != 0) + + +def system_check_psuspresent(): + global cs5435_psuattrnodes + cs5435totaldirct = system_cs5435_getdirection() + psutatus = 0 + + for psu in cs5435_psuattrnodes: + psu.updatepresent() + psu.checkstatus(cs5435totaldirct) + psutatus = psu.status + psutatus + + return (psutatus != 0) + + +def system_check_fansstate(): + global cs5435_fanattrnodes + global cs5435_ledpath + cs5435totaldirct = system_cs5435_getdirection() + fanstatus = 0 + fanexspeed = 0 + + fanexspeed = system_cs5435_getfanexspeed() + + for fan in cs5435_fanattrnodes: + fan.updatedevice() + fan.checkstatus(fanexspeed, cs5435totaldirct) + fanstatus = fanstatus + fan.status + + if fanstatus > 0: + misclogger.error(':fan error.set fans speed 100.') + system_cs5435_setfanexspeed(100) + system_bright_leds(cs5435_ledpath['fan'], 3) + else: + system_bright_leds(cs5435_ledpath['fan'], 1) + + return (fanstatus != 0) + + +def system_misc_polling(threadName,delay): + for count in range(1,5): + if device_exist() == False: + time.sleep(delay+3) + print "%s: %s, count=%d" % ( threadName, time.ctime(time.time()), count) + else: + break + + if count == 4: + return + + status, output = log_os_system("echo 1 > /sys/devices/platform/cs5435_54p_led/leds/cs5435_54p_led::sys/brightness", 1) + status, output = log_os_system("hwconfig -cfp 1", 1) + + global AGFlag + if os.access(ageing_controlfile, os.F_OK): + AGFlag = 1 + else: + AGFlag = 0 + + os.system('csw_daemon &') + + + global cs5435_fanattrnodes + global cs5435_psuattrnodes + + for num in range(1,6): + name = 'fan{}'.format(num) + fannode = cs5435_fanattr(name) + cs5435_fanattrnodes.append(fannode) + for num in range(1,3): + name = 'psu{}'.format(num) + psunode = cs5435_psuattr(name) + cs5435_psuattrnodes.append(psunode) + + tempcontrol = system_init_coretemppath() + + misclogger.info("%s: %s misc start." % ( threadName, time.ctime(time.time()))) + count = 0 + while 1: + count = count + 1 + ret = system_check_psuspresent() + ret = system_check_fansstate() + + if count % 10 == 0: + misclogger.info(": adjust fans and check psu direction.") + system_check_psusdirection() + if tempcontrol == 0: + system_monitor_temperature() + count = 0 + time.sleep(delay) + + return + +if __name__ == '__main__': + target=system_misc_polling("Thread-misc",10) + diff --git a/platform/nephos/sonic-platform-modules-cig/cs5435-54p/utils/cig_cs5435_util.py b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/utils/cig_cs5435_util.py new file mode 100755 index 00000000000..03302592257 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs5435-54p/utils/cig_cs5435_util.py @@ -0,0 +1,563 @@ +#!/usr/bin/env python +# +# Copyright (C) 2018 Cambridge, 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 = 'cs5435_54p' +version = '0.1.1' +verbose = False +DEBUG = False +args = [] +ALL_DEVICE = {} +DEVICE_NO = {'led':9, 'fan':5, 'thermal':4, 'psu':2, 'sfp':54} +FORCE = 0 +CPU_TYPE = 'C3308' + +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-54 {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 "[ROY]"+txt + return + +def log_os_system(cmd, show): + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) + my_log (cmd +"with result:" + str(status)) + my_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + +def driver_check(): + for count in range(1,5): + time.sleep(1) + ret, lsmod = log_os_system("lsmod| grep i2c_i801", 0) + if len(lsmod) > 2: + log_os_system("rmmod i2c_i801", 0) + break + + ret, lsmod = log_os_system("lsmod| grep i2c_designware_platform", 0) + if len(lsmod) > 2: + log_os_system("rmmod i2c_designware_platform", 0) + log_os_system("modprobe i2c-designware-platform", 0) + + ret, lsmod = log_os_system("lsmod| grep cig", 0) + logging.info('mods:'+lsmod) + if len(lsmod) ==0: + return False + return True + + + +kos = [ + 'depmod', + 'modprobe i2c_dev', + 'modprobe i2c_mux_pca954x force_deselect_on_exit=1', + 'modprobe x86-64-cig-cs5435-54p-sysfs ' , + 'modprobe x86-64-cig-cs5435-54p-cpld ' , + 'modprobe x86-64-cig-cs5435-54p-fan' , + 'modprobe x86-64-cig-cs5435-54p-psu' , + 'modprobe x86-64-cig-cs5435-54p-sfp' , + 'modprobe x86-64-cig-cs5435-54p-led' ] + +def driver_install(): + global FORCE + + for i in range(0,len(kos)): + if i == 4: + ret, CPU_TYPE = log_os_system("cat /proc/cpuinfo | grep \"model name\" | cut -b 32-39 | head -n 1", 0) + if CPU_TYPE=='i3-6100U': + kos[i] =kos[i] + 'board_id=1' + ret, CPU_TYPE = log_os_system("cat /proc/cpuinfo | grep \"model name\" | cut -b 36-40 | head -n 1", 0) + if CPU_TYPE=='C3758' or CPU_TYPE=='C3308': + kos[i] =kos[i] + 'board_id=2' + + 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 + +led_prefix ='/sys/class/leds/'+PROJECT_NAME+'_led::' +hwmon_types = {'led': ['sys','fan','fan1','fan2','fan3','fan4','fan5','psu1','psu2']} +hwmon_nodes = {'led': ['brightness'] } +hwmon_prefix ={'led': led_prefix} + +i2c_prefix = '/sys/bus/i2c/devices/' +i2c_bus = {'thermal': ['4-0048','4-0049', '5-004a', '5-004b'] , + 'psu': ['5-005a','5-005b'], + 'sfp': ['-0050']} +i2c_nodes = {'thermal': ['hwmon/hwmon*/temp1_input'] , + 'psu': ['psu_present ', 'psu_power_good'] , + 'sfp': ['sfp_is_present ', 'sfp_tx_disable']} + +fan_prefix ='/sys/bus/platform/devices/'+PROJECT_NAME+'_fan' +fan_types = {'fan': ['fan1','fan2', 'fan3', 'fan4', 'fan5']} +fan_nodes = {'fan': ['state', 'front_speed_rpm', 'rear_speed_rpm', 'fault']} + + +sfp_map = [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,51,52,53,54,55,56, + 57,60,61,62,63] + +mknod =[ + 'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-2/new_device', + 'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-2/new_device', + 'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-2/new_device', + 'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-2/new_device', + 'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-3/new_device', + 'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-3/new_device', + 'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-3/new_device', + 'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-4/new_device', + 'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-4/new_device', + 'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-5/new_device', + 'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-5/new_device', + 'echo cs5435_54p_psu1 0x5a > /sys/bus/i2c/devices/i2c-5/new_device', + 'echo cs5435_54p_psu2 0x5b > /sys/bus/i2c/devices/i2c-5/new_device', + 'echo cs5435_54p_psu1 0x52 > /sys/bus/i2c/devices/i2c-5/new_device', + 'echo cs5435_54p_psu2 0x53 > /sys/bus/i2c/devices/i2c-5/new_device', + 'echo 24c128 0x57 > /sys/bus/i2c/devices/i2c-7/new_device'] + +port = 0 + +def device_install(): + global FORCE + global port + for i in range(0,len(mknod)): + #all nodes need times to built new i2c buses + time.sleep(1) + + 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 == 50): + port = port + 3 + else: + port = port + 1 + + + status, output =log_os_system("echo cs5435_54p_sfp"+str(port)+" 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + + if port <= 48: + status, output =log_os_system("echo cs5435_54p_sfp"+str(port)+" 0x51 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + + return + +def device_uninstall(): + global FORCE + + 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_check() == False: + return False + if not device_exist(): + return False + return True + +def do_install(): + print "Checking system...." + if driver_check() == 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_check()== 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, fan_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 '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) + + for key in fan_types: + itypes = fan_types[key] + nodes = fan_nodes[key] + for i in range(0,len(itypes)): + for j in range(0,len(nodes)): + node = key+"_"+itypes[i] + path = fan_prefix+"/"+ 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], 'sfp_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 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['fan'] ['fan1'][0] + node = node.replace(node.split("/")[-1], 'fan_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 + +def get_value(input): + digit = re.findall('\d+', input) + return int(digit[0]) + + +def get_ledname(ledx): + name_table={'led1':'SYS','led2':'FSTUS','led3':'FAN1','led4':'FAN2','led5':'FAN3','led6':'FAN4','led7':'FAN5','led8':'PSU1','led9':'PSU2'} + if name_table.has_key(ledx): + name = name_table[ledx] + else: + name = ledx + return name + + +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): + nwnamex = get_ledname(j) + if nwnamex == j: + print " "+j+":", + else: + print " "+nwnamex+":", + 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-3", 0) + return not(ret1 or ret2) + + +if __name__ == "__main__": + main() diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/classes/__init__.py b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/classes/__init__.py new file mode 100755 index 00000000000..e69de29bb2d diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/classes/fanutil.py b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/classes/fanutil.py new file mode 100755 index 00000000000..e69de29bb2d diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/classes/thermalutil.py b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/classes/thermalutil.py new file mode 100755 index 00000000000..e69de29bb2d diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/Makefile b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/Makefile new file mode 100644 index 00000000000..e37e985a214 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/Makefile @@ -0,0 +1,6 @@ +obj-m :=x86-64-cig-cs6436-54p-sysfs.o \ + x86-64-cig-cs6436-54p-cpld.o \ + x86-64-cig-cs6436-54p-fan.o \ + x86-64-cig-cs6436-54p-led.o \ + x86-64-cig-cs6436-54p-psu.o \ + x86-64-cig-cs6436-54p-sfp.o diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/i2c-algo-lpc.h b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/i2c-algo-lpc.h new file mode 100644 index 00000000000..749aa94ef93 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/i2c-algo-lpc.h @@ -0,0 +1,222 @@ +/* -------------------------------------------------------------------- + + * A hwmon driver for the CIG cs6436-54P + * + * Copyright (C) 2018 Cambridge, 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 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 I2C_LPC_H +#define I2C_LPC_H 1 + +/* ----- Control register bits ---------------------------------------- */ +#define I2C_LPC_PIN 0x80 +#define I2C_LPC_ESO 0x40 +#define I2C_LPC_ES1 0x20 +#define I2C_LPC_ES2 0x10 +#define I2C_LPC_ENI 0x08 + +#define I2C_LPC_STO 0x40 +#define I2C_LPC_ACK 0x01 + +/*command register*/ +#define I2C_LPC_STA 0x80 +#define I2C_LPC_ABT 0x40 + +/*status register*/ +#define I2C_LPC_TBE 0x02 +#define I2C_LPC_IBB 0x80 +#define I2C_LPC_RBF 0x01 +#define I2C_LPC_TD 0x08 + +#define I2C_LPC_START I2C_LPC_STA +#define I2C_LPC_STOP I2C_LPC_STO +#define I2C_LPC_REPSTART I2C_LPC_STA +#define I2C_LPC_IDLE + +/* ----- Status register bits ----------------------------------------- */ +/*#define I2C_LPC_PIN 0x80 as above*/ + +#define I2C_LPC_INI 0x40 /* 1 if not initialized */ +#define I2C_LPC_STS 0x20 +#define I2C_LPC_BER 0x10 +#define I2C_LPC_AD0 0x08 +#define I2C_LPC_LRB 0x08 +#define I2C_LPC_AAS 0x04 +#define I2C_LPC_LAB 0x02 +#define I2C_LPC_BB 0x80 + +/* ----- Chip clock frequencies --------------------------------------- */ +#define I2C_LPC_CLK3 0x00 +#define I2C_LPC_CLK443 0x10 +#define I2C_LPC_CLK6 0x14 +#define I2C_LPC_CLK 0x18 +#define I2C_LPC_CLK12 0x1c + +/* ----- transmission frequencies ------------------------------------- */ +#define I2C_LPC_TRNS90 0x00 /* 90 kHz */ +#define I2C_LPC_TRNS45 0x01 /* 45 kHz */ +#define I2C_LPC_TRNS11 0x02 /* 11 kHz */ +#define I2C_LPC_TRNS15 0x03 /* 1.5 kHz */ + + +#define I2C_LPC_OWNADR 0 +#define I2C_LPC_INTREG I2C_LPC_ES2 +#define I2C_LPC_CLKREG I2C_LPC_ES1 + +#define I2C_LPC_REG_TEST 0x01 +#define I2C_LPC_REG_BUS_SEL 0x80 +#define I2C_LPC_REG_DEVICE_ADDR 0x81 +#define I2C_LPC_REG_BYTE_COUNT 0x83 +#define I2C_LPC_REG_COMMAND 0x84 +#define I2C_LPC_REG_STATUS 0x85 +#define I2C_LPC_REG_DATA_RX1 0x86 +#define I2C_LPC_REG_DATA_RX2 0x87 +#define I2C_LPC_REG_DATA_RX3 0x88 +#define I2C_LPC_REG_DATA_RX4 0x89 +#define I2C_LPC_REG_DATA_TX1 0x8a +#define I2C_LPC_REG_DATA_TX2 0x8b +#define I2C_LPC_REG_DATA_TX3 0x8c +#define I2C_LPC_REG_DATA_TX4 0x8d + + +#define ADDR_REG_SFP_STATUS_ADDR 0X62 //reg addr +R/W# //1031 +#define ADDR_REG_SFP_STATUS_TX 0X63 // write data +#define ADDR_REG_SFP_STATUS_RX 0X64 //read data +#define ADDR_REG_SFP_STATUS_COMMAND 0X65 //cmd bit7=1,go +#define ADDR_REG_SFP_STATUS_STATUS 0X66 //status + +#define CPLD_MASTER_INTERRUPT_STATUS_REG 0x20 +#define CPLD_MASTER_INTERRUPT_MASK_REG 0x21 +#define CPLD_MASTER_INTERRUPT_ALL 0x3f +#define CPLD_MASTER_INTERRUPT_CPLD2 0x20 +#define CPLD_MASTER_INTERRUPT_CPLD1 0x10 +#define CPLD_MASTER_INTERRUPT_PSU2 0x08 +#define CPLD_MASTER_INTERRUPT_PSU1 0x04 +#define CPLD_MASTER_INTERRUPT_6320 0x02 +#define CPLD_MASTER_INTERRUPT_LSW 0x01 + + + +#define CPLD_SLAVE1_INTERRUPT_STATUS_L_REG 0x20 +#define CPLD_SLAVE1_INTERRUPT_STATUS_H_REG 0x21 +#define CPLD_SLAVE2_INTERRUPT_STATUS_L_REG 0x22 +#define CPLD_SLAVE2_INTERRUPT_STATUS_H_REG 0x23 +#define CPLD_SLAVE1_INTERRUPT_MASK_REG 0x24 +#define CPLD_SLAVE2_INTERRUPT_MASK_REG 0x25 + + +#define CPLD_SLAVE1_PRESENT08_REG 0x01 +#define CPLD_SLAVE1_PRESENT16_REG 0x02 +#define CPLD_SLAVE1_PRESENT24_REG 0x03 +#define CPLD_SLAVE2_PRESENT32_REG 0x04 +#define CPLD_SLAVE2_PRESENT40_REG 0x05 +#define CPLD_SLAVE2_PRESENT48_REG 0x06 + +#define CPLD_SLAVE1_RX_LOST08_REG 0x07 +#define CPLD_SLAVE1_RX_LOST16_REG 0x08 +#define CPLD_SLAVE1_RX_LOST24_REG 0x09 +#define CPLD_SLAVE2_RX_LOST32_REG 0x0a +#define CPLD_SLAVE2_RX_LOST40_REG 0x0b +#define CPLD_SLAVE2_RX_LOST48_REG 0x0c + +#define CPLD_SLAVE1_TX_FAULT08_REG 0x0d +#define CPLD_SLAVE1_TX_FAULT16_REG 0x0e +#define CPLD_SLAVE1_TX_FAULT24_REG 0x0f +#define CPLD_SLAVE2_TX_FAULT32_REG 0x10 +#define CPLD_SLAVE2_TX_FAULT40_REG 0x11 +#define CPLD_SLAVE2_TX_FAULT48_REG 0x12 + +#define CPLD_SLAVE2_PRESENT56_REG 0x19 +#define CPLD_SLAVE2_QSFP_CR56_REG 0x1a + + +#define CPLD_SLAVE1_INTERRUPT_PRESENT08 0x0001 +#define CPLD_SLAVE1_INTERRUPT_PRESENT16 0x0002 +#define CPLD_SLAVE1_INTERRUPT_PRESENT24 0x0004 +#define CPLD_SLAVE2_INTERRUPT_PRESENT32 0x0001 +#define CPLD_SLAVE2_INTERRUPT_PRESENT40 0x0002 +#define CPLD_SLAVE2_INTERRUPT_PRESENT48 0x0004 + +#define CPLD_SLAVE2_INTERRUPT_QSFP_CR56 0x0200 +#define CPLD_SLAVE2_INTERRUPT_PRESENT56 0x0400 + +#define CPLD_SLAVE1_INTERRUPT_RX_LOST08 0x0008 +#define CPLD_SLAVE1_INTERRUPT_RX_LOST16 0x0010 +#define CPLD_SLAVE1_INTERRUPT_RX_LOST24 0x0020 +#define CPLD_SLAVE2_INTERRUPT_RX_LOST32 0x0008 +#define CPLD_SLAVE2_INTERRUPT_RX_LOST40 0x0010 +#define CPLD_SLAVE2_INTERRUPT_RX_LOST48 0x0020 + +#define CPLD_SLAVE1_INTERRUPT_TX_FAULT08 0x0040 +#define CPLD_SLAVE1_INTERRUPT_TX_FAULT16 0x0080 +#define CPLD_SLAVE1_INTERRUPT_TX_FAULT24 0x0100 +#define CPLD_SLAVE2_INTERRUPT_TX_FAULT32 0x0040 +#define CPLD_SLAVE2_INTERRUPT_TX_FAULT40 0x0080 +#define CPLD_SLAVE2_INTERRUPT_TX_FAULT48 0x0100 + + + + + + + +#define WAIT_TIME_OUT_COUNT 100 + + +struct i2c_algo_lpc_data { + void *data; /* private data for lolevel routines */ + void (*setlpc) (void *data, int ctl, int val); + int (*getlpc) (void *data, int ctl); + int (*getown) (void *data); + int (*getclock) (void *data); + void (*waitforpin) (void *data); + + int (*xfer_begin) (void *data); + int (*xfer_end) (void *data); + + /* Multi-master lost arbitration back-off delay (msecs) + * This should be set by the bus adapter or knowledgable client + * if bus is multi-mastered, else zero + */ + unsigned long lab_mdelay; +}; + + +struct subsys_private { + struct kset subsys; + struct kset *devices_kset; + struct list_head interfaces; + struct mutex mutex; + + struct kset *drivers_kset; + struct klist klist_devices; + struct klist klist_drivers; + struct blocking_notifier_head bus_notifier; + unsigned int drivers_autoprobe:1; + struct bus_type *bus; + + struct kset glue_dirs; + struct class *class; +}; + +void cs6436_54p_sysfs_add_client(struct i2c_client *client); +void cs6436_54p_sysfs_remove_client(struct i2c_client *client); + + +#endif /* I2C_LPC8584_H */ diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-cpld.c b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-cpld.c new file mode 100644 index 00000000000..1c7930b3d26 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-cpld.c @@ -0,0 +1,2202 @@ +/* + * A hwmon driver for the CIG cs6436-54P CPLD + * + * Copyright (C) 2018 Cambridge, 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 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 "i2c-algo-lpc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CPLD_USER +# include +#else +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + + + + + +/********************************************** Start ********************************************************/ + +/* + * ISA bus. + */ + +static void platform_isa_bus_release(struct device * dev) +{ + return ; +} + + +static struct device isa_bus = { + .init_name = "lpc-isa", + .release = platform_isa_bus_release, +}; + +struct isa_dev { + struct device dev; + struct device *next; + unsigned int id; +}; + +#define to_isa_dev(x) container_of((x), struct isa_dev, dev) + +static int isa_bus_match(struct device *dev, struct device_driver *driver) +{ + struct isa_driver *isa_driver = to_isa_driver(driver); + + if (dev->platform_data == isa_driver) { + if (!isa_driver->match || + isa_driver->match(dev, to_isa_dev(dev)->id)) + return 1; + dev->platform_data = NULL; + } + return 0; +} + +static int isa_bus_probe(struct device *dev) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->probe) + return isa_driver->probe(dev, to_isa_dev(dev)->id); + + return 0; +} + +static int isa_bus_remove(struct device *dev) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->remove) + return isa_driver->remove(dev, to_isa_dev(dev)->id); + + return 0; +} + +static void isa_bus_shutdown(struct device *dev) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->shutdown) + isa_driver->shutdown(dev, to_isa_dev(dev)->id); +} + +static int isa_bus_suspend(struct device *dev, pm_message_t state) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->suspend) + return isa_driver->suspend(dev, to_isa_dev(dev)->id, state); + + return 0; +} + +static int isa_bus_resume(struct device *dev) +{ + struct isa_driver *isa_driver = dev->platform_data; + + if (isa_driver->resume) + return isa_driver->resume(dev, to_isa_dev(dev)->id); + + return 0; +} + +static struct bus_type isa_bus_type = { + .name = "lpc-isa", + .match = isa_bus_match, + .probe = isa_bus_probe, + .remove = isa_bus_remove, + .shutdown = isa_bus_shutdown, + .suspend = isa_bus_suspend, + .resume = isa_bus_resume +}; + +static void isa_dev_release(struct device *dev) +{ + kfree(to_isa_dev(dev)); +} + +void lpc_unregister_driver(struct isa_driver *isa_driver) +{ + struct device *dev = isa_driver->devices; + + while (dev) { + struct device *tmp = to_isa_dev(dev)->next; + device_unregister(dev); + dev = tmp; + } + driver_unregister(&isa_driver->driver); +} + + +int lpc_register_driver(struct isa_driver *isa_driver, unsigned int ndev) +{ + int error; + unsigned int id; + + isa_driver->driver.bus = &isa_bus_type; + isa_driver->devices = NULL; + + error = driver_register(&isa_driver->driver); + if (error) + return error; + + for (id = 0; id < ndev; id++) { + struct isa_dev *isa_dev; + + isa_dev = kzalloc(sizeof *isa_dev, GFP_KERNEL); + if (!isa_dev) { + error = -ENOMEM; + break; + } + + isa_dev->dev.parent = &isa_bus; + isa_dev->dev.bus = &isa_bus_type; + + dev_set_name(&isa_dev->dev, "%s.%u", + isa_driver->driver.name, id); + isa_dev->dev.platform_data = isa_driver; + isa_dev->dev.release = isa_dev_release; + isa_dev->id = id; + + isa_dev->dev.coherent_dma_mask = DMA_BIT_MASK(24); + isa_dev->dev.dma_mask = &isa_dev->dev.coherent_dma_mask; + + error = device_register(&isa_dev->dev); + if (error) { + put_device(&isa_dev->dev); + break; + } + + if (isa_dev->dev.platform_data) { + isa_dev->next = isa_driver->devices; + isa_driver->devices = &isa_dev->dev; + } else + device_unregister(&isa_dev->dev); + } + + if (!error && !isa_driver->devices) + error = -ENODEV; + + if (error) + isa_unregister_driver(isa_driver); + + return error; +} + + +int lpc_bus_init(void) +{ + int error; + + error = bus_register(&isa_bus_type); + if (!error) { + error = device_register(&isa_bus); + if (error) + bus_unregister(&isa_bus_type); + } + return error; +} + +void lpc_bus_exit(void) +{ + + device_unregister(&isa_bus); + + bus_unregister(&isa_bus_type); +} + + +/********************************************** End ********************************************************/ + + + + + + +/********************************************** Start ********************************************************/ +/* + * module parameters: + */ +static int i2c_debug = 0; +static struct mutex lpc_lock; + + +#define DEB2(x) if (i2c_debug == 2) x +#define DEB3(x) if (i2c_debug == 3) x + /* print several statistical values */ +#define DEBPROTO(x) if (i2c_debug == 9) x; + /* debug the protocol by showing transferred bits */ +#define DEF_TIMEOUT 160 + + + +/* setting states on the bus with the right timing: */ + +#define set_lpc(adap, ctl, val) adap->setlpc(adap->data, ctl, val) +#define get_lpc(adap, ctl) adap->getlpc(adap->data, ctl) +#define get_own(adap) adap->getown(adap->data) +#define get_clock(adap) adap->getclock(adap->data) +#define i2c_outaddr(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DEVICE_ADDR, val) + +#define i2c_outbyte1(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DATA_TX1, val) +#define i2c_outbyte2(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DATA_TX2, val) +#define i2c_outbyte3(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DATA_TX3, val) +#define i2c_outbyte4(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DATA_TX4, val) +#define i2c_inbyte1(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX1) +#define i2c_inbyte2(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX2) +#define i2c_inbyte3(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX3) +#define i2c_inbyte4(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX4) + + + +#define LPC_FPRINTF_LOG_PATH "/tmp/file.log" +struct file *lpc_fprintf_file = NULL; + +static int lpc_fprintf_debug(const char *fmt, ...) +{ + char lpc_fprintf_buf[256]={0}; + struct va_format vaf; + va_list args; + int r; + mm_segment_t old_fs; + struct timeval tv; + struct rtc_time tm; + + do_gettimeofday(&tv); + + rtc_time_to_tm(tv.tv_sec,&tm); + + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + r=snprintf(lpc_fprintf_buf,sizeof(lpc_fprintf_buf),"[%04d.%08d] %pV\n",tm.tm_sec, (int)tv.tv_usec, &vaf); + va_end(args); + old_fs = get_fs(); + set_fs(KERNEL_DS); + vfs_write(lpc_fprintf_file, (char *)&lpc_fprintf_buf, strlen(lpc_fprintf_buf), &lpc_fprintf_file->f_pos); + set_fs(old_fs); + memset(lpc_fprintf_buf,0x0,sizeof(lpc_fprintf_buf)); + return r; + +} + + + +static int lpc_fprintf_init(void) +{ + printk("lpc_fprintf_init.\n"); + + if(lpc_fprintf_file == NULL) + lpc_fprintf_file = filp_open(LPC_FPRINTF_LOG_PATH, O_RDWR | O_APPEND | O_CREAT, 0644); + + if (IS_ERR(lpc_fprintf_file)) { + printk("Error occured while opening file %s, exiting...\n", LPC_FPRINTF_LOG_PATH); + return -1; + } + + return 0; +} + +static int lpc_fprintf_exit(void) +{ + printk("lpc_fprintf_exit.\n"); + + if(lpc_fprintf_file != NULL) + filp_close(lpc_fprintf_file, NULL); + + return 0; +} + + +/* other auxiliary functions */ + + +void print_reg(struct i2c_algo_lpc_data *adap) +{ + unsigned char status; + DEBPROTO(lpc_fprintf_debug("================================================\n");) + status = get_lpc(adap, I2C_LPC_REG_BUS_SEL); + DEBPROTO(lpc_fprintf_debug("%s select reg %x : %x\n",__func__,I2C_LPC_REG_BUS_SEL, status);) + status = get_lpc(adap, I2C_LPC_REG_BYTE_COUNT); + DEBPROTO(lpc_fprintf_debug("%s count reg %x : %x\n",__func__,I2C_LPC_REG_BYTE_COUNT, status);) + + status = get_lpc(adap, I2C_LPC_REG_COMMAND); + DEBPROTO(lpc_fprintf_debug("%s command reg %x : %x\n",__func__,I2C_LPC_REG_COMMAND, status);) + status = get_lpc(adap, I2C_LPC_REG_DEVICE_ADDR); + DEBPROTO(lpc_fprintf_debug("%s address reg %x : %x\n",__func__,I2C_LPC_REG_DEVICE_ADDR, status);) + + status = get_lpc(adap, I2C_LPC_REG_STATUS); + DEBPROTO(lpc_fprintf_debug("%s status reg %x : %x\n",__func__,I2C_LPC_REG_STATUS, status);) +} + + + +static void i2c_repstart(struct i2c_algo_lpc_data *adap) +{ + DEBPROTO(lpc_fprintf_debug("%s :\n",__func__);) + set_lpc(adap, I2C_LPC_REG_COMMAND, I2C_LPC_REPSTART); +} + +static void i2c_stop(struct i2c_algo_lpc_data *adap) +{ + DEBPROTO(lpc_fprintf_debug("%s :\n",__func__);) + set_lpc(adap, I2C_LPC_REG_COMMAND, I2C_LPC_STOP); + udelay(60); + set_lpc(adap, I2C_LPC_REG_COMMAND, 0x00); +} + + + + +static void i2c_start(struct i2c_algo_lpc_data *adap) +{ + print_reg(adap); + + set_lpc(adap, I2C_LPC_REG_COMMAND, I2C_LPC_START); + + print_reg(adap); +} + + + + +static int wait_for_bb(struct i2c_algo_lpc_data *adap) +{ + + int timeout = DEF_TIMEOUT; + int status; + + while (--timeout) { + status = get_lpc(adap, I2C_LPC_REG_STATUS); + + DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus free status : %x\n",__func__,status);) + + if(status == I2C_LPC_TD) + { + DEBPROTO(lpc_fprintf_debug("%s : Bus is free status : %x\n",__func__,status);) + break; + } + } + + if (timeout == 0) { + DEBPROTO(lpc_fprintf_debug("%s : Timeout for free busy status : %x\n",__func__,status);) + return -ETIMEDOUT; + } + + + + return 0; +} + + +static int wait_for_be(int mode,struct i2c_algo_lpc_data *adap) +{ + + int timeout = DEF_TIMEOUT; + unsigned char status; + + + while (--timeout) { + + status = get_lpc(adap, I2C_LPC_REG_STATUS); + + DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus empty status : %x\n",__func__,status);) + + if(mode == 1) + { + if((status & I2C_LPC_IBB) && (status & I2C_LPC_TBE)) + { + DEBPROTO(lpc_fprintf_debug("%s : Bus is empty status : %x\n",__func__,status);) + break; + } + } + else + { + if(status & I2C_LPC_TD) + { + DEBPROTO(lpc_fprintf_debug("%s : Bus is empty status : %x\n",__func__,status);) + break; + } + } + + status = get_lpc(adap, I2C_LPC_REG_TEST); + + DEBPROTO(lpc_fprintf_debug("%s : The test register data : %x\n",__func__,status);) + udelay(1); /* wait for 100 us */ + } + + if (timeout == 0) { + DEBPROTO(lpc_fprintf_debug("%s : Timeout waiting for Bus Empty\n",__func__);) + return -ETIMEDOUT; + } + + return 0; +} + + +static int wait_for_bf(struct i2c_algo_lpc_data *adap) +{ + + int timeout = DEF_TIMEOUT; + int status; + + + while (--timeout) { + status = get_lpc(adap, I2C_LPC_REG_STATUS); + + DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus full status : %x\n",__func__,status);) + + if(status & I2C_LPC_RBF) + { + DEBPROTO(lpc_fprintf_debug("%s : Bus is full status : %x\n",__func__,status);) + break; + } + + status = get_lpc(adap, I2C_LPC_REG_TEST); + + DEBPROTO(lpc_fprintf_debug("%s : The test register data : %x\n",__func__,status);) + udelay(1); /* wait for 100 us */ + } + + if (timeout == 0) { + DEBPROTO(lpc_fprintf_debug("%s : Timeout waiting for Bus Full\n",__func__);) + return -ETIMEDOUT; + } + + return 0; +} + +static int wait_for_td(struct i2c_algo_lpc_data *adap) +{ + + int timeout = DEF_TIMEOUT; + int status=0; + + while (--timeout) { + udelay(4); + status = get_lpc(adap, I2C_LPC_REG_STATUS); + + DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus done status : %x\n",__func__,status);) + + if(status == I2C_LPC_TD) + { + DEBPROTO(lpc_fprintf_debug("%s : Bus is done status : %x\n",__func__,status);) + break; + } + } + + if (timeout == 0) { + DEBPROTO(lpc_fprintf_debug("%s : Timeout waiting for Bus Done\n",__func__);) + return -ETIMEDOUT; + } + + return 0; +} + + + +static int wait_for_pin(struct i2c_algo_lpc_data *adap, int *status) +{ + int timeout = DEF_TIMEOUT; + *status = get_lpc(adap, I2C_LPC_REG_STATUS); + + while ((*status & I2C_LPC_TBE) && --timeout) { + *status = get_lpc(adap, I2C_LPC_REG_STATUS); + } + + if (timeout == 0) + return -ETIMEDOUT; + + + return 0; +} + + +static int lpc_doAddress(struct i2c_algo_lpc_data *adap,struct i2c_msg *msg) +{ + unsigned short flags = msg->flags; + unsigned char addr; + + addr = msg->addr << 1; + if (flags & I2C_M_RD) + { + addr |= 1; + DEBPROTO(lpc_fprintf_debug("step 7 : read mode then write device address 0x%x\n",addr);) + } + else + { + DEBPROTO(lpc_fprintf_debug("step 2 : write mode then write device address 0x%x\n",addr);) + } + + if (flags & I2C_M_REV_DIR_ADDR) + { + addr ^= 1; + + } + i2c_outaddr(adap, addr); + return 0; + +} + + +static int lpc_sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) +{ + struct i2c_algo_lpc_data *adap = i2c_adap->algo_data; + int i = 0,timeout=0; + + unsigned int count = msg->len; + unsigned char *buf = msg->buf; + + do{ + lpc_doAddress(adap,msg); + set_lpc(adap, I2C_LPC_REG_BYTE_COUNT, (count-i) >= 4 ? 4:(count - i)); + DEBPROTO(lpc_fprintf_debug("step 3 : write register count %x\n",count);) + + if((count -i) >= 4) + { + i2c_outbyte1(adap, buf[i+0] & 0xff); + i2c_outbyte2(adap, buf[i+1] & 0xff); + i2c_outbyte3(adap, buf[i+2] & 0xff); + i2c_outbyte4(adap, buf[i+3] & 0xff); + + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+0,buf[i+0]);) + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+1,buf[i+1]);) + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+2,buf[i+2]);) + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+3,buf[i+3]);) + i += 4; + } + else if((count -i) == 3) + { + i2c_outbyte1(adap, buf[i+0] & 0xff); + i2c_outbyte2(adap, buf[i+1] & 0xff); + i2c_outbyte3(adap, buf[i+2] & 0xff); + + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+0,buf[i+0]);) + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+1,buf[i+1]);) + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+2,buf[i+2]);) + + i += 3; + } + else if((count -i) == 2) + { + i2c_outbyte1(adap, buf[i+0] & 0xff); + i2c_outbyte2(adap, buf[i+1] & 0xff); + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+0,buf[i+0]);) + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+1,buf[i+1]);) + i += 2; + } + else if((count -i) == 1) + { + i2c_outbyte1(adap, buf[i+0] & 0xff); + DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+0,buf[i+0]);) + i += 1; + } + + /* Send START */ + DEBPROTO(lpc_fprintf_debug("step 5-1 : Delay 6mS \n");) + udelay(6000); + DEBPROTO(lpc_fprintf_debug("step 5-2 : Start to transfrom \n");) + i2c_stop(adap); + i2c_start(adap); + DEBPROTO(lpc_fprintf_debug("step 5-3 : Start done\n");) + + udelay(400); + DEBPROTO(lpc_fprintf_debug("step 6 : Waiting for BE\n");) + timeout = wait_for_td(adap); + if (timeout) { + DEBPROTO(lpc_fprintf_debug("step 6 : Timeout waiting for BE \n");) + return -EREMOTEIO; + } + }while (i < count); + + if(i == count) + { + DEBPROTO(lpc_fprintf_debug("Writen %d bytes successd !\n",count);) + return i; + } + else + { + DEBPROTO(lpc_fprintf_debug("Writen %d bytes failed \n",count);) + return -EIO; + } +} + +static int lpc_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) +{ + int i=0,timeout=0; + struct i2c_algo_lpc_data *adap = i2c_adap->algo_data; + + unsigned int count = msg->len; + unsigned char *buf = msg->buf; + + do{ + lpc_doAddress(adap,msg); + set_lpc(adap, I2C_LPC_REG_BYTE_COUNT, (count-i) >= 4 ? 4:(count - i)); + DEBPROTO(lpc_fprintf_debug("step 8 : write register count %d\n",count);) + + /* Send START */ + DEBPROTO(lpc_fprintf_debug("step 9-1 : Delay 6mS\n");) + udelay(6000); + DEBPROTO(lpc_fprintf_debug("step 9-2 : Start to receive data\n");) + i2c_stop(adap); + i2c_start(adap); + DEBPROTO(lpc_fprintf_debug("step 9-3 : Start done\n");) + + udelay(400); + DEBPROTO(lpc_fprintf_debug("step 10 : Waiting for TD\n");) + timeout = wait_for_td(adap); + if (timeout) { + DEBPROTO(lpc_fprintf_debug("step 10 : Timeout waiting for TD \n");) + return -EREMOTEIO; + } + + if((count -i) >= 4) + { + buf[i+0] = 0xff & i2c_inbyte1(adap); + buf[i+1] = 0xff & i2c_inbyte2(adap); + buf[i+2] = 0xff & i2c_inbyte3(adap); + buf[i+3] = 0xff & i2c_inbyte4(adap); + + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+0,buf[i+0]);) + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+1,buf[i+1]);) + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+2,buf[i+2]);) + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+3,buf[i+3]);) + + i += 4; + } + else if((count -i) == 3) + { + buf[i+0] = 0xff & i2c_inbyte1(adap); + buf[i+1] = 0xff & i2c_inbyte2(adap); + buf[i+2] = 0xff & i2c_inbyte3(adap); + + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+0,buf[i+0]);) + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+1,buf[i+1]);) + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+2,buf[i+2]);) + + i += 3; + } + else if((count -i) == 2) + { + buf[i+0] = 0xff & i2c_inbyte1(adap); + buf[i+1] = 0xff & i2c_inbyte2(adap); + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+0,buf[i+0]);) + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+1,buf[i+1]);) + i += 2; + } + else if((count -i) == 1) + { + buf[i+0] = 0xff & i2c_inbyte1(adap); + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+0,buf[i+0]);) + i += 1; + } + + + }while(i < count); + + if(i == count) + { + DEBPROTO(lpc_fprintf_debug("Read %d bytes successd !\n",count);) + return i; + } + else + { + DEBPROTO(lpc_fprintf_debug("Read %d bytes failed \n",count);) + return -EIO; + } +} + + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; +#define LPC_I2C_MAX_NCHANS 6 + + +struct lpc_iic { + struct i2c_adapter *virt_adaps[LPC_I2C_MAX_NCHANS]; + u8 last_chan; /* last register value */ +}; + + +static int lpc_master_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, + int num) +{ + struct i2c_algo_lpc_data *adap = i2c_adap->algo_data; + struct i2c_msg *pmsg; + int i; + int ret=0; + + mutex_lock(&lpc_lock); + + if (adap->xfer_begin) + adap->xfer_begin(&i2c_adap->nr); + + + for (i = 0;ret >= 0 && i < num; i++) { + pmsg = &msgs[i]; + + DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n", + pmsg->flags & I2C_M_RD ? "read" : "write", + pmsg->len, pmsg->addr, i + 1, num);) + + DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n", + i, msgs[i].addr, msgs[i].flags, msgs[i].len);) + + if (pmsg->flags & I2C_M_RD) { + ret = lpc_readbytes(i2c_adap, pmsg); + + if (ret != pmsg->len) { + DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: fail: " + "only read %d bytes.\n",ret)); + } else { + DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: read %d bytes.\n",ret)); + } + } else { + + ret = lpc_sendbytes(i2c_adap, pmsg); + + if (ret != pmsg->len) { + DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: fail: " + "only wrote %d bytes.\n",ret)); + } else { + DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: wrote %d bytes.\n",ret)); + } + } + } + + if (adap->xfer_end) + adap->xfer_end(&i2c_adap->nr); + + mutex_unlock(&lpc_lock); + + DEBPROTO(lpc_fprintf_debug("ret = 0x%x num = 0x%x i = 0x%x.\n",ret,num,i)); + + return ret = (ret < 0) ? ret : num; +} + + +static u32 lpc_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_QUICK; +} + +/* exported algorithm data: */ +static const struct i2c_algorithm lpc_algo = { + .master_xfer = lpc_master_xfer, + //.smbus_xfer = lpc_smbus_xfer, + .functionality = lpc_func, +}; + + +/********************************************** End ********************************************************/ + + + + + + +/********************************************** Start ********************************************************/ +#define DEFAULT_BASE 0x0a00 + +static int lpc_base= 0x0a00; +static u8 __iomem *lpc_base_iomem; + +static int lpc_irq; +static int lpc_clock = 0x1c; +static int lpc_own = 0x55; +static int lpc_mmapped; + +static unsigned long lpc_base_addr = 0x0a00; +static unsigned int lpc_io_space_size = 2; + +static unsigned long LPC_INDEX_REG; +static unsigned long LPC_DATA_REG; + + +/* notice : removed static struct i2c_lpc_iic gpi; code - + this module in real supports only one device, due to missing arguments + in some functions, called from the algo-lpc module. Sometimes it's + need to be rewriten - but for now just remove this for simpler reading */ + +static wait_queue_head_t lpc_wait; +static int lpc_pending; +static spinlock_t lock; +static spinlock_t lpc_slock; + +static struct i2c_adapter lpc_iic_ops; + +struct cpld_dev_type { + struct resource *io_resource; + struct semaphore sem; + struct cdev cdev; +}; + +struct cpld_dev_type *cpld_device; + + +/* ----- local functions ---------------------------------------------- */ + +static void lpc_cpld_setbyte(void *data, int ctl, int val) +{ + outb(ctl, LPC_INDEX_REG); + mb(); + + outb(val, LPC_DATA_REG); + mb(); +} + +static int lpc_cpld_getbyte(void *data, int ctl) +{ + u8 val = 0; + + outb(ctl, LPC_INDEX_REG); + mb(); + + val = inb(LPC_DATA_REG); + mb(); + + return val; +} + +static void lpc_iic_setbyte(void *data, int ctl, int val) +{ + if (!cpld_device) + { + return ; + } + + if (down_interruptible(&cpld_device->sem)) + { + return ; + } + + + lpc_cpld_setbyte(data,ctl,val); + + up(&cpld_device->sem); + DEBPROTO(lpc_fprintf_debug("%s REG[%x] = %x\n",__func__,ctl,val);) +} + + +static int lpc_iic_getbyte(void *data, int ctl) +{ + u8 val = 0; + if (!cpld_device) + return -ENOTTY; + + if (down_interruptible(&cpld_device->sem)) + return -ERESTARTSYS; + + val = lpc_cpld_getbyte(data,ctl); + + up(&cpld_device->sem); + DEBPROTO(lpc_fprintf_debug("%s REG[%x] = %x\n",__func__,ctl,val);) + return val; +} + +int cig_cpld_read_register(u8 reg_off, u8 *val) +{ + if (!cpld_device) + return -ENOTTY; + + if (down_interruptible(&cpld_device->sem)) + return -ERESTARTSYS; + + *val = lpc_cpld_getbyte(cpld_device, reg_off); + + up(&cpld_device->sem); + + return 0; +} +EXPORT_SYMBOL(cig_cpld_read_register); + +int cig_cpld_write_register(u8 reg_off, u8 val) +{ + if (!cpld_device) + return -ENOTTY; + + if (down_interruptible(&cpld_device->sem)) + return -ERESTARTSYS; + + lpc_cpld_setbyte(cpld_device, reg_off, val); + up(&cpld_device->sem); + return 0; +} +EXPORT_SYMBOL(cig_cpld_write_register); + + + +static int lpc_iic_getown(void *data) +{ + return (lpc_own); +} + + +static int lpc_iic_getclock(void *data) +{ + return (lpc_clock); +} + +static void lpc_iic_waitforpin(void *data) +{ + DEFINE_WAIT(wait); + int timeout = 2; + unsigned long flags; + + if (lpc_irq > 0) { + spin_lock_irqsave(&lock, flags); + if (lpc_pending == 0) { + spin_unlock_irqrestore(&lock, flags); + prepare_to_wait(&lpc_wait, &wait, TASK_INTERRUPTIBLE); + if (schedule_timeout(timeout*HZ)) { + spin_lock_irqsave(&lock, flags); + if (lpc_pending == 1) { + lpc_pending = 0; + } + spin_unlock_irqrestore(&lock, flags); + } + finish_wait(&lpc_wait, &wait); + } else { + lpc_pending = 0; + spin_unlock_irqrestore(&lock, flags); + } + } else { + udelay(100); + } +} + + +static irqreturn_t lpc_iic_handler(int this_irq, void *dev_id) { + spin_lock(&lock); + lpc_pending = 1; + spin_unlock(&lock); + wake_up_interruptible(&lpc_wait); + return IRQ_HANDLED; +} + +static int board_id = 0; + + +static int lpc_iic_select(void *data) +{ + unsigned int chan_id=0; + chan_id = *(unsigned int *)data; + chan_id -= 2; + DEBPROTO(lpc_fprintf_debug("step 1 : selest channel id = %d\n",chan_id);) + lpc_iic_setbyte(data,I2C_LPC_REG_BUS_SEL,chan_id); + + return 0; +} + +static int lpc_iic_deselect(void *data) +{ + + unsigned int chan_id=0; + chan_id = *(unsigned int *)data; + chan_id -= 2; + DEBPROTO(lpc_fprintf_debug("step last :deselect channel id = %d\n",chan_id);) + + return 0; +} + + +/* ------------------------------------------------------------------------ + * Encapsulate the above functions in the correct operations structure. + * This is only done when more than one hardware adapter is supported. + */ +static struct i2c_algo_lpc_data lpc_iic_data = { + .setlpc = lpc_iic_setbyte, + .getlpc = lpc_iic_getbyte, + .getown = lpc_iic_getown, + .getclock = lpc_iic_getclock, + .waitforpin = lpc_iic_waitforpin, + .xfer_begin = lpc_iic_select, + .xfer_end = lpc_iic_deselect, +}; + +#include + +static struct i2c_adapter lpc_iic_arr_ops[LPC_I2C_MAX_NCHANS] = {0}; + +static void dummy_setscl(void *data, int state) +{ + return; +} + +static void dummy_setsda(void *data, int state) +{ + return; + +} + +static int dummy_getscl(void *data) +{ + return 1; + +} + +static int dummy_getsda(void *data) +{ + return 1; +} + + +static struct i2c_algo_bit_data dummy_algo_data = { + .setsda = dummy_setsda, + .setscl = dummy_setscl, + .getsda = dummy_getsda, + .getscl = dummy_getscl, + .udelay = 50, + .timeout = HZ, +}; + + +static int dummy_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, + int num) +{ + return 1; +} + +static u32 dummy_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_QUICK; +} + + +static const struct i2c_algorithm dummy_algo = { + .master_xfer = dummy_xfer, + .functionality = dummy_func, +}; + + + +static struct i2c_adapter i2c_dummy = { + .owner = THIS_MODULE, + .class = I2C_CLASS_HWMON, + .algo_data = &dummy_algo_data, + .algo = &dummy_algo, + .name = "i2c_dummy", +}; + + +static int lpc_iic_match(struct device *dev, unsigned int id) +{ + /* sanity checks for lpc_mmapped I/O */ + + DEB2(printk("lpc_iic_match\n");) + + + if (lpc_base < DEFAULT_BASE) { + dev_err(dev, "incorrect lpc_base address (%#x) specified " + "for lpc_mmapped I/O\n", lpc_base); + return 0; + } + + if (lpc_base == 0) { + lpc_base = DEFAULT_BASE; + } + return 1; +} + +static int lpc_iic_probe(struct device *dev, unsigned int id) +{ + int rval,num; + + lpc_fprintf_init(); + + DEB2(printk("lpc_iic_probe\n");) + + mutex_init(&lpc_lock); + + for(num = 0; num < LPC_I2C_MAX_NCHANS;num++) + { + lpc_iic_arr_ops[num].dev.parent = dev; + lpc_iic_arr_ops[num].owner = THIS_MODULE; + lpc_iic_arr_ops[num].class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + lpc_iic_arr_ops[num].algo = &lpc_algo; + lpc_iic_arr_ops[num].algo_data = &lpc_iic_data, + lpc_iic_arr_ops[num].nr=num; + snprintf(lpc_iic_arr_ops[num].name, sizeof(lpc_iic_arr_ops[num].name), "i2c-%d-lpc", i2c_adapter_id(&lpc_iic_arr_ops[num])); + rval |= i2c_add_adapter(&lpc_iic_arr_ops[num]); + DEB2(printk("%s\n",lpc_iic_arr_ops[num].name);) + } + + return 0; +} + +static int lpc_iic_remove(struct device *dev, unsigned int id) +{ + int num; + DEB2(printk("lpc_iic_remove\n")); + + lpc_fprintf_exit(); + for(num = LPC_I2C_MAX_NCHANS - 1; num >= 0 ;num--) + i2c_del_adapter(&lpc_iic_arr_ops[num]); + + + return 0; +} + +static struct isa_driver i2c_lpc_driver = { + .match = lpc_iic_match, + .probe = lpc_iic_probe, + .remove = lpc_iic_remove, + .driver = { + .owner = THIS_MODULE, + .name = "lpc-iic", + }, +}; + +/********************************************** End ********************************************************/ + + + + + + +/********************************************** Start ********************************************************/ + +static int cpld_major = 0; +static int cpld_minor = 0; + +struct cpld_rw_msg { + unsigned char addr; + unsigned char data; +}; + + +static struct cpld_rw_msg param_read = {-1}; +static struct cpld_rw_msg param_write = {-1}; +static struct cpld_rw_msg param_reads = {-1}; +static struct cpld_rw_msg param_writes = {-1}; + +void cpld_sysfs_kobj_release(struct kobject *kobj) +{ + return; +} + +int cpld_sysfs_add_attr(struct kobject* kobj, char* attr_name) +{ + + struct attribute *attr; + + attr = kmalloc(sizeof(struct attribute), GFP_KERNEL); + attr->name = attr_name; + attr->mode = 0644; + + return sysfs_create_file(kobj, attr); +} + +static int cig_cpld_write_slave_cpld_register(u8 reg_addr, u8 reg_data); +static int cig_cpld_read_slave_cpld_register(u8 reg_addr, u8 *reg_data); + + +static ssize_t cpld_sysfs_show(struct kobject *kobj, struct attribute *attr, char *buffer) +{ + u8 val=0,ret=0,year=0,month=0,day=0,cpld_m=0,cpld_1=0,cpld_2=0; + + if (0 == strcmp(attr->name, "read")) + { + val = lpc_iic_getbyte(NULL,param_read.addr); + ret = sprintf(buffer,"read : addr = 0x%x val = 0x%x\n",param_read.addr, val); + + } + else if (0 == strcmp(attr->name, "write")) + { + lpc_iic_setbyte(NULL, param_write.addr,param_write.data); + ret = sprintf(buffer,"write : addr = 0x%x val = 0x%x\n",param_write.addr, param_write.data); + } + else if (0 == strcmp(attr->name, "version")) + { + cpld_m = lpc_iic_getbyte(NULL, 0x02); + year = lpc_iic_getbyte(NULL, 0x03); + month = lpc_iic_getbyte(NULL, 0x04); + day = lpc_iic_getbyte(NULL, 0x05); + + cig_cpld_read_slave_cpld_register(0x1d,&cpld_1); + cig_cpld_read_slave_cpld_register(0x1e,&cpld_2); + + ret = sprintf(buffer,"Main CPLD version : V%02x\n"\ + "Main CPLD date : 20%02x-%02x-%02x\n"\ + "Slave 1 CPLD version : V%02x\n"\ + "Slave 2 CPLD version : V%02x\n",cpld_m,year,month,day,cpld_1,cpld_2); + } + if (0 == strcmp(attr->name, "reads")) + { + ret = cig_cpld_read_slave_cpld_register(param_reads.addr,&val); + if (ret < 0) + printk("ERROR:Failed to read slave cpld.\n"); + ret = sprintf(buffer,"reads : addr = 0x%x val = 0x%x\n",param_reads.addr, val); + + } + else if (0 == strcmp(attr->name, "writes")) + { + ret = cig_cpld_write_slave_cpld_register(param_writes.addr,param_writes.data); + if (ret < 0) + printk("ERROR:Failed to read slave cpld.\n"); + ret = sprintf(buffer,"writes : addr = 0x%x val = 0x%x\n",param_writes.addr, param_writes.data); + } + + + return ret; + +} + +static ssize_t cpld_sysfs_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) +{ + int param[3]; + + if (0 == strcmp(attr->name, "read")) + { + sscanf(buffer, "0x%02x", ¶m[0]); + param_read.addr = param[0]; + } + else if (0 == strcmp(attr->name, "write")) + { + sscanf(buffer, "0x%2x 0x%02x", ¶m[0], ¶m[1]); + param_write.addr = param[0]; + param_write.data = param[1]; + } + if (0 == strcmp(attr->name, "reads")) + { + sscanf(buffer, "0x%02x", ¶m[0]); + param_reads.addr = param[0]; + } + else if (0 == strcmp(attr->name, "writes")) + { + sscanf(buffer, "0x%2x 0x%02x", ¶m[0], ¶m[1]); + param_writes.addr = param[0]; + param_writes.data = param[1]; + } + return count; +} + + + +static struct sysfs_ops cpld_sysfs_ops = +{ + .show = cpld_sysfs_show, + .store = cpld_sysfs_store, +}; + +static struct kobj_type cpld_kobj_type = +{ + .release = cpld_sysfs_kobj_release, + .sysfs_ops = &cpld_sysfs_ops, + .default_attrs = NULL, +}; + + +static const char driver_name[] = "cpld_drv"; +static atomic_t cpld_available = ATOMIC_INIT(1); +static struct class *cpld_class; +static struct device *cpld_dev; + + + +#define CPLD_IOC_MAGIC '[' + +#define CPLD_IOC_RDREG _IOR(CPLD_IOC_MAGIC, 0, struct cpld_rw_msg) +#define CPLD_IOC_WRREG _IOW(CPLD_IOC_MAGIC, 1, struct cpld_rw_msg) + +#define CPLD_IOC_MAXNR 2 + + +int cpld_open(struct inode *inode, struct file *filp) +{ + struct cpld_dev_type *dev; + + if (! atomic_dec_and_test(&cpld_available)) { + atomic_inc(&cpld_available); + return -EBUSY; + } + + dev = container_of(inode->i_cdev, struct cpld_dev_type, cdev); + filp->private_data = dev; + + return 0; +} + +int cpld_release(struct inode *inode, struct file *flip) +{ + atomic_inc(&cpld_available); + return 0; +} + + +long cpld_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int rc = 0; + int err = 0; + struct cpld_dev_type *dev = (struct cpld_dev_type *)filp->private_data; + struct cpld_rw_msg msg; + + if (_IOC_TYPE(cmd) != CPLD_IOC_MAGIC) + return -ENOTTY; + if (_IOC_NR(cmd) > CPLD_IOC_MAXNR) + return -ENOTTY; + + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (err) + return -EFAULT; + + if (down_interruptible(&dev->sem)) + return -ERESTARTSYS; + + switch(cmd){ + case CPLD_IOC_RDREG: + rc = copy_from_user(&msg, (void __user *)arg, sizeof(msg)); + if (!rc) { + msg.data = lpc_cpld_getbyte(dev, msg.addr); + rc = copy_to_user((void __user *)arg, &msg, sizeof(msg)); + } + break; + + case CPLD_IOC_WRREG: + rc = copy_from_user(&msg, (void __user *)arg, sizeof(msg)); + if (!rc) { + lpc_cpld_setbyte(dev, msg.addr, msg.data); + } + break; + default: + rc = -ENOTTY; + break; + } + up(&dev->sem); + + return rc; +} + +struct file_operations cpld_fops = { + .owner = THIS_MODULE, + .open = cpld_open, + .unlocked_ioctl = cpld_ioctl, + .release = cpld_release, +}; + + +static void cpld_setup_cdev(struct cpld_dev_type *dev) +{ + int err, devno = MKDEV(cpld_major, cpld_minor); + + cdev_init(&dev->cdev, &cpld_fops); + dev->cdev.owner = THIS_MODULE; + dev->cdev.ops = &cpld_fops; + err = cdev_add(&dev->cdev, devno, 1); + + if (err) + DEB2(printk(KERN_NOTICE "Error %d adding cpld", err);) +} +/********************************************** End ********************************************************/ + + + + +/********************************************** Start ********************************************************/ +#include +#include +#include + +static spinlock_t irq_inter_lock; +static struct delayed_work irq_inter_work; +static unsigned long irq_inter_delay; + + +static int cig_cpld_write_slave_cpld_register(u8 reg_addr, u8 reg_data) +{ + u8 read_status = 0; + u8 wait_time_out = WAIT_TIME_OUT_COUNT; + DEB2(printk("<=======write=========>")); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_ADDR, reg_addr << 1); + DEB2(printk("[62]=%x\n",reg_addr << 1)); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_TX, reg_data); + DEB2(printk("[63]=%x\n",reg_data)); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_COMMAND, 0x80); + DEB2(printk("[65]=%x\n",0x80)); + do{ + cig_cpld_read_register(ADDR_REG_SFP_STATUS_STATUS, &read_status); + DEB2(printk("[66]=%x\n",read_status)); + udelay(60); + wait_time_out--; + if(wait_time_out == 0) + break; + }while(read_status != 0x02); + DEB2(printk("<=======write=========>")); + + + if(wait_time_out == 0) + return -1; + + return 1; +} + + +static int cig_cpld_read_slave_cpld_register(u8 reg_addr, u8 *reg_data) +{ + u8 read_status = 0; + u8 wait_time_out = WAIT_TIME_OUT_COUNT; + DEB2(printk("<========read=========>")); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_ADDR, reg_addr << 1 | 1); + DEB2(printk("[62]=%x\n",reg_addr << 1 | 1)); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_COMMAND, 0x80); + DEB2(printk("[65]=%x\n",0x80)); + do{ + udelay(60); + cig_cpld_read_register(ADDR_REG_SFP_STATUS_STATUS, &read_status); + DEB2(printk("[66]=%x\n",read_status)); + wait_time_out--; + if(wait_time_out == 0) + break; + }while(read_status != 0x01); + + cig_cpld_read_register(ADDR_REG_SFP_STATUS_RX,reg_data); + DEB2(printk("[64]=%x\n",*reg_data)); + DEB2(printk("<========read=========>")); + + if(wait_time_out == 0) + return -1; + + return 1; +} + + + +struct sock *nlsk = NULL; +extern struct net init_net; +#define NETLINK_TEST 26 +#define MSG_LEN 125 +#define USER_PORT 100 +static u32 irq_present_status_low_current,irq_present_status_low_next; +static u32 irq_present_status_high_current,irq_present_status_high_next; +static u32 irq_tx_fault_status_low_current,irq_tx_fault_status_low_next; +static u32 irq_tx_fault_status_high_current,irq_tx_fault_status_high_next; +static u32 irq_rx_lost_status_low_current,irq_rx_lost_status_low_next; +static u32 irq_rx_lost_status_high_current,irq_rx_lost_status_high_next; + +static u8 irq_present_qsfp_current,irq_present_qsfp_next; +static u8 irq_interrupt_qsfp_current,irq_interrupt_qsfp_next; + +struct input_dev *cpld_input_dev; + + + +int send_usrmsg(char *pbuf, uint16_t len) +{ + struct sk_buff *nl_skb; + struct nlmsghdr *nlh; + + int ret; + + + nl_skb = nlmsg_new(len, GFP_ATOMIC); + if(!nl_skb) + { + printk("netlink alloc failure\n"); + return -1; + } + + + nlh = nlmsg_put(nl_skb, 0, 0, NETLINK_TEST, len, 0); + if(nlh == NULL) + { + printk("nlmsg_put failaure \n"); + nlmsg_free(nl_skb); + return -1; + } + + memcpy(nlmsg_data(nlh), pbuf, len); + ret = netlink_unicast(nlsk, nl_skb, USER_PORT, MSG_DONTWAIT); + + return ret; +} + +static void netlink_rcv_msg(struct sk_buff *skb) +{ + + struct nlmsghdr *nlh = NULL; + char *umsg = NULL; + char kmsg[1024] = {0}; + char kmsg_tmp[16] = {0}; + u8 i = 0; + u8 tmp[3]={0}; + + if(skb->len >= nlmsg_total_size(0)) + { + nlh = nlmsg_hdr(skb); + umsg = NLMSG_DATA(nlh); + if(umsg) + { + for(i = 0;i < 24;i++) + { + if(!(irq_present_status_low_current & (0x1 << i))) + { + tmp[0] = 1; + } + else + { + tmp[0] = 0; + } + + if(!(irq_rx_lost_status_low_current & (0x1 << i))) + { + tmp[1] = 1; + } + else + { + tmp[1] = 0; + } + + if(!(irq_tx_fault_status_low_current & (0x1 << i))) + { + tmp[2] = 1; + } + else + { + tmp[2] = 0; + } + memset(kmsg_tmp,0xff,sizeof(kmsg_tmp)); + sprintf(kmsg_tmp,"sfp%02d:%1d:%1d:%1d ",i+1,tmp[0],tmp[1],tmp[2]); + strcat(kmsg,kmsg_tmp); + } + + for(i = 0;i < 24;i++) + { + if(!(irq_present_status_high_current & (0x1 << i))) + { + tmp[0] = 1; + } + else + { + tmp[0] = 0; + } + + if(!(irq_rx_lost_status_high_current & (0x1 << i))) + { + tmp[1] = 1; + } + else + { + tmp[1] = 0; + } + + if(!(irq_tx_fault_status_high_current & (0x1 << i))) + { + tmp[2] = 1; + } + else + { + tmp[2] = 0; + } + memset(kmsg_tmp,0xff,sizeof(kmsg_tmp)); + sprintf(kmsg_tmp,"sfp%02d:%1d:%1d:%1d ",i+25,tmp[0],tmp[1],tmp[2]); + strcat(kmsg,kmsg_tmp); + } + + + for(i = 0;i < 8;i++) + { + if(!(irq_present_qsfp_current & (0x1 << i))) + { + tmp[0] = 1; + } + else + { + tmp[0] = 0; + } + + if(!(irq_interrupt_qsfp_current & (0x1 << i))) + { + tmp[1] = 1; + } + else + { + tmp[1] = 0; + } + + memset(kmsg_tmp,0xff,sizeof(kmsg_tmp)); + sprintf(kmsg_tmp,"qsfp%02d:%1d:%1d:%1d ",i+49,tmp[0],tmp[1],0); + strcat(kmsg,kmsg_tmp); + } + + printk("kernel recv from user: %s\n", umsg); + send_usrmsg(kmsg, strlen(kmsg)); + } + } + + return ; +} + + + +struct netlink_kernel_cfg cfg = { + .input = netlink_rcv_msg, /* set recv callback */ +}; + + + +#define RANGE_OF_BYTE_SHIFT(to_arg,shift,from_arg) {to_arg &= ~(0xff << shift); to_arg |= from_arg << shift;} + + +static void irq_inter_wapper(struct work_struct * work) +{ + + u8 m_data = 0; + u8 data_high8 = 0,data_low8 = 0; + u16 data_16 = 0; + u8 status = 0; + u8 i = 0; + char kmsg[64]={0}; + u8 tmp[3] = {0}; + + DEB2(printk("CPLD_MASTER_INTERRUPT\r\n")); + + m_data = lpc_iic_getbyte(NULL,CPLD_MASTER_INTERRUPT_STATUS_REG); + lpc_iic_setbyte(NULL,CPLD_MASTER_INTERRUPT_STATUS_REG,0xff); + + cig_cpld_write_slave_cpld_register(CPLD_SLAVE1_INTERRUPT_MASK_REG,0xff); + cig_cpld_write_slave_cpld_register(CPLD_SLAVE2_INTERRUPT_MASK_REG,0xff); + if(!(m_data & CPLD_MASTER_INTERRUPT_CPLD1)) + { + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_INTERRUPT_STATUS_H_REG,&data_high8); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_INTERRUPT_STATUS_L_REG,&data_low8); + data_16 = data_low8 | data_high8 << 8; + if( + !(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT08) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT16) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT24) + ) + { + if(!(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT08)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT08\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_PRESENT08_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_low_current,0,status); + + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT16)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT16\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_PRESENT16_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_low_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT24)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT24\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_PRESENT24_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_low_current,16,status); + } + DEB2(printk("irq_present_status_low_next = %08x irq_present_status_low_current = %08x \n",irq_present_status_low_next,irq_present_status_low_current)); + } + + if( + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST08) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST16) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST24) + ) + { + if(!(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST08)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_RX_LOST08\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_RX_LOST08_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_low_current,0,status); + + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST16)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT16\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_RX_LOST16_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_low_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST24)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT24\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_RX_LOST24_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_low_current,16,status); + } + DEB2(printk("irq_rx_lost_status_low_next = %08x irq_rx_lost_status_low_current = %08x \n",irq_rx_lost_status_low_next,irq_rx_lost_status_low_current)); + } + + if( + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST08) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST16) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST24) + ) + { + if(!(data_16 & CPLD_SLAVE1_INTERRUPT_TX_FAULT08)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_TX_FAULT08\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_TX_FAULT08_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_low_current,0,status); + + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_TX_FAULT16)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_TX_FAULT16\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_TX_FAULT16_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_low_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_TX_FAULT24)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_TX_FAULT24\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_TX_FAULT24_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_low_current,16,status); + } + DEB2(printk("irq_tx_fault_status_low_next = %08x irq_tx_fault_status_low_current = %08x \n",irq_tx_fault_status_low_next,irq_tx_fault_status_low_current)); + + } + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_CPLD2)) + { + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_INTERRUPT_STATUS_H_REG,&data_high8); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_INTERRUPT_STATUS_L_REG,&data_low8); + data_16 = data_low8 | data_high8 << 8; + if( + !(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT32) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT40) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT48) + ) + { + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT32)) + { + DEB2(printk("CPLD_SLAVE2_PRESENT32_REG\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_PRESENT32_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_high_current,0,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT40)) + { + DEB2(printk("CPLD_SLAVE2_PRESENT40_REG\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_PRESENT40_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_high_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT48)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT48\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_PRESENT48_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_high_current,16,status); + } + } + + if( + !(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST32) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST40) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST48) + ) + { + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST32)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_RX_LOST32\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_RX_LOST32_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_high_current,0,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST40)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT40\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_RX_LOST40_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_high_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST48)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT48\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_RX_LOST48_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_high_current,16,status); + } + + } + + if( + !(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT32) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT40) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT48) + ) + { + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT32)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_RX_LOST32\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_TX_FAULT32_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_high_current,0,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT40)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT40\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_TX_FAULT40_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_high_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT48)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT48\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_TX_FAULT48_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_high_current,16,status); + } + } + + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT56)) + { + DEB2(printk("CPLD_SLAVE2_PRESENT56_REG\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_PRESENT56_REG,&status); + irq_present_qsfp_current = status; + } + + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_QSFP_CR56)) + { + DEB2(printk("CPLD_SLAVE2_QSFP_CR56_REG\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_QSFP_CR56_REG,&status); + irq_interrupt_qsfp_current = status; + } + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_LSW)) + { + DEB2(printk("CPLD_MASTER_INTERRUPT_LSW\r\n")); + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_PSU1)) + { + DEB2(printk("CPLD_MASTER_INTERRUPT_PSU1\r\n")); + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_PSU2)) + { + DEB2(printk("CPLD_MASTER_INTERRUPT_PSU2\r\n")); + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_6320)) + { + DEB2(printk("CPLD_MASTER_INTERRUPT_6320\r\n")); + } + cig_cpld_write_slave_cpld_register(CPLD_SLAVE1_INTERRUPT_MASK_REG,0x0); + cig_cpld_write_slave_cpld_register(CPLD_SLAVE2_INTERRUPT_MASK_REG,0x0); + + memset(tmp,0xff,sizeof(tmp)); + + for(i = 0;i < 24;i++) + { + if(!(irq_present_status_low_current & (0x1 << i)) && (irq_present_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d is present\r\n",i+1)); + tmp[0] = 1; + } + else if((irq_present_status_low_current & (0x1 << i)) && !(irq_present_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d is absent\r\n",i+1)); + tmp[0] = 0; + } + + if(!(irq_tx_fault_status_low_current & (0x1 << i)) && (irq_tx_fault_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d transmission is right\r\n",i+1)); + tmp[1] = 1; + } + else if((irq_tx_fault_status_low_current & (0x1 << i)) && !(irq_tx_fault_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d transmission is fault\r\n",i+1)); + tmp[1] = 0; + } + + if(!(irq_rx_lost_status_low_current & (0x1 << i)) && (irq_rx_lost_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d optical is meet\r\n",i+1)); + tmp[2] = 1; + } + else if((irq_rx_lost_status_low_current & (0x1 << i)) && !(irq_rx_lost_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d optical is lost\r\n",i+1)); + tmp[2] = 0; + } + + if((tmp[0] != 0xff) || (tmp[1] != 0xff) || (tmp[2] != 0xff)) + { + memset(kmsg,0xff,sizeof(kmsg)); + snprintf(kmsg,sizeof(kmsg),"sfp%02d:%1d:%1d:%1d ",i+1,(tmp[0] == 0xff) ? 0:tmp[0],(tmp[1] == 0xff) ? 0:tmp[1],(tmp[2] == 0xff) ? 0:tmp[2]); + break; + } + } + + memset(tmp,0xff,sizeof(tmp)); + for(i = 0;i < 24;i++) + { + if(!(irq_present_status_high_current & (0x1 << i)) && (irq_present_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d is present\r\n",i+25)); + tmp[0] = 1; + } + else if((irq_present_status_high_current & (0x1 << i)) && !(irq_present_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d is absent\r\n",i+25)); + tmp[0] = 0; + + } + + if(!(irq_rx_lost_status_high_current & (0x1 << i)) && (irq_rx_lost_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d optical is meet\r\n",i+25)); + tmp[1] = 1; + } + else if((irq_rx_lost_status_high_current & (0x1 << i)) && !(irq_rx_lost_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d optical is lost\r\n",i+25)); + tmp[1] = 0; + } + + if(!(irq_tx_fault_status_high_current & (0x1 << i)) && (irq_tx_fault_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d transmission is right\r\n",i+25)); + tmp[2] = 1; + } + else if((irq_tx_fault_status_high_current & (0x1 << i)) && !(irq_tx_fault_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d transmission is fault\r\n",i+25)); + tmp[2] = 0; + } + + if((tmp[0] != 0xff) || (tmp[1] != 0xff) || (tmp[2] != 0xff)) + { + memset(kmsg,0xff,sizeof(kmsg)); + snprintf(kmsg,sizeof(kmsg),"sfp%02d:%1d:%1d:%1d ",i+25,(tmp[0] == 0xff) ? 0:tmp[0],(tmp[1] == 0xff) ? 0:tmp[1],(tmp[2] == 0xff) ? 0:tmp[2]); + break; + } + } + + memset(tmp,0xff,sizeof(tmp)); + for(i = 0 ; i < 8; i++) + { + if(!(irq_present_qsfp_current & (0x1 << i)) && (irq_present_qsfp_next & (0x1 << i))) + { + DEB2(printk("SFP%d is present\r\n",i+49)); + tmp[0] = 1; + } + else if((irq_present_qsfp_current & (0x1 << i)) && !(irq_present_qsfp_next & (0x1 << i))) + { + DEB2(printk("SFP%d is absent\r\n",i+49)); + tmp[0] = 0; + } + + if(!(irq_interrupt_qsfp_current & (0x1 << i)) && (irq_interrupt_qsfp_next & (0x1 << i))) + { + DEB2(printk("SFP%d interrupt is occured \r\n",i+49)); + tmp[1] = 1; + } + else if((irq_interrupt_qsfp_current & (0x1 << i)) && !(irq_interrupt_qsfp_next & (0x1 << i))) + { + DEB2(printk("SFP%d interrupt is cleaned\r\n",i+49)); + tmp[1] = 0; + } + + if((tmp[0] != 0xff) || (tmp[1] != 0xff)) + { + memset(kmsg,0xff,sizeof(kmsg)); + snprintf(kmsg,sizeof(kmsg),"qsfp%02d:%1d:%1d:%1d ",i+49,(tmp[0] == 0xff) ? 0:tmp[0],(tmp[1] == 0xff) ? 0:tmp[1],0); + break; + } + } + + + irq_present_status_low_next = irq_present_status_low_current; + irq_rx_lost_status_low_next = irq_rx_lost_status_low_current; + irq_tx_fault_status_low_next = irq_tx_fault_status_low_current; + irq_present_status_high_next = irq_present_status_high_current; + irq_rx_lost_status_high_next = irq_rx_lost_status_high_current; + irq_tx_fault_status_high_next = irq_tx_fault_status_high_current; + irq_present_qsfp_next = irq_present_qsfp_current; + irq_interrupt_qsfp_next = irq_interrupt_qsfp_current; + + send_usrmsg(kmsg, strlen(kmsg)); +} + +static void disableIrq(unsigned short maskReg, unsigned short mask) +{ + u8 data = 0; + + data = lpc_iic_getbyte(NULL,maskReg); + data |= mask; + lpc_iic_setbyte(NULL,maskReg, data); +} + +static void enableIrq(unsigned short maskReg, unsigned short mask) +{ + unsigned short data; + + data = lpc_iic_getbyte(NULL,maskReg); + data &= ~mask; + lpc_iic_setbyte(NULL,maskReg, data); +} + + +static irqreturn_t irq_inter_isr(int irq, void *handle) +{ + + /* + * use keventd context to read the event fifo registers + * Schedule readout at least 25ms after notification for + * REVID < 4 + */ + + schedule_delayed_work(&irq_inter_work, irq_inter_delay); + + return IRQ_HANDLED; +} + + +#define CIG_CPLD_CHR_NAME "cpld" + + +static int __init cpld_init(void) +{ + int rval,rc=0; + dev_t dev; + u8 s_data; + + DEB2(printk("cpld_init\n");) + +/**************************************************************************************/ + + LPC_INDEX_REG = lpc_base_addr; + LPC_DATA_REG = lpc_base_addr + 1; + + cpld_device = kzalloc(sizeof(struct cpld_dev_type), GFP_KERNEL); + if (!cpld_device) + goto error3; + cpld_device->io_resource = request_region(lpc_base_addr, + lpc_io_space_size, "lpc-i2c"); + if (!cpld_device->io_resource) { + printk("lpc: claim I/O resource fail\n"); + goto error2; + } + sema_init(&cpld_device->sem, 1); + + if (cpld_major) { + dev = MKDEV(cpld_major, cpld_minor); + rc = register_chrdev_region(dev, 1, CIG_CPLD_CHR_NAME); + } else { + rc = alloc_chrdev_region(&dev, cpld_major, 1, CIG_CPLD_CHR_NAME); + cpld_major = MAJOR(dev); + } + + cpld_setup_cdev(cpld_device); + + cpld_class = class_create(THIS_MODULE,CIG_CPLD_CHR_NAME); + if (!cpld_class) { + DEB2(printk("failed to create class\n");) + goto error1; + } + + cpld_class->p->subsys.kobj.ktype= &cpld_kobj_type; + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "read"); + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "write"); + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "reads"); + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "writes"); + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "version"); + + cpld_dev = device_create(cpld_class, NULL, dev, NULL, CIG_CPLD_CHR_NAME); + +/**************************************************************************************/ + + rval = lpc_bus_init(); + rval = lpc_register_driver(&i2c_lpc_driver, 1); + +/**************************************************************************************/ + return 0; +error1: + cdev_del(&cpld_device->cdev); + unregister_chrdev_region(dev, 1); +error2: + release_resource(cpld_device->io_resource); +error3: + kfree(cpld_device); + + return rc; +} + +static void __exit cpld_exit(void) +{ + DEB2(printk("cpld_exit\n")); + + lpc_unregister_driver(&i2c_lpc_driver); + lpc_bus_exit(); + dev_t devno = MKDEV(cpld_major, cpld_minor); + + cdev_del(&cpld_device->cdev); + if (cpld_class) { + device_destroy(cpld_class, devno); + class_destroy(cpld_class); + } + + if (cpld_device) { + if (cpld_device->io_resource) + release_resource(cpld_device->io_resource); + + kfree(cpld_device); + } + unregister_chrdev_region(devno, 1); + + +} + +module_param(cpld_major, int, S_IRUGO); +module_param(cpld_minor, int, S_IRUGO); +module_param(i2c_debug, int, S_IRUGO); +module_param(board_id, int, S_IRUGO); + +module_init(cpld_init); +module_exit(cpld_exit); + +MODULE_AUTHOR("Zhang Peng "); +MODULE_DESCRIPTION("cs6436-54p-cpld driver"); +MODULE_LICENSE("GPL"); + + +/********************************************** End ********************************************************/ + + + diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-fan.c b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-fan.c new file mode 100644 index 00000000000..881cb7304b0 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-fan.c @@ -0,0 +1,521 @@ +/* + * A hwmon driver for the CIG cs6436-54p fan + * + * Copyright (C) 2018 Cambridge, 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 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 +#include +#include +#include +#include + + + +#define FAN_SPEED_DUTY_TO_CPLD_STEP 10 + +static struct cs6436_54p_fan_data *cs6436_54p_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 set_fan_direction(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); + + +extern int cig_cpld_write_register(u8 reg_off, u8 val); +extern int cig_cpld_read_register(u8 reg_off, u8 *val); + +/* fan related data, the index should match sysfs_fan_attributes + */ +static const u8 fan_reg[] = { + 0x41, /* fan enable/disable */ + 0x40, /* fan PWM(for all fan) */ + 0x42, /* front fan 1 speed(rpm) */ + 0x44, /* front fan 2 speed(rpm) */ + 0x46, /* front fan 3 speed(rpm) */ + 0x48, /* front fan 4 speed(rpm) */ + 0x4a, /* front fan 5 speed(rpm) */ + 0x43, /* rear fan 1 speed(rpm) */ + 0x45, /* rear fan 2 speed(rpm) */ + 0x47, /* rear fan 3 speed(rpm) */ + 0x49, /* rear fan 4 speed(rpm) */ + 0x4b, /* rear fan 5 speed(rpm) */ + 0x4c, /* fan direction rear to front or front to rear */ +}; + + +/* Each client has this additional data */ +struct cs6436_54p_fan_data { + 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 reg_val[ARRAY_SIZE(fan_reg)]; /* Register value */ +}; + +static struct cs6436_54p_fan_data *fan_data = NULL; + +enum fan_id { + FAN1_ID, + FAN2_ID, + FAN3_ID, + FAN4_ID, + FAN5_ID, +}; + +enum sysfs_fan_attributes { + FAN_STATE_REG, + FAN_DUTY_CYCLE_PERCENTAGE, /* Only one CPLD register to control duty cycle for all fans */ + FAN1_FRONT_SPEED_RPM, + FAN2_FRONT_SPEED_RPM, + FAN3_FRONT_SPEED_RPM, + FAN4_FRONT_SPEED_RPM, + FAN5_FRONT_SPEED_RPM, + FAN1_REAR_SPEED_RPM, + FAN2_REAR_SPEED_RPM, + FAN3_REAR_SPEED_RPM, + FAN4_REAR_SPEED_RPM, + FAN5_REAR_SPEED_RPM, + FAN_DIRECTION, + FAN1_STATE, + FAN2_STATE, + FAN3_STATE, + FAN4_STATE, + FAN5_STATE, + FAN1_FAULT, + FAN2_FAULT, + FAN3_FAULT, + FAN4_FAULT, + FAN5_FAULT, + FAN1_DIRECTION, + FAN2_DIRECTION, + FAN3_DIRECTION, + FAN4_DIRECTION, + FAN5_DIRECTION, +}; + +/* Define attributes + */ +#define DECLARE_FAN_STATE_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_state, S_IRUGO, fan_show_value, NULL, FAN##index##_STATE) +#define DECLARE_FAN_STATE_ATTR(index) &sensor_dev_attr_fan##index##_state.dev_attr.attr + +#define DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FAULT) +#define DECLARE_FAN_FAULT_ATTR(index) &sensor_dev_attr_fan##index##_fault.dev_attr.attr + +#define DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN##index##_DUTY_CYCLE_PERCENTAGE) +#define DECLARE_FAN_DUTY_CYCLE_ATTR(index) &sensor_dev_attr_fan##index##_duty_cycle_percentage.dev_attr.attr + +#define DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_front_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_FRONT_SPEED_RPM);\ + static SENSOR_DEVICE_ATTR(fan##index##_rear_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_REAR_SPEED_RPM) +#define DECLARE_FAN_SPEED_RPM_ATTR(index) &sensor_dev_attr_fan##index##_front_speed_rpm.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_rear_speed_rpm.dev_attr.attr + +#define DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_direction, S_IWUSR | S_IRUGO, fan_show_value, set_fan_direction, FAN##index##_DIRECTION) +#define DECLARE_FAN_DIRECTION_ATTR(index) &sensor_dev_attr_fan##index##_direction.dev_attr.attr + + +/* 5 fan state attributes in this platform */ +DECLARE_FAN_STATE_SENSOR_DEV_ATTR(1); +DECLARE_FAN_STATE_SENSOR_DEV_ATTR(2); +DECLARE_FAN_STATE_SENSOR_DEV_ATTR(3); +DECLARE_FAN_STATE_SENSOR_DEV_ATTR(4); +DECLARE_FAN_STATE_SENSOR_DEV_ATTR(5); + + +/* 5 fan fault attributes in this platform */ +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(1); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(2); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(3); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(4); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(5); + +/* 5 fan speed(rpm) attributes in this platform */ +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(1); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(2); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(3); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(4); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(5); + +/* 1 fan duty cycle attribute in this platform */ +DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(); + +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(1); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(2); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(3); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(4); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(5); + + +static struct attribute *cs6436_54p_fan_attributes[] = { + /* fan related attributes */ + DECLARE_FAN_STATE_ATTR(1), + DECLARE_FAN_STATE_ATTR(2), + DECLARE_FAN_STATE_ATTR(3), + DECLARE_FAN_STATE_ATTR(4), + DECLARE_FAN_STATE_ATTR(5), + DECLARE_FAN_FAULT_ATTR(1), + DECLARE_FAN_FAULT_ATTR(2), + DECLARE_FAN_FAULT_ATTR(3), + DECLARE_FAN_FAULT_ATTR(4), + DECLARE_FAN_FAULT_ATTR(5), + DECLARE_FAN_SPEED_RPM_ATTR(1), + DECLARE_FAN_SPEED_RPM_ATTR(2), + DECLARE_FAN_SPEED_RPM_ATTR(3), + DECLARE_FAN_SPEED_RPM_ATTR(4), + DECLARE_FAN_SPEED_RPM_ATTR(5), + DECLARE_FAN_DUTY_CYCLE_ATTR(), + DECLARE_FAN_DIRECTION_ATTR(1), + DECLARE_FAN_DIRECTION_ATTR(2), + DECLARE_FAN_DIRECTION_ATTR(3), + DECLARE_FAN_DIRECTION_ATTR(4), + DECLARE_FAN_DIRECTION_ATTR(5), + NULL +}; + +#define FAN_MAX_DUTY_CYCLE 100 +#define FAN_REG_VAL_TO_SPEED_RPM_STEP 100 + +/* fan utility functions + */ +static u32 reg_val_to_duty_cycle(u8 reg_val) +{ + if (reg_val +== 0xFF) { + return 100; + } + return ((u32)(reg_val) * 100)/ 255; +} + +static u8 duty_cycle_to_reg_val(u8 duty_cycle) +{ + if (duty_cycle >= FAN_MAX_DUTY_CYCLE) { + return 0xFF; + } + + return 255 / 10 * (duty_cycle / 10); +} + +static u32 reg_val_to_speed_rpm(u8 reg_val) +{ + return (u32)reg_val * FAN_REG_VAL_TO_SPEED_RPM_STEP; +} + +static u8 reg_val_to_is_state(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 cs6436_54p_fan_data *data, enum fan_id id) +{ + u8 ret = 1; + int front_fan_index = FAN1_FRONT_SPEED_RPM + id; + int rear_fan_index = FAN1_REAR_SPEED_RPM + id; + + /* Check if the speed of front or rear fan is ZERO, + */ + if (reg_val_to_speed_rpm(data->reg_val[front_fan_index]) && + reg_val_to_speed_rpm(data->reg_val[rear_fan_index])) { + ret = 0; + } + + return ret; +} + + +static ssize_t 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 <= 0 || value > FAN_MAX_DUTY_CYCLE) + return -EINVAL; + + cig_cpld_write_register(fan_reg[FAN_DUTY_CYCLE_PERCENTAGE], duty_cycle_to_reg_val(value)); + + return count; +} + +static ssize_t set_fan_direction(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value,fan_index; + u8 mask,reg_val; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + fan_index = attr->index - FAN1_DIRECTION; + error = kstrtoint(buf, 10, &value); + if (error) + return error; + + if (!(value == 0 || value == 1)) + return -EINVAL; + + + cig_cpld_read_register(fan_reg[FAN_DIRECTION],®_val); + + if(value == 1) + { + reg_val |= (1 << fan_index); + } + else + { + reg_val &= ~(1 << fan_index); + } + + cig_cpld_write_register(fan_reg[FAN_DIRECTION], reg_val); + + return count; +} + + + + + +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); + + cs6436_54p_fan_update_device(dev); + + struct cs6436_54p_fan_data *data = fan_data; + + ssize_t ret = 0; + + if (data->valid) { + switch (attr->index) { + + case FAN1_STATE: + case FAN2_STATE: + case FAN3_STATE: + case FAN4_STATE: + case FAN5_STATE: + //printk("FAN_STATE_REG: 0x%x\n", data->reg_val[FAN_STATE_REG]); + //printk("index: %d\n", attr->index); + ret = sprintf(buf, "%d\n", + reg_val_to_is_state(data->reg_val[FAN_STATE_REG], + attr->index - FAN1_STATE)); + break; + case FAN_DUTY_CYCLE_PERCENTAGE: + { + u32 duty_cycle = reg_val_to_duty_cycle(data->reg_val[FAN_DUTY_CYCLE_PERCENTAGE]); + ret = sprintf(buf, "%u\n", duty_cycle); + break; + } + case FAN1_FRONT_SPEED_RPM: + case FAN2_FRONT_SPEED_RPM: + case FAN3_FRONT_SPEED_RPM: + case FAN4_FRONT_SPEED_RPM: + case FAN5_FRONT_SPEED_RPM: + case FAN1_REAR_SPEED_RPM: + case FAN2_REAR_SPEED_RPM: + case FAN3_REAR_SPEED_RPM: + case FAN4_REAR_SPEED_RPM: + case FAN5_REAR_SPEED_RPM: +// printk("FAN_seed_REG: 0x%x\n", data->reg_val[attr->index]); +// printk("index: %d\n", attr->index); + ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_val[attr->index])); + break; + + case FAN1_FAULT: + case FAN2_FAULT: + case FAN3_FAULT: + case FAN4_FAULT: + case FAN5_FAULT: + ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN1_FAULT)); + break; + case FAN1_DIRECTION: + case FAN2_DIRECTION: + case FAN3_DIRECTION: + case FAN4_DIRECTION: + case FAN5_DIRECTION: + ret = sprintf(buf, "%d\n",reg_val_to_is_state(data->reg_val[FAN_DIRECTION],attr->index - FAN1_DIRECTION)); + break; + default: + break; + } + } + + return ret; +} + +static const struct attribute_group cs6436_54p_fan_group = { + .attrs = cs6436_54p_fan_attributes, +}; + +static struct cs6436_54p_fan_data *cs6436_54p_fan_update_device(struct device *dev) +{ + struct cs6436_54p_fan_data *data = fan_data; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || + !data->valid) { + int i; + + data->valid = 0; + + /* Update fan data + */ + for (i = 0; i < ARRAY_SIZE(data->reg_val); i++) { + u8 status; + (void)cig_cpld_read_register(fan_reg[i], &status); + + if (status < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + return data; + } + else { + data->reg_val[i] = status; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int cs6436_54p_fan_probe(struct platform_device *pdev) +{ + int status = -1; + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &cs6436_54p_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, "cs6436_54p_fan\n"); + + return 0; + +exit_remove: + sysfs_remove_group(&pdev->dev.kobj, &cs6436_54p_fan_group); +exit: + return status; +} + +static int cs6436_54p_fan_remove(struct platform_device *pdev) +{ + hwmon_device_unregister(fan_data->hwmon_dev); + sysfs_remove_group(&fan_data->pdev->dev.kobj, &cs6436_54p_fan_group); + + return 0; +} + +#define DRVNAME "cs6436_54p_fan" + +static struct platform_driver cs6436_54p_fan_driver = { + .probe = cs6436_54p_fan_probe, + .remove = cs6436_54p_fan_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + + + + + +static int __init cs6436_54p_fan_init(void) +{ + int ret; + + cig_cpld_write_register(0x40, duty_cycle_to_reg_val(50)); + + ret = platform_driver_register(&cs6436_54p_fan_driver); + if (ret < 0) { + goto exit; + } + + fan_data = kzalloc(sizeof(struct cs6436_54p_fan_data), GFP_KERNEL); + if (!fan_data) { + ret = -ENOMEM; + platform_driver_unregister(&cs6436_54p_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(&cs6436_54p_fan_driver); + kfree(fan_data); + goto exit; + } + +exit: + return ret; +} + +static void __exit cs6436_54p_fan_exit(void) +{ + platform_device_unregister(fan_data->pdev); + platform_driver_unregister(&cs6436_54p_fan_driver); + kfree(fan_data); +} + +MODULE_AUTHOR("CIG"); +MODULE_DESCRIPTION("cs6436_54p_fan driver"); +MODULE_LICENSE("GPL"); + +module_init(cs6436_54p_fan_init); +module_exit(cs6436_54p_fan_exit); + +MODULE_AUTHOR("Zhang Peng "); +MODULE_DESCRIPTION("cs6436_54p_fan driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-led.c b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-led.c new file mode 100644 index 00000000000..74c8b6d0b10 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-led.c @@ -0,0 +1,594 @@ +/* + * A hwmon driver for the CIG cs6436-54P LED + * + * Copyright (C) 2018 Cambridge, 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 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 cig_cpld_write_register(u8 reg_off, u8 val); + +extern int cig_cpld_read_register(u8 reg_off, u8 *val); + +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 "cs6436_54p_led" + +struct cs6436_54p_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[6]; /* 0: system & location + 1: PSU1 &PSU12 + 2: fan & management + 3: console & ToD + 4-5 : fan1-fan5*/ +}; + +static struct cs6436_54p_led_data *ledctl = NULL; + +/* LED related data + */ +#define LED_TYPE_PSU1_REG_MASK 0x0C +#define LED_MODE_PSU1_GREEN_MASK 0x08 +#define LED_MODE_PSU1_RED_MASK 0x04 +#define LED_MODE_PSU1_AMBER_MASK 0x0C +#define LED_MODE_PSU1_OFF_MASK 0x00 + +#define LED_TYPE_PSU2_REG_MASK 0x30 +#define LED_MODE_PSU2_GREEN_MASK 0x20 +#define LED_MODE_PSU2_RED_MASK 0x10 +#define LED_MODE_PSU2_AMBER_MASK 0x30 +#define LED_MODE_PSU2_OFF_MASK 0x00 + +#define LED_TYPE_SYS_REG_MASK 0xF0 +#define LED_MODE_SYS_GREEN_MASK 0x40 +#define LED_MODE_SYS_RED_MASK 0x20 +#define LED_MODE_SYS_AMBER_MASK 0x60 +#define LED_MODE_SYS_AMBER_FLASHING_MASK 0x70 +#define LED_MODE_SYS_OFF_MASK 0x00 + +#define LED_TYPE_RES_REG_MASK 0x0F +#define LED_MODE_RES_GREEN_MASK 0x04 +#define LED_MODE_RES_RED_MASK 0x02 +#define LED_MODE_RES_AMBER_MASK 0x06 +#define LED_MODE_RES_AMBER_FLASHING_MASK 0x07 +#define LED_MODE_RES_OFF_MASK 0x00 + +#define LED_TYPE_FAN_REG_MASK 0x03 +#define LED_MODE_FAN_GREEN_MASK 0x02 +#define LED_MODE_FAN_RED_MASK 0x01 +#define LED_MODE_FAN_AMBER_MASK 0x03 +#define LED_MODE_FAN_OFF_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_MODE_FANX_GREEN_MASK 0x02 +#define LED_MODE_FANX_RED_MASK 0x01 +#define LED_MODE_FANX_AMBER_MASK 0x03 +#define LED_MODE_FANX_OFF_MASK 0x00 + +enum led_type { + LED_TYPE_SYS, + LED_TYPE_PSU2, + LED_TYPE_PSU1, + LED_TYPE_FAN, + LED_TYPE_FAN1, + LED_TYPE_FAN2, + LED_TYPE_FAN3, + LED_TYPE_FAN4, + LED_TYPE_FAN5, +}; + +static const u8 led_reg[] = { + 0x30, /* system & reserved*/ + 0x31, /* fan & PSU1 & PSU2 */ + 0x32, /* FAN5 LED */ + 0x33, /* FAN1-4 LED */ +}; + + +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_GREEN_FLASHING, + LED_MODE_AMBER_FLASHING, + LED_MODE_RED_FLASHING, + LED_MODE_AUTO, + LED_MODE_UNKNOWN +}; + +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_RED, LED_MODE_PSU1_RED_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_RED, LED_MODE_PSU2_RED_MASK}, +{LED_TYPE_PSU2, LED_TYPE_PSU2_REG_MASK, LED_MODE_OFF, LED_MODE_PSU2_OFF_MASK}, + +{LED_TYPE_SYS, LED_TYPE_SYS_REG_MASK, LED_MODE_GREEN, LED_MODE_SYS_GREEN_MASK}, +{LED_TYPE_SYS, LED_TYPE_SYS_REG_MASK, LED_MODE_AMBER, LED_MODE_SYS_AMBER_MASK}, +{LED_TYPE_SYS, LED_TYPE_SYS_REG_MASK, LED_MODE_RED, LED_MODE_SYS_RED_MASK}, +{LED_TYPE_SYS, LED_TYPE_SYS_REG_MASK, LED_MODE_AMBER_FLASHING, LED_MODE_SYS_AMBER_FLASHING_MASK}, +{LED_TYPE_SYS, LED_TYPE_SYS_REG_MASK, LED_MODE_OFF, LED_MODE_SYS_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_RED, LED_MODE_FAN_RED_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_AMBER, LED_MODE_FANX_AMBER_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_AMBER, LED_MODE_FANX_AMBER_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_AMBER, LED_MODE_FANX_AMBER_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_AMBER, LED_MODE_FANX_AMBER_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_AMBER, LED_MODE_FANX_AMBER_MASK << 0}, +{LED_TYPE_FAN5, LED_TYPE_FAN5_REG_MASK, LED_MODE_OFF, LED_MODE_FANX_OFF_MASK << 0}, +}; + +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, 3}, + {'2', LED_TYPE_FAN2, 3}, + {'3', LED_TYPE_FAN3, 3}, + {'4', LED_TYPE_FAN4, 3}, + {'5', LED_TYPE_FAN5, 2}, +}; + + +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)); + break; + } + + return reg_val; +} + +static void cs6436_54p_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 cs6436_54p_led update\n"); + + /* Update LED data + */ + for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) { + u8 status; + cig_cpld_read_register(led_reg[i], &status); + + 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 cs6436_54p_led_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode, + u8 reg, enum led_type type) +{ + u8 reg_val; + mutex_lock(&ledctl->update_lock); + + cig_cpld_read_register(reg, ®_val); + 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); + + cig_cpld_write_register(reg, reg_val); + + /* to prevent the slow-update issue */ + ledctl->valid = 0; + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void cs6436_54p_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; + + cs6436_54p_led_set(led_cdev, led_light_mode, led_reg[reg_id], led_type1); + return; + } + } +} + + +static enum led_brightness cs6436_54p_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; + cs6436_54p_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[5]); +} + + +static void cs6436_54p_led_psu1_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + cs6436_54p_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU1); +} + +static enum led_brightness cs6436_54p_led_psu1_get(struct led_classdev *cdev) +{ + cs6436_54p_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU1, ledctl->reg_val[1]); +} + +static void cs6436_54p_led_psu2_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + cs6436_54p_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU2); +} + +static enum led_brightness cs6436_54p_led_psu2_get(struct led_classdev *cdev) +{ + cs6436_54p_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]); +} + +static void cs6436_54p_led_sys_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + cs6436_54p_led_set(led_cdev, led_light_mode,led_reg[0], LED_TYPE_SYS); +} + +static enum led_brightness cs6436_54p_led_sys_get(struct led_classdev *cdev) +{ + cs6436_54p_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_SYS, ledctl->reg_val[0]); +} + + +static enum led_brightness cs6436_54p_led_fan_get(struct led_classdev *cdev) +{ + cs6436_54p_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[1]); +} + +static void cs6436_54p_led_fan_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + cs6436_54p_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_FAN); +} + + +static struct led_classdev cs6436_54p_leds[] = { + [LED_TYPE_SYS] = { + .name = "cs6436_54p_led::sys", + .default_trigger = "unused", + .brightness_set = cs6436_54p_led_sys_set, + .brightness_get = cs6436_54p_led_sys_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN] = { + .name = "cs6436_54p_led::fan", + .default_trigger = "unused", + .brightness_set = cs6436_54p_led_fan_set, + .brightness_get = cs6436_54p_led_fan_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + + [LED_TYPE_PSU1] = { + .name = "cs6436_54p_led::psu1", + .default_trigger = "unused", + .brightness_set = cs6436_54p_led_psu1_set, + .brightness_get = cs6436_54p_led_psu1_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_PSU2] = { + .name = "cs6436_54p_led::psu2", + .default_trigger = "unused", + .brightness_set = cs6436_54p_led_psu2_set, + .brightness_get = cs6436_54p_led_psu2_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + + [LED_TYPE_FAN1] = { + .name = "cs6436_54p_led::fan1", + .default_trigger = "unused", + .brightness_set = cs6436_54p_led_fanx_set, + .brightness_get = cs6436_54p_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN2] = { + .name = "cs6436_54p_led::fan2", + .default_trigger = "unused", + .brightness_set = cs6436_54p_led_fanx_set, + .brightness_get = cs6436_54p_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN3] = { + .name = "cs6436_54p_led::fan3", + .default_trigger = "unused", + .brightness_set = cs6436_54p_led_fanx_set, + .brightness_get = cs6436_54p_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN4] = { + .name = "cs6436_54p_led::fan4", + .default_trigger = "unused", + .brightness_set = cs6436_54p_led_fanx_set, + .brightness_get = cs6436_54p_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN5] = { + .name = "cs6436_54p_led::fan5", + .default_trigger = "unused", + .brightness_set = cs6436_54p_led_fanx_set, + .brightness_get = cs6436_54p_led_fanx_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AUTO, + } +}; + +static int cs6436_54p_led_suspend(struct platform_device *dev, + pm_message_t state) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(cs6436_54p_leds); i++) { + led_classdev_suspend(&cs6436_54p_leds[i]); + } + + return 0; +} + +static int cs6436_54p_led_resume(struct platform_device *dev) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(cs6436_54p_leds); i++) { + led_classdev_resume(&cs6436_54p_leds[i]); + } + + return 0; +} + +static int cs6436_54p_led_probe(struct platform_device *pdev) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(cs6436_54p_leds); i++) { + ret = led_classdev_register(&pdev->dev, &cs6436_54p_leds[i]); + + if (ret < 0) + break; + } + + /* Check if all LEDs were successfully registered */ + if (i != ARRAY_SIZE(cs6436_54p_leds)) { + int j; + + /* only unregister the LEDs that were successfully registered */ + for (j = 0; j < i; j++) { + led_classdev_unregister(&cs6436_54p_leds[i]); + } + } + + return ret; +} + +static int cs6436_54p_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs6436_54p_leds); i++) { + led_classdev_unregister(&cs6436_54p_leds[i]); + } + + return 0; +} + +static struct platform_driver cs6436_54p_led_driver = { + .probe = cs6436_54p_led_probe, + .remove = cs6436_54p_led_remove, + .suspend = cs6436_54p_led_suspend, + .resume = cs6436_54p_led_resume, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int cs6436_54p_led_default(void) +{ + cig_cpld_write_register(0x30, 0x40);// system green led solid on +} + +static int __init cs6436_54p_led_init(void) +{ + int ret; + + ret = platform_driver_register(&cs6436_54p_led_driver); + if (ret < 0) { + goto exit; + } + + ledctl = kzalloc(sizeof(struct cs6436_54p_led_data), GFP_KERNEL); + if (!ledctl) { + ret = -ENOMEM; + platform_driver_unregister(&cs6436_54p_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(&cs6436_54p_led_driver); + kfree(ledctl); + goto exit; + } + + cs6436_54p_led_default(); + +exit: + return ret; +} + +static void __exit cs6436_54p_led_exit(void) +{ + platform_device_unregister(ledctl->pdev); + platform_driver_unregister(&cs6436_54p_led_driver); + kfree(ledctl); +} + +module_init(cs6436_54p_led_init); +module_exit(cs6436_54p_led_exit); + +MODULE_AUTHOR("Zhang Peng "); +MODULE_DESCRIPTION("cs6436_54p_led driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-psu.c b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-psu.c new file mode 100644 index 00000000000..e8fc896ea13 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-psu.c @@ -0,0 +1,943 @@ +/* + * A hwmon driver for the CIG cs6436-54P Power Module + * + * Copyright (C) 2018 Cambridge, 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 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 +#include +#include +#include +#include +#include "i2c-algo-lpc.h" + + + +#define MAX_FAN_DUTY_CYCLE 100 + +/* Address scanned */ +static const unsigned short normal_i2c[] = {I2C_CLIENT_END }; + +/* This is additional data */ +struct cs6436_54p_psu_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; + unsigned long last_updated; /* In jiffies */ + + /* Registers value */ + u8 vout_mode; + u16 v_in; + u16 v_out; + u16 i_in; + u16 i_out; + u16 p_in; + u16 p_out; + u16 temp_input[3]; + u8 temp_fault; + u8 fan_fault; + u16 fan_duty_cycle[2]; + u16 fan_speed[2]; + u8 mfr_id[8]; + u8 mfr_model[20]; + u8 mfr_serial[20]; + u8 psu_is_present; + u8 psu_is_good; + struct i2c_client *client; + struct bin_attribute *bin; /* eeprom data */ +}; + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask); +static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count); +static ssize_t for_linear_data(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_fan_fault(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_fan_warning(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_temp_fault(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_temp_warning(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_vout_data(struct device *dev, struct device_attribute *dev_attr, char *buf); +static int cs6436_54p_psu_read_byte(struct i2c_client *client, u8 reg); +static int cs6436_54p_psu_read_word(struct i2c_client *client, u8 reg); +static int cs6436_54p_psu_write_word(struct i2c_client *client, u8 reg, u16 value); +static int cs6436_54p_psu_read_block(struct i2c_client *client, u8 command, u8 *data, int data_len); +static struct cs6436_54p_psu_data *cs6436_54p_psu_update_device(struct device *dev); +static ssize_t for_ascii(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_status(struct device *dev, struct device_attribute *dev_attr, char *buf); + +enum cs6436_54p_psu_sysfs_attributes { + PSU_V_IN, + PSU_V_OUT, + PSU_I_IN, + PSU_I_OUT, + PSU_P_IN, + PSU_P_OUT, + PSU_TEMP1_INPUT, + PSU_TEMP2_INPUT, + PSU_TEMP3_INPUT, + PSU_TEMP_FAULT, + PSU_TEMP_WARN, + PSU_FAN1_FAULT, + PSU_FAN1_WARN, + PSU_FAN1_DUTY_CYCLE, + PSU_FAN1_SPEED, + PSU_MFR_ID, + PSU_MFR_MODEL, + PSU_MFR_SERIAL, + PSU_PRESENT, + PSU_P_GOOD, +}; + +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 \ + *dev_attr, const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct i2c_client *client = to_i2c_client(dev); + struct cs6436_54p_psu_data *data = i2c_get_clientdata(client); + int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1; + long speed; + int error; + + if (data->valid != 1) + { + return -ENODEV; + } + + 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; + cs6436_54p_psu_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t for_linear_data(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs6436_54p_psu_data *data = cs6436_54p_psu_update_device(dev); + + u16 value = 0; + int exponent, mantissa; + int multiplier = 1000; + + if (data->valid != 1) + { + return -ENODEV; + } + + 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_TEMP2_INPUT: + value = data->temp_input[1]; + break; + case PSU_TEMP3_INPUT: + value = data->temp_input[2]; + 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 for_fan_fault(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs6436_54p_psu_data *data = cs6436_54p_psu_update_device(dev); + + if (data->valid != 1) + { + return -ENODEV; + } + + u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; + + return sprintf(buf, "%d\n", data->fan_fault >> shift); +} + +static ssize_t for_fan_warning(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs6436_54p_psu_data *data = cs6436_54p_psu_update_device(dev); + + if (data->valid != 1) + { + return -ENODEV; + } + + u8 shift = (attr->index == PSU_FAN1_WARN) ? 5 : 4; + + return sprintf(buf, "%d\n", data->fan_fault >> shift); +} + +static ssize_t for_temp_fault(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs6436_54p_psu_data *data = cs6436_54p_psu_update_device(dev); + + if (data->valid != 1) + { + return -ENODEV; + } + + + + return sprintf(buf, "%d\n", data->temp_fault >> 7); +} + +static ssize_t for_temp_warning(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs6436_54p_psu_data *data = cs6436_54p_psu_update_device(dev); + if (data->valid != 1) + { + return -ENODEV; + } + + + return sprintf(buf, "%d\n", data->temp_fault >> 6); +} +static ssize_t for_vout_data(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct cs6436_54p_psu_data *data = cs6436_54p_psu_update_device(dev); + int exponent, mantissa; + int multiplier = 1000; + if (data->valid != 1) + { + return -ENODEV; + } + + + 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) >> (-exponent))); +} + +static ssize_t for_ascii(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs6436_54p_psu_data *data = cs6436_54p_psu_update_device(dev); + u8 *ptr = NULL; + + if (data->valid != 1) + { + return -ENODEV; + } + + switch (attr->index) { + case PSU_MFR_ID: + ptr = data->mfr_id + 1; + break; + case PSU_MFR_MODEL: + ptr = data->mfr_model + 1; + break; + case PSU_MFR_SERIAL: + ptr = data->mfr_serial + 1; + break; + default: + return 0; + } + return sprintf(buf, "%s\n", ptr); +} + + +static ssize_t for_status(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs6436_54p_psu_data *data = cs6436_54p_psu_update_device(dev); + u8 *ptr = NULL; + + u8 status = 0; + + if (attr->index == PSU_PRESENT) { + status = data->psu_is_present; + } + else { /* PSU_POWER_GOOD */ + if (!data->valid) { + return -ENODEV; + } + + status = data->psu_is_good; + } + + return sprintf(buf, "%d\n", status); +} + + +static int cs6436_54p_psu_read_byte(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int cs6436_54p_psu_read_word(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_word_data(client, reg); +} + +static int cs6436_54p_psu_write_word(struct i2c_client *client, u8 reg, \ + u16 value) +{ + union i2c_smbus_data data; + data.word = value; + return i2c_smbus_xfer(client->adapter, client->addr, + client->flags |= I2C_CLIENT_PEC, + I2C_SMBUS_WRITE, reg, + I2C_SMBUS_WORD_DATA, &data); + +} + +static int cs6436_54p_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; + +} + +struct reg_data_byte { + u8 reg; + u8 *value; +}; + +struct reg_data_word { + u8 reg; + u16 *value; +}; + + + +#define EEPROM_NAME "psu_eeprom" +#define EEPROM_SIZE 256 /* 256 byte eeprom */ + +/* Platform dependent --- */ +static ssize_t psu_eeprom_write(struct i2c_client *client, u8 command, const char *data, + int data_len) +{ + int status, retry = 3; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_write_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(100); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + return status; + } + + return data_len; + +} + + +static ssize_t psu_page_write(struct i2c_client *client,const char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + return count; + } + + /* + * Write data to chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + + + while (count) { + ssize_t status; + + status = psu_eeprom_write(client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + buf += status; + off += status; + count -= status; + retval += status; + } + + + return retval; +} + + + +static ssize_t psu_bin_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct cs6436_54p_psu_data *data; + ssize_t retval = 0; + struct i2c_client *client; + + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + client = to_i2c_client(container_of(kobj, struct device, kobj)); + + mutex_lock(&data->update_lock); + retval = psu_page_write(client, buf, off, count); + mutex_unlock(&data->update_lock); + return retval; +} + + +static ssize_t psu_eeprom_read(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int status, retry = 3; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(100); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + goto abort; + } + if (unlikely(status != data_len)) { + status = -EIO; + goto abort; + } + +abort: + return status; +} + + + +static ssize_t psu_page_read(struct i2c_client *client,char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + printk("Count = 0, return"); + return count; + } + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + + + while (count) { + ssize_t status; + + status = psu_eeprom_read(client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + + buf += status; + off += status; + count -= status; + retval += status; + } + + + return retval; + +} + + +static ssize_t psu_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct cs6436_54p_psu_data *data; + struct i2c_client *client; + ssize_t retval = 0; + + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + client = to_i2c_client(container_of(kobj, struct device, kobj)); + mutex_lock(&data->update_lock); + retval = psu_page_read(client, buf, off, count); + mutex_unlock(&data->update_lock); + + return retval; +} + + + +static int psu_sysfs_eeprom_init(struct kobject *kobj, struct bin_attribute *eeprom) +{ + int err; + + sysfs_bin_attr_init(eeprom); + eeprom->attr.name = EEPROM_NAME; + eeprom->attr.mode = S_IWUSR | S_IRUGO; + eeprom->read = psu_bin_read; + eeprom->write = psu_bin_write; + eeprom->size = EEPROM_SIZE; + + /* Create eeprom file */ + err = sysfs_create_bin_file(kobj, eeprom); + if (err) { + return err; + } + + return 0; +} + + +static int psu_sysfs_eeprom_cleanup(struct kobject *kobj, struct bin_attribute *eeprom) +{ + sysfs_remove_bin_file(kobj, eeprom); + return 0; +} + + +static int psu_i2c_check_functionality(struct i2c_client *client) +{ + return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK); +} + + + +static int psu_eeprom_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) +{ + int status; + + struct cs6436_54p_psu_data *data; + + if (!psu_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + mutex_init(&data->update_lock); + + data->bin = kzalloc(sizeof(struct bin_attribute), GFP_KERNEL); + if (!data->bin) { + status = -ENOMEM; + goto eeprom_bin_error; + } + + /* init eeprom */ + status = psu_sysfs_eeprom_init(&client->dev.kobj, data->bin); + if (status) { + status = -ENOMEM; + goto sys_init_error; + } + + dev_info(&client->dev, "psu eeprom '%s'\n", client->name); + + return 0; + + sys_init_error: + kfree(data->bin); + + eeprom_bin_error: + kfree(data); + + exit: + return status; +} + + + + +static struct cs6436_54p_psu_data *cs6436_54p_psu_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cs6436_54p_psu_data *data = i2c_get_clientdata(client); + + + mutex_lock(&data->update_lock); + + + if (time_after(jiffies, data->last_updated)) { + int i, status; + u8 command; + struct reg_data_byte regs_byte[] = { + {0x20, &data->vout_mode}, + {0x81, &data->fan_fault}, + {0x7d, &data->temp_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])}, + {0x90, &(data->fan_speed[0])}, + }; + data->valid = 1; + + dev_dbg(&client->dev, "start data update\n"); + + /* one milliseconds from now */ + data->last_updated = jiffies + HZ / 1000; + + for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { + status = cs6436_54p_psu_read_byte(client, + regs_byte[i].reg); + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_byte[i].reg, status); + *(regs_byte[i].value) = 0; + data->valid = 0; + } else { + *(regs_byte[i].value) = status; + } + } + + for (i = 0; i < ARRAY_SIZE(regs_word); i++) { + status = cs6436_54p_psu_read_word(client, + regs_word[i].reg); + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_word[i].reg, status); + *(regs_word[i].value) = 0; + data->valid = 0; + } else { + *(regs_word[i].value) = status; + } + } + + command = 0x99; /* PSU mfr_id */ + status = cs6436_54p_psu_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); + memset(data->mfr_id, 0, sizeof(data->mfr_id)); + data->valid = 0; + } + + command = 0x9a; /* PSU mfr_model */ + status = cs6436_54p_psu_read_block(client, command, + data->mfr_model, ARRAY_SIZE(data->mfr_model) - 1); + data->mfr_model[ARRAY_SIZE(data->mfr_model) - 1] = '\0'; + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + memset(data->mfr_model, 0, sizeof(data->mfr_id)); + data->valid = 0; + } + + command = 0x9e; /* PSU mfr_serial */ + status = cs6436_54p_psu_read_block(client, command, + data->mfr_serial, ARRAY_SIZE(data->mfr_serial) - 1); + data->mfr_serial[ARRAY_SIZE(data->mfr_serial) - 1] = '\0'; + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + memset(data->mfr_serial, 0, sizeof(data->mfr_id)); + data->valid = 0; + } + + data->psu_is_present = strlen(data->mfr_id) > 1 ? 1:0; + if(data->psu_is_present) + { + data->psu_is_good = ((data->fan_fault) || (data->temp_fault))? 0:1; + } + else + { + data->valid = 0; + data->psu_is_good = 0; + } + } + + mutex_unlock(&data->update_lock); + + return data; + +} + +/* sysfs attributes for hwmon */ +static SENSOR_DEVICE_ATTR(psu_v_in, S_IRUGO, for_linear_data, NULL, PSU_V_IN); +static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, for_vout_data, NULL, PSU_V_OUT); +static SENSOR_DEVICE_ATTR(psu_i_in, S_IRUGO, for_linear_data, NULL, PSU_I_IN); +static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, for_linear_data, NULL, PSU_I_OUT); +static SENSOR_DEVICE_ATTR(psu_p_in, S_IRUGO, for_linear_data, NULL, PSU_P_IN); +static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, for_linear_data, NULL, PSU_P_OUT); +static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, for_linear_data, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp2_input, S_IRUGO, for_linear_data, NULL, PSU_TEMP2_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp3_input, S_IRUGO, for_linear_data, NULL, PSU_TEMP3_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp_fault, S_IRUGO, for_temp_fault, NULL, PSU_TEMP_FAULT); +static SENSOR_DEVICE_ATTR(psu_temp_warning, S_IRUGO, for_temp_warning, NULL, PSU_TEMP_WARN); +static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, for_fan_fault, NULL, PSU_FAN1_FAULT); +static SENSOR_DEVICE_ATTR(psu_fan1_warning, S_IRUGO, for_fan_warning, NULL, PSU_FAN1_WARN); +static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, for_linear_data, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE); +static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, for_linear_data, NULL, PSU_FAN1_SPEED); +static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, for_ascii, NULL, PSU_MFR_ID); +static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, for_ascii, NULL, PSU_MFR_MODEL); +static SENSOR_DEVICE_ATTR(psu_mfr_serial, S_IRUGO, for_ascii, NULL, PSU_MFR_SERIAL); +static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, for_status, NULL, PSU_PRESENT); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, for_status, NULL, PSU_P_GOOD); + + + +static struct attribute *cs6436_54p_psu_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_temp2_input.dev_attr.attr, + &sensor_dev_attr_psu_temp3_input.dev_attr.attr, + &sensor_dev_attr_psu_temp_fault.dev_attr.attr, + &sensor_dev_attr_psu_temp_warning.dev_attr.attr, + &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, + &sensor_dev_attr_psu_fan1_warning.dev_attr.attr, + &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, + &sensor_dev_attr_psu_fan1_speed_rpm.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_serial.dev_attr.attr, + &sensor_dev_attr_psu_present.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + NULL +}; + +static const struct attribute_group cs6436_54p_psu_group = { + .attrs = cs6436_54p_psu_attributes, +}; + + +static int psu_register_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int status; + + + struct cs6436_54p_psu_data *data; + + if (!psu_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + mutex_init(&data->update_lock); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &cs6436_54p_psu_group); + if (status) + goto exit_sysfs_create_group; + + cs6436_54p_sysfs_add_client(client); + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_hwmon_device_register; + } + + /* init eeprom */ + + return 0; + + exit_hwmon_device_register: + sysfs_remove_group(&client->dev.kobj, &cs6436_54p_psu_group); + exit_sysfs_create_group: + kfree(data); + exit: + return status; + +} + + +static int cs6436_54p_psu_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int status; + + if((client->addr == 0x52) ||(client->addr == 0x53)) + { + status = psu_eeprom_probe(client, id); + } + else if((client->addr == 0x5a) ||(client->addr == 0x5b)) + { + status = psu_register_probe(client, id); + } + return status; +} + +static int cs6436_54p_psu_remove(struct i2c_client *client) +{ + cs6436_54p_sysfs_remove_client(client); + + if((client->addr == 0x52) ||(client->addr == 0x53)) + { + struct cs6436_54p_psu_data *data; + data = i2c_get_clientdata(client); + psu_sysfs_eeprom_cleanup(&client->dev.kobj,data->bin); + kfree(data); + } + else if((client->addr == 0x5a) ||(client->addr == 0x5b)) + { + struct cs6436_54p_psu_data *data; + data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &cs6436_54p_psu_group); + kfree(data); + } + + return 0; +} + +enum psu_index +{ + cs6436_54p_psu1, + cs6436_54p_psu2 +}; + +static const struct i2c_device_id cs6436_54p_psu_id[] = { + { "cs6436_54p_psu1", cs6436_54p_psu1 }, + { "cs6436_54p_psu2", cs6436_54p_psu2 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, cs6436_54p_psu_id); + +static struct i2c_driver cs6436_54p_psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "cs6436_54p_psu", + }, + .probe = cs6436_54p_psu_probe, + .remove = cs6436_54p_psu_remove, + .id_table = cs6436_54p_psu_id, + .address_list = normal_i2c, +}; + +module_i2c_driver(cs6436_54p_psu_driver); + +MODULE_AUTHOR("Zhang Peng "); +MODULE_DESCRIPTION("cs6436_54p_psu driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-sfp.c b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-sfp.c new file mode 100644 index 00000000000..5d02bd849a5 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-sfp.c @@ -0,0 +1,1713 @@ +/* + * A hwmon driver for the CIG cs6436-54P SFP Module + * + * Copyright (C) 2018 Cambridge, 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 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 "i2c-algo-lpc.h" + +#define DRIVER_NAME "cs6436_54p_sfp" /* Platform dependent */ + +#define DEBUG_MODE 0 + +#if (DEBUG_MODE == 1) + #define DEBUG_PRINT(fmt, args...) \ + printk (KERN_INFO "%s:%s[%d]: " fmt "\r\n", __FILE__, __FUNCTION__, __LINE__, ##args) +#else + #define DEBUG_PRINT(fmt, args...) +#endif + +#define EEPROM_NAME "sfp_eeprom" +#define EEPROM_SIZE 256 /* 256 byte eeprom */ +#define BIT_INDEX(i) (1ULL << (i)) +#define USE_I2C_BLOCK_READ 1 /* Platform dependent */ +#define I2C_RW_RETRY_COUNT 3 +#define I2C_RW_RETRY_INTERVAL 100 /* ms */ + +#define SFP_EEPROM_A0_I2C_ADDR (0xA0 >> 1) +#define SFP_EEPROM_A2_I2C_ADDR (0xA2 >> 1) + +#define SFF8024_PHYSICAL_DEVICE_ID_ADDR 0x0 +#define SFF8024_DEVICE_ID_SFP 0x3 +#define SFF8024_DEVICE_ID_QSFP 0xC +#define SFF8024_DEVICE_ID_QSFP_PLUS 0xD +#define SFF8024_DEVICE_ID_QSFP28 0x11 + +#define SFF8472_DIAG_MON_TYPE_ADDR 92 +#define SFF8472_DIAG_MON_TYPE_DDM_MASK 0x40 +#define SFF8472_10G_ETH_COMPLIANCE_ADDR 0x3 +#define SFF8472_10G_BASE_MASK 0xF0 + +#define SFF8436_RX_LOS_ADDR 3 +#define SFF8436_TX_FAULT_ADDR 4 +#define SFF8436_TX_DISABLE_ADDR 86 +#define QSFP_RESET_ADDR 0x1b +#define QSFP_INTER_ADDR 0x1a +#define QSFP_LPMODE_ADDR 0x1c + +static ssize_t show_port_number(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_port_type(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_present(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t sfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t sfp_set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t qsfp_set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count);; +static ssize_t sfp_show_ddm_implemented(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t sfp_eeprom_read(struct i2c_client *, u8, u8 *,int); +static ssize_t sfp_eeprom_write(struct i2c_client *, u8 , const char *,int); +extern int cig_cpld_read_register(u8 reg_off, u8 *val); +extern int cig_cpld_write_register(u8 reg_off, u8 val); + +static ssize_t qsfp_reset_read(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_reset_write(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t qsfp_inter_read(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_lpmode_read(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_lpmode_write(struct device *dev, struct device_attribute *da, const char *buf, size_t count); + +enum sfp_sysfs_attributes { + PRESENT, + PRESENT_ALL, + PORT_NUMBER, + PORT_TYPE, + DDM_IMPLEMENTED, + TX_FAULT, + TX_FAULT1, + TX_FAULT2, + TX_FAULT3, + TX_FAULT4, + TX_DISABLE, + TX_DISABLE1, + TX_DISABLE2, + TX_DISABLE3, + TX_DISABLE4, + RX_LOS, + RX_LOS1, + RX_LOS2, + RX_LOS3, + RX_LOS4, + RX_LOS_ALL, + QSFPRESET, + QSFPINT, + QSFPLPMODE +}; + +/* SFP/QSFP common attributes for sysfs */ +static SENSOR_DEVICE_ATTR(sfp_port_number, S_IRUGO, show_port_number, NULL, PORT_NUMBER); +static SENSOR_DEVICE_ATTR(sfp_port_type, S_IRUGO, show_port_type, NULL, PORT_TYPE); +static SENSOR_DEVICE_ATTR(sfp_is_present, S_IRUGO, show_present, NULL, PRESENT); +static SENSOR_DEVICE_ATTR(sfp_is_present_all, S_IRUGO, show_present, NULL, PRESENT_ALL); +static SENSOR_DEVICE_ATTR(sfp_rx_los, S_IRUGO, sfp_show_tx_rx_status, NULL, RX_LOS); +static SENSOR_DEVICE_ATTR(sfp_tx_disable, S_IWUSR | S_IRUGO, sfp_show_tx_rx_status, sfp_set_tx_disable, TX_DISABLE); +static SENSOR_DEVICE_ATTR(sfp_tx_fault, S_IRUGO, sfp_show_tx_rx_status, NULL, TX_FAULT); + +/* QSFP attributes for sysfs */ +static SENSOR_DEVICE_ATTR(sfp_rx_los1, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS1); +static SENSOR_DEVICE_ATTR(sfp_rx_los2, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS2); +static SENSOR_DEVICE_ATTR(sfp_rx_los3, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS3); +static SENSOR_DEVICE_ATTR(sfp_rx_los4, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS4); +static SENSOR_DEVICE_ATTR(sfp_tx_disable1, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE1); +static SENSOR_DEVICE_ATTR(sfp_tx_disable2, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE2); +static SENSOR_DEVICE_ATTR(sfp_tx_disable3, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE3); +static SENSOR_DEVICE_ATTR(sfp_tx_disable4, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE4); +static SENSOR_DEVICE_ATTR(sfp_tx_fault1, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT1); +static SENSOR_DEVICE_ATTR(sfp_tx_fault2, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT2); +static SENSOR_DEVICE_ATTR(sfp_tx_fault3, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT3); +static SENSOR_DEVICE_ATTR(sfp_tx_fault4, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT4); +static SENSOR_DEVICE_ATTR(sfp_reset, S_IWUSR | S_IRUGO, qsfp_reset_read, qsfp_reset_write, QSFPRESET); +static SENSOR_DEVICE_ATTR(sfp_inter, S_IRUGO, qsfp_inter_read, NULL, QSFPINT); +static SENSOR_DEVICE_ATTR(sfp_lpmode, S_IWUSR | S_IRUGO, qsfp_lpmode_read, qsfp_lpmode_write, QSFPLPMODE); +static struct attribute *qsfp_attributes[] = { + &sensor_dev_attr_sfp_port_number.dev_attr.attr, + &sensor_dev_attr_sfp_port_type.dev_attr.attr, + &sensor_dev_attr_sfp_is_present.dev_attr.attr, + &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los1.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los2.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los3.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los4.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable1.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable2.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable3.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable4.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault1.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault2.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault3.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault4.dev_attr.attr, + &sensor_dev_attr_sfp_reset.dev_attr.attr, + &sensor_dev_attr_sfp_inter.dev_attr.attr, + &sensor_dev_attr_sfp_lpmode.dev_attr.attr, + NULL +}; + +/* SFP msa attributes for sysfs */ +static SENSOR_DEVICE_ATTR(sfp_ddm_implemented, S_IRUGO, sfp_show_ddm_implemented, NULL, DDM_IMPLEMENTED); +static SENSOR_DEVICE_ATTR(sfp_rx_los_all, S_IRUGO, sfp_show_tx_rx_status, NULL, RX_LOS_ALL); +static struct attribute *sfp_msa_attributes[] = { + &sensor_dev_attr_sfp_port_number.dev_attr.attr, + &sensor_dev_attr_sfp_port_type.dev_attr.attr, + &sensor_dev_attr_sfp_is_present.dev_attr.attr, + &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, + &sensor_dev_attr_sfp_ddm_implemented.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los_all.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable.dev_attr.attr, + NULL +}; + +/* SFP ddm attributes for sysfs */ +static struct attribute *sfp_ddm_attributes[] = { + NULL +}; + +/* Platform dependent +++ */ +#define CPLD_PORT_TO_FRONT_PORT(port) (port+1) + +enum port_numbers { +cs6436_54p_sfp1, cs6436_54p_sfp2, cs6436_54p_sfp3, cs6436_54p_sfp4, +cs6436_54p_sfp5, cs6436_54p_sfp6, cs6436_54p_sfp7, cs6436_54p_sfp8, +cs6436_54p_sfp9, cs6436_54p_sfp10, cs6436_54p_sfp11, cs6436_54p_sfp12, +cs6436_54p_sfp13, cs6436_54p_sfp14, cs6436_54p_sfp15, cs6436_54p_sfp16, +cs6436_54p_sfp17, cs6436_54p_sfp18, cs6436_54p_sfp19, cs6436_54p_sfp20, +cs6436_54p_sfp21, cs6436_54p_sfp22, cs6436_54p_sfp23, cs6436_54p_sfp24, +cs6436_54p_sfp25, cs6436_54p_sfp26, cs6436_54p_sfp27, cs6436_54p_sfp28, +cs6436_54p_sfp29, cs6436_54p_sfp30, cs6436_54p_sfp31, cs6436_54p_sfp32, +cs6436_54p_sfp33, cs6436_54p_sfp34, cs6436_54p_sfp35, cs6436_54p_sfp36, +cs6436_54p_sfp37, cs6436_54p_sfp38, cs6436_54p_sfp39, cs6436_54p_sfp40, +cs6436_54p_sfp41, cs6436_54p_sfp42, cs6436_54p_sfp43, cs6436_54p_sfp44, +cs6436_54p_sfp45, cs6436_54p_sfp46, cs6436_54p_sfp47, cs6436_54p_sfp48, +cs6436_54p_sfp49, cs6436_54p_sfp50, cs6436_54p_sfp51, cs6436_54p_sfp52, +cs6436_54p_sfp53, cs6436_54p_sfp54, cs6436_54p_sfp55, cs6436_54p_sfp56 +}; + +#define I2C_DEV_ID(x) { #x, x} + +static const struct i2c_device_id sfp_device_id[] = { +I2C_DEV_ID(cs6436_54p_sfp1), +I2C_DEV_ID(cs6436_54p_sfp2), +I2C_DEV_ID(cs6436_54p_sfp3), +I2C_DEV_ID(cs6436_54p_sfp4), +I2C_DEV_ID(cs6436_54p_sfp5), +I2C_DEV_ID(cs6436_54p_sfp6), +I2C_DEV_ID(cs6436_54p_sfp7), +I2C_DEV_ID(cs6436_54p_sfp8), +I2C_DEV_ID(cs6436_54p_sfp9), +I2C_DEV_ID(cs6436_54p_sfp10), +I2C_DEV_ID(cs6436_54p_sfp11), +I2C_DEV_ID(cs6436_54p_sfp12), +I2C_DEV_ID(cs6436_54p_sfp13), +I2C_DEV_ID(cs6436_54p_sfp14), +I2C_DEV_ID(cs6436_54p_sfp15), +I2C_DEV_ID(cs6436_54p_sfp16), +I2C_DEV_ID(cs6436_54p_sfp17), +I2C_DEV_ID(cs6436_54p_sfp18), +I2C_DEV_ID(cs6436_54p_sfp19), +I2C_DEV_ID(cs6436_54p_sfp20), +I2C_DEV_ID(cs6436_54p_sfp21), +I2C_DEV_ID(cs6436_54p_sfp22), +I2C_DEV_ID(cs6436_54p_sfp23), +I2C_DEV_ID(cs6436_54p_sfp24), +I2C_DEV_ID(cs6436_54p_sfp25), +I2C_DEV_ID(cs6436_54p_sfp26), +I2C_DEV_ID(cs6436_54p_sfp27), +I2C_DEV_ID(cs6436_54p_sfp28), +I2C_DEV_ID(cs6436_54p_sfp29), +I2C_DEV_ID(cs6436_54p_sfp30), +I2C_DEV_ID(cs6436_54p_sfp31), +I2C_DEV_ID(cs6436_54p_sfp32), +I2C_DEV_ID(cs6436_54p_sfp33), +I2C_DEV_ID(cs6436_54p_sfp34), +I2C_DEV_ID(cs6436_54p_sfp35), +I2C_DEV_ID(cs6436_54p_sfp36), +I2C_DEV_ID(cs6436_54p_sfp37), +I2C_DEV_ID(cs6436_54p_sfp38), +I2C_DEV_ID(cs6436_54p_sfp39), +I2C_DEV_ID(cs6436_54p_sfp40), +I2C_DEV_ID(cs6436_54p_sfp41), +I2C_DEV_ID(cs6436_54p_sfp42), +I2C_DEV_ID(cs6436_54p_sfp43), +I2C_DEV_ID(cs6436_54p_sfp44), +I2C_DEV_ID(cs6436_54p_sfp45), +I2C_DEV_ID(cs6436_54p_sfp46), +I2C_DEV_ID(cs6436_54p_sfp47), +I2C_DEV_ID(cs6436_54p_sfp48), +I2C_DEV_ID(cs6436_54p_sfp49), +I2C_DEV_ID(cs6436_54p_sfp50), +I2C_DEV_ID(cs6436_54p_sfp51), +I2C_DEV_ID(cs6436_54p_sfp52), +I2C_DEV_ID(cs6436_54p_sfp53), +I2C_DEV_ID(cs6436_54p_sfp54), +I2C_DEV_ID(cs6436_54p_sfp55), +I2C_DEV_ID(cs6436_54p_sfp56), +{ /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i2c, sfp_device_id); + +/* + * list of valid port types + * note OOM_PORT_TYPE_NOT_PRESENT to indicate no + * module is present in this port + */ +typedef enum oom_driver_port_type_e { + OOM_DRIVER_PORT_TYPE_INVALID, + OOM_DRIVER_PORT_TYPE_NOT_PRESENT, + OOM_DRIVER_PORT_TYPE_SFP, + OOM_DRIVER_PORT_TYPE_SFP_PLUS, + OOM_DRIVER_PORT_TYPE_QSFP, + OOM_DRIVER_PORT_TYPE_QSFP_PLUS, + OOM_DRIVER_PORT_TYPE_QSFP28 +} oom_driver_port_type_t; + +enum driver_type_e { + DRIVER_TYPE_SFP_MSA, + DRIVER_TYPE_SFP_DDM, + DRIVER_TYPE_QSFP +}; + +/* Each client has this additional data + */ +struct eeprom_data { + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + struct bin_attribute bin; /* eeprom data */ +}; + +struct sfp_msa_data { + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u64 status[6]; /* bit0:port0, bit1:port1 and so on */ + /* index 0 => tx_fail + 1 => tx_disable + 2 => rx_loss + 3 => device id + 4 => 10G Ethernet Compliance Codes + to distinguish SFP or SFP+ + 5 => DIAGNOSTIC MONITORING TYPE */ + struct eeprom_data eeprom; +}; + +struct sfp_ddm_data { + struct eeprom_data eeprom; +}; + +struct qsfp_data { + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 status[3]; /* bit0:port0, bit1:port1 and so on */ + /* index 0 => tx_fail + 1 => tx_disable + 2 => rx_loss */ + + u8 device_id; + struct eeprom_data eeprom; +}; + +struct sfp_port_data { + struct mutex update_lock; + enum driver_type_e driver_type; + int port; /* CPLD port index */ + oom_driver_port_type_t port_type; + u64 present; /* present status, bit0:port0, bit1:port1 and so on */ + + struct sfp_msa_data *msa; + struct sfp_ddm_data *ddm; + struct qsfp_data *qsfp; + + struct i2c_client *client; +}; + +static ssize_t show_port_number(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + return sprintf(buf, "%d\n", CPLD_PORT_TO_FRONT_PORT(data->port)); +} + + + +static int cig_cpld_write_sfp_register(u8 sfp_reg_addr, u8 sfp_write_reg_data) +{ + u8 sfp_read_status = 0; + u8 wait_time_out = WAIT_TIME_OUT_COUNT; + + cig_cpld_write_register(ADDR_REG_SFP_STATUS_ADDR, sfp_reg_addr << 1); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_TX, sfp_write_reg_data); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_COMMAND, 0x80); + do{ + cig_cpld_read_register(ADDR_REG_SFP_STATUS_STATUS, &sfp_read_status); + udelay(60); + wait_time_out--; + if(wait_time_out == 0) + break; + }while(sfp_read_status != 0x02); + + if(wait_time_out == 0) + return -1; + + return 1; +} + + +static int cig_cpld_read_sfp_register(u8 sfp_reg_addr, u8 *sfp_read_reg_data) +{ + u8 sfp_read_status = 0; + u8 wait_time_out = WAIT_TIME_OUT_COUNT; + + cig_cpld_write_register(ADDR_REG_SFP_STATUS_ADDR, sfp_reg_addr << 1 | 1); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_COMMAND, 0x80); + do{ + udelay(60); + cig_cpld_read_register(ADDR_REG_SFP_STATUS_STATUS, &sfp_read_status); + wait_time_out--; + if(wait_time_out == 0) + break; + }while(sfp_read_status != 0x01); + + cig_cpld_read_register(ADDR_REG_SFP_STATUS_RX,sfp_read_reg_data); + + if(wait_time_out == 0) + return -1; + + return 1; +} + + + + + + +/* Platform dependent +++ */ +static struct sfp_port_data *sfp_update_present(struct i2c_client *client) +{ + int i = 0, j = 0, status = -1; + unsigned char cpld_reg_data = 0,cpld_reg_addr = 0; + struct sfp_port_data *data = i2c_get_clientdata(client); + + DEBUG_PRINT("Starting sfp present status update"); + mutex_lock(&data->update_lock); + data->present = 0; + + udelay(6000); + + /* Read present status of port 1~48(SFP port) */ + for (i = 0; i < 6; i++) { + cpld_reg_addr = 1 + i; + + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); + + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_reg_addr, cpld_reg_data, status); + goto exit; + } + + data->present |= (u64)cpld_reg_data << (i*8); + + DEBUG_PRINT("Present status = 0x%lx\r\n", data->present); + } + + /* Read present status of port 49-56(QSFP port) */ + cpld_reg_addr = 25; + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_reg_addr, cpld_reg_data, status); + goto exit; + } + else { + data->present |= (u64)cpld_reg_data << 48; + } + + DEBUG_PRINT("Present status = 0x%lx", data->present); +exit: + mutex_unlock(&data->update_lock); + return (status < 0) ? ERR_PTR(status) : data; +} + +static struct sfp_port_data *sfp_update_tx_rx_status(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + int i = 0, j = 0; + int status = -1; + unsigned char cpld_reg_data = 0,cpld_reg_addr = 0; + + if (time_before(jiffies, data->msa->last_updated + HZ + HZ / 2) && data->msa->valid) { + return data; + } + + DEBUG_PRINT("Starting cs6436_54p sfp tx rx status update"); + mutex_lock(&data->update_lock); + data->msa->valid = 0; + memset(data->msa->status, 0, sizeof(data->msa->status)); + + udelay(6000); + + /* Read status of port 1~48(SFP port) */ + for (i = 0; i < 6; i++) { + cpld_reg_addr = 13+i; + + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_reg_addr, cpld_reg_data, status); + goto exit; + } + + data->msa->status[0] |= (u64)cpld_reg_data << (i * 8); + + DEBUG_PRINT("tx rx status[0] = 0x%lx\r\n", data->msa->status[0]); + } + + + for (i = 0; i < 6; i++) { + cpld_reg_addr = 19+i; + + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_reg_addr, cpld_reg_data, status); + goto exit; + } + + data->msa->status[1] |= (u64)cpld_reg_data << (i * 8); + + DEBUG_PRINT("tx rx status[1] = 0x%lx\r\n", data->msa->status[1]); + } + + for (i = 0; i < 6; i++) { + cpld_reg_addr = 7+i; + + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_reg_addr, cpld_reg_data, status); + goto exit; + } + + data->msa->status[2] |= (u64)cpld_reg_data << (i * 8); + + DEBUG_PRINT("tx rx status[2] = 0x%lx\r\n", data->msa->status[2]); + } + + data->msa->valid = 1; + data->msa->last_updated = jiffies; + +exit: + mutex_unlock(&data->update_lock); + return (status < 0) ? ERR_PTR(status) : data; +} + +static ssize_t sfp_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 sfp_port_data *data = i2c_get_clientdata(client); + unsigned char cpld_reg_data = 0,cpld_reg_addr = 0,cpld_reg_bit = 0,cpld_reg_val = 0; + long disable; + int error; + + if (data->driver_type == DRIVER_TYPE_QSFP) { + return qsfp_set_tx_disable(dev, da, buf, count); + } + + error = kstrtol(buf, 10, &disable); + if (error) { + return error; + } + + mutex_lock(&data->update_lock); + + udelay(6000); + + if(data->port <= 48) { + cpld_reg_addr = 19 + data->port / 8; + cpld_reg_bit = 1 << ((data->port) % 8); + } + + /* Read current status */ + error = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); + + /* Update tx_disable status */ + if (disable) { + data->msa->status[1] |= BIT_INDEX(data->port); + cpld_reg_data |= cpld_reg_bit; + } + else { + data->msa->status[1] &= ~ BIT_INDEX(data->port); + cpld_reg_data &= ~cpld_reg_bit; + } + + error = cig_cpld_write_sfp_register(cpld_reg_addr,cpld_reg_data); + + mutex_unlock(&data->update_lock); + return count; +} +/* Platform dependent --- */ + +static int sfp_is_port_present(struct i2c_client *client, int port) +{ + struct sfp_port_data *data = i2c_get_clientdata(client); + + data = sfp_update_present(client); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + return !(data->present & BIT_INDEX(data->port)); /* Platform dependent */ +} + +/* Platform dependent +++ */ +static ssize_t show_present(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); + + if (PRESENT_ALL == attr->index) { + int i; + u8 values[7] = {0}; + struct sfp_port_data *data = sfp_update_present(client); + + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + for (i = 0; i < ARRAY_SIZE(values); i++) { + values[i] = ~(u8)(data->present >> (i * 8)); + } + + /* Return values 1 -> 56 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]); + } + else { + struct sfp_port_data *data = i2c_get_clientdata(client); + int present = sfp_is_port_present(client, data->port); + + if (IS_ERR_VALUE(present)) { + return present; + } + + /* PRESENT */ + return sprintf(buf, "%d\n", present); + } +} +/* Platform dependent --- */ + +static struct sfp_port_data *sfp_update_port_type(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + u8 buf = 0; + int status; + + mutex_lock(&data->update_lock); + + switch (data->driver_type) { + case DRIVER_TYPE_SFP_MSA: + { + status = sfp_eeprom_read(client, SFF8024_PHYSICAL_DEVICE_ID_ADDR, &buf, sizeof(buf)); + if (unlikely(status < 0)) { + data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; + break; + } + + if (buf != SFF8024_DEVICE_ID_SFP) { + data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; + break; + } + + status = sfp_eeprom_read(client, SFF8472_10G_ETH_COMPLIANCE_ADDR, &buf, sizeof(buf)); + if (unlikely(status < 0)) { + data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; + break; + } + + DEBUG_PRINT("sfp port type (0x3) data = (0x%x)", buf); + data->port_type = buf & SFF8472_10G_BASE_MASK ? OOM_DRIVER_PORT_TYPE_SFP_PLUS : OOM_DRIVER_PORT_TYPE_SFP; + break; + } + case DRIVER_TYPE_QSFP: + { + status = sfp_eeprom_read(client, SFF8024_PHYSICAL_DEVICE_ID_ADDR, &buf, sizeof(buf)); + if (unlikely(status < 0)) { + data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; + break; + } + + DEBUG_PRINT("qsfp port type (0x0) buf = (0x%x)", buf); + switch (buf) { + case SFF8024_DEVICE_ID_QSFP: + data->port_type = OOM_DRIVER_PORT_TYPE_QSFP; + break; + case SFF8024_DEVICE_ID_QSFP_PLUS: + data->port_type = OOM_DRIVER_PORT_TYPE_QSFP_PLUS; + break; + case SFF8024_DEVICE_ID_QSFP28: + data->port_type = OOM_DRIVER_PORT_TYPE_QSFP_PLUS; + break; + default: + data->port_type = buf; + break; + } + + break; + } + default: + break; + } + + mutex_unlock(&data->update_lock); + return data; +} + +static ssize_t show_port_type(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + int present = sfp_is_port_present(client, data->port); + + if (IS_ERR_VALUE(present)) { + return present; + } + + if (!present) { + /* port is not present */ + return sprintf(buf, "%d\n", OOM_DRIVER_PORT_TYPE_NOT_PRESENT); + } + + sfp_update_port_type(dev); + return sprintf(buf, "%d\n", data->port_type); +} + +static struct sfp_port_data *qsfp_update_tx_rx_status(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + int i, status = -1; + u8 buf = 0; + u8 reg[] = {SFF8436_TX_FAULT_ADDR, SFF8436_TX_DISABLE_ADDR, SFF8436_RX_LOS_ADDR}; + + DEBUG_PRINT(""); + if (time_before(jiffies, data->qsfp->last_updated + HZ + HZ / 2) && data->qsfp->valid) { + return data; + } + + DEBUG_PRINT("Starting sfp tx rx status update"); + mutex_lock(&data->update_lock); + data->qsfp->valid = 0; + memset(data->qsfp->status, 0, sizeof(data->qsfp->status)); + + DEBUG_PRINT(""); + /* Notify device to update tx fault/ tx disable/ rx los status */ + for (i = 0; i < ARRAY_SIZE(reg); i++) { + status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); + if (unlikely(status < 0)) { + DEBUG_PRINT(""); + goto exit; + } + } + msleep(200); + DEBUG_PRINT(""); + + /* Read actual tx fault/ tx disable/ rx los status */ + for (i = 0; i < ARRAY_SIZE(reg); i++) { + status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); + if (unlikely(status < 0)) { + DEBUG_PRINT(""); + goto exit; + } + + DEBUG_PRINT("qsfp reg(0x%x) status = (0x%x)", reg[i], data->qsfp->status[i]); + data->qsfp->status[i] = (buf & 0xF); + } + + DEBUG_PRINT(""); + data->qsfp->valid = 1; + data->qsfp->last_updated = jiffies; + +exit: + DEBUG_PRINT(""); + mutex_unlock(&data->update_lock); + return (status < 0) ? ERR_PTR(status) : data; +} + +static ssize_t qsfp_inter_read(struct device *dev, struct device_attribute *da, char *buf) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_INTER_ADDR, &cpld_reg_data); + index = data->port - 48; + index = 1 << index; + val = (cpld_reg_data & index) > 0 ? 1 : 0; + + printk("inter read:data->port = %d, index = %hhu, cpld_reg_data = %hhu\n", data->port, index, cpld_reg_data); + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", val); +} + + +static ssize_t qsfp_reset_read(struct device *dev, struct device_attribute *da, char *buf) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_RESET_ADDR, &cpld_reg_data); + index = data->port - 48; + index = 1 << index; + val = (cpld_reg_data & index) > 0 ? 1 : 0; + + printk("reset read:data->port = %d, index = %hhu, cpld_reg_data = %hhu\n", data->port, index, cpld_reg_data); + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t qsfp_reset_write(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + long usrdata; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + ret = kstrtol(buf, 10, &usrdata); + if (ret) { + return ret; + } + + usrdata = usrdata > 0 ? 1 : 0; + index = data->port - 48; + + DEBUG_PRINT("usrdata = %u, index = %hhu\n", usrdata, index); + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_RESET_ADDR, &cpld_reg_data); + if (ret == 1) + { + + DEBUG_PRINT("cpld_reg_data = %x\n", cpld_reg_data); + cpld_reg_data &= ~(1 << index); + cpld_reg_data |= usrdata << index; + + DEBUG_PRINT("cpld_reg_data = %x\n", cpld_reg_data); + ret = cig_cpld_write_sfp_register(QSFP_RESET_ADDR, cpld_reg_data); + if (1 != ret) + { + DEBUG_PRINT("write failed\n"); + } + } + else + { + DEBUG_PRINT("read failed\n"); + } + + mutex_unlock(&data->update_lock); + + if (ret != 1) + return -1; + + return count; +} + + + + +static ssize_t qsfp_lpmode_read(struct device *dev, struct device_attribute *da, char *buf) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_LPMODE_ADDR, &cpld_reg_data); + index = data->port - 48; + index = 1 << index; + val = (cpld_reg_data & index) > 0 ? 1 : 0; + + printk("lpmode read:data->port = %d, index = %hhu, cpld_reg_data = %hhu\n", data->port, index, cpld_reg_data); + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t qsfp_lpmode_write(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + long usrdata; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + ret = kstrtol(buf, 10, &usrdata); + if (ret) { + return ret; + } + + usrdata = usrdata > 0 ? 1 : 0; + index = data->port - 48; + + DEBUG_PRINT("usrdata = %u, index = %hhu\n", usrdata, index); + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_LPMODE_ADDR, &cpld_reg_data); + if (ret == 1) + { + + DEBUG_PRINT("cpld_reg_data = %x\n", cpld_reg_data); + cpld_reg_data &= ~(1 << index); + cpld_reg_data |= usrdata << index; + + DEBUG_PRINT("cpld_reg_data = %x\n", cpld_reg_data); + ret = cig_cpld_write_sfp_register(QSFP_LPMODE_ADDR, cpld_reg_data); + if (1 != ret) + { + DEBUG_PRINT("write failed\n"); + } + } + else + { + DEBUG_PRINT("read failed\n"); + } + + mutex_unlock(&data->update_lock); + + if (ret != 1) + return -1; + + return count; +} + + + +static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + int present; + u8 val = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + DEBUG_PRINT(""); + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + DEBUG_PRINT(""); + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + DEBUG_PRINT(""); + data = qsfp_update_tx_rx_status(dev); + DEBUG_PRINT(""); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + DEBUG_PRINT(""); + switch (attr->index) { + case TX_FAULT: + val = !!(data->qsfp->status[2] & 0xF); + break; + case TX_FAULT1: + case TX_FAULT2: + case TX_FAULT3: + case TX_FAULT4: + val = !!(data->qsfp->status[2] & BIT_INDEX(attr->index - TX_FAULT1)); + break; + case TX_DISABLE: + val = data->qsfp->status[1] & 0xF; + break; + case TX_DISABLE1: + case TX_DISABLE2: + case TX_DISABLE3: + case TX_DISABLE4: + val = !!(data->qsfp->status[1] & BIT_INDEX(attr->index - TX_DISABLE1)); + break; + case RX_LOS: + val = !!(data->qsfp->status[0] & 0xF); + break; + case RX_LOS1: + case RX_LOS2: + case RX_LOS3: + case RX_LOS4: + val = !!(data->qsfp->status[0] & BIT_INDEX(attr->index - RX_LOS1)); + break; + default: + break; + } + + DEBUG_PRINT(""); + return sprintf(buf, "%d\n", val); +} + +static ssize_t qsfp_set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long disable; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + status = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(status)) { + return status; + } + + if (!status) { + /* port is not present */ + return -ENXIO; + } + + status = kstrtol(buf, 10, &disable); + if (status) { + return status; + } + + data = qsfp_update_tx_rx_status(dev); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + mutex_lock(&data->update_lock); + + if (attr->index == TX_DISABLE) { + data->qsfp->status[1] = disable & 0xF; + } + else {/* TX_DISABLE1 ~ TX_DISABLE4*/ + if (disable) { + data->qsfp->status[1] |= (1 << (attr->index - TX_DISABLE1)); + } + else { + data->qsfp->status[1] &= ~(1 << (attr->index - TX_DISABLE1)); + } + } + + DEBUG_PRINT("index = (%d), status = (0x%x)", attr->index, data->qsfp->status[1]); + status = sfp_eeprom_write(data->client, SFF8436_TX_DISABLE_ADDR, &data->qsfp->status[1], sizeof(data->qsfp->status[1])); + if (unlikely(status < 0)) { + count = status; + } + + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t sfp_show_ddm_implemented(struct device *dev, struct device_attribute *da, + char *buf) +{ + int status; + char ddm; + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + status = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(status)) { + return status; + } + + if (status == 0) { + /* port is not present */ + return -ENODEV; + } + + status = sfp_eeprom_read(client, SFF8472_DIAG_MON_TYPE_ADDR, &ddm, sizeof(ddm)); + if (unlikely(status < 0)) { + return status; + } + + return sprintf(buf, "%d\n", !!(ddm & SFF8472_DIAG_MON_TYPE_DDM_MASK)); +} + +/* Platform dependent +++ */ +static ssize_t sfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + u8 val = 0, index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + DEBUG_PRINT("driver type = (%d)", data->driver_type); + if (data->driver_type == DRIVER_TYPE_QSFP) { + DEBUG_PRINT(""); + return qsfp_show_tx_rx_status(dev, da, buf); + } + + DEBUG_PRINT(""); + data = sfp_update_tx_rx_status(dev); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + if(attr->index == RX_LOS_ALL) { + int i = 0; + u8 values[6] = {0}; + + for (i = 0; i < ARRAY_SIZE(values); i++) { + values[i] = (u8)(data->msa->status[2] >> (i * 8)); + } + + /** 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]); + } + + switch (attr->index) { + case TX_FAULT: + index = 0; + break; + case TX_DISABLE: + index = 1; + break; + case RX_LOS: + index = 2; + break; + default: + break; + } + + val = !!(data->msa->status[index] & BIT_INDEX(data->port)); + return sprintf(buf, "%d\n", val); +} +/* Platform dependent --- */ +static ssize_t sfp_eeprom_write(struct i2c_client *client, u8 command, const char *data, + int data_len) +{ +#if USE_I2C_BLOCK_READ + int status, retry = I2C_RW_RETRY_COUNT; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_write_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + return status; + } + + return data_len; +#else + int status, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, command, *data); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + return status; + } + + return 1; +#endif + + +} + +static ssize_t sfp_port_write(struct sfp_port_data *data, + const char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + return count; + } + + /* + * Write data to chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&data->update_lock); + + while (count) { + ssize_t status; + + status = sfp_eeprom_write(data->client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + buf += status; + off += status; + count -= status; + retval += status; + } + + mutex_unlock(&data->update_lock); + return retval; +} + + +static ssize_t sfp_bin_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct sfp_port_data *data; + DEBUG_PRINT("%s(%d) offset = (%d), count = (%d)", off, count); + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + + present = sfp_is_port_present(data->client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + return sfp_port_write(data, buf, off, count); +} + +static ssize_t sfp_eeprom_read(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ +#if USE_I2C_BLOCK_READ + int status, retry = I2C_RW_RETRY_COUNT; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + goto abort; + } + if (unlikely(status != data_len)) { + status = -EIO; + goto abort; + } + + //result = data_len; + +abort: + return status; +#else + int status, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, command); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "sfp read byte data failed, command(0x%2x), data(0x%2x)\r\n", command, status); + goto abort; + } + + *data = (u8)status; + status = 1; + +abort: + return status; +#endif +} + +static ssize_t sfp_port_read(struct sfp_port_data *data, + char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + DEBUG_PRINT("Count = 0, return"); + return count; + } + + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&data->update_lock); + + while (count) { + ssize_t status; + + status = sfp_eeprom_read(data->client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + + buf += status; + off += status; + count -= status; + retval += status; + } + + mutex_unlock(&data->update_lock); + return retval; + +} + +static ssize_t sfp_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct sfp_port_data *data; + DEBUG_PRINT("offset = (%d), count = (%d)", off, count); + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + + present = sfp_is_port_present(data->client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + return sfp_port_read(data, buf, off, count); +} + +static int sfp_sysfs_eeprom_init(struct kobject *kobj, struct bin_attribute *eeprom) +{ + int err; + + sysfs_bin_attr_init(eeprom); + eeprom->attr.name = EEPROM_NAME; + eeprom->attr.mode = S_IWUSR | S_IRUGO; + eeprom->read = sfp_bin_read; + eeprom->write = sfp_bin_write; + eeprom->size = EEPROM_SIZE; + + /* Create eeprom file */ + err = sysfs_create_bin_file(kobj, eeprom); + if (err) { + return err; + } + + return 0; +} + +static int sfp_sysfs_eeprom_cleanup(struct kobject *kobj, struct bin_attribute *eeprom) +{ + sysfs_remove_bin_file(kobj, eeprom); + return 0; +} + +static const struct attribute_group sfp_msa_group = { + .attrs = sfp_msa_attributes, +}; + +static int sfp_i2c_check_functionality(struct i2c_client *client) +{ +#if USE_I2C_BLOCK_READ + return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK); +#else + return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA); +#endif +} + +static int sfp_msa_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, + struct sfp_msa_data **data) +{ + int status; + struct sfp_msa_data *msa; + + if (!sfp_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + msa = kzalloc(sizeof(struct sfp_msa_data), GFP_KERNEL); + if (!msa) { + status = -ENOMEM; + goto exit; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &sfp_msa_group); + if (status) { + goto exit_free; + } + + /* init eeprom */ + status = sfp_sysfs_eeprom_init(&client->dev.kobj, &msa->eeprom.bin); + if (status) { + goto exit_remove; + } + + *data = msa; + dev_info(&client->dev, "sfp msa '%s'\n", client->name); + + cs6436_54p_sysfs_add_client(client); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &sfp_msa_group); +exit_free: + kfree(msa); +exit: + + return status; +} + +static const struct attribute_group sfp_ddm_group = { + .attrs = sfp_ddm_attributes, +}; + +static int sfp_ddm_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, + struct sfp_ddm_data **data) +{ + int status; + struct sfp_ddm_data *ddm; + + if (!sfp_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + ddm = kzalloc(sizeof(struct sfp_ddm_data), GFP_KERNEL); + if (!ddm) { + status = -ENOMEM; + goto exit; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &sfp_ddm_group); + if (status) { + goto exit_free; + } + + /* init eeprom */ + status = sfp_sysfs_eeprom_init(&client->dev.kobj, &ddm->eeprom.bin); + if (status) { + goto exit_remove; + } + + *data = ddm; + dev_info(&client->dev, "sfp ddm '%s'\n", client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &sfp_ddm_group); +exit_free: + kfree(ddm); +exit: + + return status; +} + +static const struct attribute_group qsfp_group = { + .attrs = qsfp_attributes, +}; + +static int qsfp_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, + struct qsfp_data **data) +{ + int status; + struct qsfp_data *qsfp; + + if (!sfp_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + qsfp = kzalloc(sizeof(struct qsfp_data), GFP_KERNEL); + if (!qsfp) { + status = -ENOMEM; + goto exit; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &qsfp_group); + if (status) { + goto exit_free; + } + + /* init eeprom */ + status = sfp_sysfs_eeprom_init(&client->dev.kobj, &qsfp->eeprom.bin); + if (status) { + goto exit_remove; + } + + /* Bring QSFPs out of reset */ + //cig_lpc_write(0x62, 0x15, 0x3F); + + *data = qsfp; + dev_info(&client->dev, "qsfp '%s'\n", client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &qsfp_group); +exit_free: + kfree(qsfp); +exit: + + return status; +} + +/* Platform dependent +++ */ +static int sfp_device_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct sfp_port_data *data = NULL; + + data = kzalloc(sizeof(struct sfp_port_data), GFP_KERNEL); + if (!data) { + return -ENOMEM; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->port = dev_id->driver_data; + data->client = client; + + if (dev_id->driver_data >= cs6436_54p_sfp1 && dev_id->driver_data <= cs6436_54p_sfp48) { + if (client->addr == SFP_EEPROM_A0_I2C_ADDR) { + data->driver_type = DRIVER_TYPE_SFP_MSA; + return sfp_msa_probe(client, dev_id, &data->msa); + } + else if (client->addr == SFP_EEPROM_A2_I2C_ADDR) { + data->driver_type = DRIVER_TYPE_SFP_DDM; + return sfp_ddm_probe(client, dev_id, &data->ddm); + } + } + else { /* cs6436_54p_sfp49 ~ cs6436_54p_sfp56 */ + if (client->addr == SFP_EEPROM_A0_I2C_ADDR) { + data->driver_type = DRIVER_TYPE_QSFP; + return qsfp_probe(client, dev_id, &data->qsfp); + } + } + + return -ENODEV; +} +/* Platform dependent --- */ + +static int sfp_msa_remove(struct i2c_client *client, struct sfp_msa_data *data) +{ + sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); + sysfs_remove_group(&client->dev.kobj, &sfp_msa_group); + kfree(data); + return 0; +} + +static int sfp_ddm_remove(struct i2c_client *client, struct sfp_ddm_data *data) +{ + sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); + sysfs_remove_group(&client->dev.kobj, &sfp_ddm_group); + kfree(data); + return 0; +} + +static int qfp_remove(struct i2c_client *client, struct qsfp_data *data) +{ + sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); + sysfs_remove_group(&client->dev.kobj, &qsfp_group); + kfree(data); + return 0; +} + +static int sfp_device_remove(struct i2c_client *client) +{ + struct sfp_port_data *data = i2c_get_clientdata(client); + + cs6436_54p_sysfs_remove_client(client); + switch (data->driver_type) { + case DRIVER_TYPE_SFP_MSA: + return sfp_msa_remove(client, data->msa); + case DRIVER_TYPE_SFP_DDM: + return sfp_ddm_remove(client, data->ddm); + case DRIVER_TYPE_QSFP: + return qfp_remove(client, data->qsfp); + } + + return 0; +} + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static struct i2c_driver cs6436_54p_sfp_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .probe = sfp_device_probe, + .remove = sfp_device_remove, + .id_table = sfp_device_id, + .address_list = normal_i2c, +}; + +module_i2c_driver(cs6436_54p_sfp_driver); + + +MODULE_AUTHOR("Zhang Peng "); +MODULE_DESCRIPTION("cs6436_54p_sfp driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-sysfs.c b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-sysfs.c new file mode 100644 index 00000000000..1383fcfd40f --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/modules/x86-64-cig-cs6436-54p-sysfs.c @@ -0,0 +1,335 @@ +/* + * A hwmon driver for the CIG cs6436-54P sysfs Module + * + * Copyright (C) 2018 Cambridge, 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 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c-algo-lpc.h" + + +static LIST_HEAD(sysfs_client_list); +static struct mutex list_lock; + +struct sysfs_client_node { + struct i2c_client *client; + struct list_head list; +}; + +#define DEVICE_NAME "cigfs" +static int dev_major; +static struct class *dev_class; +static struct cdev *dev_cdev; +static struct device *dev_device; +static struct class *psu_class; +static struct class *sfp_class; + + +void cs6436_54p_sysfs_add_client(struct i2c_client *client) +{ + struct sysfs_client_node *node = kzalloc(sizeof(struct sysfs_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate sysfs_client_node (0x%x)\n", client->addr); + return; + } + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &sysfs_client_list); + mutex_unlock(&list_lock); +} + +EXPORT_SYMBOL(cs6436_54p_sysfs_add_client); + +void cs6436_54p_sysfs_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct sysfs_client_node *sysfs_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &sysfs_client_list) + { + sysfs_node = list_entry(list_node, struct sysfs_client_node, list); + if (IS_ERR(sysfs_node)) + { + break; + } + if (sysfs_node->client == client) { + found = 1; + break; + } + } + if (found) { + list_del(list_node); + kfree(sysfs_node); + } + + mutex_unlock(&list_lock); +} + +EXPORT_SYMBOL(cs6436_54p_sysfs_remove_client); + +struct class * cs6436_54p_sysfs_create_symclass(char *cls_name) +{ + int rc = 0; + struct class *my_class; +/**************************************************************************************/ + my_class = class_create(THIS_MODULE,cls_name); + if (IS_ERR(my_class)) { + pr_err("failed to create my class\n"); + } + return my_class; + +/**************************************************************************************/ +} + +void cs6436_54p_sysfs_delete_symclass(struct class *my_class) +{ +/**************************************************************************************/ + + if (IS_ERR(my_class)) { + pr_err("Pointer is invaild\n"); + } + class_destroy(my_class); + +/**************************************************************************************/ +} + + + + + +int cs6436_54p_sysfs_create_symlink(struct class *my_class,char * driver_name,char *device_name) +{ + struct list_head *list_node = NULL; + struct sysfs_client_node *sysfs_node = NULL; + int ret = -EPERM; + int rc = 0; + + mutex_lock(&list_lock); + list_for_each(list_node, &sysfs_client_list) + { + sysfs_node = list_entry(list_node, struct sysfs_client_node, list); + if (!strcmp(sysfs_node->client->name,driver_name)) { + rc = sysfs_create_link(&my_class->p->subsys.kobj, &sysfs_node->client->dev.kobj,device_name); + if(rc) + { + pr_err("failed to create symlink %d\n",rc); + } + break; + } + } + mutex_unlock(&list_lock); + return ret; +} + + +int cs6436_54p_sysfs_delete_symlink(struct class *my_class,char * driver_name,char *device_name) +{ + struct list_head *list_node = NULL; + struct sysfs_client_node *sysfs_node = NULL; + int ret = -EPERM; + int rc = 0; + + mutex_lock(&list_lock); + list_for_each(list_node, &sysfs_client_list) + { + sysfs_node = list_entry(list_node, struct sysfs_client_node, list); + if (!strcmp(sysfs_node->client->name,driver_name)) { + sysfs_remove_link(&my_class->p->subsys.kobj,device_name); + break; + } + } + mutex_unlock(&list_lock); + return ret; +} + + +static int cs6436_54p_sysfs_open(struct inode *inode, struct file *file) +{ + return 0; +} + + + +static ssize_t cs6436_54p_sysfs_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) +{ + char str[10],name[18],port[8]; + int ret; + int i; + memset(str, 0, sizeof(str)); + ret = copy_from_user(str, buf, count); + if (ret) + { + printk(KERN_ERR "copy_from_user fail\n"); + return -EINVAL; + } + + if(!strncmp(str,"start",5)) + { + psu_class = cs6436_54p_sysfs_create_symclass("psu"); + cs6436_54p_sysfs_create_symlink(psu_class,"cs6436_54p_psu1","psu1"); + cs6436_54p_sysfs_create_symlink(psu_class,"cs6436_54p_psu2","psu2"); + sfp_class = cs6436_54p_sysfs_create_symclass("swps"); + for(i = 1; i <= 48;i++) + { + memset(name,0xff,sizeof(name)); + memset(port,0xff,sizeof(port)); + snprintf(name,sizeof(name),"cs6436_54p_sfp%d",i); + snprintf(port,sizeof(port),"port%d",i); + cs6436_54p_sysfs_create_symlink(sfp_class,name,port); + } + } + else if(!strncmp(str,"stop",4)) + { + cs6436_54p_sysfs_delete_symlink(psu_class,"cs6436_54p_psu1","psu1"); + cs6436_54p_sysfs_delete_symlink(psu_class,"cs6436_54p_psu2","psu2"); + cs6436_54p_sysfs_delete_symclass(psu_class); + + for(i = 1; i <= 48;i++) + { + memset(name,0xff,sizeof(name)); + memset(port,0xff,sizeof(port)); + snprintf(name,sizeof(name),"cs6436_54p_sfp%d",i); + snprintf(port,sizeof(port),"port%d",i); + cs6436_54p_sysfs_delete_symlink(sfp_class,name,port); + } + cs6436_54p_sysfs_delete_symclass(sfp_class); + } + return count; +} + + +static struct file_operations cs6436_54p_sysfs_fops = { + .owner = THIS_MODULE, + .open = cs6436_54p_sysfs_open, + .write = cs6436_54p_sysfs_write, +}; + + +static int __init cs6436_54p_sysfs_init(void) +{ + int result = 0; + int err = 0; + dev_t dev = MKDEV(dev_major, 0); + + if (dev_major) + result = register_chrdev_region(dev, 1, DEVICE_NAME); + else { + result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME); + dev_major = MAJOR(dev); + } + if (result < 0) + { + printk("unable to get major %d\n", dev_major); + err= -EINVAL; + } + printk("get major is %d\n", dev_major); + if (dev_major == 0) + dev_major = result; + + dev_cdev= kmalloc(sizeof(struct cdev), GFP_KERNEL); + if(IS_ERR(dev_cdev)) { + err= -ENOMEM; + } + + cdev_init(dev_cdev, &cs6436_54p_sysfs_fops); + dev_cdev->owner = THIS_MODULE; + dev_cdev->ops = &cs6436_54p_sysfs_fops; + err = cdev_add(dev_cdev, dev, 1); + if (err) + { + printk("error %d add fpga ", err); + goto err_malloc; + } + + dev_class = class_create(THIS_MODULE, DEVICE_NAME); + if (IS_ERR(dev_class)) + { + printk("Err:failed in creating class.\n"); + goto err_cdev_add; + } + + dev_device = device_create(dev_class, NULL, MKDEV(dev_major, 0), NULL, DEVICE_NAME); + if (IS_ERR(dev_device)) + { + printk("Err:failed in creating device.\n"); + goto err_class_crt; + } + + mutex_init(&list_lock); + + return err; + + err_class_crt: + cdev_del(dev_cdev); + err_cdev_add: + kfree(dev_cdev); + err_malloc: + unregister_chrdev_region(MKDEV(dev_major,0), 1); + + return err; + +} + +static void __exit cs6436_54p_sysfs_exit(void) +{ + cdev_del(dev_cdev); + printk("cdev_del ok\n"); + device_destroy(dev_class, MKDEV(dev_major, 0)); + + class_destroy(dev_class); + + if(dev_cdev != NULL) + kfree(dev_cdev); + + unregister_chrdev_region(MKDEV(dev_major, 0), 1); + printk("cs6436_54p_sysfs_exit...\r\n"); +} + + +MODULE_AUTHOR("Zhang Peng "); +MODULE_DESCRIPTION("cs6436-54p-sysfs driver"); +MODULE_LICENSE("GPL"); + +module_init(cs6436_54p_sysfs_init); +module_exit(cs6436_54p_sysfs_exit); + + diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/service/cs6436-platform-init.service b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/service/cs6436-platform-init.service new file mode 100644 index 00000000000..ad18c2c2703 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/service/cs6436-platform-init.service @@ -0,0 +1,13 @@ +[Unit] +Description=Cig CS6436-54P Platform initialization service +Before=pmon.service +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/cig_cs6436_util.py install +ExecStop=/usr/local/bin/cig_cs6436_util.py clean +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/service/cs6436-platform-misc.service b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/service/cs6436-platform-misc.service new file mode 100644 index 00000000000..33f99935cd9 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/service/cs6436-platform-misc.service @@ -0,0 +1,15 @@ +[Unit] +Description=Cig CS6436-54P Platform miscellaneous service +After=cs6436-platform-init.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/cig_cs6436_misc.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/setup.py b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/setup.py new file mode 100755 index 00000000000..05ee2c6e36a --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/setup.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +import os +import sys +from setuptools import setup +os.listdir + +setup( + name='cs6436-54p', + version='1.0.0', + description='Module to initialize Cig CS6436-54P platforms', + + packages=['cs6436-54p'], + package_dir={'cs6436-54p': 'cs6436-54p/classes'}, + ) diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/utils/cig_cs6436_misc.py b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/utils/cig_cs6436_misc.py new file mode 100755 index 00000000000..c186676cbf3 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/utils/cig_cs6436_misc.py @@ -0,0 +1,574 @@ +#!/usr/bin/env python +# +# Copyright (C) 2018 Cambridge, 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 . + +import os +import commands +import sys, getopt +import logging +import re +import time +import datetime +from collections import namedtuple +from threading import Thread + +DEBUG = False +i2c_prefix = '/sys/bus/i2c/devices/' +leds_prefix = '/sys/devices/platform/cs6436_54p_led/leds/' +fans_prefix = '/sys/devices/platform/cs6436_54p_fan/' +fansdir_prefix = fans_prefix + 'fan{}_direction' + +ageing_controlfile = '/etc/sonic/agcontrol' +AGFlag = 0 + + +platform_misc_log = '/var/log/platform_misc.log' +misclogger = logging.getLogger('platform_misc') +misclogger.setLevel(logging.INFO) +miscformatter = logging.Formatter('%(asctime)s-%(levelname)s-%(message)s') + +if not os.path.isfile(platform_misc_log): + try: + os.mknod(platform_misc_log) + except: + print 'Failed to creat platform_misc.log' + +fileHandler = logging.FileHandler(platform_misc_log) +fileHandler.setLevel(logging.INFO) +fileHandler.setFormatter(miscformatter) +misclogger.addHandler(fileHandler) + + +starttime = datetime.datetime.now() +IsGetlswt = 0 +coretemp_prefix = '/sys/class/hwmon/hwmon1/' +coretemp_ps = [] +psu1_p = '/sys/bus/i2c/devices/5-005a/psu_present' +psu2_p = '/sys/bus/i2c/devices/5-005b/psu_present' +psu1_d = '/sys/bus/i2c/devices/5-0052/psu_eeprom' +psu2_d = '/sys/bus/i2c/devices/5-0053/psu_eeprom' +psu1led_d = leds_prefix + 'cs6436_54p_led::psu1/brightness' +psu2led_d = leds_prefix + 'cs6436_54p_led::psu2/brightness' +cs6436_ledpath = {'fan':leds_prefix + 'cs6436_54p_led::fan/brightness', + 'fan1':leds_prefix + 'cs6436_54p_led::fan1/brightness', + 'fan2':leds_prefix + 'cs6436_54p_led::fan2/brightness', + 'fan3':leds_prefix + 'cs6436_54p_led::fan3/brightness', + 'fan4':leds_prefix + 'cs6436_54p_led::fan4/brightness', + 'fan5':leds_prefix + 'cs6436_54p_led::fan5/brightness', + 'psu1':leds_prefix + 'cs6436_54p_led::psu1/brightness', + 'psu2':leds_prefix + 'cs6436_54p_led::psu2/brightness', + 'sys':leds_prefix + 'cs6436_54p_led::sys/brightness'} + + +def system_read_filestr(node): + with open(node, 'r') as f: + try: + str = f.read() + except IOError as e: + misclogger.error('Failed to get node, str={}'.format(node)) + return "0" + return str + + +def system_bright_leds(dev, colour): + global AGFlag + + if AGFlag == 1: + return + + cmd = 'echo {} > {}'.format(colour, dev) + log_os_system(cmd, 1) + return + +''' +1: front in tail out +0: front out tail in +''' +def system_getpsu_direction(dev): + try: + with open(dev) as f: + f.seek(0x30) + str = f.read(2) + except IOError as e: + misclogger.error('Failed to get psu eep') + return 1 + if str == 'AA': ## front in tail out + return 1 + elif str == 'RA':## tail in front out + return 0 + else: + misclogger.error('Failed to get psu eep, str={}'.format(str)) + return -1 + + +def system_get_cputype(): + cmdretfd = os.popen("lscpu | grep 'Model name'") + retstring = cmdretfd.read() + endindex = retstring.find('@') - 1 + startindex = retstring[:endindex].rfind(' ') + 1 + cputype = retstring[startindex:endindex] + + return cputype + + +def system_init_coretemppath(): + global coretemp_ps + + cmdstr = "ls {} | grep 'input'".format(coretemp_prefix) + cmdretfd = os.popen(cmdstr) + + coretemppss = cmdretfd.read().splitlines() + if len(coretemppss) < 3: + cputype = system_get_cputype() + misclogger.error('Failed to init core temperature path.' + ' cpu type = {}, num thermal = {}'.format(cputype, len(coretemp_ps))) + return 1 + + for i in range(0,3): + coretemp_ps.append(coretemp_prefix + coretemppss[i]) + + print coretemp_ps + + return 0 + + +class cs6436_fanattr: + def __init__(self, name): + self.name = name + self.direction = 0 + self.direction_p = '' + self.rear = 0 + self.rear_p = '' + self.front = 0 + self.front_p = '' + self.fault = 0 + self.fault_p = '' + self.status = 0 + self.setpath() + self.updatedevice() + + return + + def setpath(self): + self.direction_p = fans_prefix + '{}_direction'.format(self.name) + self.rear_p = fans_prefix + '{}_rear_speed_rpm'.format(self.name) + self.front_p = fans_prefix + '{}_front_speed_rpm'.format(self.name) + self.fault_p = fans_prefix + '{}_fault'.format(self.name) + + return + + def updatedevice(self): + self.direction = int(system_read_filestr(self.direction_p)) + self.rear = int(system_read_filestr(self.rear_p)) + self.front = int(system_read_filestr(self.front_p)) + self.fault = int(system_read_filestr(self.fault_p)) + + return + + def checkspeedrpm(self, speedrpm): + frontrpmexp = speedrpm * 21000 / 100 + rearrpmexp = speedrpm * 19000 / 100 + deviationfront = abs(frontrpmexp - self.front) / float(frontrpmexp) + deviationrear = abs(rearrpmexp - self.rear) / float(rearrpmexp) + + if deviationfront < 0.3 and deviationrear < 0.3: + return 0 + else: + misclogger.error(':{} speed wrong. frontexp is {}, but rpm is {}.rearexp is {}, but rpm is {}'.format(self.name, frontrpmexp, self.front, rearrpmexp, self.rear)) + return 1 + + def checkstatus(self, speedrpm, totaldirct): + speedstatus = self.checkspeedrpm(speedrpm) + if self.direction != totaldirct: + self.status = 1 + misclogger.error(':{} direction = {}.fan direction is not ok.'.format(self.name, self.direction)) + elif speedstatus != 0: + self.status = 1 + elif self.fault != 0: + misclogger.error(':{} fault.'.format(self.name)) + self.status = 1 + else: + self.status = 0 + + if self.status == 1: + system_bright_leds(cs6436_ledpath[self.name], 3) + else: + system_bright_leds(cs6436_ledpath[self.name], 1) + + return self.status + +cs6436_fanattrnodes = [] + + +class cs6436_psuattr: + def __init__(self, name): + self.name = name + self.direction = 0 + self.direction_p = '' + self.present = 0 + self.present_p = '' + self.status = 0 + + self.setpath() + self.updatepresent() + self.updatedirection() + + return + + def setpath(self): + if self.name == 'psu1': + self.present_p = psu1_p + self.direction_p = psu1_d + if self.name == 'psu2': + self.present_p = psu2_p + self.direction_p = psu2_d + + return + + def updatepresent(self): + self.present = int(system_read_filestr(self.present_p)) + + return + + def updatedirection(self): + if self.present == 1: + self.direction = system_getpsu_direction(self.direction_p) + else: + self.direction = 2 + + return + + def checkstatus(self, totaldirct): + if self.present != 1: + self.status = 1 + misclogger.error(':{} not present.'.format(self.name)) + elif self.direction == 2: + self.status = 0 + misclogger.info(':{} direction need to be update.'.format(self.name)) + elif self.direction != totaldirct: + self.status = 1 + misclogger.info(':{} direction is wrong.'.format(self.name)) + else: + self.status = 0 + + if self.status == 1: + system_bright_leds(cs6436_ledpath[self.name], 3) + else: + system_bright_leds(cs6436_ledpath[self.name], 1) + + return self.status + +cs6436_psuattrnodes = [] + + + +def my_log(txt): + if DEBUG == True: + print "[ROY]"+txt + return + +def device_exist(): + ret1, log = log_os_system("ls "+i2c_prefix+"5-005a", 0) + ret2, log = log_os_system("ls "+i2c_prefix+"5-005b", 0) + ret3, log = log_os_system("ls "+leds_prefix+"cs6436_54p_led*", 0) + return not(ret1 or ret2 or ret3) + + +def log_os_system(cmd, show): + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) + my_log (cmd +"with result:" + str(status)) + my_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + + +def system_get_coretemp(): + temp1 = system_read_filestr(coretemp_ps[0]).strip() + temp2 = system_read_filestr(coretemp_ps[1]).strip() + temp3 = system_read_filestr(coretemp_ps[2]).strip() + + return int(temp1), int(temp2), int(temp3) + +def system_get_boardtemp(): + for i in range(0,16): + temp1path = "/sys/bus/i2c/devices/5-004a/hwmon/hwmon%d/temp1_input" % i + if os.access(temp1path, os.F_OK): + break + for i in range(0,16): + temp2path = "/sys/bus/i2c/devices/5-004b/hwmon/hwmon%d/temp1_input" % i + if os.access(temp2path, os.F_OK): + break + temp1 = system_read_filestr(temp1path).strip() + temp2 = system_read_filestr(temp2path).strip() + + return int(temp1), int(temp2) + + +def system_get_lswtemp(): + global IsGetlswt + global starttime + if IsGetlswt == 0: + now = datetime.datetime.now() + misclogger.info("time wait.") + misclogger.info("start = {}, now = {}.".format(starttime, now)) + if (now - starttime).seconds > 150: + misclogger.info("time = ".format((now - starttime).seconds)) + IsGetlswt = 1 + + return 25 + +# chp = subprocess.Popen("docker ps --filter name=syncd", shell=True, stdout=subprocess.PIPE) +# if chp.poll() == None: +# misclogger.info("No subp.") +# chp.kill() +# +# return 25 + +# retstring = chp.stdout.read() +# chp.kill() +# if 'Up' not in retstring: +# misclogger.info("lsw not up.") +# +# return 25 + + status, output = log_os_system('npx_diag swc show temperature', 1) + if status: + misclogger.error('failed to show lsw temperature') + + return 25 + + output = output.strip() + if output.find("it 0, temperature ") > 0: + startindex = output.find('temperature') + len('temperature') + 1 + endindex = output[startindex:].find(" ") + endindex = startindex + endindex + temp = output[startindex:endindex] + b = temp.find('.') + if b > 0: + temp=temp[:b] + temp = int(temp) + else: + misclogger.error("Failed to get temperature.") + temp = 0 + + return int(temp) + +def system_monitor_temperature(): + + ctemp1, ctemp2, ctemp3 = system_get_coretemp() + btemp1, btemp2 = system_get_boardtemp() + ltemp = system_get_lswtemp() + fan_speed_str = system_cs6436_getfanexspeed() + fan_speed = int(fan_speed_str) + policy = 'stay' + pos = 0 + #speed c1 c2 c3 b1 b2 lsw + fan_policy_up = ([30, 40000, 40000, 40000, 42000, 35000, 95], + [40, 44000, 44000, 44000, 44000, 39000, 96], + [50, 49000, 49000, 49000, 47000, 44000, 91], + [60, 52000, 52000, 52000, 51500, 47500, 92], + [70, 53000, 53000, 53000, 52000, 49000, 93], + [100,999999,999999,999999,999999,999999,999]) + + fan_policy_down=([30, 0, 0, 0, 0, 0, 0], + [40, 34000, 34000, 34000, 34000, 30000, 80], + [50, 38000, 38000, 38000, 37000, 33000, 81], + [60, 44000, 44000, 44000, 43000, 39000, 84], + [70, 44000, 44000, 44000, 43000, 40000, 84], + [100, 48000, 48000, 48000, 46000, 42000, 85],) + + for policytable in fan_policy_up: + if fan_speed <= policytable[0]: + break + pos = pos + 1 + fan_speed = policytable[0] + if (ctemp1 < policytable[1]) and (ctemp2 < policytable[2]) and (ctemp3 < policytable[3]) and (btemp1 < policytable[4]) and (btemp2 < policytable[5]) and (ltemp < policytable[6]): + policy = 'stay' + policytable = fan_policy_down[pos] + if (ctemp1 < policytable[1]) and (ctemp2 < policytable[2]) and (ctemp3 < policytable[3]) and (btemp1 < policytable[4]) and (btemp2 < policytable[5]) and (ltemp < policytable[6]): + policy = 'down' + else: + policy = 'up' + + if policy == 'up': + misclogger.info("speed = %d." % fan_speed) + misclogger.info("core1 = %d, core2 = %d, core3 = %d." % (ctemp1, ctemp2, ctemp3)) + misclogger.info("board1 = %d, board2 = %d." % (btemp1, btemp2)) + misclogger.info("lsw = %d" % ltemp) + fan_speed = fan_policy_down[pos + 1][0] + misclogger.info("fan policy: up. speedexp = {}".format(fan_speed)) + + if policy == 'stay': + fan_speed = fan_policy_down[pos] + return + + if policy == 'down': + misclogger.info("speed = %d." % fan_speed) + misclogger.info("core1 = %d, core2 = %d, core3 = %d." % (ctemp1, ctemp2, ctemp3)) + misclogger.info("board1 = %d, board2 = %d." % (btemp1, btemp2)) + misclogger.info("lsw = %d" % ltemp) + fan_speed = fan_policy_down[pos - 1][0] + misclogger.info("fan policy: down.speedexp = {}".format(fan_speed)) + + cmd = "echo {} > /sys/devices/platform/cs6436_54p_fan/fan_duty_cycle_percentage".format(fan_speed) + status, output = log_os_system(cmd, 1) + if status: + misclogger.error("set fan speed fault") + + return + + +def system_cs6436_setfanexspeed(num): + fanspeednode = fans_prefix + 'fan_duty_cycle_percentage' + numstr = str(num) + with open(fanspeednode, 'w') as f: + f.write(numstr) + + +def system_cs6436_getfanexspeed(): + fanspeednode = fans_prefix + 'fan_duty_cycle_percentage' + fanspeedstr = system_read_filestr(fanspeednode) + fanspeedexp = int(fanspeedstr) + + return fanspeedexp + + +def system_cs6436_getdirection(): + global cs6436_fanattrnodes + direction = 0 + + for fan in cs6436_fanattrnodes: + direction = direction + fan.direction + + if direction > 2: + direction = 1 + else: + direction = 0 + + return direction + + +def system_check_psusdirection(): + global cs6436_psuattrnodes + cs6436totaldirct = system_cs6436_getdirection() + psutatus = 0 + + for psu in cs6436_psuattrnodes: + psu.updatedirection() + psu.checkstatus(cs6436totaldirct) + psutatus = psu.status + psutatus + + return (psutatus != 0) + + +def system_check_psuspresent(): + global cs6436_psuattrnodes + cs6436totaldirct = system_cs6436_getdirection() + psutatus = 0 + + for psu in cs6436_psuattrnodes: + psu.updatepresent() + psu.checkstatus(cs6436totaldirct) + psutatus = psu.status + psutatus + + return (psutatus != 0) + + +def system_check_fansstate(): + global cs6436_fanattrnodes + global cs6436_ledpath + cs6436totaldirct = system_cs6436_getdirection() + fanstatus = 0 + fanexspeed = 0 + + fanexspeed = system_cs6436_getfanexspeed() + + for fan in cs6436_fanattrnodes: + fan.updatedevice() + fan.checkstatus(fanexspeed, cs6436totaldirct) + fanstatus = fanstatus + fan.status + + if fanstatus > 0: + misclogger.error(':fan error.set fans speed 100.') + system_cs6436_setfanexspeed(100) + system_bright_leds(cs6436_ledpath['fan'], 3) + else: + system_bright_leds(cs6436_ledpath['fan'], 1) + + return (fanstatus != 0) + + +def system_misc_polling(threadName,delay): + for count in range(1,5): + if device_exist() == False: + time.sleep(delay+3) + print "%s: %s, count=%d" % ( threadName, time.ctime(time.time()), count) + else: + break + + if count == 4: + return + + status, output = log_os_system("echo 1 > /sys/devices/platform/cs6436_54p_led/leds/cs6436_54p_led::sys/brightness", 1) + status, output = log_os_system("hwconfig -cfp 1", 1) + + global AGFlag + if os.access(ageing_controlfile, os.F_OK): + AGFlag = 1 + else: + AGFlag = 0 + + os.system('csw_daemon &') + + + global cs6436_fanattrnodes + global cs6436_psuattrnodes + + for num in range(1,6): + name = 'fan{}'.format(num) + fannode = cs6436_fanattr(name) + cs6436_fanattrnodes.append(fannode) + for num in range(1,3): + name = 'psu{}'.format(num) + psunode = cs6436_psuattr(name) + cs6436_psuattrnodes.append(psunode) + + tempcontrol = system_init_coretemppath() + + misclogger.info("%s: %s misc start." % ( threadName, time.ctime(time.time()))) + count = 0 + while 1: + count = count + 1 + ret = system_check_psuspresent() + ret = system_check_fansstate() + + if count % 10 == 0: + misclogger.info(": adjust fans and check psu direction.") + system_check_psusdirection() + if tempcontrol == 0: + system_monitor_temperature() + count = 0 + time.sleep(delay) + + return + +if __name__ == '__main__': + target=system_misc_polling("Thread-misc",10) + diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-54p/utils/cig_cs6436_util.py b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/utils/cig_cs6436_util.py new file mode 100755 index 00000000000..81e6bb7c0b6 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-54p/utils/cig_cs6436_util.py @@ -0,0 +1,565 @@ +#!/usr/bin/env python +# +# Copyright (C) 2018 Cambridge, 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 = 'cs6436_54p' +version = '0.1.1' +verbose = False +DEBUG = False +args = [] +ALL_DEVICE = {} +DEVICE_NO = {'led':9, 'fan':5, 'thermal':4, 'psu':2, 'sfp':54} +FORCE = 0 +CPU_TYPE = 'C3308' + + +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-54 {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 "[ROY]"+txt + return + +def log_os_system(cmd, show): + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) + my_log (cmd +"with result:" + str(status)) + my_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + +def driver_check(): + for count in range(1,5): + time.sleep(1) + ret, lsmod = log_os_system("lsmod| grep i2c_i801", 0) + if len(lsmod) > 2: + log_os_system("rmmod i2c_i801", 0) + break + + ret, lsmod = log_os_system("lsmod| grep i2c_designware_platform", 0) + if len(lsmod) > 2: + log_os_system("rmmod i2c_designware_platform", 0) + log_os_system("modprobe i2c-designware-platform", 0) + + ret, lsmod = log_os_system("lsmod| grep cig", 0) + logging.info('mods:'+lsmod) + if len(lsmod) ==0: + return False + return True + + + +kos = [ + 'depmod', + 'modprobe i2c_dev', + 'modprobe i2c_mux_pca954x force_deselect_on_exit=1', + 'modprobe x86-64-cig-cs6436-54p-sysfs ' , + 'modprobe x86-64-cig-cs6436-54p-cpld ' , + 'modprobe x86-64-cig-cs6436-54p-fan' , + 'modprobe x86-64-cig-cs6436-54p-psu' , + 'modprobe x86-64-cig-cs6436-54p-sfp' , + 'modprobe x86-64-cig-cs6436-54p-led' ] + +def driver_install(): + global FORCE + + for i in range(0,len(kos)): + if i == 4: + ret, CPU_TYPE = log_os_system("cat /proc/cpuinfo | grep \"model name\" | cut -b 32-39 | head -n 1", 0) + if CPU_TYPE=='i3-6100U': + kos[i] =kos[i] + 'board_id=1' + ret, CPU_TYPE = log_os_system("cat /proc/cpuinfo | grep \"model name\" | cut -b 36-40 | head -n 1", 0) + if CPU_TYPE=='C3758' or CPU_TYPE=='C3308': + kos[i] =kos[i] + 'board_id=2' + + 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 + +led_prefix ='/sys/class/leds/'+PROJECT_NAME+'_led::' +hwmon_types = {'led': ['sys','fan','fan1','fan2','fan3','fan4','fan5','psu1','psu2']} +hwmon_nodes = {'led': ['brightness'] } +hwmon_prefix ={'led': led_prefix} + +i2c_prefix = '/sys/bus/i2c/devices/' +i2c_bus = {'thermal': ['4-0048','4-0049', '5-004a', '5-004b'] , + 'psu': ['5-005a','5-005b'], + 'sfp': ['-0050']} +i2c_nodes = {'thermal': ['hwmon/hwmon*/temp1_input'] , + 'psu': ['psu_present ', 'psu_power_good'] , + 'sfp': ['sfp_is_present ', 'sfp_tx_disable']} + +fan_prefix ='/sys/bus/platform/devices/'+PROJECT_NAME+'_fan' +fan_types = {'fan': ['fan1','fan2', 'fan3', 'fan4', 'fan5']} +fan_nodes = {'fan': ['state', 'front_speed_rpm', 'rear_speed_rpm', 'fault']} + + +sfp_map = [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,51,52,53,54,55,56, + 57,60,61,62,63] + +mknod =[ + 'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-2/new_device', + 'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-2/new_device', + 'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-2/new_device', + 'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-2/new_device', + 'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-3/new_device', + 'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-3/new_device', + 'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-3/new_device', + 'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-4/new_device', + 'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-4/new_device', + 'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-5/new_device', + 'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-5/new_device', + 'echo cs6436_54p_psu1 0x5a > /sys/bus/i2c/devices/i2c-5/new_device', + 'echo cs6436_54p_psu2 0x5b > /sys/bus/i2c/devices/i2c-5/new_device', + 'echo cs6436_54p_psu1 0x52 > /sys/bus/i2c/devices/i2c-5/new_device', + 'echo cs6436_54p_psu2 0x53 > /sys/bus/i2c/devices/i2c-5/new_device', + 'echo 24c128 0x57 > /sys/bus/i2c/devices/i2c-7/new_device'] + +port = 0 + +def device_install(): + global FORCE + global port + + for i in range(0,len(mknod)): + #all nodes need times to built new i2c buses + time.sleep(1) + + 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 == 50): + port = port + 3 + else: + port = port + 1 + + + status, output =log_os_system("echo cs6436_54p_sfp"+str(port)+" 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + + if port <= 48: + status, output =log_os_system("echo cs6436_54p_sfp"+str(port)+" 0x51 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + + return + +def device_uninstall(): + global FORCE + + 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_check() == False: + return False + if not device_exist(): + return False + return True + +def do_install(): + print "Checking system...." + if driver_check() == 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_check()== 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, fan_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 '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) + + for key in fan_types: + itypes = fan_types[key] + nodes = fan_nodes[key] + for i in range(0,len(itypes)): + for j in range(0,len(nodes)): + node = key+"_"+itypes[i] + path = fan_prefix+"/"+ 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], 'sfp_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 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['fan'] ['fan1'][0] + node = node.replace(node.split("/")[-1], 'fan_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 + +def get_value(input): + digit = re.findall('\d+', input) + return int(digit[0]) + + +def get_ledname(ledx): + name_table={'led1':'SYS','led2':'FSTUS','led3':'FAN1','led4':'FAN2','led5':'FAN3','led6':'FAN4','led7':'FAN5','led8':'PSU1','led9':'PSU2'} + if name_table.has_key(ledx): + name = name_table[ledx] + else: + name = ledx + return name + + +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): + nwnamex = get_ledname(j) + if nwnamex == j: + print " "+j+":", + else: + print " "+nwnamex+":", + 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-3", 0) + return not(ret1 or ret2) + + +if __name__ == "__main__": + main() diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/Makefile b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/Makefile index cdb114aad51..b0b4f1f7df0 100755 --- a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/Makefile +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/Makefile @@ -1,4 +1,5 @@ -obj-m := x86-64-cig-cs6436-56p-cpld.o \ +obj-m :=x86-64-cig-cs6436-56p-sysfs.o \ + x86-64-cig-cs6436-56p-cpld.o \ x86-64-cig-cs6436-56p-fan.o \ x86-64-cig-cs6436-56p-led.o \ x86-64-cig-cs6436-56p-psu.o \ diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/i2c-algo-lpc.h b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/i2c-algo-lpc.h index 7ce6ae37859..9f1acd52ea6 100755 --- a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/i2c-algo-lpc.h +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/i2c-algo-lpc.h @@ -65,7 +65,7 @@ #define I2C_LPC_CLK3 0x00 #define I2C_LPC_CLK443 0x10 #define I2C_LPC_CLK6 0x14 -#define I2C_LPC_CLK 0x18 +#define I2C_LPC_CLK 0x18 #define I2C_LPC_CLK12 0x1c /* ----- transmission frequencies ------------------------------------- */ @@ -94,4 +94,129 @@ #define I2C_LPC_REG_DATA_TX3 0x8c #define I2C_LPC_REG_DATA_TX4 0x8d -#endif /* I2C_LPC_H */ + +#define ADDR_REG_SFP_STATUS_ADDR 0X62 //reg addr +R/W# //1031 +#define ADDR_REG_SFP_STATUS_TX 0X63 // write data +#define ADDR_REG_SFP_STATUS_RX 0X64 //read data +#define ADDR_REG_SFP_STATUS_COMMAND 0X65 //cmd bit7=1,go +#define ADDR_REG_SFP_STATUS_STATUS 0X66 //status + +#define CPLD_MASTER_INTERRUPT_STATUS_REG 0x20 +#define CPLD_MASTER_INTERRUPT_MASK_REG 0x21 +#define CPLD_MASTER_INTERRUPT_ALL 0x3f +#define CPLD_MASTER_INTERRUPT_CPLD2 0x20 +#define CPLD_MASTER_INTERRUPT_CPLD1 0x10 +#define CPLD_MASTER_INTERRUPT_PSU2 0x08 +#define CPLD_MASTER_INTERRUPT_PSU1 0x04 +#define CPLD_MASTER_INTERRUPT_6320 0x02 +#define CPLD_MASTER_INTERRUPT_LSW 0x01 + + + +#define CPLD_SLAVE1_INTERRUPT_STATUS_L_REG 0x20 +#define CPLD_SLAVE1_INTERRUPT_STATUS_H_REG 0x21 +#define CPLD_SLAVE2_INTERRUPT_STATUS_L_REG 0x22 +#define CPLD_SLAVE2_INTERRUPT_STATUS_H_REG 0x23 +#define CPLD_SLAVE1_INTERRUPT_MASK_REG 0x24 +#define CPLD_SLAVE2_INTERRUPT_MASK_REG 0x25 + + +#define CPLD_SLAVE1_PRESENT08_REG 0x01 +#define CPLD_SLAVE1_PRESENT16_REG 0x02 +#define CPLD_SLAVE1_PRESENT24_REG 0x03 +#define CPLD_SLAVE2_PRESENT32_REG 0x04 +#define CPLD_SLAVE2_PRESENT40_REG 0x05 +#define CPLD_SLAVE2_PRESENT48_REG 0x06 + +#define CPLD_SLAVE1_RX_LOST08_REG 0x07 +#define CPLD_SLAVE1_RX_LOST16_REG 0x08 +#define CPLD_SLAVE1_RX_LOST24_REG 0x09 +#define CPLD_SLAVE2_RX_LOST32_REG 0x0a +#define CPLD_SLAVE2_RX_LOST40_REG 0x0b +#define CPLD_SLAVE2_RX_LOST48_REG 0x0c + +#define CPLD_SLAVE1_TX_FAULT08_REG 0x0d +#define CPLD_SLAVE1_TX_FAULT16_REG 0x0e +#define CPLD_SLAVE1_TX_FAULT24_REG 0x0f +#define CPLD_SLAVE2_TX_FAULT32_REG 0x10 +#define CPLD_SLAVE2_TX_FAULT40_REG 0x11 +#define CPLD_SLAVE2_TX_FAULT48_REG 0x12 + +#define CPLD_SLAVE2_PRESENT56_REG 0x19 +#define CPLD_SLAVE2_QSFP_CR56_REG 0x1a + + +#define CPLD_SLAVE1_INTERRUPT_PRESENT08 0x0001 +#define CPLD_SLAVE1_INTERRUPT_PRESENT16 0x0002 +#define CPLD_SLAVE1_INTERRUPT_PRESENT24 0x0004 +#define CPLD_SLAVE2_INTERRUPT_PRESENT32 0x0001 +#define CPLD_SLAVE2_INTERRUPT_PRESENT40 0x0002 +#define CPLD_SLAVE2_INTERRUPT_PRESENT48 0x0004 + +#define CPLD_SLAVE2_INTERRUPT_QSFP_CR56 0x0200 +#define CPLD_SLAVE2_INTERRUPT_PRESENT56 0x0400 + +#define CPLD_SLAVE1_INTERRUPT_RX_LOST08 0x0008 +#define CPLD_SLAVE1_INTERRUPT_RX_LOST16 0x0010 +#define CPLD_SLAVE1_INTERRUPT_RX_LOST24 0x0020 +#define CPLD_SLAVE2_INTERRUPT_RX_LOST32 0x0008 +#define CPLD_SLAVE2_INTERRUPT_RX_LOST40 0x0010 +#define CPLD_SLAVE2_INTERRUPT_RX_LOST48 0x0020 + +#define CPLD_SLAVE1_INTERRUPT_TX_FAULT08 0x0040 +#define CPLD_SLAVE1_INTERRUPT_TX_FAULT16 0x0080 +#define CPLD_SLAVE1_INTERRUPT_TX_FAULT24 0x0100 +#define CPLD_SLAVE2_INTERRUPT_TX_FAULT32 0x0040 +#define CPLD_SLAVE2_INTERRUPT_TX_FAULT40 0x0080 +#define CPLD_SLAVE2_INTERRUPT_TX_FAULT48 0x0100 + + + + + + + +#define WAIT_TIME_OUT_COUNT 100 + + +struct i2c_algo_lpc_data { + void *data; /* private data for lolevel routines */ + void (*setlpc) (void *data, int ctl, int val); + int (*getlpc) (void *data, int ctl); + int (*getown) (void *data); + int (*getclock) (void *data); + void (*waitforpin) (void *data); + + int (*xfer_begin) (void *data); + int (*xfer_end) (void *data); + + /* Multi-master lost arbitration back-off delay (msecs) + * This should be set by the bus adapter or knowledgable client + * if bus is multi-mastered, else zero + */ + unsigned long lab_mdelay; +}; + + +struct subsys_private { + struct kset subsys; + struct kset *devices_kset; + struct list_head interfaces; + struct mutex mutex; + + struct kset *drivers_kset; + struct klist klist_devices; + struct klist klist_drivers; + struct blocking_notifier_head bus_notifier; + unsigned int drivers_autoprobe:1; + struct bus_type *bus; + + struct kset glue_dirs; + struct class *class; +}; + +void cs6436_56p_sysfs_add_client(struct i2c_client *client); +void cs6436_56p_sysfs_remove_client(struct i2c_client *client); + + +#endif /* I2C_LPC8584_H */ diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-cpld.c b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-cpld.c index a3c6e2db54e..dcff94085f0 100755 --- a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-cpld.c +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-cpld.c @@ -17,8 +17,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - - #include #include #include @@ -32,7 +30,6 @@ #include #include #include "i2c-algo-lpc.h" -#include "i2c-algo-lpc2iic.h" #include #include #include @@ -41,11 +38,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -56,6 +51,20 @@ # include #endif +#include +#include +#include +#include +#include +#include +#include + + + + + +/********************************************** Start ********************************************************/ + /* * ISA bus. */ @@ -65,7 +74,7 @@ static void platform_isa_bus_release(struct device * dev) return ; } - + static struct device isa_bus = { .init_name = "lpc-isa", .release = platform_isa_bus_release, @@ -76,9 +85,9 @@ struct isa_dev { struct device *next; unsigned int id; }; - -#define to_isa_dev(x) container_of((x), struct isa_dev, dev) - + +#define to_isa_dev(x) container_of((x), struct isa_dev, dev) + static int isa_bus_match(struct device *dev, struct device_driver *driver) { struct isa_driver *isa_driver = to_isa_driver(driver); @@ -223,7 +232,7 @@ int lpc_register_driver(struct isa_driver *isa_driver, unsigned int ndev) return error; } - + int lpc_bus_init(void) { int error; @@ -246,28 +255,36 @@ void lpc_bus_exit(void) } +/********************************************** End ********************************************************/ + + + + + + +/********************************************** Start ********************************************************/ /* * module parameters: */ static int i2c_debug = 0; static struct mutex lpc_lock; - -#define DEB2(x) if (i2c_debug >= 2) x -#define DEB3(x) if (i2c_debug >= 3) x + +#define DEB2(x) if (i2c_debug == 2) x +#define DEB3(x) if (i2c_debug == 3) x /* print several statistical values */ -#define DEBPROTO(x) if (i2c_debug >= 9) x; - /* debug the protocol by showing transferred bits */ +#define DEBPROTO(x) if (i2c_debug == 9) x; + /* debug the protocol by showing transferred bits */ #define DEF_TIMEOUT 160 - - - -/* setting states on the bus with the right timing: */ - + + + +/* setting states on the bus with the right timing: */ + #define set_lpc(adap, ctl, val) adap->setlpc(adap->data, ctl, val) #define get_lpc(adap, ctl) adap->getlpc(adap->data, ctl) -#define get_own(adap) adap->getown(adap->data) -#define get_clock(adap) adap->getclock(adap->data) +#define get_own(adap) adap->getown(adap->data) +#define get_clock(adap) adap->getclock(adap->data) #define i2c_outaddr(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DEVICE_ADDR, val) #define i2c_outbyte1(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DATA_TX1, val) @@ -278,54 +295,52 @@ static struct mutex lpc_lock; #define i2c_inbyte2(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX2) #define i2c_inbyte3(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX3) #define i2c_inbyte4(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX4) - + #define LPC_FPRINTF_LOG_PATH "/tmp/file.log" struct file *lpc_fprintf_file = NULL; - static int lpc_fprintf_debug(const char *fmt, ...) { char lpc_fprintf_buf[256]={0}; - struct va_format vaf; va_list args; int r; - unsigned int file_size = 0; mm_segment_t old_fs; struct timeval tv; + struct rtc_time tm; + do_gettimeofday(&tv); + rtc_time_to_tm(tv.tv_sec,&tm); + va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; - r=snprintf(lpc_fprintf_buf,"[%012d.%012d] %pV\n",sizeof(lpc_fprintf_buf),tv.tv_sec, tv.tv_usec, &vaf); + r=snprintf(lpc_fprintf_buf,sizeof(lpc_fprintf_buf),"[%04d.%08d] %pV\n",tm.tm_sec, (int)tv.tv_usec, &vaf); va_end(args); - old_fs = get_fs(); set_fs(KERNEL_DS); - lpc_fprintf_file->f_op->write(lpc_fprintf_file, (char *)lpc_fprintf_buf, strlen(lpc_fprintf_buf), &lpc_fprintf_file->f_pos); + vfs_write(lpc_fprintf_file, (char *)&lpc_fprintf_buf, strlen(lpc_fprintf_buf), &lpc_fprintf_file->f_pos); set_fs(old_fs); - memset(lpc_fprintf_buf,0x0,sizeof(lpc_fprintf_buf)); return r; } + static int lpc_fprintf_init(void) { - mm_segment_t old_fs; - - DEB2(printk("lpc_fprintf_init.\n");) - + printk("lpc_fprintf_init.\n"); if(lpc_fprintf_file == NULL) lpc_fprintf_file = filp_open(LPC_FPRINTF_LOG_PATH, O_RDWR | O_APPEND | O_CREAT, 0644); + if (IS_ERR(lpc_fprintf_file)) { - DEB2(printk("error occured while opening file %s, exiting...\n", LPC_FPRINTF_LOG_PATH);) - return 0; + printk("Error occured while opening file %s, exiting...\n", LPC_FPRINTF_LOG_PATH); + return -1; } return 0; @@ -333,10 +348,11 @@ static int lpc_fprintf_init(void) static int lpc_fprintf_exit(void) { - DEB2(printk("lpc_fprintf_exit.\n");) + printk("lpc_fprintf_exit.\n"); if(lpc_fprintf_file != NULL) filp_close(lpc_fprintf_file, NULL); + return 0; } @@ -366,14 +382,13 @@ void print_reg(struct i2c_algo_lpc_data *adap) static void i2c_repstart(struct i2c_algo_lpc_data *adap) { - DEBPROTO(lpc_fprintf_debug(" Sr\n")); + DEBPROTO(lpc_fprintf_debug("%s :\n",__func__);) set_lpc(adap, I2C_LPC_REG_COMMAND, I2C_LPC_REPSTART); } static void i2c_stop(struct i2c_algo_lpc_data *adap) { DEBPROTO(lpc_fprintf_debug("%s :\n",__func__);) - set_lpc(adap, I2C_LPC_REG_COMMAND, I2C_LPC_STOP); udelay(60); set_lpc(adap, I2C_LPC_REG_COMMAND, 0x00); @@ -384,60 +399,56 @@ static void i2c_stop(struct i2c_algo_lpc_data *adap) static void i2c_start(struct i2c_algo_lpc_data *adap) { - unsigned char status; - int timeout = DEF_TIMEOUT; - print_reg(adap); set_lpc(adap, I2C_LPC_REG_COMMAND, I2C_LPC_START); print_reg(adap); - } static int wait_for_bb(struct i2c_algo_lpc_data *adap) -{ - - int timeout = DEF_TIMEOUT; - int status; - +{ + + int timeout = DEF_TIMEOUT; + int status; + while (--timeout) { status = get_lpc(adap, I2C_LPC_REG_STATUS); - + DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus free status : %x\n",__func__,status);) - + if(status == I2C_LPC_TD) { DEBPROTO(lpc_fprintf_debug("%s : Bus is free status : %x\n",__func__,status);) break; } - } - - if (timeout == 0) { + } + + if (timeout == 0) { DEBPROTO(lpc_fprintf_debug("%s : Timeout for free busy status : %x\n",__func__,status);) - return -ETIMEDOUT; - } + return -ETIMEDOUT; + } + - - - return 0; + + return 0; } static int wait_for_be(int mode,struct i2c_algo_lpc_data *adap) -{ - - int timeout = DEF_TIMEOUT; - unsigned char status; - +{ + + int timeout = DEF_TIMEOUT; + unsigned char status; + while (--timeout) { - + status = get_lpc(adap, I2C_LPC_REG_STATUS); - + DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus empty status : %x\n",__func__,status);) if(mode == 1) @@ -446,42 +457,42 @@ static int wait_for_be(int mode,struct i2c_algo_lpc_data *adap) { DEBPROTO(lpc_fprintf_debug("%s : Bus is empty status : %x\n",__func__,status);) break; - } + } } else - { + { if(status & I2C_LPC_TD) { DEBPROTO(lpc_fprintf_debug("%s : Bus is empty status : %x\n",__func__,status);) break; } } - + status = get_lpc(adap, I2C_LPC_REG_TEST); - + DEBPROTO(lpc_fprintf_debug("%s : The test register data : %x\n",__func__,status);) udelay(1); /* wait for 100 us */ } - if (timeout == 0) { + if (timeout == 0) { DEBPROTO(lpc_fprintf_debug("%s : Timeout waiting for Bus Empty\n",__func__);) - return -ETIMEDOUT; - } - - return 0; + return -ETIMEDOUT; + } + + return 0; } static int wait_for_bf(struct i2c_algo_lpc_data *adap) -{ - - int timeout = DEF_TIMEOUT; - int status; - +{ + + int timeout = DEF_TIMEOUT; + int status; + while (--timeout) { status = get_lpc(adap, I2C_LPC_REG_STATUS); - + DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus full status : %x\n",__func__,status);) if(status & I2C_LPC_RBF) @@ -491,29 +502,29 @@ static int wait_for_bf(struct i2c_algo_lpc_data *adap) } status = get_lpc(adap, I2C_LPC_REG_TEST); - + DEBPROTO(lpc_fprintf_debug("%s : The test register data : %x\n",__func__,status);) udelay(1); /* wait for 100 us */ } - - if (timeout == 0) { + + if (timeout == 0) { DEBPROTO(lpc_fprintf_debug("%s : Timeout waiting for Bus Full\n",__func__);) - return -ETIMEDOUT; - } - - return 0; + return -ETIMEDOUT; + } + + return 0; } static int wait_for_td(struct i2c_algo_lpc_data *adap) -{ - - int timeout = DEF_TIMEOUT; - int status=0; - +{ + + int timeout = DEF_TIMEOUT; + int status=0; + while (--timeout) { - udelay(4); + udelay(4); status = get_lpc(adap, I2C_LPC_REG_STATUS); - + DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus done status : %x\n",__func__,status);) if(status == I2C_LPC_TD) @@ -521,18 +532,18 @@ static int wait_for_td(struct i2c_algo_lpc_data *adap) DEBPROTO(lpc_fprintf_debug("%s : Bus is done status : %x\n",__func__,status);) break; } - } - - if (timeout == 0) { + } + + if (timeout == 0) { DEBPROTO(lpc_fprintf_debug("%s : Timeout waiting for Bus Done\n",__func__);) - return -ETIMEDOUT; - } - - return 0; + return -ETIMEDOUT; + } + + return 0; } - + static int wait_for_pin(struct i2c_algo_lpc_data *adap, int *status) { int timeout = DEF_TIMEOUT; @@ -545,7 +556,7 @@ static int wait_for_pin(struct i2c_algo_lpc_data *adap, int *status) if (timeout == 0) return -ETIMEDOUT; - + return 0; } @@ -565,7 +576,7 @@ static int lpc_doAddress(struct i2c_algo_lpc_data *adap,struct i2c_msg *msg) { DEBPROTO(lpc_fprintf_debug("step 2 : write mode then write device address 0x%x\n",addr);) } - + if (flags & I2C_M_REV_DIR_ADDR) { addr ^= 1; @@ -629,33 +640,33 @@ static int lpc_sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+0,buf[i+0]);) i += 1; } - + /* Send START */ DEBPROTO(lpc_fprintf_debug("step 5-1 : Delay 6mS \n");) - udelay(6000); + udelay(6000); DEBPROTO(lpc_fprintf_debug("step 5-2 : Start to transfrom \n");) i2c_stop(adap); i2c_start(adap); DEBPROTO(lpc_fprintf_debug("step 5-3 : Start done\n");) - udelay(400); + udelay(400); DEBPROTO(lpc_fprintf_debug("step 6 : Waiting for BE\n");) timeout = wait_for_td(adap); if (timeout) { DEBPROTO(lpc_fprintf_debug("step 6 : Timeout waiting for BE \n");) - return -1; + return -EREMOTEIO; } }while (i < count); - + if(i == count) { DEBPROTO(lpc_fprintf_debug("Writen %d bytes successd !\n",count);) return i; } else - { + { DEBPROTO(lpc_fprintf_debug("Writen %d bytes failed \n",count);) - return -1; + return -EIO; } } @@ -663,7 +674,6 @@ static int lpc_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { int i=0,timeout=0; struct i2c_algo_lpc_data *adap = i2c_adap->algo_data; - int wfp; unsigned int count = msg->len; unsigned char *buf = msg->buf; @@ -675,27 +685,27 @@ static int lpc_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) /* Send START */ DEBPROTO(lpc_fprintf_debug("step 9-1 : Delay 6mS\n");) - udelay(6000); + udelay(6000); DEBPROTO(lpc_fprintf_debug("step 9-2 : Start to receive data\n");) i2c_stop(adap); i2c_start(adap); DEBPROTO(lpc_fprintf_debug("step 9-3 : Start done\n");) - udelay(400); + udelay(400); DEBPROTO(lpc_fprintf_debug("step 10 : Waiting for TD\n");) timeout = wait_for_td(adap); if (timeout) { DEBPROTO(lpc_fprintf_debug("step 10 : Timeout waiting for TD \n");) - return -1; + return -EREMOTEIO; } - + if((count -i) >= 4) { buf[i+0] = 0xff & i2c_inbyte1(adap); buf[i+1] = 0xff & i2c_inbyte2(adap); buf[i+2] = 0xff & i2c_inbyte3(adap); buf[i+3] = 0xff & i2c_inbyte4(adap); - + DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+0,buf[i+0]);) DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+1,buf[i+1]);) DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+2,buf[i+2]);) @@ -732,19 +742,17 @@ static int lpc_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) }while(i < count); - + if(i == count) { DEBPROTO(lpc_fprintf_debug("Read %d bytes successd !\n",count);) return i; } else - { + { DEBPROTO(lpc_fprintf_debug("Read %d bytes failed \n",count);) - return -1; + return -EIO; } - - return i; } @@ -768,7 +776,7 @@ static int lpc_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_algo_lpc_data *adap = i2c_adap->algo_data; struct i2c_msg *pmsg; int i; - int ret=0, timeout, status; + int ret=0; mutex_lock(&lpc_lock); @@ -810,11 +818,12 @@ static int lpc_master_xfer(struct i2c_adapter *i2c_adap, if (adap->xfer_end) adap->xfer_end(&i2c_adap->nr); - + mutex_unlock(&lpc_lock); - return i; + DEBPROTO(lpc_fprintf_debug("ret = 0x%x num = 0x%x i = 0x%x.\n",ret,num,i)); + return ret = (ret < 0) ? ret : num; } @@ -831,38 +840,14 @@ static const struct i2c_algorithm lpc_algo = { }; -/* - * registering functions to load algorithms at runtime - */ -int lpc_add_iic_bus(struct i2c_adapter *adap,unsigned int id) -{ - //struct i2c_algo_lpc_data *lpc_adap = adap->3; - int rval,num; +/********************************************** End ********************************************************/ + + - DEB2(dev_dbg(&adap->dev, "hw routines registered.\n")); - /* register new adapter to i2c module... */ - adap->algo = &lpc_algo; - - for(num = 0; num < LPC_I2C_MAX_NCHANS;num++) - { - adap->nr = num; - snprintf(adap->name, sizeof(adap->name), - "i2c-%d-lpc (chan_id %d)", i2c_adapter_id(adap), num); - if(num) - { - rval = i2c_add_numbered_adapter(adap); - } - else - { - rval = i2c_add_adapter(adap); - } - } - return rval; -} -EXPORT_SYMBOL(lpc_add_iic_bus); +/********************************************** Start ********************************************************/ #define DEFAULT_BASE 0x0a00 static int lpc_base= 0x0a00; @@ -905,7 +890,6 @@ struct cpld_dev_type *cpld_device; static void lpc_cpld_setbyte(void *data, int ctl, int val) { - //udelay(2); outb(ctl, LPC_INDEX_REG); mb(); @@ -916,7 +900,7 @@ static void lpc_cpld_setbyte(void *data, int ctl, int val) static int lpc_cpld_getbyte(void *data, int ctl) { u8 val = 0; - //udelay(2); + outb(ctl, LPC_INDEX_REG); mb(); @@ -929,17 +913,23 @@ static int lpc_cpld_getbyte(void *data, int ctl) static void lpc_iic_setbyte(void *data, int ctl, int val) { if (!cpld_device) - return -ENOTTY; + { + return ; + } if (down_interruptible(&cpld_device->sem)) - return -ERESTARTSYS; - + { + return ; + } + + lpc_cpld_setbyte(data,ctl,val); - + up(&cpld_device->sem); - DEB2(printk("%s REG[%x] = %x\n",__func__,ctl,val);) + DEBPROTO(lpc_fprintf_debug("%s REG[%x] = %x\n",__func__,ctl,val);) } + static int lpc_iic_getbyte(void *data, int ctl) { u8 val = 0; @@ -950,9 +940,9 @@ static int lpc_iic_getbyte(void *data, int ctl) return -ERESTARTSYS; val = lpc_cpld_getbyte(data,ctl); - + up(&cpld_device->sem); - DEB2(printk("%s REG[%x] = %x\n",__func__,ctl,val);) + DEBPROTO(lpc_fprintf_debug("%s REG[%x] = %x\n",__func__,ctl,val);) return val; } @@ -964,7 +954,7 @@ int cig_cpld_read_register(u8 reg_off, u8 *val) if (down_interruptible(&cpld_device->sem)) return -ERESTARTSYS; - *val = lpc_cpld_getbyte(cpld_device, reg_off); + *val = lpc_cpld_getbyte(cpld_device, reg_off); up(&cpld_device->sem); @@ -1039,24 +1029,24 @@ static irqreturn_t lpc_iic_handler(int this_irq, void *dev_id) { static int board_id = 0; -static int lpc_select_chan(void *data) +static int lpc_iic_select(void *data) { unsigned int chan_id=0; chan_id = *(unsigned int *)data; - chan_id -= 1; - DEB2(printk("step 1 : selest channel id = %d\n",chan_id);) + chan_id -= 2; + DEBPROTO(lpc_fprintf_debug("step 1 : selest channel id = %d\n",chan_id);) lpc_iic_setbyte(data,I2C_LPC_REG_BUS_SEL,chan_id); return 0; } -static int lpc_deselect_chan(void *data) +static int lpc_iic_deselect(void *data) { unsigned int chan_id=0; chan_id = *(unsigned int *)data; - chan_id -= 1; - DEB2(printk("step last :deselect channel id = %d\n",chan_id);) + chan_id -= 2; + DEBPROTO(lpc_fprintf_debug("step last :deselect channel id = %d\n",chan_id);) return 0; } @@ -1072,8 +1062,8 @@ static struct i2c_algo_lpc_data lpc_iic_data = { .getown = lpc_iic_getown, .getclock = lpc_iic_getclock, .waitforpin = lpc_iic_waitforpin, - .xfer_begin = lpc_select_chan, - .xfer_end = lpc_deselect_chan, + .xfer_begin = lpc_iic_select, + .xfer_end = lpc_iic_deselect, }; #include @@ -1082,12 +1072,12 @@ static struct i2c_adapter lpc_iic_arr_ops[LPC_I2C_MAX_NCHANS] = {0}; static void dummy_setscl(void *data, int state) { - return 1; + return; } static void dummy_setsda(void *data, int state) { - return 1; + return; } @@ -1170,9 +1160,7 @@ static int lpc_iic_probe(struct device *dev, unsigned int id) DEB2(printk("lpc_iic_probe\n");) mutex_init(&lpc_lock); - if(board_id == 1) - i2c_add_adapter(&i2c_dummy); - + for(num = 0; num < LPC_I2C_MAX_NCHANS;num++) { lpc_iic_arr_ops[num].dev.parent = dev; @@ -1181,11 +1169,11 @@ static int lpc_iic_probe(struct device *dev, unsigned int id) lpc_iic_arr_ops[num].algo = &lpc_algo; lpc_iic_arr_ops[num].algo_data = &lpc_iic_data, lpc_iic_arr_ops[num].nr=num; - snprintf(lpc_iic_arr_ops[num].name, sizeof(lpc_iic_arr_ops[num].name), "i2c-%d-lpc", i2c_adapter_id(&lpc_iic_arr_ops[num]), num); + snprintf(lpc_iic_arr_ops[num].name, sizeof(lpc_iic_arr_ops[num].name), "i2c-%d-lpc", i2c_adapter_id(&lpc_iic_arr_ops[num])); rval |= i2c_add_adapter(&lpc_iic_arr_ops[num]); DEB2(printk("%s\n",lpc_iic_arr_ops[num].name);) } - + return 0; } @@ -1198,8 +1186,6 @@ static int lpc_iic_remove(struct device *dev, unsigned int id) for(num = LPC_I2C_MAX_NCHANS - 1; num >= 0 ;num--) i2c_del_adapter(&lpc_iic_arr_ops[num]); - if(board_id == 1) - i2c_del_adapter(&i2c_dummy); return 0; } @@ -1214,8 +1200,15 @@ static struct isa_driver i2c_lpc_driver = { }, }; +/********************************************** End ********************************************************/ + + + + + + +/********************************************** Start ********************************************************/ -struct kset cpld_kset; static int cpld_major = 0; static int cpld_minor = 0; @@ -1227,6 +1220,8 @@ struct cpld_rw_msg { static struct cpld_rw_msg param_read = {-1}; static struct cpld_rw_msg param_write = {-1}; +static struct cpld_rw_msg param_reads = {-1}; +static struct cpld_rw_msg param_writes = {-1}; void cpld_sysfs_kobj_release(struct kobject *kobj) { @@ -1245,28 +1240,57 @@ int cpld_sysfs_add_attr(struct kobject* kobj, char* attr_name) return sysfs_create_file(kobj, attr); } +static int cig_cpld_write_slave_cpld_register(u8 reg_addr, u8 reg_data); +static int cig_cpld_read_slave_cpld_register(u8 reg_addr, u8 *reg_data); + static ssize_t cpld_sysfs_show(struct kobject *kobj, struct attribute *attr, char *buffer) { - u8 val,ret; + u8 val=0,ret=0,year=0,month=0,day=0,cpld_m=0,cpld_1=0,cpld_2=0; if (0 == strcmp(attr->name, "read")) { - val = lpc_iic_getbyte(NULL,param_read.addr); - ret = sprintf(buffer,"read : addr = %x val = %x\n",param_read.addr, val); + val = lpc_iic_getbyte(NULL,param_read.addr); + ret = sprintf(buffer,"read : addr = 0x%x val = 0x%x\n",param_read.addr, val); } else if (0 == strcmp(attr->name, "write")) { lpc_iic_setbyte(NULL, param_write.addr,param_write.data); - ret = sprintf(buffer,"write : addr = %x val = %x\n",param_write.addr, param_write.data); + ret = sprintf(buffer,"write : addr = 0x%x val = 0x%x\n",param_write.addr, param_write.data); } else if (0 == strcmp(attr->name, "version")) { - val = lpc_iic_getbyte(NULL, 0x02); - ret = sprintf(buffer,"CPLD version : V%02x\n",val); + cpld_m = lpc_iic_getbyte(NULL, 0x02); + year = lpc_iic_getbyte(NULL, 0x03); + month = lpc_iic_getbyte(NULL, 0x04); + day = lpc_iic_getbyte(NULL, 0x05); + + cig_cpld_read_slave_cpld_register(0x1d,&cpld_1); + cig_cpld_read_slave_cpld_register(0x1e,&cpld_2); + + ret = sprintf(buffer,"Main CPLD version : V%02x\n"\ + "Main CPLD date : 20%02x-%02x-%02x\n"\ + "Slave 1 CPLD version : V%02x\n"\ + "Slave 2 CPLD version : V%02x\n",cpld_m,year,month,day,cpld_1,cpld_2); + } + if (0 == strcmp(attr->name, "reads")) + { + ret = cig_cpld_read_slave_cpld_register(param_reads.addr,&val); + if (ret < 0) + printk("ERROR:Failed to read slave cpld.\n"); + ret = sprintf(buffer,"reads : addr = 0x%x val = 0x%x\n",param_reads.addr, val); + + } + else if (0 == strcmp(attr->name, "writes")) + { + ret = cig_cpld_write_slave_cpld_register(param_writes.addr,param_writes.data); + if (ret < 0) + printk("ERROR:Failed to read slave cpld.\n"); + ret = sprintf(buffer,"writes : addr = 0x%x val = 0x%x\n",param_writes.addr, param_writes.data); } - + + return ret; } @@ -1274,7 +1298,7 @@ static ssize_t cpld_sysfs_show(struct kobject *kobj, struct attribute *attr, cha static ssize_t cpld_sysfs_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count) { int param[3]; - + if (0 == strcmp(attr->name, "read")) { sscanf(buffer, "0x%02x", ¶m[0]); @@ -1285,19 +1309,30 @@ static ssize_t cpld_sysfs_store(struct kobject *kobj, struct attribute *attr, co sscanf(buffer, "0x%2x 0x%02x", ¶m[0], ¶m[1]); param_write.addr = param[0]; param_write.data = param[1]; + } + if (0 == strcmp(attr->name, "reads")) + { + sscanf(buffer, "0x%02x", ¶m[0]); + param_reads.addr = param[0]; + } + else if (0 == strcmp(attr->name, "writes")) + { + sscanf(buffer, "0x%2x 0x%02x", ¶m[0], ¶m[1]); + param_writes.addr = param[0]; + param_writes.data = param[1]; } return count; } -static struct sysfs_ops cpld_sysfs_ops = -{ +static struct sysfs_ops cpld_sysfs_ops = +{ .show = cpld_sysfs_show, .store = cpld_sysfs_store, }; -static struct kobj_type cpld_kobj_type = +static struct kobj_type cpld_kobj_type = { .release = cpld_sysfs_kobj_release, .sysfs_ops = &cpld_sysfs_ops, @@ -1308,6 +1343,10 @@ static struct kobj_type cpld_kobj_type = static const char driver_name[] = "cpld_drv"; static atomic_t cpld_available = ATOMIC_INIT(1); static struct class *cpld_class; +static struct device *cpld_dev; + + + #define CPLD_IOC_MAGIC '[' #define CPLD_IOC_RDREG _IOR(CPLD_IOC_MAGIC, 0, struct cpld_rw_msg) @@ -1340,7 +1379,7 @@ int cpld_release(struct inode *inode, struct file *flip) long cpld_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - int rc = 0; + int rc = 0; int err = 0; struct cpld_dev_type *dev = (struct cpld_dev_type *)filp->private_data; struct cpld_rw_msg msg; @@ -1390,7 +1429,7 @@ struct file_operations cpld_fops = { .unlocked_ioctl = cpld_ioctl, .release = cpld_release, }; - + static void cpld_setup_cdev(struct cpld_dev_type *dev) { @@ -1404,166 +1443,710 @@ static void cpld_setup_cdev(struct cpld_dev_type *dev) if (err) DEB2(printk(KERN_NOTICE "Error %d adding cpld", err);) } -//#define CPLD_KTHREAD_TEST -#ifdef CPLD_KTHREAD_TEST -#include -#include -#include -#include -#include -#include -static struct task_struct *test_TaskStruct; -void get_random_bytes(void *buf, int nbytes); +/********************************************** End ********************************************************/ + + + -#define LM75_REAR_LEFT_PATH "/sys/class/hwmon/hwmon5/temp1_input" -#define LM75_REAR_RIGHT_PATH "/sys/class/hwmon/hwmon6/temp1_input" +/********************************************** Start ********************************************************/ +#include +#include +#include + +static spinlock_t irq_inter_lock; +static struct delayed_work irq_inter_work; +static unsigned long irq_inter_delay; -static int threadTask(void* arg) +static int cig_cpld_write_slave_cpld_register(u8 reg_addr, u8 reg_data) { - static int count =0; - unsigned char lpc_read_data=0; - unsigned char lpc_write_data=0; - unsigned char lpc_random_data=0; - - struct file *temp1_file = NULL,*temp2_file = NULL; - unsigned char temp1_buffer[8]={0},temp2_buffer[8]={0}; - - mm_segment_t old_fs; - while(1) + u8 read_status = 0; + u8 wait_time_out = WAIT_TIME_OUT_COUNT; + DEB2(printk("<=======write=========>")); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_ADDR, reg_addr << 1); + DEB2(printk("[62]=%x\n",reg_addr << 1)); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_TX, reg_data); + DEB2(printk("[63]=%x\n",reg_data)); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_COMMAND, 0x80); + DEB2(printk("[65]=%x\n",0x80)); + do{ + cig_cpld_read_register(ADDR_REG_SFP_STATUS_STATUS, &read_status); + DEB2(printk("[66]=%x\n",read_status)); + udelay(60); + wait_time_out--; + if(wait_time_out == 0) + break; + }while(read_status != 0x02); + DEB2(printk("<=======write=========>")); + + + if(wait_time_out == 0) + return -1; + + return 1; +} + + +static int cig_cpld_read_slave_cpld_register(u8 reg_addr, u8 *reg_data) +{ + u8 read_status = 0; + u8 wait_time_out = WAIT_TIME_OUT_COUNT; + DEB2(printk("<========read=========>")); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_ADDR, reg_addr << 1 | 1); + DEB2(printk("[62]=%x\n",reg_addr << 1 | 1)); + cig_cpld_write_register(ADDR_REG_SFP_STATUS_COMMAND, 0x80); + DEB2(printk("[65]=%x\n",0x80)); + do{ + udelay(60); + cig_cpld_read_register(ADDR_REG_SFP_STATUS_STATUS, &read_status); + DEB2(printk("[66]=%x\n",read_status)); + wait_time_out--; + if(wait_time_out == 0) + break; + }while(read_status != 0x01); + + cig_cpld_read_register(ADDR_REG_SFP_STATUS_RX,reg_data); + DEB2(printk("[64]=%x\n",*reg_data)); + DEB2(printk("<========read=========>")); + + if(wait_time_out == 0) + return -1; + + return 1; +} + + + +struct sock *nlsk = NULL; +extern struct net init_net; +#define NETLINK_TEST 26 +#define MSG_LEN 125 +#define USER_PORT 100 +static u32 irq_present_status_low_current,irq_present_status_low_next; +static u32 irq_present_status_high_current,irq_present_status_high_next; +static u32 irq_tx_fault_status_low_current,irq_tx_fault_status_low_next; +static u32 irq_tx_fault_status_high_current,irq_tx_fault_status_high_next; +static u32 irq_rx_lost_status_low_current,irq_rx_lost_status_low_next; +static u32 irq_rx_lost_status_high_current,irq_rx_lost_status_high_next; + +static u8 irq_present_qsfp_current,irq_present_qsfp_next; +static u8 irq_interrupt_qsfp_current,irq_interrupt_qsfp_next; + +struct input_dev *cpld_input_dev; + + + +int send_usrmsg(char *pbuf, uint16_t len) +{ + struct sk_buff *nl_skb; + struct nlmsghdr *nlh; + + int ret; + + + nl_skb = nlmsg_new(len, GFP_ATOMIC); + if(!nl_skb) + { + printk("netlink alloc failure\n"); + return -1; + } + + + nlh = nlmsg_put(nl_skb, 0, 0, NETLINK_TEST, len, 0); + if(nlh == NULL) + { + printk("nlmsg_put failaure \n"); + nlmsg_free(nl_skb); + return -1; + } + + memcpy(nlmsg_data(nlh), pbuf, len); + ret = netlink_unicast(nlsk, nl_skb, USER_PORT, MSG_DONTWAIT); + + return ret; +} + +static void netlink_rcv_msg(struct sk_buff *skb) +{ + + struct nlmsghdr *nlh = NULL; + char *umsg = NULL; + char kmsg[1024] = {0}; + char kmsg_tmp[16] = {0}; + u8 i = 0; + u8 tmp[3]={0}; + + if(skb->len >= nlmsg_total_size(0)) + { + nlh = nlmsg_hdr(skb); + umsg = NLMSG_DATA(nlh); + if(umsg) + { + for(i = 0;i < 24;i++) + { + if(!(irq_present_status_low_current & (0x1 << i))) + { + tmp[0] = 1; + } + else + { + tmp[0] = 0; + } + + if(!(irq_rx_lost_status_low_current & (0x1 << i))) + { + tmp[1] = 1; + } + else + { + tmp[1] = 0; + } + + if(!(irq_tx_fault_status_low_current & (0x1 << i))) + { + tmp[2] = 1; + } + else + { + tmp[2] = 0; + } + memset(kmsg_tmp,0xff,sizeof(kmsg_tmp)); + sprintf(kmsg_tmp,"sfp%02d:%1d:%1d:%1d ",i+1,tmp[0],tmp[1],tmp[2]); + strcat(kmsg,kmsg_tmp); + } + + for(i = 0;i < 24;i++) + { + if(!(irq_present_status_high_current & (0x1 << i))) + { + tmp[0] = 1; + } + else + { + tmp[0] = 0; + } + + if(!(irq_rx_lost_status_high_current & (0x1 << i))) + { + tmp[1] = 1; + } + else + { + tmp[1] = 0; + } + + if(!(irq_tx_fault_status_high_current & (0x1 << i))) + { + tmp[2] = 1; + } + else + { + tmp[2] = 0; + } + memset(kmsg_tmp,0xff,sizeof(kmsg_tmp)); + sprintf(kmsg_tmp,"sfp%02d:%1d:%1d:%1d ",i+25,tmp[0],tmp[1],tmp[2]); + strcat(kmsg,kmsg_tmp); + } + + + for(i = 0;i < 8;i++) + { + if(!(irq_present_qsfp_current & (0x1 << i))) + { + tmp[0] = 1; + } + else + { + tmp[0] = 0; + } + + if(!(irq_interrupt_qsfp_current & (0x1 << i))) + { + tmp[1] = 1; + } + else + { + tmp[1] = 0; + } + + memset(kmsg_tmp,0xff,sizeof(kmsg_tmp)); + sprintf(kmsg_tmp,"qsfp%02d:%1d:%1d:%1d ",i+49,tmp[0],tmp[1],0); + strcat(kmsg,kmsg_tmp); + } + + printk("kernel recv from user: %s\n", umsg); + send_usrmsg(kmsg, strlen(kmsg)); + } + } + + return ; +} + + + +struct netlink_kernel_cfg cfg = { + .input = netlink_rcv_msg, /* set recv callback */ +}; + + + +#define RANGE_OF_BYTE_SHIFT(to_arg,shift,from_arg) {to_arg &= ~(0xff << shift); to_arg |= from_arg << shift;} + + +static void irq_inter_wapper(struct work_struct * work) +{ + + u8 m_data = 0; + u8 data_high8 = 0,data_low8 = 0; + u16 data_16 = 0; + u8 status = 0; + u8 i = 0; + char kmsg[64]={0}; + u8 tmp[3] = {0}; + + DEB2(printk("CPLD_MASTER_INTERRUPT\r\n")); + + m_data = lpc_iic_getbyte(NULL,CPLD_MASTER_INTERRUPT_STATUS_REG); + lpc_iic_setbyte(NULL,CPLD_MASTER_INTERRUPT_STATUS_REG,0xff); + + cig_cpld_write_slave_cpld_register(CPLD_SLAVE1_INTERRUPT_MASK_REG,0xff); + cig_cpld_write_slave_cpld_register(CPLD_SLAVE2_INTERRUPT_MASK_REG,0xff); + if(!(m_data & CPLD_MASTER_INTERRUPT_CPLD1)) { - if(kthread_should_stop()) + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_INTERRUPT_STATUS_H_REG,&data_high8); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_INTERRUPT_STATUS_L_REG,&data_low8); + data_16 = data_low8 | data_high8 << 8; + if( + !(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT08) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT16) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT24) + ) { - DEB2(printk("threadTask: kthread_should_stop\n")); - break; - } - -#if 1 - get_random_bytes(&lpc_random_data,1); - - lpc_write_data = lpc_random_data; - - lpc_iic_setbyte(NULL,I2C_LPC_REG_TEST,lpc_write_data); - //DEB2(printk("threadTask: lpc write reg[01] data : %02x\n",lpc_write_data)); - - lpc_read_data = lpc_iic_getbyte(NULL,I2C_LPC_REG_TEST); - //DEB2(printk("threadTask: lpc read reg[01] data : %02x\n",lpc_read_data)); - udelay(10000); - if(lpc_write_data != lpc_read_data) + if(!(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT08)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT08\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_PRESENT08_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_low_current,0,status); + + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT16)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT16\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_PRESENT16_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_low_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_PRESENT24)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT24\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_PRESENT24_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_low_current,16,status); + } + DEB2(printk("irq_present_status_low_next = %08x irq_present_status_low_current = %08x \n",irq_present_status_low_next,irq_present_status_low_current)); + } + + if( + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST08) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST16) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST24) + ) { - printk("Error : WRITE %02x != READ %02x\n",lpc_write_data,lpc_read_data); + if(!(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST08)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_RX_LOST08\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_RX_LOST08_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_low_current,0,status); + + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST16)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT16\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_RX_LOST16_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_low_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST24)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_PRESENT24\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_RX_LOST24_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_low_current,16,status); + } + DEB2(printk("irq_rx_lost_status_low_next = %08x irq_rx_lost_status_low_current = %08x \n",irq_rx_lost_status_low_next,irq_rx_lost_status_low_current)); } - msleep(10); -#else - if(temp1_file != NULL) - temp1_file = filp_open(LM75_REAR_LEFT_PATH, O_RDONLY , 0); - if (IS_ERR(temp1_file)) { - printk("error occured while opening file %s, exiting...\n", LM75_REAR_LEFT_PATH); + if( + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST08) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST16) || + !(data_16 & CPLD_SLAVE1_INTERRUPT_RX_LOST24) + ) + { + if(!(data_16 & CPLD_SLAVE1_INTERRUPT_TX_FAULT08)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_TX_FAULT08\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_TX_FAULT08_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_low_current,0,status); + + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_TX_FAULT16)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_TX_FAULT16\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_TX_FAULT16_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_low_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE1_INTERRUPT_TX_FAULT24)) + { + DEB2(printk("CPLD_SLAVE1_INTERRUPT_TX_FAULT24\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE1_TX_FAULT24_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_low_current,16,status); + } + DEB2(printk("irq_tx_fault_status_low_next = %08x irq_tx_fault_status_low_current = %08x \n",irq_tx_fault_status_low_next,irq_tx_fault_status_low_current)); + + } + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_CPLD2)) + { + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_INTERRUPT_STATUS_H_REG,&data_high8); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_INTERRUPT_STATUS_L_REG,&data_low8); + data_16 = data_low8 | data_high8 << 8; + if( + !(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT32) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT40) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT48) + ) + { + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT32)) + { + DEB2(printk("CPLD_SLAVE2_PRESENT32_REG\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_PRESENT32_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_high_current,0,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT40)) + { + DEB2(printk("CPLD_SLAVE2_PRESENT40_REG\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_PRESENT40_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_high_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT48)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT48\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_PRESENT48_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_present_status_high_current,16,status); + } } - if(temp2_file != NULL) - temp2_file = filp_open(LM75_REAR_RIGHT_PATH, O_RDONLY ,0); - if (IS_ERR(temp2_file)) { - printk("error occured while opening file %s, exiting...\n", LM75_REAR_RIGHT_PATH); + if( + !(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST32) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST40) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST48) + ) + { + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST32)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_RX_LOST32\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_RX_LOST32_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_high_current,0,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST40)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT40\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_RX_LOST40_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_high_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_RX_LOST48)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT48\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_RX_LOST48_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_rx_lost_status_high_current,16,status); + } + } + if( + !(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT32) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT40) || + !(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT48) + ) + { + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT32)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_RX_LOST32\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_TX_FAULT32_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_high_current,0,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT40)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT40\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_TX_FAULT40_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_high_current,8,status); + } + else if(!(data_16 & CPLD_SLAVE2_INTERRUPT_TX_FAULT48)) + { + DEB2(printk("CPLD_SLAVE2_INTERRUPT_PRESENT48\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_TX_FAULT48_REG,&status); + RANGE_OF_BYTE_SHIFT(irq_tx_fault_status_high_current,16,status); + } + } - old_fs = get_fs(); - set_fs(KERNEL_DS); + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_PRESENT56)) + { + DEB2(printk("CPLD_SLAVE2_PRESENT56_REG\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_PRESENT56_REG,&status); + irq_present_qsfp_current = status; + } - temp1_file->f_op->read(temp1_file, (char *)temp1_buffer, strlen(temp1_buffer), &temp1_file->f_pos); + if(!(data_16 & CPLD_SLAVE2_INTERRUPT_QSFP_CR56)) + { + DEB2(printk("CPLD_SLAVE2_QSFP_CR56_REG\r\n")); + cig_cpld_read_slave_cpld_register(CPLD_SLAVE2_QSFP_CR56_REG,&status); + irq_interrupt_qsfp_current = status; + } + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_LSW)) + { + DEB2(printk("CPLD_MASTER_INTERRUPT_LSW\r\n")); + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_PSU1)) + { + DEB2(printk("CPLD_MASTER_INTERRUPT_PSU1\r\n")); + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_PSU2)) + { + DEB2(printk("CPLD_MASTER_INTERRUPT_PSU2\r\n")); + } + else if(!(m_data & CPLD_MASTER_INTERRUPT_6320)) + { + DEB2(printk("CPLD_MASTER_INTERRUPT_6320\r\n")); + } + cig_cpld_write_slave_cpld_register(CPLD_SLAVE1_INTERRUPT_MASK_REG,0x0); + cig_cpld_write_slave_cpld_register(CPLD_SLAVE2_INTERRUPT_MASK_REG,0x0); - temp2_file->f_op->read(temp2_file, (char *)temp2_buffer, strlen(temp2_buffer), &temp2_file->f_pos); - - set_fs(old_fs); + memset(tmp,0xff,sizeof(tmp)); - if((simple_strtoul(temp1_buffer,NULL,10) >=30000) || (simple_strtoul(temp2_buffer,NULL,10) >=30000)) + for(i = 0;i < 24;i++) + { + if(!(irq_present_status_low_current & (0x1 << i)) && (irq_present_status_low_next & (0x1 << i))) { - lpc_iic_setbyte(NULL,0x40,0xff); - printk("Full speed\n"); + DEB2(printk("SFP%d is present\r\n",i+1)); + tmp[0] = 1; + } + else if((irq_present_status_low_current & (0x1 << i)) && !(irq_present_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d is absent\r\n",i+1)); + tmp[0] = 0; } - msleep(1000); -#endif + if(!(irq_tx_fault_status_low_current & (0x1 << i)) && (irq_tx_fault_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d transmission is right\r\n",i+1)); + tmp[1] = 1; + } + else if((irq_tx_fault_status_low_current & (0x1 << i)) && !(irq_tx_fault_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d transmission is fault\r\n",i+1)); + tmp[1] = 0; + } + + if(!(irq_rx_lost_status_low_current & (0x1 << i)) && (irq_rx_lost_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d optical is meet\r\n",i+1)); + tmp[2] = 1; + } + else if((irq_rx_lost_status_low_current & (0x1 << i)) && !(irq_rx_lost_status_low_next & (0x1 << i))) + { + DEB2(printk("SFP%d optical is lost\r\n",i+1)); + tmp[2] = 0; + } + + if((tmp[0] != 0xff) || (tmp[1] != 0xff) || (tmp[2] != 0xff)) + { + memset(kmsg,0xff,sizeof(kmsg)); + snprintf(kmsg,sizeof(kmsg),"sfp%02d:%1d:%1d:%1d ",i+1,(tmp[0] == 0xff) ? 0:tmp[0],(tmp[1] == 0xff) ? 0:tmp[1],(tmp[2] == 0xff) ? 0:tmp[2]); + break; + } } -} - -static int init_kernel_Thread(void) -{ - test_TaskStruct=kthread_create(threadTask,NULL,"KernelThead",0); - if(IS_ERR(test_TaskStruct)) + + memset(tmp,0xff,sizeof(tmp)); + for(i = 0;i < 24;i++) { - printk("kthread_create error\n"); + if(!(irq_present_status_high_current & (0x1 << i)) && (irq_present_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d is present\r\n",i+25)); + tmp[0] = 1; + } + else if((irq_present_status_high_current & (0x1 << i)) && !(irq_present_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d is absent\r\n",i+25)); + tmp[0] = 0; + + } + + if(!(irq_rx_lost_status_high_current & (0x1 << i)) && (irq_rx_lost_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d optical is meet\r\n",i+25)); + tmp[1] = 1; + } + else if((irq_rx_lost_status_high_current & (0x1 << i)) && !(irq_rx_lost_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d optical is lost\r\n",i+25)); + tmp[1] = 0; + } + + if(!(irq_tx_fault_status_high_current & (0x1 << i)) && (irq_tx_fault_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d transmission is right\r\n",i+25)); + tmp[2] = 1; + } + else if((irq_tx_fault_status_high_current & (0x1 << i)) && !(irq_tx_fault_status_high_next & (0x1 << i))) + { + DEB2(printk("SFP%d transmission is fault\r\n",i+25)); + tmp[2] = 0; + } + + if((tmp[0] != 0xff) || (tmp[1] != 0xff) || (tmp[2] != 0xff)) + { + memset(kmsg,0xff,sizeof(kmsg)); + snprintf(kmsg,sizeof(kmsg),"sfp%02d:%1d:%1d:%1d ",i+25,(tmp[0] == 0xff) ? 0:tmp[0],(tmp[1] == 0xff) ? 0:tmp[1],(tmp[2] == 0xff) ? 0:tmp[2]); + break; + } } - else + + memset(tmp,0xff,sizeof(tmp)); + for(i = 0 ; i < 8; i++) { - wake_up_process(test_TaskStruct); + if(!(irq_present_qsfp_current & (0x1 << i)) && (irq_present_qsfp_next & (0x1 << i))) + { + DEB2(printk("SFP%d is present\r\n",i+49)); + tmp[0] = 1; + } + else if((irq_present_qsfp_current & (0x1 << i)) && !(irq_present_qsfp_next & (0x1 << i))) + { + DEB2(printk("SFP%d is absent\r\n",i+49)); + tmp[0] = 0; + } + + if(!(irq_interrupt_qsfp_current & (0x1 << i)) && (irq_interrupt_qsfp_next & (0x1 << i))) + { + DEB2(printk("SFP%d interrupt is occured \r\n",i+49)); + tmp[1] = 1; + } + else if((irq_interrupt_qsfp_current & (0x1 << i)) && !(irq_interrupt_qsfp_next & (0x1 << i))) + { + DEB2(printk("SFP%d interrupt is cleaned\r\n",i+49)); + tmp[1] = 0; + } + + if((tmp[0] != 0xff) || (tmp[1] != 0xff)) + { + memset(kmsg,0xff,sizeof(kmsg)); + snprintf(kmsg,sizeof(kmsg),"qsfp%02d:%1d:%1d:%1d ",i+49,(tmp[0] == 0xff) ? 0:tmp[0],(tmp[1] == 0xff) ? 0:tmp[1],0); + break; + } } - return 0; + + + irq_present_status_low_next = irq_present_status_low_current; + irq_rx_lost_status_low_next = irq_rx_lost_status_low_current; + irq_tx_fault_status_low_next = irq_tx_fault_status_low_current; + irq_present_status_high_next = irq_present_status_high_current; + irq_rx_lost_status_high_next = irq_rx_lost_status_high_current; + irq_tx_fault_status_high_next = irq_tx_fault_status_high_current; + irq_present_qsfp_next = irq_present_qsfp_current; + irq_interrupt_qsfp_next = irq_interrupt_qsfp_current; + + send_usrmsg(kmsg, strlen(kmsg)); } -static void exit_kernel_Thread(void) +static void disableIrq(unsigned short maskReg, unsigned short mask) { - kthread_stop(test_TaskStruct); - test_TaskStruct = NULL; + u8 data = 0; + + data = lpc_iic_getbyte(NULL,maskReg); + data |= mask; + lpc_iic_setbyte(NULL,maskReg, data); } -#endif +static void enableIrq(unsigned short maskReg, unsigned short mask) +{ + unsigned short data; + + data = lpc_iic_getbyte(NULL,maskReg); + data &= ~mask; + lpc_iic_setbyte(NULL,maskReg, data); +} + + +static irqreturn_t irq_inter_isr(int irq, void *handle) +{ + + /* + * use keventd context to read the event fifo registers + * Schedule readout at least 25ms after notification for + * REVID < 4 + */ + + schedule_delayed_work(&irq_inter_work, irq_inter_delay); + + return IRQ_HANDLED; +} + + +#define CIG_CPLD_CHR_NAME "cpld" static int __init cpld_init(void) { - int rval,rc; + int rval,rc=0; dev_t dev; - + u8 s_data; + int isr_GPIO_num = 289; + DEB2(printk("cpld_init\n");) +/**************************************************************************************/ + + LPC_INDEX_REG = lpc_base_addr; + LPC_DATA_REG = lpc_base_addr + 1; + cpld_device = kzalloc(sizeof(struct cpld_dev_type), GFP_KERNEL); if (!cpld_device) goto error3; - cpld_device->io_resource = request_region(lpc_base_addr, + cpld_device->io_resource = request_region(lpc_base_addr, lpc_io_space_size, "lpc-i2c"); if (!cpld_device->io_resource) { - DEB2(printk("lpc: claim I/O resource fail\n");) + printk("lpc: claim I/O resource fail\n"); goto error2; } sema_init(&cpld_device->sem, 1); - LPC_INDEX_REG = lpc_base_addr; - LPC_DATA_REG = lpc_base_addr + 1; - - rval = lpc_bus_init(); - rval = lpc_register_driver(&i2c_lpc_driver, 1); - - kobject_set_name(&cpld_kset.kobj, "cpld"); - cpld_kset.kobj.ktype= &cpld_kobj_type; - kset_register(&cpld_kset); - cpld_sysfs_add_attr(&cpld_kset.kobj, "read"); - cpld_sysfs_add_attr(&cpld_kset.kobj, "write"); - cpld_sysfs_add_attr(&cpld_kset.kobj, "version"); - if (cpld_major) { dev = MKDEV(cpld_major, cpld_minor); - rc = register_chrdev_region(dev, 1, "cpld"); + rc = register_chrdev_region(dev, 1, CIG_CPLD_CHR_NAME); } else { - rc = alloc_chrdev_region(&dev, cpld_major, 1, "cpld"); + rc = alloc_chrdev_region(&dev, cpld_major, 1, CIG_CPLD_CHR_NAME); cpld_major = MAJOR(dev); } cpld_setup_cdev(cpld_device); - cpld_class = class_create(THIS_MODULE, KBUILD_MODNAME); + cpld_class = class_create(THIS_MODULE,CIG_CPLD_CHR_NAME); if (!cpld_class) { DEB2(printk("failed to create class\n");) goto error1; } - device_create(cpld_class, NULL, dev, NULL, "cpld"); -#ifdef CPLD_KTHREAD_TEST - init_kernel_Thread(); -#endif - + cpld_class->p->subsys.kobj.ktype= &cpld_kobj_type; + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "read"); + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "write"); + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "reads"); + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "writes"); + cpld_sysfs_add_attr(&cpld_class->p->subsys.kobj, "version"); + + cpld_dev = device_create(cpld_class, NULL, dev, NULL, CIG_CPLD_CHR_NAME); + +/**************************************************************************************/ + + rval = lpc_bus_init(); + rval = lpc_register_driver(&i2c_lpc_driver, 1); + +/**************************************************************************************/ return 0; error1: cdev_del(&cpld_device->cdev); @@ -1572,20 +2155,18 @@ static int __init cpld_init(void) release_resource(cpld_device->io_resource); error3: kfree(cpld_device); - + return rc; } static void __exit cpld_exit(void) { - DEB2(printk("cpld_exit\n")); - - lpc_unregister_driver(&i2c_lpc_driver); - lpc_bus_exit(); -#ifdef CPLD_KTHREAD_TEST - exit_kernel_Thread(); -#endif - dev_t devno = MKDEV(cpld_major, cpld_minor); + + DEB2(printk("cpld_exit\n")); + + lpc_unregister_driver(&i2c_lpc_driver); + lpc_bus_exit(); + dev_t devno = MKDEV(cpld_major, cpld_minor); cdev_del(&cpld_device->cdev); if (cpld_class) { @@ -1593,11 +2174,6 @@ static void __exit cpld_exit(void) class_destroy(cpld_class); } - kobject_put(&cpld_kset.kobj); - - if(cpld_kset.kobj.ktype) - kset_unregister(&cpld_kset); - if (cpld_device) { if (cpld_device->io_resource) release_resource(cpld_device->io_resource); @@ -1622,11 +2198,7 @@ MODULE_DESCRIPTION("cs6436-56p-cpld driver"); MODULE_LICENSE("GPL"); - - - - - +/********************************************** End ********************************************************/ diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-fan.c b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-fan.c index 09beb6912c3..33eaaa84030 100755 --- a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-fan.c +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-fan.c @@ -44,6 +44,9 @@ static struct cs6436_56p_fan_data *cs6436_56p_fan_update_device(struct device *d 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 set_fan_direction(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); + extern int cig_cpld_write_register(u8 reg_off, u8 val); extern int cig_cpld_read_register(u8 reg_off, u8 *val); @@ -63,6 +66,7 @@ static const u8 fan_reg[] = { 0x47, /* rear fan 3 speed(rpm) */ 0x49, /* rear fan 4 speed(rpm) */ 0x4b, /* rear fan 5 speed(rpm) */ + 0x4c, /* fan direction rear to front or front to rear */ }; @@ -99,6 +103,7 @@ enum sysfs_fan_attributes { FAN3_REAR_SPEED_RPM, FAN4_REAR_SPEED_RPM, FAN5_REAR_SPEED_RPM, + FAN_DIRECTION, FAN1_STATE, FAN2_STATE, FAN3_STATE, @@ -109,6 +114,11 @@ enum sysfs_fan_attributes { FAN3_FAULT, FAN4_FAULT, FAN5_FAULT, + FAN1_DIRECTION, + FAN2_DIRECTION, + FAN3_DIRECTION, + FAN4_DIRECTION, + FAN5_DIRECTION, }; /* Define attributes @@ -131,6 +141,11 @@ enum sysfs_fan_attributes { #define DECLARE_FAN_SPEED_RPM_ATTR(index) &sensor_dev_attr_fan##index##_front_speed_rpm.dev_attr.attr, \ &sensor_dev_attr_fan##index##_rear_speed_rpm.dev_attr.attr +#define DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_direction, S_IWUSR | S_IRUGO, fan_show_value, set_fan_direction, FAN##index##_DIRECTION) +#define DECLARE_FAN_DIRECTION_ATTR(index) &sensor_dev_attr_fan##index##_direction.dev_attr.attr + + /* 5 fan state attributes in this platform */ DECLARE_FAN_STATE_SENSOR_DEV_ATTR(1); DECLARE_FAN_STATE_SENSOR_DEV_ATTR(2); @@ -156,6 +171,13 @@ DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(5); /* 1 fan duty cycle attribute in this platform */ DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(1); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(2); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(3); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(4); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(5); + + static struct attribute *cs6436_56p_fan_attributes[] = { /* fan related attributes */ DECLARE_FAN_STATE_ATTR(1), @@ -174,6 +196,11 @@ static struct attribute *cs6436_56p_fan_attributes[] = { DECLARE_FAN_SPEED_RPM_ATTR(4), DECLARE_FAN_SPEED_RPM_ATTR(5), DECLARE_FAN_DUTY_CYCLE_ATTR(), + DECLARE_FAN_DIRECTION_ATTR(1), + DECLARE_FAN_DIRECTION_ATTR(2), + DECLARE_FAN_DIRECTION_ATTR(3), + DECLARE_FAN_DIRECTION_ATTR(4), + DECLARE_FAN_DIRECTION_ATTR(5), NULL }; @@ -230,6 +257,7 @@ static u8 is_fan_fault(struct cs6436_56p_fan_data *data, enum fan_id id) return ret; } + static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { @@ -247,6 +275,41 @@ static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, return count; } +static ssize_t set_fan_direction(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value,fan_index; + u8 mask,reg_val; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + fan_index = attr->index - FAN1_DIRECTION; + error = kstrtoint(buf, 10, &value); + if (error) + return error; + + if (!(value == 0 || value == 1)) + return -EINVAL; + + + cig_cpld_read_register(fan_reg[FAN_DIRECTION],®_val); + + if(value == 1) + { + reg_val |= (1 << fan_index); + } + else + { + reg_val &= ~(1 << fan_index); + } + + cig_cpld_write_register(fan_reg[FAN_DIRECTION], reg_val); + + return count; +} + + + + + static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf) { @@ -300,6 +363,13 @@ static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, case FAN5_FAULT: ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN1_FAULT)); break; + case FAN1_DIRECTION: + case FAN2_DIRECTION: + case FAN3_DIRECTION: + case FAN4_DIRECTION: + case FAN5_DIRECTION: + ret = sprintf(buf, "%d\n",reg_val_to_is_state(data->reg_val[FAN_DIRECTION],attr->index - FAN1_DIRECTION)); + break; default: break; } diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-psu.c b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-psu.c index 8754007408c..1a4734d4ba2 100755 --- a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-psu.c +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-psu.c @@ -17,265 +17,306 @@ * 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 -#include -#include -#include -#include - - - -#define MAX_FAN_DUTY_CYCLE 100 - -/* Address scanned */ -static const unsigned short normal_i2c[] = {I2C_CLIENT_END }; - -/* This is additional data */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i2c-algo-lpc.h" + + + +#define MAX_FAN_DUTY_CYCLE 100 + +/* Address scanned */ +static const unsigned short normal_i2c[] = {I2C_CLIENT_END }; + +/* This is additional data */ struct cs6436_56p_psu_data { - struct device *hwmon_dev; - struct mutex update_lock; - char valid; - unsigned long last_updated; /* In jiffies */ - - /* Registers value */ - u8 vout_mode; - u16 v_in; - u16 v_out; - u16 i_in; - u16 i_out; - u16 p_in; - u16 p_out; - u16 temp_input[3]; - u8 temp_fault; - u8 fan_fault; - u16 fan_duty_cycle[2]; - u16 fan_speed[2]; - u8 mfr_id[8]; - u8 mfr_model[20]; - u8 mfr_serial[20]; + struct device *hwmon_dev; + struct mutex update_lock; + char valid; + unsigned long last_updated; /* In jiffies */ + + /* Registers value */ + u8 vout_mode; + u16 v_in; + u16 v_out; + u16 i_in; + u16 i_out; + u16 p_in; + u16 p_out; + u16 temp_input[3]; + u8 temp_fault; + u8 fan_fault; + u16 fan_duty_cycle[2]; + u16 fan_speed[2]; + u8 mfr_id[8]; + u8 mfr_model[20]; + u8 mfr_serial[20]; u8 psu_is_present; u8 psu_is_good; -}; - -static int two_complement_to_int(u16 data, u8 valid_bit, int mask); -static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count); -static ssize_t for_linear_data(struct device *dev, struct device_attribute *dev_attr, char *buf); -static ssize_t for_fan_fault(struct device *dev, struct device_attribute *dev_attr, char *buf); -static ssize_t for_fan_warning(struct device *dev, struct device_attribute *dev_attr, char *buf); -static ssize_t for_temp_fault(struct device *dev, struct device_attribute *dev_attr, char *buf); -static ssize_t for_temp_warning(struct device *dev, struct device_attribute *dev_attr, char *buf); -static ssize_t for_vout_data(struct device *dev, struct device_attribute *dev_attr, char *buf); + struct i2c_client *client; + struct bin_attribute *bin; /* eeprom data */ +}; + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask); +static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *dev_attr, const char *buf, size_t count); +static ssize_t for_linear_data(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_fan_fault(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_fan_warning(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_temp_fault(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_temp_warning(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_vout_data(struct device *dev, struct device_attribute *dev_attr, char *buf); static int cs6436_56p_psu_read_byte(struct i2c_client *client, u8 reg); static int cs6436_56p_psu_read_word(struct i2c_client *client, u8 reg); static int cs6436_56p_psu_write_word(struct i2c_client *client, u8 reg, u16 value); static int cs6436_56p_psu_read_block(struct i2c_client *client, u8 command, u8 *data, int data_len); static struct cs6436_56p_psu_data *cs6436_56p_psu_update_device(struct device *dev); -static ssize_t for_ascii(struct device *dev, struct device_attribute *dev_attr, char *buf); -static ssize_t for_status(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_ascii(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_status(struct device *dev, struct device_attribute *dev_attr, char *buf); enum cs6436_56p_psu_sysfs_attributes { - PSU_V_IN, - PSU_V_OUT, - PSU_I_IN, - PSU_I_OUT, - PSU_P_IN, - PSU_P_OUT, - PSU_TEMP1_INPUT, - PSU_TEMP2_INPUT, - PSU_TEMP3_INPUT, - PSU_TEMP_FAULT, - PSU_TEMP_WARN, - PSU_FAN1_FAULT, - PSU_FAN1_WARN, - PSU_FAN1_DUTY_CYCLE, - PSU_FAN1_SPEED, - PSU_MFR_ID, - PSU_MFR_MODEL, - PSU_MFR_SERIAL, + PSU_V_IN, + PSU_V_OUT, + PSU_I_IN, + PSU_I_OUT, + PSU_P_IN, + PSU_P_OUT, + PSU_TEMP1_INPUT, + PSU_TEMP2_INPUT, + PSU_TEMP3_INPUT, + PSU_TEMP_FAULT, + PSU_TEMP_WARN, + PSU_FAN1_FAULT, + PSU_FAN1_WARN, + PSU_FAN1_DUTY_CYCLE, + PSU_FAN1_SPEED, + PSU_MFR_ID, + PSU_MFR_MODEL, + PSU_MFR_SERIAL, PSU_PRESENT, PSU_P_GOOD, -}; - -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 \ - *dev_attr, const char *buf, size_t count) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); - struct i2c_client *client = to_i2c_client(dev); +}; + +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 \ + *dev_attr, const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct i2c_client *client = to_i2c_client(dev); struct cs6436_56p_psu_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; + int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1; + long speed; + int error; + + if (data->valid != 1) + { + return -ENODEV; + } + + 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; cs6436_56p_psu_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]); - mutex_unlock(&data->update_lock); - - return count; -} - -static ssize_t for_linear_data(struct device *dev, struct device_attribute *dev_attr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t for_linear_data(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); struct cs6436_56p_psu_data *data = cs6436_56p_psu_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_TEMP2_INPUT: - value = data->temp_input[1]; - break; - case PSU_TEMP3_INPUT: - value = data->temp_input[2]; - 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 for_fan_fault(struct device *dev, struct device_attribute \ - *dev_attr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); - struct cs6436_56p_psu_data *data = cs6436_56p_psu_update_device(dev); - - u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; - - return sprintf(buf, "%d\n", data->fan_fault >> shift); -} - -static ssize_t for_fan_warning(struct device *dev, struct device_attribute \ - *dev_attr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); - struct cs6436_56p_psu_data *data = cs6436_56p_psu_update_device(dev); - - u8 shift = (attr->index == PSU_FAN1_WARN) ? 5 : 4; - - return sprintf(buf, "%d\n", data->fan_fault >> shift); -} - -static ssize_t for_temp_fault(struct device *dev, struct device_attribute \ - *dev_attr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); - struct cs6436_56p_psu_data *data = cs6436_56p_psu_update_device(dev); - - - return sprintf(buf, "%d\n", data->temp_fault >> 7); -} - -static ssize_t for_temp_warning(struct device *dev, struct device_attribute \ - *dev_attr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); - struct cs6436_56p_psu_data *data = cs6436_56p_psu_update_device(dev); - - return sprintf(buf, "%d\n", data->temp_fault >> 6); -} -static ssize_t for_vout_data(struct device *dev, struct device_attribute \ - *dev_attr, char *buf) -{ + + u16 value = 0; + int exponent, mantissa; + int multiplier = 1000; + + if (data->valid != 1) + { + return -ENODEV; + } + + 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_TEMP2_INPUT: + value = data->temp_input[1]; + break; + case PSU_TEMP3_INPUT: + value = data->temp_input[2]; + 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 for_fan_fault(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs6436_56p_psu_data *data = cs6436_56p_psu_update_device(dev); + + if (data->valid != 1) + { + return -ENODEV; + } + + u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; + + return sprintf(buf, "%d\n", data->fan_fault >> shift); +} + +static ssize_t for_fan_warning(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs6436_56p_psu_data *data = cs6436_56p_psu_update_device(dev); + + if (data->valid != 1) + { + return -ENODEV; + } + + u8 shift = (attr->index == PSU_FAN1_WARN) ? 5 : 4; + + return sprintf(buf, "%d\n", data->fan_fault >> shift); +} + +static ssize_t for_temp_fault(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs6436_56p_psu_data *data = cs6436_56p_psu_update_device(dev); + + if (data->valid != 1) + { + return -ENODEV; + } + + + + return sprintf(buf, "%d\n", data->temp_fault >> 7); +} + +static ssize_t for_temp_warning(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct cs6436_56p_psu_data *data = cs6436_56p_psu_update_device(dev); + if (data->valid != 1) + { + return -ENODEV; + } + + + return sprintf(buf, "%d\n", data->temp_fault >> 6); +} +static ssize_t for_vout_data(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ struct cs6436_56p_psu_data *data = cs6436_56p_psu_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) >> (-exponent))); -} - -static ssize_t for_ascii(struct device *dev, struct device_attribute \ - *dev_attr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + int exponent, mantissa; + int multiplier = 1000; + if (data->valid != 1) + { + return -ENODEV; + } + + + 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) >> (-exponent))); +} + +static ssize_t for_ascii(struct device *dev, struct device_attribute \ + *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); struct cs6436_56p_psu_data *data = cs6436_56p_psu_update_device(dev); - u8 *ptr = NULL; - - if (!data->valid) - return 0; - - switch (attr->index) { - case PSU_MFR_ID: - ptr = data->mfr_id + 1; - break; - case PSU_MFR_MODEL: - ptr = data->mfr_model + 1; - break; - case PSU_MFR_SERIAL: - ptr = data->mfr_serial + 1; - break; - default: - return 0; - } - return sprintf(buf, "%s\n", ptr); -} + u8 *ptr = NULL; + + if (data->valid != 1) + { + return -ENODEV; + } + + switch (attr->index) { + case PSU_MFR_ID: + ptr = data->mfr_id + 1; + break; + case PSU_MFR_MODEL: + ptr = data->mfr_model + 1; + break; + case PSU_MFR_SERIAL: + ptr = data->mfr_serial + 1; + break; + default: + return 0; + } + return sprintf(buf, "%s\n", ptr); +} static ssize_t for_status(struct device *dev, struct device_attribute *dev_attr, char *buf) @@ -286,14 +327,14 @@ static ssize_t for_status(struct device *dev, struct device_attribute *dev_attr, u8 status = 0; - if (!data->valid) { - return -EIO; - } - if (attr->index == PSU_PRESENT) { status = data->psu_is_present; } else { /* PSU_POWER_GOOD */ + if (!data->valid) { + return -ENODEV; + } + status = data->psu_is_good; } @@ -301,286 +342,602 @@ static ssize_t for_status(struct device *dev, struct device_attribute *dev_attr, } - static int cs6436_56p_psu_read_byte(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - +{ + return i2c_smbus_read_byte_data(client, reg); +} + static int cs6436_56p_psu_read_word(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_word_data(client, reg); -} - +{ + return i2c_smbus_read_word_data(client, reg); +} + static int cs6436_56p_psu_write_word(struct i2c_client *client, u8 reg, \ - u16 value) -{ - union i2c_smbus_data data; - data.word = value; - return i2c_smbus_xfer(client->adapter, client->addr, - client->flags |= I2C_CLIENT_PEC, - I2C_SMBUS_WRITE, reg, - I2C_SMBUS_WORD_DATA, &data); - -} - + u16 value) +{ + union i2c_smbus_data data; + data.word = value; + return i2c_smbus_xfer(client->adapter, client->addr, + client->flags |= I2C_CLIENT_PEC, + I2C_SMBUS_WRITE, reg, + I2C_SMBUS_WORD_DATA, &data); + +} + static int cs6436_56p_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; - -} - -struct reg_data_byte { - u8 reg; - u8 *value; -}; - -struct reg_data_word { - u8 reg; - u16 *value; -}; - -static struct cs6436_56p_psu_data *cs6436_56p_psu_update_device( \ - struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); + 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; +}; + + + +#define EEPROM_NAME "psu_eeprom" +#define EEPROM_SIZE 256 /* 256 byte eeprom */ + +/* Platform dependent --- */ +static ssize_t psu_eeprom_write(struct i2c_client *client, u8 command, const char *data, + int data_len) +{ + int status, retry = 3; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_write_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(100); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + return status; + } + + return data_len; + +} + + +static ssize_t psu_page_write(struct i2c_client *client,const char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + return count; + } + + /* + * Write data to chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + + + while (count) { + ssize_t status; + + status = psu_eeprom_write(client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + buf += status; + off += status; + count -= status; + retval += status; + } + + + return retval; +} + + + +static ssize_t psu_bin_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct cs6436_56p_psu_data *data; + ssize_t retval = 0; + struct i2c_client *client; + + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + client = to_i2c_client(container_of(kobj, struct device, kobj)); + + mutex_lock(&data->update_lock); + retval = psu_page_write(client, buf, off, count); + mutex_unlock(&data->update_lock); + return retval; +} + + +static ssize_t psu_eeprom_read(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int status, retry = 3; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(100); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + goto abort; + } + if (unlikely(status != data_len)) { + status = -EIO; + goto abort; + } + +abort: + return status; +} + + + +static ssize_t psu_page_read(struct i2c_client *client,char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + printk("Count = 0, return"); + return count; + } + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + + + while (count) { + ssize_t status; + + status = psu_eeprom_read(client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + + buf += status; + off += status; + count -= status; + retval += status; + } + + + return retval; + +} + + +static ssize_t psu_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct cs6436_56p_psu_data *data; + struct i2c_client *client; + ssize_t retval = 0; + + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + client = to_i2c_client(container_of(kobj, struct device, kobj)); + mutex_lock(&data->update_lock); + retval = psu_page_read(client, buf, off, count); + mutex_unlock(&data->update_lock); + + return retval; +} + + + +static int psu_sysfs_eeprom_init(struct kobject *kobj, struct bin_attribute *eeprom) +{ + int err; + + sysfs_bin_attr_init(eeprom); + eeprom->attr.name = EEPROM_NAME; + eeprom->attr.mode = S_IWUSR | S_IRUGO; + eeprom->read = psu_bin_read; + eeprom->write = psu_bin_write; + eeprom->size = EEPROM_SIZE; + + /* Create eeprom file */ + err = sysfs_create_bin_file(kobj, eeprom); + if (err) { + return err; + } + + return 0; +} + + +static int psu_sysfs_eeprom_cleanup(struct kobject *kobj, struct bin_attribute *eeprom) +{ + sysfs_remove_bin_file(kobj, eeprom); + return 0; +} + + +static int psu_i2c_check_functionality(struct i2c_client *client) +{ + return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK); +} + + + +static int psu_eeprom_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) +{ + int status; + + struct cs6436_56p_psu_data *data; + + if (!psu_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + mutex_init(&data->update_lock); + + data->bin = kzalloc(sizeof(struct bin_attribute), GFP_KERNEL); + if (!data->bin) { + status = -ENOMEM; + goto eeprom_bin_error; + } + + /* init eeprom */ + status = psu_sysfs_eeprom_init(&client->dev.kobj, data->bin); + if (status) { + status = -ENOMEM; + goto sys_init_error; + } + + dev_info(&client->dev, "psu eeprom '%s'\n", client->name); + + return 0; + + sys_init_error: + kfree(data->bin); + + eeprom_bin_error: + kfree(data); + + exit: + return status; +} + + + + +static struct cs6436_56p_psu_data *cs6436_56p_psu_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); struct cs6436_56p_psu_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); - - - if (time_after(jiffies, data->last_updated)) { - int i, status; - u8 command; - struct reg_data_byte regs_byte[] = { - {0x20, &data->vout_mode}, - {0x81, &data->fan_fault}, - {0x7d, &data->temp_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])}, - {0x8f, &(data->temp_input[2])}, - {0x3b, &(data->fan_duty_cycle[0])}, - {0x90, &(data->fan_speed[0])}, - }; - - dev_dbg(&client->dev, "start data update\n"); - - /* one milliseconds from now */ - data->last_updated = jiffies + HZ / 1000; - - for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { - status = cs6436_56p_psu_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; - } - } - - for (i = 0; i < ARRAY_SIZE(regs_word); i++) { + + + mutex_lock(&data->update_lock); + + + if (time_after(jiffies, data->last_updated)) { + int i, status; + u8 command; + struct reg_data_byte regs_byte[] = { + {0x20, &data->vout_mode}, + {0x81, &data->fan_fault}, + {0x7d, &data->temp_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])}, + {0x90, &(data->fan_speed[0])}, + }; + data->valid = 1; + + dev_dbg(&client->dev, "start data update\n"); + + /* one milliseconds from now */ + data->last_updated = jiffies + HZ / 1000; + + for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { + status = cs6436_56p_psu_read_byte(client, + regs_byte[i].reg); + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_byte[i].reg, status); + *(regs_byte[i].value) = 0; + data->valid = 0; + } else { + *(regs_byte[i].value) = status; + } + } + + for (i = 0; i < ARRAY_SIZE(regs_word); i++) { status = cs6436_56p_psu_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; - } - } - - command = 0x99; /* PSU mfr_id */ - status = cs6436_56p_psu_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); - } - - command = 0x9a; /* PSU mfr_model */ - status = cs6436_56p_psu_read_block(client, command, - data->mfr_model, ARRAY_SIZE(data->mfr_model) - 1); - data->mfr_model[ARRAY_SIZE(data->mfr_model) - 1] = '\0'; - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - } - - command = 0x9e; /* PSU mfr_serial */ - status = cs6436_56p_psu_read_block(client, command, - data->mfr_serial, ARRAY_SIZE(data->mfr_serial) - 1); - data->mfr_serial[ARRAY_SIZE(data->mfr_serial) - 1] = '\0'; - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - } - data->valid = 1; + regs_word[i].reg); + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_word[i].reg, status); + *(regs_word[i].value) = 0; + data->valid = 0; + } else { + *(regs_word[i].value) = status; + } + } + + command = 0x99; /* PSU mfr_id */ + status = cs6436_56p_psu_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); + memset(data->mfr_id, 0, sizeof(data->mfr_id)); + data->valid = 0; + } + + command = 0x9a; /* PSU mfr_model */ + status = cs6436_56p_psu_read_block(client, command, + data->mfr_model, ARRAY_SIZE(data->mfr_model) - 1); + data->mfr_model[ARRAY_SIZE(data->mfr_model) - 1] = '\0'; + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + memset(data->mfr_model, 0, sizeof(data->mfr_id)); + data->valid = 0; + } + + command = 0x9e; /* PSU mfr_serial */ + status = cs6436_56p_psu_read_block(client, command, + data->mfr_serial, ARRAY_SIZE(data->mfr_serial) - 1); + data->mfr_serial[ARRAY_SIZE(data->mfr_serial) - 1] = '\0'; + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + memset(data->mfr_serial, 0, sizeof(data->mfr_id)); + data->valid = 0; + } + data->psu_is_present = strlen(data->mfr_id) > 1 ? 1:0; if(data->psu_is_present) + { data->psu_is_good = ((data->fan_fault) || (data->temp_fault))? 0:1; - else + } + else + { + data->valid = 0; data->psu_is_good = 0; - } - - mutex_unlock(&data->update_lock); - - return data; - -} - -/* sysfs attributes for hwmon */ -static SENSOR_DEVICE_ATTR(psu_v_in, S_IRUGO, for_linear_data, NULL, PSU_V_IN); -static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, for_vout_data, NULL, PSU_V_OUT); -static SENSOR_DEVICE_ATTR(psu_i_in, S_IRUGO, for_linear_data, NULL, PSU_I_IN); -static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, for_linear_data, NULL, PSU_I_OUT); -static SENSOR_DEVICE_ATTR(psu_p_in, S_IRUGO, for_linear_data, NULL, PSU_P_IN); -static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, for_linear_data, NULL, PSU_P_OUT); -static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, for_linear_data, NULL, PSU_TEMP1_INPUT); -static SENSOR_DEVICE_ATTR(psu_temp2_input, S_IRUGO, for_linear_data, NULL, PSU_TEMP2_INPUT); -static SENSOR_DEVICE_ATTR(psu_temp3_input, S_IRUGO, for_linear_data, NULL, PSU_TEMP3_INPUT); -static SENSOR_DEVICE_ATTR(psu_temp_fault, S_IRUGO, for_temp_fault, NULL, PSU_TEMP_FAULT); -static SENSOR_DEVICE_ATTR(psu_temp_warning, S_IRUGO, for_temp_warning, NULL, PSU_TEMP_WARN); -static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, for_fan_fault, NULL, PSU_FAN1_FAULT); -static SENSOR_DEVICE_ATTR(psu_fan1_warning, S_IRUGO, for_fan_warning, NULL, PSU_FAN1_WARN); -static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, for_linear_data, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE); -static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, for_linear_data, NULL, PSU_FAN1_SPEED); -static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, for_ascii, NULL, PSU_MFR_ID); -static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, for_ascii, NULL, PSU_MFR_MODEL); -static SENSOR_DEVICE_ATTR(psu_mfr_serial, S_IRUGO, for_ascii, NULL, PSU_MFR_SERIAL); + } + } + + mutex_unlock(&data->update_lock); + + return data; + +} + +/* sysfs attributes for hwmon */ +static SENSOR_DEVICE_ATTR(psu_v_in, S_IRUGO, for_linear_data, NULL, PSU_V_IN); +static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, for_vout_data, NULL, PSU_V_OUT); +static SENSOR_DEVICE_ATTR(psu_i_in, S_IRUGO, for_linear_data, NULL, PSU_I_IN); +static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, for_linear_data, NULL, PSU_I_OUT); +static SENSOR_DEVICE_ATTR(psu_p_in, S_IRUGO, for_linear_data, NULL, PSU_P_IN); +static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, for_linear_data, NULL, PSU_P_OUT); +static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, for_linear_data, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp2_input, S_IRUGO, for_linear_data, NULL, PSU_TEMP2_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp3_input, S_IRUGO, for_linear_data, NULL, PSU_TEMP3_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp_fault, S_IRUGO, for_temp_fault, NULL, PSU_TEMP_FAULT); +static SENSOR_DEVICE_ATTR(psu_temp_warning, S_IRUGO, for_temp_warning, NULL, PSU_TEMP_WARN); +static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, for_fan_fault, NULL, PSU_FAN1_FAULT); +static SENSOR_DEVICE_ATTR(psu_fan1_warning, S_IRUGO, for_fan_warning, NULL, PSU_FAN1_WARN); +static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, for_linear_data, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE); +static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, for_linear_data, NULL, PSU_FAN1_SPEED); +static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, for_ascii, NULL, PSU_MFR_ID); +static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, for_ascii, NULL, PSU_MFR_MODEL); +static SENSOR_DEVICE_ATTR(psu_mfr_serial, S_IRUGO, for_ascii, NULL, PSU_MFR_SERIAL); static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, for_status, NULL, PSU_PRESENT); static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, for_status, NULL, PSU_P_GOOD); - + static struct attribute *cs6436_56p_psu_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_temp2_input.dev_attr.attr, - &sensor_dev_attr_psu_temp3_input.dev_attr.attr, - &sensor_dev_attr_psu_temp_fault.dev_attr.attr, - &sensor_dev_attr_psu_temp_warning.dev_attr.attr, - &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, - &sensor_dev_attr_psu_fan1_warning.dev_attr.attr, - &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, - &sensor_dev_attr_psu_fan1_speed_rpm.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_serial.dev_attr.attr, + &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_temp2_input.dev_attr.attr, + &sensor_dev_attr_psu_temp3_input.dev_attr.attr, + &sensor_dev_attr_psu_temp_fault.dev_attr.attr, + &sensor_dev_attr_psu_temp_warning.dev_attr.attr, + &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, + &sensor_dev_attr_psu_fan1_warning.dev_attr.attr, + &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, + &sensor_dev_attr_psu_fan1_speed_rpm.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_serial.dev_attr.attr, &sensor_dev_attr_psu_present.dev_attr.attr, &sensor_dev_attr_psu_power_good.dev_attr.attr, - NULL -}; - + NULL +}; + static const struct attribute_group cs6436_56p_psu_group = { .attrs = cs6436_56p_psu_attributes, -}; - -static int cs6436_56p_psu_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ +}; + + +static int psu_register_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int status; + + struct cs6436_56p_psu_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(*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, "new chip found\n"); - - /* Register sysfs hooks */ + + if (!psu_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + mutex_init(&data->update_lock); + + /* Register sysfs hooks */ status = sysfs_create_group(&client->dev.kobj, &cs6436_56p_psu_group); - if (status) - goto exit_sysfs_create_group; - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - status = PTR_ERR(data->hwmon_dev); - goto exit_hwmon_device_register; - } - - return 0; - -exit_hwmon_device_register: - sysfs_remove_group(&client->dev.kobj, &cs6436_56p_psu_group); -exit_sysfs_create_group: - kfree(data); -exit: - return status; -} - + if (status) + goto exit_sysfs_create_group; + + cs6436_56p_sysfs_add_client(client); + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_hwmon_device_register; + } + + /* init eeprom */ + + return 0; + + exit_hwmon_device_register: + sysfs_remove_group(&client->dev.kobj, &cs6436_56p_psu_group); + exit_sysfs_create_group: + kfree(data); + exit: + return status; + +} + + +static int cs6436_56p_psu_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int status; + + if((client->addr == 0x52) ||(client->addr == 0x53)) + { + status = psu_eeprom_probe(client, id); + } + else if((client->addr == 0x5a) ||(client->addr == 0x5b)) + { + status = psu_register_probe(client, id); + } + return status; +} + static int cs6436_56p_psu_remove(struct i2c_client *client) -{ - struct cs6436_56p_psu_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &cs6436_56p_psu_group); - kfree(data); - - return 0; -} - -enum psu_index -{ +{ + cs6436_56p_sysfs_remove_client(client); + + if((client->addr == 0x52) ||(client->addr == 0x53)) + { + struct cs6436_56p_psu_data *data; + data = i2c_get_clientdata(client); + psu_sysfs_eeprom_cleanup(&client->dev.kobj,data->bin); + kfree(data); + } + else if((client->addr == 0x5a) ||(client->addr == 0x5b)) + { + struct cs6436_56p_psu_data *data; + data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &cs6436_56p_psu_group); + kfree(data); + } + + return 0; +} + +enum psu_index +{ cs6436_56p_psu1, cs6436_56p_psu2 -}; - +}; + static const struct i2c_device_id cs6436_56p_psu_id[] = { { "cs6436_56p_psu1", cs6436_56p_psu1 }, { "cs6436_56p_psu2", cs6436_56p_psu2 }, - {} -}; + {} +}; MODULE_DEVICE_TABLE(i2c, cs6436_56p_psu_id); - + static struct i2c_driver cs6436_56p_psu_driver = { - .class = I2C_CLASS_HWMON, - .driver = { + .class = I2C_CLASS_HWMON, + .driver = { .name = "cs6436_56p_psu", - }, + }, .probe = cs6436_56p_psu_probe, .remove = cs6436_56p_psu_remove, .id_table = cs6436_56p_psu_id, - .address_list = normal_i2c, -}; + .address_list = normal_i2c, +}; module_i2c_driver(cs6436_56p_psu_driver); - -MODULE_AUTHOR("Zhang Peng "); + +MODULE_AUTHOR("Zhang Peng "); MODULE_DESCRIPTION("cs6436_56p_psu driver"); MODULE_LICENSE("GPL"); diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-sfp.c b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-sfp.c index f2b54a260fc..5665fa33048 100755 --- a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-sfp.c +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-sfp.c @@ -28,6 +28,7 @@ #include #include #include +#include "i2c-algo-lpc.h" #define DRIVER_NAME "cs6436_56p_sfp" /* Platform dependent */ @@ -64,15 +65,9 @@ #define SFF8436_RX_LOS_ADDR 3 #define SFF8436_TX_FAULT_ADDR 4 #define SFF8436_TX_DISABLE_ADDR 86 - - -#define ADDR_REG_SFP_STATUS_ADDR 0X62 //reg addr +R/W# //1031 -#define ADDR_REG_SFP_STATUS_TX 0X63 // write data -#define ADDR_REG_SFP_STATUS_RX 0X64 //read data -#define ADDR_REG_SFP_STATUS_COMMAND 0X65 //cmd bit7=1,go -#define ADDR_REG_SFP_STATUS_STATUS 0X66 //status - - +#define QSFP_RESET_ADDR 0x1b +#define QSFP_INTER_ADDR 0x1a +#define QSFP_LPMODE_ADDR 0x1c static ssize_t show_port_number(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_port_type(struct device *dev, struct device_attribute *da, char *buf); @@ -87,6 +82,11 @@ static ssize_t sfp_eeprom_write(struct i2c_client *, u8 , const char *,int); extern int cig_cpld_read_register(u8 reg_off, u8 *val); extern int cig_cpld_write_register(u8 reg_off, u8 val); +static ssize_t qsfp_reset_read(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_reset_write(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t qsfp_inter_read(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_lpmode_read(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_lpmode_write(struct device *dev, struct device_attribute *da, const char *buf, size_t count); enum sfp_sysfs_attributes { PRESENT, @@ -109,7 +109,10 @@ enum sfp_sysfs_attributes { RX_LOS2, RX_LOS3, RX_LOS4, - RX_LOS_ALL + RX_LOS_ALL, + QSFPRESET, + QSFPINT, + QSFPLPMODE }; /* SFP/QSFP common attributes for sysfs */ @@ -134,6 +137,9 @@ static SENSOR_DEVICE_ATTR(sfp_tx_fault1, S_IRUGO, qsfp_show_tx_rx_status, NULL, static SENSOR_DEVICE_ATTR(sfp_tx_fault2, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT2); static SENSOR_DEVICE_ATTR(sfp_tx_fault3, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT3); static SENSOR_DEVICE_ATTR(sfp_tx_fault4, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT4); +static SENSOR_DEVICE_ATTR(sfp_reset, S_IWUSR | S_IRUGO, qsfp_reset_read, qsfp_reset_write, QSFPRESET); +static SENSOR_DEVICE_ATTR(sfp_inter, S_IRUGO, qsfp_inter_read, NULL, QSFPINT); +static SENSOR_DEVICE_ATTR(sfp_lpmode, S_IWUSR | S_IRUGO, qsfp_lpmode_read, qsfp_lpmode_write, QSFPLPMODE); static struct attribute *qsfp_attributes[] = { &sensor_dev_attr_sfp_port_number.dev_attr.attr, &sensor_dev_attr_sfp_port_type.dev_attr.attr, @@ -154,6 +160,9 @@ static struct attribute *qsfp_attributes[] = { &sensor_dev_attr_sfp_tx_fault2.dev_attr.attr, &sensor_dev_attr_sfp_tx_fault3.dev_attr.attr, &sensor_dev_attr_sfp_tx_fault4.dev_attr.attr, + &sensor_dev_attr_sfp_reset.dev_attr.attr, + &sensor_dev_attr_sfp_inter.dev_attr.attr, + &sensor_dev_attr_sfp_lpmode.dev_attr.attr, NULL }; @@ -342,13 +351,13 @@ static ssize_t show_port_number(struct device *dev, struct device_attribute *da, return sprintf(buf, "%d\n", CPLD_PORT_TO_FRONT_PORT(data->port)); } -#define WAIT_TIME_OUT_COUNT 100 + static int cig_cpld_write_sfp_register(u8 sfp_reg_addr, u8 sfp_write_reg_data) { u8 sfp_read_status = 0; u8 wait_time_out = WAIT_TIME_OUT_COUNT; - + cig_cpld_write_register(ADDR_REG_SFP_STATUS_ADDR, sfp_reg_addr << 1); cig_cpld_write_register(ADDR_REG_SFP_STATUS_TX, sfp_write_reg_data); cig_cpld_write_register(ADDR_REG_SFP_STATUS_COMMAND, 0x80); @@ -371,7 +380,7 @@ static int cig_cpld_read_sfp_register(u8 sfp_reg_addr, u8 *sfp_read_reg_data) { u8 sfp_read_status = 0; u8 wait_time_out = WAIT_TIME_OUT_COUNT; - + cig_cpld_write_register(ADDR_REG_SFP_STATUS_ADDR, sfp_reg_addr << 1 | 1); cig_cpld_write_register(ADDR_REG_SFP_STATUS_COMMAND, 0x80); do{ @@ -393,7 +402,7 @@ static int cig_cpld_read_sfp_register(u8 sfp_reg_addr, u8 *sfp_read_reg_data) - + /* Platform dependent +++ */ static struct sfp_port_data *sfp_update_present(struct i2c_client *client) @@ -411,7 +420,7 @@ static struct sfp_port_data *sfp_update_present(struct i2c_client *client) /* Read present status of port 1~48(SFP port) */ for (i = 0; i < 6; i++) { cpld_reg_addr = 1 + i; - + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); if (unlikely(status < 0)) { @@ -420,8 +429,8 @@ static struct sfp_port_data *sfp_update_present(struct i2c_client *client) } data->present |= (u64)cpld_reg_data << (i*8); - - DEBUG_PRINT("Present status = 0x%lx\r\n", data->present); + + DEBUG_PRINT("Present status = 0x%lx\r\n", data->present); } /* Read present status of port 49-56(QSFP port) */ @@ -433,7 +442,7 @@ static struct sfp_port_data *sfp_update_present(struct i2c_client *client) } else { data->present |= (u64)cpld_reg_data << 48; - } + } DEBUG_PRINT("Present status = 0x%lx", data->present); exit: @@ -463,7 +472,7 @@ static struct sfp_port_data *sfp_update_tx_rx_status(struct device *dev) /* Read status of port 1~48(SFP port) */ for (i = 0; i < 6; i++) { cpld_reg_addr = 13+i; - + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); if (unlikely(status < 0)) { dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_reg_addr, cpld_reg_data, status); @@ -471,14 +480,14 @@ static struct sfp_port_data *sfp_update_tx_rx_status(struct device *dev) } data->msa->status[0] |= (u64)cpld_reg_data << (i * 8); - - DEBUG_PRINT("tx rx status[0] = 0x%lx\r\n", data->msa->status[0]); + + DEBUG_PRINT("tx rx status[0] = 0x%lx\r\n", data->msa->status[0]); } - + for (i = 0; i < 6; i++) { cpld_reg_addr = 19+i; - + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); if (unlikely(status < 0)) { dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_reg_addr, cpld_reg_data, status); @@ -486,13 +495,13 @@ static struct sfp_port_data *sfp_update_tx_rx_status(struct device *dev) } data->msa->status[1] |= (u64)cpld_reg_data << (i * 8); - - DEBUG_PRINT("tx rx status[1] = 0x%lx\r\n", data->msa->status[1]); + + DEBUG_PRINT("tx rx status[1] = 0x%lx\r\n", data->msa->status[1]); } for (i = 0; i < 6; i++) { cpld_reg_addr = 7+i; - + status = cig_cpld_read_sfp_register(cpld_reg_addr, &cpld_reg_data); if (unlikely(status < 0)) { dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_reg_addr, cpld_reg_data, status); @@ -500,8 +509,8 @@ static struct sfp_port_data *sfp_update_tx_rx_status(struct device *dev) } data->msa->status[2] |= (u64)cpld_reg_data << (i * 8); - - DEBUG_PRINT("tx rx status[2] = 0x%lx\r\n", data->msa->status[2]); + + DEBUG_PRINT("tx rx status[2] = 0x%lx\r\n", data->msa->status[2]); } data->msa->valid = 1; @@ -531,12 +540,12 @@ static ssize_t sfp_set_tx_disable(struct device *dev, struct device_attribute *d } mutex_lock(&data->update_lock); - + udelay(6000); if(data->port <= 48) { cpld_reg_addr = 19 + data->port / 8; - cpld_reg_bit = 1 << (data->port); + cpld_reg_bit = 1 << ((data->port) % 8); } /* Read current status */ @@ -548,10 +557,10 @@ static ssize_t sfp_set_tx_disable(struct device *dev, struct device_attribute *d cpld_reg_data |= cpld_reg_bit; } else { - data->msa->status[1] &= ~BIT_INDEX(data->port); + data->msa->status[1] &= ~ BIT_INDEX(data->port); cpld_reg_data &= ~cpld_reg_bit; } - + error = cig_cpld_write_sfp_register(cpld_reg_addr,cpld_reg_data); mutex_unlock(&data->update_lock); @@ -582,7 +591,7 @@ static ssize_t show_present(struct device *dev, struct device_attribute *da, int i; u8 values[7] = {0}; struct sfp_port_data *data = sfp_update_present(client); - + if (IS_ERR(data)) { return PTR_ERR(data); } @@ -682,7 +691,7 @@ static ssize_t show_port_type(struct device *dev, struct device_attribute *da, char *buf) { struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); + struct sfp_port_data *data = i2c_get_clientdata(client); int present = sfp_is_port_present(client, data->port); if (IS_ERR_VALUE(present)) { @@ -750,6 +759,253 @@ static struct sfp_port_data *qsfp_update_tx_rx_status(struct device *dev) return (status < 0) ? ERR_PTR(status) : data; } +static ssize_t qsfp_inter_read(struct device *dev, struct device_attribute *da, char *buf) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_INTER_ADDR, &cpld_reg_data); + index = data->port - 48; + index = 1 << index; + val = (cpld_reg_data & index) > 0 ? 1 : 0; + + printk("inter read:data->port = %d, index = %hhu, cpld_reg_data = %hhu\n", data->port, index, cpld_reg_data); + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", val); +} + + +static ssize_t qsfp_reset_read(struct device *dev, struct device_attribute *da, char *buf) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_RESET_ADDR, &cpld_reg_data); + index = data->port - 48; + index = 1 << index; + val = (cpld_reg_data & index) > 0 ? 1 : 0; + + printk("reset read:data->port = %d, index = %hhu, cpld_reg_data = %hhu\n", data->port, index, cpld_reg_data); + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t qsfp_reset_write(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + long usrdata; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + ret = kstrtol(buf, 10, &usrdata); + if (ret) { + return ret; + } + + usrdata = usrdata > 0 ? 1 : 0; + index = data->port - 48; + + DEBUG_PRINT("usrdata = %u, index = %hhu\n", usrdata, index); + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_RESET_ADDR, &cpld_reg_data); + if (ret == 1) + { + + DEBUG_PRINT("cpld_reg_data = %x\n", cpld_reg_data); + cpld_reg_data &= ~(1 << index); + cpld_reg_data |= usrdata << index; + + DEBUG_PRINT("cpld_reg_data = %x\n", cpld_reg_data); + ret = cig_cpld_write_sfp_register(QSFP_RESET_ADDR, cpld_reg_data); + if (1 != ret) + { + DEBUG_PRINT("write failed\n"); + } + } + else + { + DEBUG_PRINT("read failed\n"); + } + + mutex_unlock(&data->update_lock); + + if (ret != 1) + return -1; + + return count; +} + + + + +static ssize_t qsfp_lpmode_read(struct device *dev, struct device_attribute *da, char *buf) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_LPMODE_ADDR, &cpld_reg_data); + index = data->port - 48; + index = 1 << index; + val = (cpld_reg_data & index) > 0 ? 1 : 0; + + printk("lpmode read:data->port = %d, index = %hhu, cpld_reg_data = %hhu\n", data->port, index, cpld_reg_data); + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t qsfp_lpmode_write(struct device *dev, struct device_attribute *da, const char *buf, size_t count) +{ + int present; + int status; + u8 val = 0; + int ret = 0; + u8 cpld_reg_data = 0; + u8 index = 0; + long usrdata; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + ret = kstrtol(buf, 10, &usrdata); + if (ret) { + return ret; + } + + usrdata = usrdata > 0 ? 1 : 0; + index = data->port - 48; + + DEBUG_PRINT("usrdata = %u, index = %hhu\n", usrdata, index); + + mutex_lock(&data->update_lock); + + udelay(6000); + /* Read current status */ + ret = cig_cpld_read_sfp_register(QSFP_LPMODE_ADDR, &cpld_reg_data); + if (ret == 1) + { + + DEBUG_PRINT("cpld_reg_data = %x\n", cpld_reg_data); + cpld_reg_data &= ~(1 << index); + cpld_reg_data |= usrdata << index; + + DEBUG_PRINT("cpld_reg_data = %x\n", cpld_reg_data); + ret = cig_cpld_write_sfp_register(QSFP_LPMODE_ADDR, cpld_reg_data); + if (1 != ret) + { + DEBUG_PRINT("write failed\n"); + } + } + else + { + DEBUG_PRINT("read failed\n"); + } + + mutex_unlock(&data->update_lock); + + if (ret != 1) + return -1; + + return count; +} + + + static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, char *buf) { @@ -822,7 +1078,7 @@ static ssize_t qsfp_set_tx_disable(struct device *dev, struct device_attribute * int status; struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); + struct sfp_port_data *data = i2c_get_clientdata(client); status = sfp_is_port_present(client, data->port); if (IS_ERR_VALUE(status)) { @@ -922,13 +1178,13 @@ static ssize_t sfp_show_tx_rx_status(struct device *dev, struct device_attribute for (i = 0; i < ARRAY_SIZE(values); i++) { values[i] = (u8)(data->msa->status[2] >> (i * 8)); } - + /** 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]); + values[3], values[4], values[5]); } - + switch (attr->index) { case TX_FAULT: index = 0; @@ -938,7 +1194,7 @@ static ssize_t sfp_show_tx_rx_status(struct device *dev, struct device_attribute break; case RX_LOS: index = 2; - break; + break; default: break; } @@ -1246,6 +1502,8 @@ static int sfp_msa_probe(struct i2c_client *client, const struct i2c_device_id * *data = msa; dev_info(&client->dev, "sfp msa '%s'\n", client->name); + cs6436_56p_sysfs_add_client(client); + return 0; exit_remove: @@ -1386,7 +1644,7 @@ static int sfp_device_probe(struct i2c_client *client, return qsfp_probe(client, dev_id, &data->qsfp); } } - + return -ENODEV; } /* Platform dependent --- */ @@ -1419,6 +1677,7 @@ static int sfp_device_remove(struct i2c_client *client) { struct sfp_port_data *data = i2c_get_clientdata(client); + cs6436_56p_sysfs_remove_client(client); switch (data->driver_type) { case DRIVER_TYPE_SFP_MSA: return sfp_msa_remove(client, data->msa); diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-sysfs.c b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-sysfs.c new file mode 100644 index 00000000000..89f6bba3aab --- /dev/null +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-sysfs.c @@ -0,0 +1,335 @@ +/* + * A hwmon driver for the CIG cs6436-56P sysfs Module + * + * Copyright (C) 2018 Cambridge, 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 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c-algo-lpc.h" + + +static LIST_HEAD(sysfs_client_list); +static struct mutex list_lock; + +struct sysfs_client_node { + struct i2c_client *client; + struct list_head list; +}; + +#define DEVICE_NAME "cigfs" +static int dev_major; +static struct class *dev_class; +static struct cdev *dev_cdev; +static struct device *dev_device; +static struct class *psu_class; +static struct class *sfp_class; + + +void cs6436_56p_sysfs_add_client(struct i2c_client *client) +{ + struct sysfs_client_node *node = kzalloc(sizeof(struct sysfs_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate sysfs_client_node (0x%x)\n", client->addr); + return; + } + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &sysfs_client_list); + mutex_unlock(&list_lock); +} + +EXPORT_SYMBOL(cs6436_56p_sysfs_add_client); + +void cs6436_56p_sysfs_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct sysfs_client_node *sysfs_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &sysfs_client_list) + { + sysfs_node = list_entry(list_node, struct sysfs_client_node, list); + if (IS_ERR(sysfs_node)) + { + break; + } + if (sysfs_node->client == client) { + found = 1; + break; + } + } + if (found) { + list_del(list_node); + kfree(sysfs_node); + } + + mutex_unlock(&list_lock); +} + +EXPORT_SYMBOL(cs6436_56p_sysfs_remove_client); + +struct class * cs6436_56p_sysfs_create_symclass(char *cls_name) +{ + int rc = 0; + struct class *my_class; +/**************************************************************************************/ + my_class = class_create(THIS_MODULE,cls_name); + if (IS_ERR(my_class)) { + pr_err("failed to create my class\n"); + } + return my_class; + +/**************************************************************************************/ +} + +void cs6436_56p_sysfs_delete_symclass(struct class *my_class) +{ +/**************************************************************************************/ + + if (IS_ERR(my_class)) { + pr_err("Pointer is invaild\n"); + } + class_destroy(my_class); + +/**************************************************************************************/ +} + + + + + +int cs6436_56p_sysfs_create_symlink(struct class *my_class,char * driver_name,char *device_name) +{ + struct list_head *list_node = NULL; + struct sysfs_client_node *sysfs_node = NULL; + int ret = -EPERM; + int rc = 0; + + mutex_lock(&list_lock); + list_for_each(list_node, &sysfs_client_list) + { + sysfs_node = list_entry(list_node, struct sysfs_client_node, list); + if (!strcmp(sysfs_node->client->name,driver_name)) { + rc = sysfs_create_link(&my_class->p->subsys.kobj, &sysfs_node->client->dev.kobj,device_name); + if(rc) + { + pr_err("failed to create symlink %d\n",rc); + } + break; + } + } + mutex_unlock(&list_lock); + return ret; +} + + +int cs6436_56p_sysfs_delete_symlink(struct class *my_class,char * driver_name,char *device_name) +{ + struct list_head *list_node = NULL; + struct sysfs_client_node *sysfs_node = NULL; + int ret = -EPERM; + int rc = 0; + + mutex_lock(&list_lock); + list_for_each(list_node, &sysfs_client_list) + { + sysfs_node = list_entry(list_node, struct sysfs_client_node, list); + if (!strcmp(sysfs_node->client->name,driver_name)) { + sysfs_remove_link(&my_class->p->subsys.kobj,device_name); + break; + } + } + mutex_unlock(&list_lock); + return ret; +} + + +static int cs6436_56p_sysfs_open(struct inode *inode, struct file *file) +{ + return 0; +} + + + +static ssize_t cs6436_56p_sysfs_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) +{ + char str[10],name[18],port[8]; + int ret; + int i; + memset(str, 0, sizeof(str)); + ret = copy_from_user(str, buf, count); + if (ret) + { + printk(KERN_ERR "copy_from_user fail\n"); + return -EINVAL; + } + + if(!strncmp(str,"start",5)) + { + psu_class = cs6436_56p_sysfs_create_symclass("psu"); + cs6436_56p_sysfs_create_symlink(psu_class,"cs6436_56p_psu1","psu1"); + cs6436_56p_sysfs_create_symlink(psu_class,"cs6436_56p_psu2","psu2"); + sfp_class = cs6436_56p_sysfs_create_symclass("swps"); + for(i = 1; i <= 48;i++) + { + memset(name,0xff,sizeof(name)); + memset(port,0xff,sizeof(port)); + snprintf(name,sizeof(name),"cs6436_56p_sfp%d",i); + snprintf(port,sizeof(port),"port%d",i); + cs6436_56p_sysfs_create_symlink(sfp_class,name,port); + } + } + else if(!strncmp(str,"stop",4)) + { + cs6436_56p_sysfs_delete_symlink(psu_class,"cs6436_56p_psu1","psu1"); + cs6436_56p_sysfs_delete_symlink(psu_class,"cs6436_56p_psu2","psu2"); + cs6436_56p_sysfs_delete_symclass(psu_class); + + for(i = 1; i <= 48;i++) + { + memset(name,0xff,sizeof(name)); + memset(port,0xff,sizeof(port)); + snprintf(name,sizeof(name),"cs6436_56p_sfp%d",i); + snprintf(port,sizeof(port),"port%d",i); + cs6436_56p_sysfs_delete_symlink(sfp_class,name,port); + } + cs6436_56p_sysfs_delete_symclass(sfp_class); + } + return count; +} + + +static struct file_operations cs6436_56p_sysfs_fops = { + .owner = THIS_MODULE, + .open = cs6436_56p_sysfs_open, + .write = cs6436_56p_sysfs_write, +}; + + +static int __init cs6436_56p_sysfs_init(void) +{ + int result = 0; + int err = 0; + dev_t dev = MKDEV(dev_major, 0); + + if (dev_major) + result = register_chrdev_region(dev, 1, DEVICE_NAME); + else { + result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME); + dev_major = MAJOR(dev); + } + if (result < 0) + { + printk("unable to get major %d\n", dev_major); + err= -EINVAL; + } + printk("get major is %d\n", dev_major); + if (dev_major == 0) + dev_major = result; + + dev_cdev= kmalloc(sizeof(struct cdev), GFP_KERNEL); + if(IS_ERR(dev_cdev)) { + err= -ENOMEM; + } + + cdev_init(dev_cdev, &cs6436_56p_sysfs_fops); + dev_cdev->owner = THIS_MODULE; + dev_cdev->ops = &cs6436_56p_sysfs_fops; + err = cdev_add(dev_cdev, dev, 1); + if (err) + { + printk("error %d add fpga ", err); + goto err_malloc; + } + + dev_class = class_create(THIS_MODULE, DEVICE_NAME); + if (IS_ERR(dev_class)) + { + printk("Err:failed in creating class.\n"); + goto err_cdev_add; + } + + dev_device = device_create(dev_class, NULL, MKDEV(dev_major, 0), NULL, DEVICE_NAME); + if (IS_ERR(dev_device)) + { + printk("Err:failed in creating device.\n"); + goto err_class_crt; + } + + mutex_init(&list_lock); + + return err; + + err_class_crt: + cdev_del(dev_cdev); + err_cdev_add: + kfree(dev_cdev); + err_malloc: + unregister_chrdev_region(MKDEV(dev_major,0), 1); + + return err; + +} + +static void __exit cs6436_56p_sysfs_exit(void) +{ + cdev_del(dev_cdev); + printk("cdev_del ok\n"); + device_destroy(dev_class, MKDEV(dev_major, 0)); + + class_destroy(dev_class); + + if(dev_cdev != NULL) + kfree(dev_cdev); + + unregister_chrdev_region(MKDEV(dev_major, 0), 1); + printk("cs6436_56p_sysfs_exit...\r\n"); +} + + +MODULE_AUTHOR("Zhang Peng "); +MODULE_DESCRIPTION("cs6436-56p-sysfs driver"); +MODULE_LICENSE("GPL"); + +module_init(cs6436_56p_sysfs_init); +module_exit(cs6436_56p_sysfs_exit); + + diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/service/cs6436-platform-misc.service b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/service/cs6436-platform-misc.service index 7ff410cbb3c..ed44bc0b343 100755 --- a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/service/cs6436-platform-misc.service +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/service/cs6436-platform-misc.service @@ -4,7 +4,7 @@ After=cs6436-platform-init.service DefaultDependencies=no [Service] -ExecStart=/usr/local/bin/cig_cs6436_misc.py +ExecStart=/usr/local/bin/cig_cs6436_misc.py KillSignal=SIGKILL SuccessExitStatus=SIGKILL diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/utils/cig_cs6436_misc.py b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/utils/cig_cs6436_misc.py index 08decef98ad..3b685236a07 100755 --- a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/utils/cig_cs6436_misc.py +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/utils/cig_cs6436_misc.py @@ -21,12 +21,259 @@ import logging import re import time +import datetime from collections import namedtuple from threading import Thread DEBUG = False i2c_prefix = '/sys/bus/i2c/devices/' -cs6436__prefix = '/sys/devices/platform/cs6436_56p_led/leds/' +leds_prefix = '/sys/devices/platform/cs6436_56p_led/leds/' +fans_prefix = '/sys/devices/platform/cs6436_56p_fan/' +fansdir_prefix = fans_prefix + 'fan{}_direction' + +ageing_controlfile = '/etc/sonic/agcontrol' +AGFlag = 0 + + +platform_misc_log = '/var/log/platform_misc.log' +misclogger = logging.getLogger('platform_misc') +misclogger.setLevel(logging.INFO) +miscformatter = logging.Formatter('%(asctime)s-%(levelname)s-%(message)s') + +if not os.path.isfile(platform_misc_log): + try: + os.mknod(platform_misc_log) + except: + print 'Failed to creat platform_misc.log' + +fileHandler = logging.FileHandler(platform_misc_log) +fileHandler.setLevel(logging.INFO) +fileHandler.setFormatter(miscformatter) +misclogger.addHandler(fileHandler) + + +starttime = datetime.datetime.now() +IsGetlswt = 0 +coretemp_prefix = '/sys/class/hwmon/hwmon1/' +coretemp_ps = [] +psu1_p = '/sys/bus/i2c/devices/5-005a/psu_present' +psu2_p = '/sys/bus/i2c/devices/5-005b/psu_present' +psu1_d = '/sys/bus/i2c/devices/5-0052/psu_eeprom' +psu2_d = '/sys/bus/i2c/devices/5-0053/psu_eeprom' +psu1led_d = leds_prefix + 'cs6436_56p_led::psu1/brightness' +psu2led_d = leds_prefix + 'cs6436_56p_led::psu2/brightness' +cs6436_ledpath = {'fan':leds_prefix + 'cs6436_56p_led::fan/brightness', + 'fan1':leds_prefix + 'cs6436_56p_led::fan1/brightness', + 'fan2':leds_prefix + 'cs6436_56p_led::fan2/brightness', + 'fan3':leds_prefix + 'cs6436_56p_led::fan3/brightness', + 'fan4':leds_prefix + 'cs6436_56p_led::fan4/brightness', + 'fan5':leds_prefix + 'cs6436_56p_led::fan5/brightness', + 'psu1':leds_prefix + 'cs6436_56p_led::psu1/brightness', + 'psu2':leds_prefix + 'cs6436_56p_led::psu2/brightness', + 'sys':leds_prefix + 'cs6436_56p_led::sys/brightness'} + + +def system_read_filestr(node): + with open(node, 'r') as f: + try: + str = f.read() + except IOError as e: + misclogger.error('Failed to get node, str={}'.format(node)) + return "0" + return str + + +def system_bright_leds(dev, colour): + global AGFlag + + if AGFlag == 1: + return + + cmd = 'echo {} > {}'.format(colour, dev) + log_os_system(cmd, 1) + return + +''' +1: front in tail out +0: front out tail in +''' +def system_getpsu_direction(dev): + try: + with open(dev) as f: + f.seek(0x30) + str = f.read(2) + except IOError as e: + misclogger.error('Failed to get psu eep') + return 1 + if str == 'AA': ## front in tail out + return 1 + elif str == 'RA':## tail in front out + return 0 + else: + misclogger.error('Failed to get psu eep, str={}'.format(str)) + return -1 + + +def system_get_cputype(): + cmdretfd = os.popen("lscpu | grep 'Model name'") + retstring = cmdretfd.read() + endindex = retstring.find('@') - 1 + startindex = retstring[:endindex].rfind(' ') + 1 + cputype = retstring[startindex:endindex] + + return cputype + + +def system_init_coretemppath(): + global coretemp_ps + + cmdstr = "ls {} | grep 'input'".format(coretemp_prefix) + cmdretfd = os.popen(cmdstr) + + coretemppss = cmdretfd.read().splitlines() + if len(coretemppss) < 3: + cputype = system_get_cputype() + misclogger.error('Failed to init core temperature path.' + ' cpu type = {}, num thermal = {}'.format(cputype, len(coretemp_ps))) + return 1 + + for i in range(0,3): + coretemp_ps.append(coretemp_prefix + coretemppss[i]) + + print coretemp_ps + + return 0 + + +class cs6436_fanattr: + def __init__(self, name): + self.name = name + self.direction = 0 + self.direction_p = '' + self.rear = 0 + self.rear_p = '' + self.front = 0 + self.front_p = '' + self.fault = 0 + self.fault_p = '' + self.status = 0 + self.setpath() + self.updatedevice() + + return + + def setpath(self): + self.direction_p = fans_prefix + '{}_direction'.format(self.name) + self.rear_p = fans_prefix + '{}_rear_speed_rpm'.format(self.name) + self.front_p = fans_prefix + '{}_front_speed_rpm'.format(self.name) + self.fault_p = fans_prefix + '{}_fault'.format(self.name) + + return + + def updatedevice(self): + self.direction = int(system_read_filestr(self.direction_p)) + self.rear = int(system_read_filestr(self.rear_p)) + self.front = int(system_read_filestr(self.front_p)) + self.fault = int(system_read_filestr(self.fault_p)) + + return + + def checkspeedrpm(self, speedrpm): + frontrpmexp = speedrpm * 21000 / 100 + rearrpmexp = speedrpm * 19000 / 100 + deviationfront = abs(frontrpmexp - self.front) / float(frontrpmexp) + deviationrear = abs(rearrpmexp - self.rear) / float(rearrpmexp) + + if deviationfront < 0.3 and deviationrear < 0.3: + return 0 + else: + misclogger.error(':{} speed wrong. frontexp is {}, but rpm is {}.rearexp is {}, but rpm is {}'.format(self.name, frontrpmexp, self.front, rearrpmexp, self.rear)) + return 1 + + def checkstatus(self, speedrpm, totaldirct): + speedstatus = self.checkspeedrpm(speedrpm) + if self.direction != totaldirct: + self.status = 1 + misclogger.error(':{} direction = {}.fan direction is not ok.'.format(self.name, self.direction)) + elif speedstatus != 0: + self.status = 1 + elif self.fault != 0: + misclogger.error(':{} fault.'.format(self.name)) + self.status = 1 + else: + self.status = 0 + + if self.status == 1: + system_bright_leds(cs6436_ledpath[self.name], 3) + else: + system_bright_leds(cs6436_ledpath[self.name], 1) + + return self.status + +cs6436_fanattrnodes = [] + + +class cs6436_psuattr: + def __init__(self, name): + self.name = name + self.direction = 0 + self.direction_p = '' + self.present = 0 + self.present_p = '' + self.status = 0 + + self.setpath() + self.updatepresent() + self.updatedirection() + + return + + def setpath(self): + if self.name == 'psu1': + self.present_p = psu1_p + self.direction_p = psu1_d + if self.name == 'psu2': + self.present_p = psu2_p + self.direction_p = psu2_d + + return + + def updatepresent(self): + self.present = int(system_read_filestr(self.present_p)) + + return + + def updatedirection(self): + if self.present == 1: + self.direction = system_getpsu_direction(self.direction_p) + else: + self.direction = 2 + + return + + def checkstatus(self, totaldirct): + if self.present != 1: + self.status = 1 + misclogger.error(':{} not present.'.format(self.name)) + elif self.direction == 2: + self.status = 0 + misclogger.info(':{} direction need to be update.'.format(self.name)) + elif self.direction != totaldirct: + self.status = 1 + misclogger.info(':{} direction is wrong.'.format(self.name)) + else: + self.status = 0 + + if self.status == 1: + system_bright_leds(cs6436_ledpath[self.name], 3) + else: + system_bright_leds(cs6436_ledpath[self.name], 1) + + return self.status + +cs6436_psuattrnodes = [] + + def my_log(txt): if DEBUG == True: @@ -36,15 +283,15 @@ def my_log(txt): def device_exist(): ret1, log = log_os_system("ls "+i2c_prefix+"5-005a", 0) ret2, log = log_os_system("ls "+i2c_prefix+"5-005b", 0) - ret3, log = log_os_system("ls "+cs6436__prefix+"cs6436_56p_led*", 0) + ret3, log = log_os_system("ls "+leds_prefix+"cs6436_56p_led*", 0) return not(ret1 or ret2 or ret3) - + def log_os_system(cmd, show): - logging.info('Run :'+cmd) - status, output = commands.getstatusoutput(cmd) + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) my_log (cmd +"with result:" + str(status)) - my_log (" output:"+output) + my_log (" output:"+output) if status: logging.info('Failed :'+cmd) if show: @@ -52,7 +299,223 @@ def log_os_system(cmd, show): return status, output -def system_misc_polling(threadName,delay): +def system_get_coretemp(): + temp1 = system_read_filestr(coretemp_ps[0]).strip() + temp2 = system_read_filestr(coretemp_ps[1]).strip() + temp3 = system_read_filestr(coretemp_ps[2]).strip() + + return int(temp1), int(temp2), int(temp3) + +def system_get_boardtemp(): + for i in range(0,16): + temp1path = "/sys/bus/i2c/devices/5-004a/hwmon/hwmon%d/temp1_input" % i + if os.access(temp1path, os.F_OK): + break + for i in range(0,16): + temp2path = "/sys/bus/i2c/devices/5-004b/hwmon/hwmon%d/temp1_input" % i + if os.access(temp2path, os.F_OK): + break + temp1 = system_read_filestr(temp1path).strip() + temp2 = system_read_filestr(temp2path).strip() + + return int(temp1), int(temp2) + + +def system_get_lswtemp(): + global IsGetlswt + global starttime + if IsGetlswt == 0: + now = datetime.datetime.now() + misclogger.info("time wait.") + misclogger.info("start = {}, now = {}.".format(starttime, now)) + if (now - starttime).seconds > 150: + misclogger.info("time = ".format((now - starttime).seconds)) + IsGetlswt = 1 + + return 25 + +# chp = subprocess.Popen("docker ps --filter name=syncd", shell=True, stdout=subprocess.PIPE) +# if chp.poll() == None: +# misclogger.info("No subp.") +# chp.kill() +# +# return 25 + +# retstring = chp.stdout.read() +# chp.kill() +# if 'Up' not in retstring: +# misclogger.info("lsw not up.") +# +# return 25 + + status, output = log_os_system('npx_diag swc show temperature', 1) + if status: + misclogger.error('failed to show lsw temperature') + + return 25 + + output = output.strip() + if output.find("it 0, temperature ") > 0: + startindex = output.find('temperature') + len('temperature') + 1 + endindex = output[startindex:].find(" ") + endindex = startindex + endindex + temp = output[startindex:endindex] + b = temp.find('.') + if b > 0: + temp=temp[:b] + temp = int(temp) + else: + misclogger.error("Failed to get temperature.") + temp = 0 + + return int(temp) + +def system_monitor_temperature(): + + ctemp1, ctemp2, ctemp3 = system_get_coretemp() + btemp1, btemp2 = system_get_boardtemp() + ltemp = system_get_lswtemp() + fan_speed_str = system_cs6436_getfanexspeed() + fan_speed = int(fan_speed_str) + policy = 'stay' + pos = 0 + #speed c1 c2 c3 b1 b2 lsw + fan_policy_up = ([30, 40000, 40000, 40000, 42000, 35000, 95], + [40, 44000, 44000, 44000, 44000, 39000, 96], + [50, 49000, 49000, 49000, 47000, 44000, 91], + [60, 52000, 52000, 52000, 51500, 47500, 92], + [70, 53000, 53000, 53000, 52000, 49000, 93], + [100,999999,999999,999999,999999,999999,999]) + + fan_policy_down=([30, 0, 0, 0, 0, 0, 0], + [40, 34000, 34000, 34000, 34000, 30000, 80], + [50, 38000, 38000, 38000, 37000, 33000, 81], + [60, 44000, 44000, 44000, 43000, 39000, 84], + [70, 44000, 44000, 44000, 43000, 40000, 84], + [100, 48000, 48000, 48000, 46000, 42000, 85],) + + for policytable in fan_policy_up: + if fan_speed <= policytable[0]: + break + pos = pos + 1 + fan_speed = policytable[0] + if (ctemp1 < policytable[1]) and (ctemp2 < policytable[2]) and (ctemp3 < policytable[3]) and (btemp1 < policytable[4]) and (btemp2 < policytable[5]) and (ltemp < policytable[6]): + policy = 'stay' + policytable = fan_policy_down[pos] + if (ctemp1 < policytable[1]) and (ctemp2 < policytable[2]) and (ctemp3 < policytable[3]) and (btemp1 < policytable[4]) and (btemp2 < policytable[5]) and (ltemp < policytable[6]): + policy = 'down' + else: + policy = 'up' + + if policy == 'up': + misclogger.info("speed = %d." % fan_speed) + misclogger.info("core1 = %d, core2 = %d, core3 = %d." % (ctemp1, ctemp2, ctemp3)) + misclogger.info("board1 = %d, board2 = %d." % (btemp1, btemp2)) + misclogger.info("lsw = %d" % ltemp) + fan_speed = fan_policy_down[pos + 1][0] + misclogger.info("fan policy: up. speedexp = {}".format(fan_speed)) + + if policy == 'stay': + fan_speed = fan_policy_down[pos] + return + + if policy == 'down': + misclogger.info("speed = %d." % fan_speed) + misclogger.info("core1 = %d, core2 = %d, core3 = %d." % (ctemp1, ctemp2, ctemp3)) + misclogger.info("board1 = %d, board2 = %d." % (btemp1, btemp2)) + misclogger.info("lsw = %d" % ltemp) + fan_speed = fan_policy_down[pos - 1][0] + misclogger.info("fan policy: down.speedexp = {}".format(fan_speed)) + + cmd = "echo %d > /sys/devices/platform/cs6436_56p_fan/fan_duty_cycle_percentage" % fan_speed + status, output = log_os_system(cmd, 1) + if status: + misclogger.error("set fan speed fault") + + return + + +def system_cs6436_setfanexspeed(num): + fanspeednode = fans_prefix + 'fan_duty_cycle_percentage' + numstr = str(num) + with open(fanspeednode, 'w') as f: + f.write(numstr) + + +def system_cs6436_getfanexspeed(): + fanspeednode = fans_prefix + 'fan_duty_cycle_percentage' + fanspeedstr = system_read_filestr(fanspeednode) + fanspeedexp = int(fanspeedstr) + + return fanspeedexp + + +def system_cs6436_getdirection(): + global cs6436_fanattrnodes + direction = 0 + + for fan in cs6436_fanattrnodes: + direction = direction + fan.direction + + if direction > 2: + direction = 1 + else: + direction = 0 + + return direction + + +def system_check_psusdirection(): + global cs6436_psuattrnodes + cs6436totaldirct = system_cs6436_getdirection() + psutatus = 0 + + for psu in cs6436_psuattrnodes: + psu.updatedirection() + psu.checkstatus(cs6436totaldirct) + psutatus = psu.status + psutatus + + return (psutatus != 0) + + +def system_check_psuspresent(): + global cs6436_psuattrnodes + cs6436totaldirct = system_cs6436_getdirection() + psutatus = 0 + + for psu in cs6436_psuattrnodes: + psu.updatepresent() + psu.checkstatus(cs6436totaldirct) + psutatus = psu.status + psutatus + + return (psutatus != 0) + + +def system_check_fansstate(): + global cs6436_fanattrnodes + global cs6436_ledpath + cs6436totaldirct = system_cs6436_getdirection() + fanstatus = 0 + fanexspeed = 0 + + fanexspeed = system_cs6436_getfanexspeed() + + for fan in cs6436_fanattrnodes: + fan.updatedevice() + fan.checkstatus(fanexspeed, cs6436totaldirct) + fanstatus = fanstatus + fan.status + + if fanstatus > 0: + misclogger.error(':fan error.set fans speed 100.') + system_cs6436_setfanexspeed(100) + system_bright_leds(cs6436_ledpath['fan'], 3) + else: + system_bright_leds(cs6436_ledpath['fan'], 1) + + return (fanstatus != 0) + + +def system_misc_polling(threadName,delay): for count in range(1,5): if device_exist() == False: time.sleep(delay+3) @@ -62,93 +525,50 @@ def system_misc_polling(threadName,delay): if count == 4: return - + status, output = log_os_system("echo 1 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::sys/brightness", 1) status, output = log_os_system("hwconfig -cfp 1", 1) + global AGFlag + if os.access(ageing_controlfile, os.F_OK): + AGFlag = 1 + else: + AGFlag = 0 + + os.system('csw_daemon &') + + + global cs6436_fanattrnodes + global cs6436_psuattrnodes + + for num in range(1,6): + name = 'fan{}'.format(num) + fannode = cs6436_fanattr(name) + cs6436_fanattrnodes.append(fannode) + for num in range(1,3): + name = 'psu{}'.format(num) + psunode = cs6436_psuattr(name) + cs6436_psuattrnodes.append(psunode) + + tempcontrol = system_init_coretemppath() + + misclogger.info("%s: %s misc start." % ( threadName, time.ctime(time.time()))) + count = 0 while 1: - status, output = log_os_system("cat /sys/bus/i2c/devices/5-005a/psu_present", 1) - if status: - print "failed to check status for 5-005a/psu_present" - continue - - if output=='1': - log_os_system("echo 1 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::psu1/brightness", 1) - else: - log_os_system("echo 0 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::psu1/brightness", 1) - - status, output = log_os_system("cat /sys/bus/i2c/devices/5-005b/psu_present", 1) - if status: - print "failed to check status for 5-005b/psu_present" - continue - - if output=='1': - log_os_system("echo 1 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::psu2/brightness", 1) - else: - log_os_system("echo 0 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::psu2/brightness", 1) - - status, fan1 = log_os_system(" cat /sys/devices/platform/cs6436_56p_fan/fan1_fault",1) - if status: - print "failed to check status for cs6436_56p_fan/fan1_fault" - continue - - if fan1=='0': - log_os_system("echo 1 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::fan1/brightness", 1) - else: - log_os_system("echo 3 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::fan1/brightness", 1) - - status, fan2 = log_os_system(" cat /sys/devices/platform/cs6436_56p_fan/fan2_fault",1) - - if status: - print "failed to check status for cs6436_56p_fan/fan2_fault" - continue - - if fan2=='0': - log_os_system("echo 1 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::fan2/brightness", 1) - else: - log_os_system("echo 3 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::fan2/brightness", 1) - - status, fan3 = log_os_system(" cat /sys/devices/platform/cs6436_56p_fan/fan3_fault",1) - if status: - print "failed to check status for cs6436_56p_fan/fan3_fault" - continue - - if fan3=='0': - log_os_system("echo 1 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::fan3/brightness", 1) - else: - log_os_system("echo 3 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::fan3/brightness", 1) - - status, fan4 = log_os_system(" cat /sys/devices/platform/cs6436_56p_fan/fan4_fault",1) - if status: - print "failed to check status for cs6436_56p_fan/fan4_fault" - continue - - if fan4=='0': - log_os_system("echo 1 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::fan4/brightness", 1) - else: - log_os_system("echo 3 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::fan4/brightness", 1) - - status, fan5 = log_os_system(" cat /sys/devices/platform/cs6436_56p_fan/fan5_fault",1) - if status: - print "failed to check status for cs6436_56p_fan/fan5_fault" - continue - - if fan5=='0': - log_os_system("echo 1 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::fan5/brightness", 1) - else: - log_os_system("echo 3 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::fan5/brightness", 1) - - if fan1=='0' or fan2=='0' or fan3=='0' or fan4=='0' or fan5=='0': - log_os_system("echo 1 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::fan/brightness", 1) - else: - log_os_system("echo 3 > /sys/devices/platform/cs6436_56p_led/leds/cs6436_56p_led::fan/brightness", 1) + count = count + 1 + ret = system_check_psuspresent() + ret = system_check_fansstate() + + if count % 10 == 0: + misclogger.info(": adjust fans and check psu direction.") + system_check_psusdirection() + if tempcontrol == 0: + system_monitor_temperature() + count = 0 time.sleep(delay) - print "%s: %s" % ( threadName, time.ctime(time.time())) + return if __name__ == '__main__': - target=system_misc_polling("Thread-misc",3) - - - + target=system_misc_polling("Thread-misc",10) diff --git a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/utils/cig_cs6436_util.py b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/utils/cig_cs6436_util.py index 2b64d2e107b..86285c7e410 100755 --- a/platform/nephos/sonic-platform-modules-cig/cs6436-56p/utils/cig_cs6436_util.py +++ b/platform/nephos/sonic-platform-modules-cig/cs6436-56p/utils/cig_cs6436_util.py @@ -21,13 +21,13 @@ options: -h | --help : this help message -d | --debug : run with debug mode - -f | --force : ignore error during installation or clean + -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 + set : change board setting with fan|led|sfp """ import os @@ -42,47 +42,48 @@ PROJECT_NAME = 'cs6436_56p' -version = '0.1.0' +version = '0.1.1' verbose = False DEBUG = False args = [] -ALL_DEVICE = {} +ALL_DEVICE = {} DEVICE_NO = {'led':9, 'fan':5, 'thermal':4, 'psu':2, 'sfp':56} FORCE = 0 +CPU_TYPE = 'C3308' if DEBUG == True: print sys.argv[0] - print 'ARGV :', sys.argv[1:] + 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: + 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'): + elif opt in ('-d', '--debug'): DEBUG = True logging.basicConfig(level=logging.INFO) - elif opt in ('-f', '--force'): + elif opt in ('-f', '--force'): FORCE = 1 else: - logging.info('no option') - for arg in args: + logging.info('no option') + for arg in args: if arg == 'install': do_install() elif arg == 'clean': @@ -92,23 +93,23 @@ def main(): elif arg == 'sff': if len(args)!=2: show_eeprom_help() - elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']: + elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']: show_eeprom_help() else: - show_eeprom(args[1]) - return + show_eeprom(args[1]) + return elif arg == 'set': if len(args)<3: show_set_help() else: - set_device(args[1:]) - return + set_device(args[1:]) + return else: show_help() - - - return 0 - + + + return 0 + def show_help(): print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} sys.exit(0) @@ -117,31 +118,31 @@ 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-56 {0|1}\" to set sfp# tx_disable" - sys.exit(0) - + print " use \""+ cmd + " fan 0-100\" to set fan duty percetage" + print " use \""+ cmd + " sfp 1-56 {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-56 \" to dump sfp# eeprom" - sys.exit(0) - + print " use \""+ cmd + " 1-56 \" to dump sfp# eeprom" + sys.exit(0) + def my_log(txt): if DEBUG == True: - print "[ROY]"+txt + print "[ROY]"+txt return - + def log_os_system(cmd, show): - logging.info('Run :'+cmd) - status, output = commands.getstatusoutput(cmd) + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) my_log (cmd +"with result:" + str(status)) - my_log (" output:"+output) + my_log (" output:"+output) if status: logging.info('Failed :'+cmd) if show: print('Failed :'+cmd) return status, output - + def driver_check(): for count in range(1,5): time.sleep(1) @@ -154,11 +155,11 @@ def driver_check(): if len(lsmod) > 2: log_os_system("rmmod i2c_designware_platform", 0) log_os_system("modprobe i2c-designware-platform", 0) - + ret, lsmod = log_os_system("lsmod| grep cig", 0) logging.info('mods:'+lsmod) if len(lsmod) ==0: - return False + return False return True @@ -167,6 +168,7 @@ def driver_check(): 'depmod', 'modprobe i2c_dev', 'modprobe i2c_mux_pca954x force_deselect_on_exit=1', + 'modprobe x86-64-cig-cs6436-56p-sysfs ' , 'modprobe x86-64-cig-cs6436-56p-cpld ' , 'modprobe x86-64-cig-cs6436-56p-fan' , 'modprobe x86-64-cig-cs6436-56p-psu' , @@ -175,28 +177,31 @@ def driver_check(): def driver_install(): global FORCE - + for i in range(0,len(kos)): - if i == 3: - ret, board_type = log_os_system("cat /proc/cpuinfo | grep \"model name\" | cut -b 32-39 | head -n 1", 0) - if board_type=='i3-6100U': - kos[i] =kos[i] + 'board_id=1' - + if i == 4: + ret, CPU_TYPE = log_os_system("cat /proc/cpuinfo | grep \"model name\" | cut -b 32-39 | head -n 1", 0) + if CPU_TYPE=='i3-6100U': + kos[i] =kos[i] + 'board_id=1' + ret, CPU_TYPE = log_os_system("cat /proc/cpuinfo | grep \"model name\" | cut -b 36-40 | head -n 1", 0) + if CPU_TYPE=='C3758' or CPU_TYPE=='C3308': + kos[i] =kos[i] + 'board_id=2' + status, output = log_os_system(kos[i], 1) if status: - if FORCE == 0: - return 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") + rm = rm.replace("insmod", "rmmod") status, output = log_os_system(rm, 1) if status: - if FORCE == 0: - return status + if FORCE == 0: + return status return 0 led_prefix ='/sys/class/leds/'+PROJECT_NAME+'_led::' @@ -245,23 +250,22 @@ def driver_uninstall(): 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(1) - + #all nodes need times to built new i2c buses + time.sleep(1) + status, output = log_os_system(mknod[i], 1) if status: print output - if FORCE == 0: + if FORCE == 0: return status - + for i in range(0,len(sfp_map)): status, output =log_os_system("echo cs6436_56p_sfp"+str(i+1)+" 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) if status: print output - if FORCE == 0: + if FORCE == 0: return status if i <= 47: @@ -271,21 +275,21 @@ def device_install(): if FORCE == 0: return status - return - + return + def device_uninstall(): global FORCE - + 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: + if FORCE == 0: return status - + nodelist = mknod - + for i in range(len(nodelist)): target = nodelist[-(i+1)] temp = target.split() @@ -294,129 +298,129 @@ def device_uninstall(): status, output = log_os_system(" ".join(temp), 1) if status: print output - if FORCE == 0: - return status - - return - + if FORCE == 0: + return status + + return + def system_ready(): if driver_check() == False: return False - if not device_exist(): + if not device_exist(): return False return True - + def do_install(): print "Checking system...." if driver_check() == False: - print "No driver, installing...." + print "No driver, installing...." status = driver_install() if status: - if FORCE == 0: + if FORCE == 0: return status else: - print PROJECT_NAME.upper()+" drivers detected...." + print PROJECT_NAME.upper()+" drivers detected...." if not device_exist(): - print "No device, installing...." - status = device_install() + print "No device, installing...." + status = device_install() if status: - if FORCE == 0: - return status + if FORCE == 0: + return status else: - print PROJECT_NAME.upper()+" devices detected...." + 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...." + print PROJECT_NAME.upper() +" has no device installed...." else: - print "Removing device...." - status = device_uninstall() + print "Removing device...." + status = device_uninstall() if status: - if FORCE == 0: - return status - + if FORCE == 0: + return status + if driver_check()== 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 + if FORCE == 0: + return status + + return def devices_info(): global DEVICE_NO global ALL_DEVICE global i2c_bus, hwmon_types, fan_types - for key in DEVICE_NO: - ALL_DEVICE[key]= {} + 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] + nodes = i2c_nodes[key] for i in range(0,len(buses)): for j in range(0,len(nodes)): if '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] + path = i2c_prefix+ str(sfp_map[k])+ buses[i]+"/"+ nodes[j] my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) + ALL_DEVICE[key][node].append(path) else: node = key+str(i+1) - path = i2c_prefix+ buses[i]+"/"+ nodes[j] + path = i2c_prefix+ buses[i]+"/"+ nodes[j] my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) - + ALL_DEVICE[key][node].append(path) + for key in hwmon_types: itypes = hwmon_types[key] - nodes = hwmon_nodes[key] + nodes = hwmon_nodes[key] for i in range(0,len(itypes)): - for j in range(0,len(nodes)): + for j in range(0,len(nodes)): node = key+"_"+itypes[i] - path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] + path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] my_log(node+": "+ path) - ALL_DEVICE[key][ key+str(i+1)].append(path) + ALL_DEVICE[key][ key+str(i+1)].append(path) for key in fan_types: itypes = fan_types[key] - nodes = fan_nodes[key] + nodes = fan_nodes[key] for i in range(0,len(itypes)): - for j in range(0,len(nodes)): + for j in range(0,len(nodes)): node = key+"_"+itypes[i] - path = fan_prefix+"/"+ itypes[i]+"_"+ nodes[j] + path = fan_prefix+"/"+ 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()): + for j in sorted(ALL_DEVICE[i].keys()): print(" "+j) - for k in (ALL_DEVICE[i][j]): + for k in (ALL_DEVICE[i][j]): print(" "+" "+k) - return - + return + def show_eeprom(index): if system_ready()==False: - print("System's not ready.") + print("System's not ready.") print("Please install first!") - return - + return + if len(ALL_DEVICE)==0: - devices_info() + devices_info() node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0] node = node.replace(node.split("/")[-1], 'sfp_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) + ret, log2 = log_os_system("which busybox hexdump", 0) if len(log): hex_cmd = 'hexdump' elif len(log2): @@ -425,109 +429,123 @@ def show_eeprom(index): log = 'Failed : no hexdump cmd!!' logging.info(log) print log - return 1 - + return 1 + print node + ":" ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1) - if ret==0: - print log + if ret==0: + print log else: - print "**********device no found**********" - return - + 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("System's not ready.") print("Please install first!") - return - + return + if len(ALL_DEVICE)==0: - devices_info() - + 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)]): + 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 + 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['fan'] ['fan1'][0] + #fan1~6 is all fine, all fan share same setting + node = ALL_DEVICE['fan'] ['fan1'][0] node = node.replace(node.split("/")[-1], 'fan_duty_cycle_percentage') - ret, log = log_os_system("cat "+ node, 1) + ret, log = log_os_system("cat "+ node, 1) if ret==0: - print ("Previous fan duty: " + log.strip() +"%") + 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] +"%") + 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 + return if len(args)<2: show_set_help() - return - + 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: + + #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 ret + return def get_value(input): digit = re.findall('\d+', input) return int(digit[0]) - + + +def get_ledname(ledx): + name_table={'led1':'SYS','led2':'FSTUS','led3':'FAN1','led4':'FAN2','led5':'FAN3','led6':'FAN4','led7':'FAN5','led8':'PSU1','led9':'PSU2'} + if name_table.has_key(ledx): + name = name_table[ledx] + else: + name = ledx + return name + + def device_traversal(): if system_ready()==False: - print("System's not ready.") + print("System's not ready.") print("Please install first!") - return - + return + if len(ALL_DEVICE)==0: devices_info() for i in sorted(ALL_DEVICE.keys()): - print("============================================") + print("============================================") print(i.upper()+": ") print("============================================") - - for j in sorted(ALL_DEVICE[i].keys(), key=get_value): - print " "+j+":", + + for j in sorted(ALL_DEVICE[i].keys(), key=get_value): + nwnamex = get_ledname(j) + if nwnamex == j: + print " "+j+":", + else: + print " "+nwnamex+":", 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) + func = re.sub(i.lower()+'_','',func,1) if ret==0: - print func+"="+log+" ", + print func+"="+log+" ", else: print func+"="+"X"+" ", - print + 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-3", 0) diff --git a/platform/nephos/sonic-platform-modules-cig/debian/control b/platform/nephos/sonic-platform-modules-cig/debian/control index 356ce313ab6..6037b42e845 100755 --- a/platform/nephos/sonic-platform-modules-cig/debian/control +++ b/platform/nephos/sonic-platform-modules-cig/debian/control @@ -9,3 +9,13 @@ Package: sonic-platform-cig-cs6436-56p Architecture: amd64 Depends: linux-image-4.9.0-9-amd64 Description: kernel modules for platform devices such as fan, led, sfp + +Package: sonic-platform-cig-cs6436-54p +Architecture: amd64 +Depends: linux-image-4.9.0-9-amd64 +Description: kernel modules for platform devices such as fan, led, sfp + +Package: sonic-platform-cig-cs5435-54p +Architecture: amd64 +Depends: linux-image-4.9.0-9-amd64 +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/nephos/sonic-platform-modules-cig/debian/rules b/platform/nephos/sonic-platform-modules-cig/debian/rules index 3192948cc08..5bcec26f0b1 100755 --- a/platform/nephos/sonic-platform-modules-cig/debian/rules +++ b/platform/nephos/sonic-platform-modules-cig/debian/rules @@ -19,7 +19,7 @@ PACKAGE_PRE_NAME := sonic-platform-cig KVERSION ?= $(shell uname -r) KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) -MODULE_DIRS:= cs6436-56p +MODULE_DIRS:= cs6436-56p cs6436-54p cs5435-54p MODULE_DIR := modules UTILS_DIR := utils SERVICE_DIR := service @@ -62,8 +62,9 @@ binary-indep: dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin; \ dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system; \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod}/etc/sonic; \ cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ - cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ + cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/*.py debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \ $(PYTHON) $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \ done) diff --git a/platform/p4/docker-sonic-p4/Dockerfile.j2 b/platform/p4/docker-sonic-p4/Dockerfile.j2 index 09849a7ae14..4988cbdb539 100644 --- a/platform/p4/docker-sonic-p4/Dockerfile.j2 +++ b/platform/p4/docker-sonic-p4/Dockerfile.j2 @@ -71,7 +71,6 @@ RUN sed -ri 's/^(save .*$)/# \1/g; ' /etc/redis/redis.conf ADD port_config.ini /port_config.ini -ADD rsyslog.conf /etc/rsyslog.conf COPY ["start.sh", "orchagent.sh", "config_bm.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] COPY ["files/configdb-load.sh", "/usr/bin/"] diff --git a/platform/p4/docker-sonic-p4/orchagent.sh b/platform/p4/docker-sonic-p4/orchagent.sh index 7e250dfa20e..9abfc22c967 100755 --- a/platform/p4/docker-sonic-p4/orchagent.sh +++ b/platform/p4/docker-sonic-p4/orchagent.sh @@ -1,6 +1,10 @@ #!/usr/bin/env bash -MAC_ADDRESS=`ip link show eth0 | grep ether | awk '{print $2}'` +MAC_ADDRESS=$(sonic-cfggen -d -v 'DEVICE_METADATA.localhost.mac') +if [ "$MAC_ADDRESS" == "None" ] || [ -z "$MAC_ADDRESS" ]; then + MAC_ADDRESS=$(ip link show eth0 | grep ether | awk '{print $2}') + logger "Mac address not found in Device Metadata, Falling back to eth0" +fi # Create a folder for SsWW record files mkdir -p /var/log/swss diff --git a/platform/p4/docker-sonic-p4/rsyslog.conf b/platform/p4/docker-sonic-p4/rsyslog.conf deleted file mode 100644 index 27e046257e1..00000000000 --- a/platform/p4/docker-sonic-p4/rsyslog.conf +++ /dev/null @@ -1,76 +0,0 @@ -############################################################################### -# Managed by Ansible -# file: ansible/roles/acs/templates/rsyslog.conf.j2 -############################################################################### -# -# /etc/rsyslog.conf Configuration file for rsyslog. -# -# For more information see -# /usr/share/doc/rsyslog-doc/html/rsyslog_conf.html - - -################# -#### MODULES #### -################# - -$ModLoad imuxsock # provides support for local system logging - -# -# Set a rate limit on messages from the container -# -$SystemLogRateLimitInterval 300 -$SystemLogRateLimitBurst 20000 - -#$ModLoad imklog # provides kernel logging support -#$ModLoad immark # provides --MARK-- message capability - -# provides UDP syslog reception -#$ModLoad imudp -#$UDPServerRun 514 - -# provides TCP syslog reception -#$ModLoad imtcp -#$InputTCPServerRun 514 - - -########################### -#### GLOBAL DIRECTIVES #### -########################### -#Set remote syslog server -#*.* @172.17.0.1:514 -#Set local syslog -*.* /var/log/messages - -# -# Use traditional timestamp format. -# To enable high precision timestamps, comment out the following line. -# -#$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat - -# Define a custom template -$template SONiCFileFormat,"%TIMESTAMP%.%timestamp:::date-subseconds% %HOSTNAME% %syslogseverity-text:::uppercase% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n" -$ActionFileDefaultTemplate SONiCFileFormat - -# -# Set the default permissions for all log files. -# -$FileOwner root -$FileGroup adm -$FileCreateMode 0640 -$DirCreateMode 0755 -$Umask 0022 - -# -# Where to place spool and state files -# -$WorkDirectory /var/spool/rsyslog - -# -# Include all config files in /etc/rsyslog.d/ -# -$IncludeConfig /etc/rsyslog.d/*.conf - - -############### -#### RULES #### -############### diff --git a/platform/template/docker-syncd-base-rpc.mk b/platform/template/docker-syncd-base-rpc.mk index 2de7fb6c3f9..4fc171ca6e9 100644 --- a/platform/template/docker-syncd-base-rpc.mk +++ b/platform/template/docker-syncd-base-rpc.mk @@ -3,7 +3,7 @@ DOCKER_SYNCD_BASE = docker-syncd-$(DOCKER_SYNCD_PLATFORM_CODE).gz DOCKER_SYNCD_BASE_RPC = docker-syncd-$(DOCKER_SYNCD_PLATFORM_CODE)-rpc.gz $(DOCKER_SYNCD_BASE_RPC)_PATH = $(PLATFORM_PATH)/docker-syncd-$(DOCKER_SYNCD_PLATFORM_CODE)-rpc -$(DOCKER_SYNCD_BASE_RPC)_DEPENDS += $(SYNCD_RPC) $(LIBTHRIFT) +$(DOCKER_SYNCD_BASE_RPC)_DEPENDS += $(SYNCD_RPC) $(LIBTHRIFT) $(PTF) $(DOCKER_SYNCD_BASE_RPC)_LOAD_DOCKERS += $(DOCKER_SYNCD_BASE) SONIC_DOCKER_IMAGES += $(DOCKER_SYNCD_BASE_RPC) ifeq ($(ENABLE_SYNCD_RPC),y) diff --git a/platform/vs/docker-sonic-vs/orchagent.sh b/platform/vs/docker-sonic-vs/orchagent.sh index 26dae28a6e1..806cb8112a7 100755 --- a/platform/vs/docker-sonic-vs/orchagent.sh +++ b/platform/vs/docker-sonic-vs/orchagent.sh @@ -2,7 +2,11 @@ export platform=vs -MAC_ADDRESS=`ip link show eth0 | grep ether | awk '{print $2}'` +MAC_ADDRESS=$(sonic-cfggen -d -v 'DEVICE_METADATA.localhost.mac') +if [ "$MAC_ADDRESS" == "None" ] || [ -z "$MAC_ADDRESS" ]; then + MAC_ADDRESS=$(ip link show eth0 | grep ether | awk '{print $2}') + logger "Mac address not found in Device Metadata, Falling back to eth0" +fi # Create a folder for SwSS record files mkdir -p /var/log/swss diff --git a/push_docker.sh b/push_docker.sh index 3ba9abfae5b..3e2da08d0b8 100755 --- a/push_docker.sh +++ b/push_docker.sh @@ -1,42 +1,79 @@ +#! /bin/bash + +sonic_version="" +sonic_platform="" + +while getopts ":v:p:" opt +do + case ${opt} in + v ) # SONiC image version + sonic_version=${OPTARG} + ;; + p ) # Platform info + sonic_platform=${OPTARG} + ;; + \? ) echo "\ +Usage: [-v ] [ -p ] \ + []" + ;; + esac +done + +shift $((OPTIND -1)) + DOCKER_IMAGE_FILE=$1 REGISTRY_SERVER=$2 REGISTRY_PORT=$3 REGISTRY_USERNAME=$4 REGISTRY_PASSWD=$5 DOCKER_IMAGE_TAG=$6 +REGISTRY_SERVER_WITH_PORT=${REGISTRY_SERVER}${REGISTRY_PORT:+:$REGISTRY_PORT} -set -e -docker load < $DOCKER_IMAGE_FILE +push_it() { + # $1 - Given image name + # $2 - Remote image name -## Fetch the Jenkins build number if inside it -[ ${BUILD_NUMBER} ] || { - echo "No BUILD_NUMBER found, setting to 0." - BUILD_NUMBER="0" + docker tag $1 $2 + echo "Pushing $2" + image_sha=$(docker push $2 | sed -n "s/.*: digest: sha256:\([0-9a-f]*\).*/\\1/p") + echo "Remove $2" + docker rmi $2 || true + echo "Image sha256: $image_sha" } -## Prepare tag -docker_image_name=$(basename $DOCKER_IMAGE_FILE | cut -d. -f1) -remote_image_name=$REGISTRY_SERVER:$REGISTRY_PORT/$docker_image_name:$DOCKER_IMAGE_TAG -timestamp="$(date -u +%Y%m%d)" -build_version="${timestamp}.bld-${BUILD_NUMBER}" -build_remote_image_name=$REGISTRY_SERVER:$REGISTRY_PORT/$docker_image_name:$build_version +set -e -## Add registry information as tag, so will push as latest -## Add additional tag with build information -docker tag $docker_image_name $remote_image_name -docker tag $docker_image_name $build_remote_image_name +echo "Loading image ${DOCKER_IMAGE_FILE}" +docker load < ${DOCKER_IMAGE_FILE} ## Login the docker image registry server ## Note: user name and password are passed from command line -docker login -u $REGISTRY_USERNAME -p "$REGISTRY_PASSWD" $REGISTRY_SERVER:$REGISTRY_PORT - -## Push image to registry server -## And get the image digest SHA256 -echo "Pushing $remote_image_name" -image_sha=$(docker push $remote_image_name | sed -n "s/.*: digest: sha256:\([0-9a-f]*\).*/\\1/p") -docker rmi $remote_image_name || true -echo "Image sha256: $image_sha" -echo "Pushing $build_remote_image_name" -docker push $build_remote_image_name -docker rmi $build_remote_image_name || true +docker login -u ${REGISTRY_USERNAME} -p "${REGISTRY_PASSWD}" ${REGISTRY_SERVER_WITH_PORT} + +## Get Docker image name +docker_image_name=$(basename ${DOCKER_IMAGE_FILE} | cut -d. -f1) +remote_image_name=${REGISTRY_SERVER_WITH_PORT}/${docker_image_name} + +[ -z "${DOCKER_IMAGE_TAG}" ] || { + push_it ${docker_image_name} ${remote_image_name}:${DOCKER_IMAGE_TAG} +} + +if [ -n "${sonic_version}" ] && [ -n "${sonic_platform}" ] +then + remote_image_name=${REGISTRY_SERVER_WITH_PORT}/sonic-dockers/${sonic_platform}/${docker_image_name}:${sonic_version} + push_it ${docker_image_name} ${remote_image_name} +else + ## Fetch the Jenkins build number if inside it + [ ${BUILD_NUMBER} ] || { + echo "No BUILD_NUMBER found, setting to 0." + BUILD_NUMBER="0" + } + + timestamp="$(date -u +%Y%m%d)" + build_version="${timestamp}.bld-${BUILD_NUMBER}" + push_it ${docker_image_name} ${remote_image_name}:${build_version} +fi + docker rmi $docker_image_name || true +echo "Job completed" + diff --git a/rules/dhcpmon.mk b/rules/dhcpmon.mk new file mode 100644 index 00000000000..173a23eac72 --- /dev/null +++ b/rules/dhcpmon.mk @@ -0,0 +1,8 @@ +# SONiC DHCP MONitor package + +SONIC_DHCPMON_VERSION = 1.0.0-0 +SONIC_DHCPMON_PKG_NAME = dhcpmon + +SONIC_DHCPMON = sonic-$(SONIC_DHCPMON_PKG_NAME)_$(SONIC_DHCPMON_VERSION)_amd64.deb +$(SONIC_DHCPMON)_SRC_PATH = $(SRC_PATH)/$(SONIC_DHCPMON_PKG_NAME) +SONIC_DPKG_DEBS += $(SONIC_DHCPMON) diff --git a/rules/docker-base.mk b/rules/docker-base.mk index 8824dfb92eb..a2b567acc35 100644 --- a/rules/docker-base.mk +++ b/rules/docker-base.mk @@ -2,7 +2,7 @@ DOCKER_BASE = docker-base.gz $(DOCKER_BASE)_PATH = $(DOCKERS_PATH)/docker-base -$(DOCKER_BASE)_DEPENDS += $(SUPERVISOR) +$(DOCKER_BASE)_DEPENDS += $(SUPERVISOR) $(REDIS_TOOLS) $(DOCKER_BASE)_DEPENDS += $(BASH) $(DOCKER_BASE)_DEPENDS += $(SOCAT) diff --git a/rules/docker-database.mk b/rules/docker-database.mk index 4622cdc1e6c..283c4db3541 100644 --- a/rules/docker-database.mk +++ b/rules/docker-database.mk @@ -24,3 +24,4 @@ $(DOCKER_DATABASE)_RUN_OPT += --net=host --privileged -t $(DOCKER_DATABASE)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro $(DOCKER_DATABASE)_BASE_IMAGE_FILES += redis-cli:/usr/bin/redis-cli +$(DOCKER_DATABASE)_BASE_IMAGE_FILES += monit_database:/etc/monit/conf.d diff --git a/rules/docker-dhcp-relay.mk b/rules/docker-dhcp-relay.mk index edb0678a6f0..31c0529d03c 100644 --- a/rules/docker-dhcp-relay.mk +++ b/rules/docker-dhcp-relay.mk @@ -6,7 +6,7 @@ DOCKER_DHCP_RELAY_DBG = $(DOCKER_DHCP_RELAY_STEM)-$(DBG_IMAGE_MARK).gz $(DOCKER_DHCP_RELAY)_PATH = $(DOCKERS_PATH)/docker-dhcp-relay -$(DOCKER_DHCP_RELAY)_DEPENDS += $(ISC_DHCP_COMMON) $(ISC_DHCP_RELAY) $(REDIS_TOOLS) +$(DOCKER_DHCP_RELAY)_DEPENDS += $(ISC_DHCP_COMMON) $(ISC_DHCP_RELAY) $(REDIS_TOOLS) $(SONIC_DHCPMON) $(DOCKER_DHCP_RELAY)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE)_DBG_DEPENDS) $(DOCKER_DHCP_RELAY)_DBG_DEPENDS += $(ISC_DHCP_DBG) $(DOCKER_DHCP_RELAY)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE)_DBG_IMAGE_PACKAGES) diff --git a/rules/docker-fpm-frr.mk b/rules/docker-fpm-frr.mk index f9d084a9abb..cb06db5e3f1 100644 --- a/rules/docker-fpm-frr.mk +++ b/rules/docker-fpm-frr.mk @@ -24,3 +24,4 @@ $(DOCKER_FPM_FRR)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro $(DOCKER_FPM_FRR)_RUN_OPT += -v /etc/sonic/frr:/etc/frr:rw $(DOCKER_FPM_FRR)_BASE_IMAGE_FILES += vtysh:/usr/bin/vtysh +$(DOCKER_FPM_FRR)_BASE_IMAGE_FILES += monit_bgp:/etc/monit/conf.d diff --git a/rules/docker-lldp-sv2.mk b/rules/docker-lldp-sv2.mk index 93f08a54123..f00a5257b90 100644 --- a/rules/docker-lldp-sv2.mk +++ b/rules/docker-lldp-sv2.mk @@ -13,3 +13,4 @@ $(DOCKER_LLDP_SV2)_RUN_OPT += --net=host --privileged -t $(DOCKER_LLDP_SV2)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro $(DOCKER_LLDP_SV2)_BASE_IMAGE_FILES += lldpctl:/usr/bin/lldpctl +$(DOCKER_LLDP_SV2)_BASE_IMAGE_FILES += monit_lldp:/etc/monit/conf.d diff --git a/rules/docker-platform-monitor.mk b/rules/docker-platform-monitor.mk index f4748915d80..b92dde47ee7 100644 --- a/rules/docker-platform-monitor.mk +++ b/rules/docker-platform-monitor.mk @@ -30,4 +30,6 @@ $(DOCKER_PLATFORM_MONITOR)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro # Mount Arista python library on Aboot images to be used by plugins $(DOCKER_PLATFORM_MONITOR)_aboot_RUN_OPT += -v /usr/lib/python2.7/dist-packages/arista:/usr/lib/python2.7/dist-packages/arista:ro -$(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += sensors:/usr/bin/sensors +$(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += cmd_wrapper:/usr/bin/sensors +$(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += cmd_wrapper:/usr/sbin/iSmart +$(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += cmd_wrapper:/usr/sbin/SmartCmd diff --git a/rules/docker-snmp-sv2.mk b/rules/docker-snmp-sv2.mk index bf84a035437..e731cf0e0b0 100644 --- a/rules/docker-snmp-sv2.mk +++ b/rules/docker-snmp-sv2.mk @@ -27,3 +27,4 @@ $(DOCKER_SNMP_SV2)_RUN_OPT += --net=host --privileged -t $(DOCKER_SNMP_SV2)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro # mount Arista platform python libraries to support corresponding platforms SNMP power status query $(DOCKER_SNMP_SV2)_RUN_OPT += -v /usr/lib/python3/dist-packages/arista:/usr/lib/python3/dist-packages/arista:ro +$(DOCKER_SNMP_SV2)_BASE_IMAGE_FILES += monit_snmp:/etc/monit/conf.d diff --git a/rules/docker-telemetry.mk b/rules/docker-telemetry.mk index 64b7aa6fbdc..83afad1da89 100644 --- a/rules/docker-telemetry.mk +++ b/rules/docker-telemetry.mk @@ -26,3 +26,4 @@ $(DOCKER_TELEMETRY)_CONTAINER_NAME = telemetry $(DOCKER_TELEMETRY)_RUN_OPT += --net=host --privileged -t $(DOCKER_TELEMETRY)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro +$(DOCKER_TELEMETRY)_BASE_IMAGE_FILES += monit_telemetry:/etc/monit/conf.d diff --git a/rules/monit.mk b/rules/monit.mk new file mode 100644 index 00000000000..26fa26f5c4a --- /dev/null +++ b/rules/monit.mk @@ -0,0 +1,14 @@ +# monit package + +MONIT_VERSION = 5.20.0-6 + +export MONIT_VERSION + +MONIT = monit_$(MONIT_VERSION)_amd64.deb +$(MONIT)_SRC_PATH = $(SRC_PATH)/monit +SONIC_MAKE_DEBS += $(MONIT) + +SONIC_STRETCH_DEBS += $(MONIT) + +MONIT_DBG = monit-dbgsym_$(MONIT_VERSION)_amd64.deb +$(eval $(call add_derived_package,$(MONIT),$(MONIT_DBG))) diff --git a/slave.mk b/slave.mk index a381a464dd9..f4d24bc612f 100644 --- a/slave.mk +++ b/slave.mk @@ -555,7 +555,8 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ $(SONIC_UTILS) \ $(BASH) \ $(LIBPAM_TACPLUS) \ - $(LIBNSS_TACPLUS)) \ + $(LIBNSS_TACPLUS) \ + $(MONIT)) \ $$(addprefix $(TARGET_PATH)/,$$($$*_DOCKERS)) \ $$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_CONFIG_ENGINE)) \ $$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_PLATFORM_COMMON_PY2)) \ @@ -619,6 +620,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ DEBUG_SRC_ARCHIVE_FILE="$(DBG_SRC_ARCHIVE_FILE)" \ USERNAME="$(USERNAME)" \ PASSWORD="$(PASSWORD)" \ + IMAGE_TYPE=$($*_IMAGE_TYPE) \ ./build_debian.sh $(LOG) USERNAME="$(USERNAME)" \ diff --git a/sonic-slave-stretch/Dockerfile b/sonic-slave-stretch/Dockerfile index eeac24ae847..9551e4b4615 100644 --- a/sonic-slave-stretch/Dockerfile +++ b/sonic-slave-stretch/Dockerfile @@ -2,6 +2,8 @@ FROM debian:stretch MAINTAINER gulv@microsoft.com +COPY ["no-check-valid-until", "/etc/apt/apt.conf.d/"] + RUN echo "deb http://debian-archive.trafficmanager.net/debian/ stretch main contrib non-free" >> /etc/apt/sources.list && \ echo "deb-src http://debian-archive.trafficmanager.net/debian/ stretch main contrib non-free" >> /etc/apt/sources.list && \ echo "deb http://debian-archive.trafficmanager.net/debian-security/ stretch/updates main contrib non-free" >> /etc/apt/sources.list && \ diff --git a/sonic-slave-stretch/no-check-valid-until b/sonic-slave-stretch/no-check-valid-until new file mode 100644 index 00000000000..c7c25d017f7 --- /dev/null +++ b/sonic-slave-stretch/no-check-valid-until @@ -0,0 +1,4 @@ +# Instruct apt-get to NOT check the "Valid Until" date in Release files +# Once the Debian team archives a repo, they stop updating this date + +Acquire::Check-Valid-Until "false"; diff --git a/sonic-slave/Dockerfile b/sonic-slave/Dockerfile index abe43d9fe60..88383e83efb 100644 --- a/sonic-slave/Dockerfile +++ b/sonic-slave/Dockerfile @@ -2,6 +2,8 @@ FROM debian:jessie MAINTAINER johnar@microsoft.com +COPY ["no-check-valid-until", "/etc/apt/apt.conf.d/"] + ## Remove retired jessie-updates repo RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list @@ -114,6 +116,7 @@ RUN apt-get update && apt-get install -y \ libdb-dev \ iptables-dev \ swig \ + ctags \ # For mellanox sai build libtool-bin \ libxml2-dev \ @@ -237,7 +240,9 @@ RUN apt-get update && apt-get install -y \ # For sonic vs image build dosfstools \ qemu-kvm \ - libvirt-bin + libvirt-bin \ +# For DHCP Monitor tool + libevent-dev # For linux build RUN apt-get -y build-dep linux diff --git a/sonic-slave/no-check-valid-until b/sonic-slave/no-check-valid-until new file mode 100644 index 00000000000..c7c25d017f7 --- /dev/null +++ b/sonic-slave/no-check-valid-until @@ -0,0 +1,4 @@ +# Instruct apt-get to NOT check the "Valid Until" date in Release files +# Once the Debian team archives a repo, they stop updating this date + +Acquire::Check-Valid-Until "false"; diff --git a/src/dhcpmon/Makefile b/src/dhcpmon/Makefile new file mode 100644 index 00000000000..61cde376730 --- /dev/null +++ b/src/dhcpmon/Makefile @@ -0,0 +1,44 @@ +RM := rm -rf +DHCPMON_TARGET := dhcpmon +CP := cp +MKDIR := mkdir +CC := gcc +MV := mv + +# All of the sources participating in the build are defined here +-include src/subdir.mk +-include objects.mk + +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(strip $(C_DEPS)),) +-include $(C_DEPS) +endif +endif + +# Add inputs and outputs from these tool invocations to the build variables + +# All Target +all: sonic-dhcpmon + +# Tool invocations +sonic-dhcpmon: $(OBJS) $(USER_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: GCC C Linker' + $(CC) -o "$(DHCPMON_TARGET)" $(OBJS) $(USER_OBJS) $(LIBS) + @echo 'Finished building target: $@' + @echo ' ' + +# Other Targets +install: + $(MKDIR) -p $(DESTDIR)/usr/sbin + $(MV) $(DHCPMON_TARGET) $(DESTDIR)/usr/sbin + +deinstall: + $(RM) $(DESTDIR)/usr/sbin/$(DHCPMON_TARGET) + $(RM) -rf $(DESTDIR)/usr/sbin + +clean: + -$(RM) $(EXECUTABLES)$(OBJS)$(C_DEPS) $(DHCPMON_TARGET) + -@echo ' ' + +.PHONY: all clean dependents diff --git a/src/dhcpmon/debian/changelog b/src/dhcpmon/debian/changelog new file mode 100644 index 00000000000..83b79d6d93b --- /dev/null +++ b/src/dhcpmon/debian/changelog @@ -0,0 +1,5 @@ +sonic-dhcpmon (1.0.0-0) UNRELEASED; urgency=medium + + * Initial release. + + -- Tamer Ahmed Mon, 09 Dec 2019 12:00:00 -0700 diff --git a/src/dhcpmon/debian/compat b/src/dhcpmon/debian/compat new file mode 100644 index 00000000000..ec635144f60 --- /dev/null +++ b/src/dhcpmon/debian/compat @@ -0,0 +1 @@ +9 diff --git a/src/dhcpmon/debian/control b/src/dhcpmon/debian/control new file mode 100644 index 00000000000..4456f10c002 --- /dev/null +++ b/src/dhcpmon/debian/control @@ -0,0 +1,15 @@ +Source: sonic-dhcpmon +Section: devel +Priority: optional +Maintainer: Tamer Ahmed +Build-Depends: debhelper (>= 8.0.0), + dh-systemd +Standards-Version: 3.9.3 +Homepage: https://github.com/Azure/sonic-buildimage +XS-Go-Import-Path: github.com/Azure/sonic-buildimage + +Package: sonic-dhcpmon +Architecture: any +Built-Using: ${misc:Built-Using} +Depends: libevent-2.0-5 +Description: SONiC DHCP Monitor diff --git a/src/dhcpmon/debian/rules b/src/dhcpmon/debian/rules new file mode 100755 index 00000000000..3995a26d7fc --- /dev/null +++ b/src/dhcpmon/debian/rules @@ -0,0 +1,3 @@ +#!/usr/bin/make -f +%: + dh $@ --with systemd diff --git a/src/dhcpmon/objects.mk b/src/dhcpmon/objects.mk new file mode 100644 index 00000000000..6bdc124b8d9 --- /dev/null +++ b/src/dhcpmon/objects.mk @@ -0,0 +1,4 @@ +USER_OBJS := + +LIBS := -levent + diff --git a/src/dhcpmon/src/dhcp_device.c b/src/dhcpmon/src/dhcp_device.c new file mode 100644 index 00000000000..118175912c0 --- /dev/null +++ b/src/dhcpmon/src/dhcp_device.c @@ -0,0 +1,532 @@ +/** + * @file dhcp_device.c + * + * device (interface) module + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dhcp_device.h" + +/** Start of Ether header of a captured frame */ +#define ETHER_START_OFFSET 0 +/** Start of IP header of a captured frame */ +#define IP_START_OFFSET (ETHER_START_OFFSET + ETHER_HDR_LEN) +/** Start of UDP header of a captured frame */ +#define UDP_START_OFFSET (IP_START_OFFSET + sizeof(struct ip)) +/** Start of DHCP header of a captured frame */ +#define DHCP_START_OFFSET (UDP_START_OFFSET + sizeof(struct udphdr)) +/** Start of DHCP Options segment of a captured frame */ +#define DHCP_OPTIONS_HEADER_SIZE 240 +/** Offset of DHCP GIADDR */ +#define DHCP_GIADDR_OFFSET 24 + +/** + * DHCP message types + **/ +typedef enum +{ + DHCP_MESSAGE_TYPE_DISCOVER = 1, + DHCP_MESSAGE_TYPE_OFFER = 2, + DHCP_MESSAGE_TYPE_REQUEST = 3, + DHCP_MESSAGE_TYPE_DECLINE = 4, + DHCP_MESSAGE_TYPE_ACK = 5, + DHCP_MESSAGE_TYPE_NAK = 6, + DHCP_MESSAGE_TYPE_RELEASE = 7, + DHCP_MESSAGE_TYPE_INFORM = 8 +} dhcp_message_type; + +#define OP_LDHA (BPF_LD | BPF_H | BPF_ABS) /** bpf ldh Abs */ +#define OP_LDHI (BPF_LD | BPF_H | BPF_IND) /** bpf ldh Ind */ +#define OP_LDB (BPF_LD | BPF_B | BPF_ABS) /** bpf ldb Abs*/ +#define OP_JEQ (BPF_JMP | BPF_JEQ | BPF_K) /** bpf jeq */ +#define OP_JGT (BPF_JMP | BPF_JGT | BPF_K) /** bpf jgt */ +#define OP_RET (BPF_RET | BPF_K) /** bpf ret */ +#define OP_JSET (BPF_JMP | BPF_JSET | BPF_K) /** bpf jset */ +#define OP_LDXB (BPF_LDX | BPF_B | BPF_MSH) /** bpf ldxb */ + +/** Berkeley Packet Filter program for "udp and (port 67 or port 68)". + * This program is obtained using the following command tcpdump: + * `tcpdump -dd "udp and (port 67 or port 68)"` + */ +static struct sock_filter dhcp_bpf_code[] = { + {.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x0000000c}, // (000) ldh [12] + {.code = OP_JEQ, .jt = 0, .jf = 7, .k = 0x000086dd}, // (001) jeq #0x86dd jt 2 jf 9 + {.code = OP_LDB, .jt = 0, .jf = 0, .k = 0x00000014}, // (002) ldb [20] + {.code = OP_JEQ, .jt = 0, .jf = 18, .k = 0x00000011}, // (003) jeq #0x11 jt 4 jf 22 + {.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x00000036}, // (004) ldh [54] + {.code = OP_JEQ, .jt = 15, .jf = 0, .k = 0x00000043}, // (005) jeq #0x43 jt 21 jf 6 + {.code = OP_JEQ, .jt = 14, .jf = 0, .k = 0x00000044}, // (006) jeq #0x44 jt 21 jf 7 + {.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x00000038}, // (007) ldh [56] + {.code = OP_JEQ, .jt = 12, .jf = 11, .k = 0x00000043}, // (008) jeq #0x43 jt 21 jf 20 + {.code = OP_JEQ, .jt = 0, .jf = 12, .k = 0x00000800}, // (009) jeq #0x800 jt 10 jf 22 + {.code = OP_LDB, .jt = 0, .jf = 0, .k = 0x00000017}, // (010) ldb [23] + {.code = OP_JEQ, .jt = 0, .jf = 10, .k = 0x00000011}, // (011) jeq #0x11 jt 12 jf 22 + {.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x00000014}, // (012) ldh [20] + {.code = OP_JSET, .jt = 8, .jf = 0, .k = 0x00001fff}, // (013) jset #0x1fff jt 22 jf 14 + {.code = OP_LDXB, .jt = 0, .jf = 0, .k = 0x0000000e}, // (014) ldxb 4*([14]&0xf) + {.code = OP_LDHI, .jt = 0, .jf = 0, .k = 0x0000000e}, // (015) ldh [x + 14] + {.code = OP_JEQ, .jt = 4, .jf = 0, .k = 0x00000043}, // (016) jeq #0x43 jt 21 jf 17 + {.code = OP_JEQ, .jt = 3, .jf = 0, .k = 0x00000044}, // (017) jeq #0x44 jt 21 jf 18 + {.code = OP_LDHI, .jt = 0, .jf = 0, .k = 0x00000010}, // (018) ldh [x + 16] + {.code = OP_JEQ, .jt = 1, .jf = 0, .k = 0x00000043}, // (019) jeq #0x43 jt 21 jf 20 + {.code = OP_JEQ, .jt = 0, .jf = 1, .k = 0x00000044}, // (020) jeq #0x44 jt 21 jf 22 + {.code = OP_RET, .jt = 0, .jf = 0, .k = 0x00040000}, // (021) ret #262144 + {.code = OP_RET, .jt = 0, .jf = 0, .k = 0x00000000}, // (022) ret #0 +}; + +/** Filter program socket struct */ +static struct sock_fprog dhcp_sock_bfp = { + .len = sizeof(dhcp_bpf_code) / sizeof(*dhcp_bpf_code), .filter = dhcp_bpf_code +}; + +/** global aggregate counter for DHCP interfaces */ +static dhcp_device_counters_t glob_counters[DHCP_DIR_COUNT] = { + [DHCP_RX] = {.discover = 0, .offer = 0, .request = 0, .ack = 0}, + [DHCP_TX] = {.discover = 0, .offer = 0, .request = 0, .ack = 0}, +}; + +/** global aggregate counter snapshot for DHCP interfaces */ +static dhcp_device_counters_t glob_counters_snapshot[DHCP_DIR_COUNT] = { + [DHCP_RX] = {.discover = 0, .offer = 0, .request = 0, .ack = 0}, + [DHCP_TX] = {.discover = 0, .offer = 0, .request = 0, .ack = 0}, +}; + +/** + * @code handle_dhcp_option_53(context, dhcp_option, dir, iphdr, dhcphdr); + * + * @brief handle the logic related to DHCP option 53 + * + * @param context Device (interface) context + * @param dhcp_option pointer to DHCP option buffer space + * @param dir packet direction + * @param iphdr pointer to packet IP header + * @param dhcphdr pointer to DHCP header + * + * @return none + */ +static void handle_dhcp_option_53(dhcp_device_context_t *context, + const u_char *dhcp_option, + dhcp_packet_direction_t dir, + struct ip *iphdr, + uint8_t *dhcphdr) +{ + in_addr_t giaddr; + switch (dhcp_option[2]) + { + case DHCP_MESSAGE_TYPE_DISCOVER: + giaddr = ntohl(dhcphdr[DHCP_GIADDR_OFFSET] << 24 | dhcphdr[DHCP_GIADDR_OFFSET + 1] << 16 | + dhcphdr[DHCP_GIADDR_OFFSET + 2] << 8 | dhcphdr[DHCP_GIADDR_OFFSET + 3]); + context->counters[dir].discover++; + if ((context->vlan_ip == giaddr && context->is_uplink && dir == DHCP_TX) || + (!context->is_uplink && dir == DHCP_RX && iphdr->ip_dst.s_addr == INADDR_BROADCAST)) { + glob_counters[dir].discover++; + } + break; + case DHCP_MESSAGE_TYPE_OFFER: + context->counters[dir].offer++; + if ((context->vlan_ip == iphdr->ip_dst.s_addr && context->is_uplink && dir == DHCP_RX) || + (!context->is_uplink && dir == DHCP_TX)) { + glob_counters[dir].offer++; + } + break; + case DHCP_MESSAGE_TYPE_REQUEST: + giaddr = ntohl(dhcphdr[DHCP_GIADDR_OFFSET] << 24 | dhcphdr[DHCP_GIADDR_OFFSET + 1] << 16 | + dhcphdr[DHCP_GIADDR_OFFSET + 2] << 8 | dhcphdr[DHCP_GIADDR_OFFSET + 3]); + context->counters[dir].request++; + if ((context->vlan_ip == giaddr && context->is_uplink && dir == DHCP_TX) || + (!context->is_uplink && dir == DHCP_RX && iphdr->ip_dst.s_addr == INADDR_BROADCAST)) { + glob_counters[dir].request++; + } + break; + case DHCP_MESSAGE_TYPE_ACK: + context->counters[dir].ack++; + if ((context->vlan_ip == iphdr->ip_dst.s_addr && context->is_uplink && dir == DHCP_RX) || + (!context->is_uplink && dir == DHCP_TX)) { + glob_counters[dir].ack++; + } + break; + case DHCP_MESSAGE_TYPE_DECLINE: + case DHCP_MESSAGE_TYPE_NAK: + case DHCP_MESSAGE_TYPE_RELEASE: + case DHCP_MESSAGE_TYPE_INFORM: + break; + default: + syslog(LOG_WARNING, "handle_dhcp_option_53(%s): Unknown DHCP option 53 type %d", context->intf, dhcp_option[2]); + break; + } +} + +/** + * @code read_callback(fd, event, arg); + * + * @brief callback for libevent which is called every time out in order to read queued packet capture + * + * @param fd socket to read from + * @param event libevent triggered event + * @param arg user provided argument for callback (interface context) + * + * @return none + */ +static void read_callback(int fd, short event, void *arg) +{ + dhcp_device_context_t *context = (dhcp_device_context_t*) arg; + ssize_t buffer_sz; + + while ((event == EV_READ) && + ((buffer_sz = recv(fd, context->buffer, context->snaplen, MSG_DONTWAIT)) > 0)) { + struct ether_header *ethhdr = (struct ether_header*) context->buffer; + struct ip *iphdr = (struct ip*) (context->buffer + IP_START_OFFSET); + struct udphdr *udp = (struct udphdr*) (context->buffer + UDP_START_OFFSET); + uint8_t *dhcphdr = context->buffer + DHCP_START_OFFSET; + int dhcp_option_offset = DHCP_START_OFFSET + DHCP_OPTIONS_HEADER_SIZE; + + if ((buffer_sz > UDP_START_OFFSET + sizeof(struct udphdr) + DHCP_OPTIONS_HEADER_SIZE) && + (ntohs(udp->len) > DHCP_OPTIONS_HEADER_SIZE)) { + int dhcp_sz = ntohs(udp->len) < buffer_sz - UDP_START_OFFSET - sizeof(struct udphdr) ? + ntohs(udp->len) : buffer_sz - UDP_START_OFFSET - sizeof(struct udphdr); + int dhcp_option_sz = dhcp_sz - DHCP_OPTIONS_HEADER_SIZE; + const u_char *dhcp_option = context->buffer + dhcp_option_offset; + dhcp_packet_direction_t dir = (ethhdr->ether_shost[0] == context->mac[0] && + ethhdr->ether_shost[1] == context->mac[1] && + ethhdr->ether_shost[2] == context->mac[2] && + ethhdr->ether_shost[3] == context->mac[3] && + ethhdr->ether_shost[4] == context->mac[4] && + ethhdr->ether_shost[5] == context->mac[5]) ? + DHCP_TX : DHCP_RX; + int offset = 0; + int stop_dhcp_processing = 0; + while ((offset < (dhcp_option_sz + 1)) && dhcp_option[offset] != 255) { + switch (dhcp_option[offset]) + { + case 53: + if (offset < (dhcp_option_sz + 2)) { + handle_dhcp_option_53(context, &dhcp_option[offset], dir, iphdr, dhcphdr); + } + stop_dhcp_processing = 1; // break while loop since we are only interested in Option 53 + break; + default: + break; + } + + if (stop_dhcp_processing == 1) { + break; + } + + if (dhcp_option[offset] == 0) { // DHCP Option Padding + offset++; + } else { + offset += dhcp_option[offset + 1] + 2; + } + } + } else { + syslog(LOG_WARNING, "read_callback(%s): read length (%ld) is too small to capture DHCP options", + context->intf, buffer_sz); + } + } +} + +/** + * @code dhcp_device_validate(counters, counters_snapshot); + * + * @brief validate current interface counters by comparing aggregate counter with snapshot counters. + * + * @param counters recent interface counter + * @param counters_snapshot snapshot counters + * + * @return DHCP_MON_STATUS_HEALTHY, DHCP_MON_STATUS_UNHEALTHY, or DHCP_MON_STATUS_INDETERMINATE + */ +static dhcp_mon_status_t dhcp_device_validate(dhcp_device_counters_t *counters, + dhcp_device_counters_t *counters_snapshot) +{ + dhcp_mon_status_t rv = DHCP_MON_STATUS_HEALTHY; + + if ((counters[DHCP_RX].discover == counters_snapshot[DHCP_RX].discover) && + (counters[DHCP_RX].offer == counters_snapshot[DHCP_RX].offer ) && + (counters[DHCP_RX].request == counters_snapshot[DHCP_RX].request ) && + (counters[DHCP_RX].ack == counters_snapshot[DHCP_RX].ack ) ) { + rv = DHCP_MON_STATUS_INDETERMINATE; + } else { + // if we have rx DORA then we should have corresponding tx DORA (DORA being relayed) + if (((counters[DHCP_RX].discover > counters_snapshot[DHCP_RX].discover) && + (counters[DHCP_TX].discover <= counters_snapshot[DHCP_TX].discover) ) || + ((counters[DHCP_RX].offer > counters_snapshot[DHCP_RX].offer ) && + (counters[DHCP_TX].offer <= counters_snapshot[DHCP_TX].offer ) ) || + ((counters[DHCP_RX].request > counters_snapshot[DHCP_RX].request ) && + (counters[DHCP_TX].request <= counters_snapshot[DHCP_TX].request ) ) || + ((counters[DHCP_RX].ack > counters_snapshot[DHCP_RX].ack ) && + (counters[DHCP_TX].ack <= counters_snapshot[DHCP_TX].ack ) ) ) { + rv = DHCP_MON_STATUS_UNHEALTHY; + } + } + + return rv; +} + +/** + * @code dhcp_print_counters(counters); + * + * @brief prints DHCP counters to sylsog. + * + * @param counters interface counter + */ +static void dhcp_print_counters(dhcp_device_counters_t *counters) +{ + syslog(LOG_NOTICE, "DHCP Discover rx: %lu, tx:%lu, Offer rx: %lu, tx:%lu, Request rx: %lu, tx:%lu, ACK rx: %lu, tx:%lu\n", + counters[DHCP_RX].discover, counters[DHCP_TX].discover, + counters[DHCP_RX].offer, counters[DHCP_TX].offer, + counters[DHCP_RX].request, counters[DHCP_TX].request, + counters[DHCP_RX].ack, counters[DHCP_TX].ack); +} + +/** + * @code init_socket(context, intf); + * + * @brief initializes socket, bind it to interface and bpf prgram, and + * associate with libevent base + * + * @param context pointer to device (interface) context + * @param intf interface name + * + * @return 0 on success, otherwise for failure + */ +static int init_socket(dhcp_device_context_t *context, const char *intf) +{ + int rv = -1; + + do { + context->sock = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, htons(ETH_P_ALL)); + if (context->sock < 0) { + syslog(LOG_ALERT, "socket: failed to open socket with '%s'\n", strerror(errno)); + break; + } + + struct sockaddr_ll addr; + memset(&addr, 0, sizeof(addr)); + addr.sll_ifindex = if_nametoindex(intf); + addr.sll_family = AF_PACKET; + addr.sll_protocol = htons(ETH_P_ALL); + if (bind(context->sock, (struct sockaddr *) &addr, sizeof(addr))) { + syslog(LOG_ALERT, "bind: failed to bind to interface '%s' with '%s'\n", intf, strerror(errno)); + break; + } + + strncpy(context->intf, intf, sizeof(context->intf) - 1); + context->intf[sizeof(context->intf) - 1] = '\0'; + + rv = 0; + } while (0); + + return rv; +} + +/** + * @code initialize_intf_mac_and_ip_addr(context); + * + * @brief initializes device (interface) mac/ip addresses + * + * @param context pointer to device (interface) context + * + * @return 0 on success, otherwise for failure + */ +static int initialize_intf_mac_and_ip_addr(dhcp_device_context_t *context) +{ + int rv = -1; + + do { + int fd; + struct ifreq ifr; + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ALERT, "socket: %s", strerror(errno)); + break; + } + + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, context->intf, sizeof(ifr.ifr_name) - 1); + ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; + + // Get network address + if (ioctl(fd, SIOCGIFADDR, &ifr) == -1) { + syslog(LOG_ALERT, "ioctl: %s", strerror(errno)); + break; + } + context->ip = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr; + + // Get mac address + if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) { + syslog(LOG_ALERT, "ioctl: %s", strerror(errno)); + break; + } + memcpy(context->mac, ifr.ifr_hwaddr.sa_data, sizeof(context->mac)); + + close(fd); + + rv = 0; + } while (0); + + return rv; +} + +/** + * @code dhcp_device_get_ip(context); + * + * @brief Accessor method + * + * @param context pointer to device (interface) context + * + * @return interface IP + */ +int dhcp_device_get_ip(dhcp_device_context_t *context, in_addr_t *ip) +{ + int rv = -1; + + if (context != NULL && ip != NULL) { + *ip = context->ip; + rv = 0; + } + + return rv; +} + +/** + * @code dhcp_device_init(context, intf, is_uplink); + * + * @brief initializes device (interface) that handles packet capture per interface. + */ +int dhcp_device_init(dhcp_device_context_t **context, const char *intf, uint8_t is_uplink) +{ + int rv = -1; + dhcp_device_context_t *dev_context = NULL; + + if ((context != NULL) && (strlen(intf) < sizeof(dev_context->intf))) { + + dev_context = (dhcp_device_context_t *) malloc(sizeof(dhcp_device_context_t)); + if (dev_context != NULL) { + if ((init_socket(dev_context, intf) == 0) && + (initialize_intf_mac_and_ip_addr(dev_context) == 0)) { + + dev_context->is_uplink = is_uplink; + + memset(&dev_context->counters, 0, sizeof(dev_context->counters)); + memset(&dev_context->counters_snapshot, 0, sizeof(dev_context->counters_snapshot)); + + *context = dev_context; + rv = 0; + } + } + else { + syslog(LOG_ALERT, "malloc: failed to allocated device context memory for '%s'", dev_context->intf); + } + } + + return rv; +} + +/** + * @code dhcp_device_start_capture(context, snaplen, base, vlan_ip); + * + * @brief starts packet capture on this interface + */ +int dhcp_device_start_capture(dhcp_device_context_t *context, + size_t snaplen, + struct event_base *base, + in_addr_t vlan_ip) +{ + int rv = -1; + + do { + if (context == NULL) { + syslog(LOG_ALERT, "NULL interface context pointer'\n"); + break; + } + + if (snaplen < UDP_START_OFFSET + sizeof(struct udphdr) + DHCP_OPTIONS_HEADER_SIZE) { + syslog(LOG_ALERT, "dhcp_device_start_capture(%s): snap length is too low to capture DHCP options", context->intf); + break; + } + + context->vlan_ip = vlan_ip; + + context->buffer = (uint8_t *) malloc(snaplen); + if (context->buffer == NULL) { + syslog(LOG_ALERT, "malloc: failed to allocate memory for socket buffer '%s'\n", strerror(errno)); + break; + } + context->snaplen = snaplen; + + if (setsockopt(context->sock, SOL_SOCKET, SO_ATTACH_FILTER, &dhcp_sock_bfp, sizeof(dhcp_sock_bfp)) != 0) { + syslog(LOG_ALERT, "setsockopt: failed to attach filter with '%s'\n", strerror(errno)); + break; + } + + struct event *ev = event_new(base, context->sock, EV_READ | EV_PERSIST, read_callback, context); + if (ev == NULL) { + syslog(LOG_ALERT, "event_new: failed to allocate memory for libevent event '%s'\n", strerror(errno)); + break; + } + event_add(ev, NULL); + + rv = 0; + } while (0); + + return rv; +} + +/** + * @code dhcp_device_shutdown(context); + * + * @brief shuts down device (interface). Also, stops packet capture on interface and cleans up any allocated memory + */ +void dhcp_device_shutdown(dhcp_device_context_t *context) +{ + free(context); +} + +/** + * @code dhcp_device_get_status(context); + * + * @brief collects DHCP relay status info for a given interface. If context is null, it will report aggregate + * status + */ +dhcp_mon_status_t dhcp_device_get_status(dhcp_device_context_t *context) +{ + dhcp_mon_status_t rv = 0; + + if (context != NULL) { + rv = dhcp_device_validate(context->counters, context->counters_snapshot); + memcpy(context->counters_snapshot, context->counters, sizeof(context->counters_snapshot)); + } else { + rv = dhcp_device_validate(glob_counters, glob_counters_snapshot); + memcpy(glob_counters_snapshot, glob_counters, sizeof(glob_counters_snapshot)); + } + + return rv; +} + +/** + * @code dhcp_device_print_status(); + * + * @brief prints status counters to syslog. If context is null, it will print aggregate status + */ +void dhcp_device_print_status(dhcp_device_context_t *context) +{ + if (context != NULL) { + dhcp_print_counters(context->counters); + } else { + dhcp_print_counters(glob_counters); + } +} diff --git a/src/dhcpmon/src/dhcp_device.h b/src/dhcpmon/src/dhcp_device.h new file mode 100644 index 00000000000..bc1582d46a8 --- /dev/null +++ b/src/dhcpmon/src/dhcp_device.h @@ -0,0 +1,139 @@ +/** + * @file dhcp_device.h + * + * device (interface) module + */ + +#ifndef DHCP_DEVICE_H_ +#define DHCP_DEVICE_H_ + +#include +#include +#include +#include + +#include +#include +#include + + +/** packet direction */ +typedef enum +{ + DHCP_RX, /** RX DHCP packet */ + DHCP_TX, /** TX DHCP packet */ + + DHCP_DIR_COUNT +} dhcp_packet_direction_t; + +/** dhcp health status */ +typedef enum +{ + DHCP_MON_STATUS_HEALTHY, /** DHCP relay is healthy */ + DHCP_MON_STATUS_UNHEALTHY, /** DHCP relay is unhealthy and is missing out on some packets */ + DHCP_MON_STATUS_INDETERMINATE, /** DHCP relay health could not be determined */ +} dhcp_mon_status_t; + +/** DHCP device (interface) health counters */ +typedef struct +{ + uint64_t discover; /** DHCP discover packets */ + uint64_t offer; /** DHCP offer packets */ + uint64_t request; /** DHCP request packets */ + uint64_t ack; /** DHCP ack packets */ +} dhcp_device_counters_t; + +/** DHCP device (interface) context */ +typedef struct +{ + int sock; /** Raw socket associated with this device/interface */ + in_addr_t ip; /** network address of this device (interface) */ + uint8_t mac[ETHER_ADDR_LEN]; /** hardware address of this device (interface) */ + in_addr_t vlan_ip; /** Vlan IP address */ + uint8_t is_uplink; /** north interface? */ + char intf[IF_NAMESIZE]; /** device (interface) name */ + uint8_t *buffer; /** buffer used to read socket data */ + size_t snaplen; /** snap length or buffer size */ + dhcp_device_counters_t counters[DHCP_DIR_COUNT]; + /** current coutners of DORA packets */ + dhcp_device_counters_t counters_snapshot[DHCP_DIR_COUNT]; + /** counter snapshot */ +} dhcp_device_context_t; + +/** + * @code dhcp_device_get_ip(context, ip); + * + * @brief Accessor method + * + * @param context pointer to device (interface) context + * @param ip(out) pointer to device IP + * + * @return 0 on success, otherwise for failure + */ +int dhcp_device_get_ip(dhcp_device_context_t *context, in_addr_t *ip); + +/** + * @code dhcp_device_init(context, intf, is_uplink); + * + * @brief initializes device (interface) that handles packet capture per interface. + * + * @param context(inout) pointer to device (interface) context + * @param intf interface name + * @param is_uplink uplink interface + * + * @return 0 on success, otherwise for failure + */ +int dhcp_device_init(dhcp_device_context_t **context, + const char *intf, + uint8_t is_uplink); + +/** + * @code dhcp_device_start_capture(context, snaplen, base, vlan_ip); + * + * @brief starts packet capture on this interface + * + * @param context pointer to device (interface) context + * @param snaplen length of packet capture + * @param base pointer to libevent base + * @param vlan_ip vlan IP address + * + * @return 0 on success, otherwise for failure + */ +int dhcp_device_start_capture(dhcp_device_context_t *context, + size_t snaplen, + struct event_base *base, + in_addr_t vlan_ip); + +/** + * @code dhcp_device_shutdown(context); + * + * @brief shuts down device (interface). Also, stops packet capture on interface and cleans up any allocated memory + * + * @param context Device (interface) context + * + * @return nonedhcp_device_shutdown + */ +void dhcp_device_shutdown(dhcp_device_context_t *context); + +/** + * @code dhcp_device_get_status(context); + * + * @brief collects DHCP relay status info for a given interface. If context is null, it will report aggregate + * status + * + * @param context Device (interface) context + * + * @return DHCP_MON_STATUS_HEALTHY, DHCP_MON_STATUS_UNHEALTHY, or DHCP_MON_STATUS_INDETERMINATE + */ +dhcp_mon_status_t dhcp_device_get_status(dhcp_device_context_t *context); + +/** + * @code dhcp_device_print_status(); + * + * @brief prints status counters to syslog. If context is null, it will print aggregate status + * + * @return none + */ +void dhcp_device_print_status(dhcp_device_context_t *context); + +#endif /* DHCP_DEVICE_H_ */ diff --git a/src/dhcpmon/src/dhcp_devman.c b/src/dhcpmon/src/dhcp_devman.c new file mode 100644 index 00000000000..077ed210a29 --- /dev/null +++ b/src/dhcpmon/src/dhcp_devman.c @@ -0,0 +1,172 @@ +/** + * @file dhcp_devman.c + * + * Device (interface) manager + */ +#include +#include +#include +#include +#include +#include + +#include "dhcp_devman.h" + +/** struct for interface information */ +struct intf +{ + const char *name; /** interface name */ + uint8_t is_uplink; /** is uplink (north) interface */ + dhcp_device_context_t *dev_context; /** device (interface_ context */ + LIST_ENTRY(intf) entry; /** list link/pointers entries */ +}; + +/** intfs list of interfaces */ +static LIST_HEAD(intf_list, intf) intfs; +/** dhcp_num_south_intf number of south interfaces */ +static uint32_t dhcp_num_south_intf = 0; +/** dhcp_num_north_intf number of north interfaces */ +static uint32_t dhcp_num_north_intf = 0; + +/** On Device vlan interface IP address corresponding vlan downlink IP + * This IP is used to filter Offer/Ack packet coming from DHCP server */ +static in_addr_t vlan_ip = 0; + +/** vlan interface name */ +static char vlan_intf[IF_NAMESIZE] = "Undefined"; + +/** + * @code dhcp_devman_get_vlan_intf(); + * + * Accessor method + */ +const char* dhcp_devman_get_vlan_intf() +{ + return vlan_intf; +} + +/** + * @code dhcp_devman_init(); + * + * initializes device (interface) manager that keeps track of interfaces and assert that there is one south + * interface and as many north interfaces + */ +void dhcp_devman_init() +{ + LIST_INIT(&intfs); +} + +/** + * @code dhcp_devman_shutdown(); + * + * shuts down device (interface) manager. Also, stops packet capture on interface and cleans up any allocated + * memory + */ +void dhcp_devman_shutdown() +{ + struct intf *int_ptr, *prev_intf = NULL; + + LIST_FOREACH(int_ptr, &intfs, entry) { + dhcp_device_shutdown(int_ptr->dev_context); + if (prev_intf) { + LIST_REMOVE(prev_intf, entry); + free(prev_intf); + prev_intf = int_ptr; + } + } + + if (prev_intf) { + LIST_REMOVE(prev_intf, entry); + free(prev_intf); + } +} + +/** + * @code dhcp_devman_add_intf(name, is_uplink); + * + * @brief adds interface to the device manager. + */ +int dhcp_devman_add_intf(const char *name, uint8_t is_uplink) +{ + int rv = -1; + struct intf *dev = malloc(sizeof(struct intf)); + + if (dev != NULL) { + dev->name = name; + dev->is_uplink = is_uplink; + if (is_uplink) { + dhcp_num_north_intf++; + } else { + dhcp_num_south_intf++; + assert(dhcp_num_south_intf <= 1); + } + + rv = dhcp_device_init(&dev->dev_context, dev->name, dev->is_uplink); + if (rv == 0 && !is_uplink) { + rv = dhcp_device_get_ip(dev->dev_context, &vlan_ip); + + strncpy(vlan_intf, name, sizeof(vlan_intf) - 1); + vlan_intf[sizeof(vlan_intf) - 1] = '\0'; + } + + LIST_INSERT_HEAD(&intfs, dev, entry); + } + else { + syslog(LOG_ALERT, "malloc: failed to allocate memory for intf '%s'\n", name); + } + + return rv; +} + +/** + * @code dhcp_devman_start_capture(snaplen, base); + * + * @brief start packet capture on the devman interface list + */ +int dhcp_devman_start_capture(size_t snaplen, struct event_base *base) +{ + int rv = -1; + struct intf *int_ptr; + + if ((dhcp_num_south_intf == 1) && (dhcp_num_north_intf >= 1)) { + LIST_FOREACH(int_ptr, &intfs, entry) { + rv = dhcp_device_start_capture(int_ptr->dev_context, snaplen, base, vlan_ip); + if (rv == 0) { + syslog(LOG_INFO, + "Capturing DHCP packets on interface %s, ip: 0x%08x, mac [%02x:%02x:%02x:%02x:%02x:%02x] \n", + int_ptr->name, int_ptr->dev_context->ip, int_ptr->dev_context->mac[0], + int_ptr->dev_context->mac[1], int_ptr->dev_context->mac[2], int_ptr->dev_context->mac[3], + int_ptr->dev_context->mac[4], int_ptr->dev_context->mac[5]); + } + else { + break; + } + } + } + else { + syslog(LOG_ERR, "Invalid number of interfaces, downlink/south %d, uplink/north %d\n", + dhcp_num_south_intf, dhcp_num_north_intf); + } + + return rv; +} + +/** + * @code dhcp_devman_get_status(); + * + * @brief collects DHCP relay status info. + */ +dhcp_mon_status_t dhcp_devman_get_status() +{ + return dhcp_device_get_status(NULL); +} + +/** + * @code dhcp_devman_print_status(); + * + * @brief prints status counters to syslog + */ +void dhcp_devman_print_status() +{ + dhcp_device_print_status(NULL); +} diff --git a/src/dhcpmon/src/dhcp_devman.h b/src/dhcpmon/src/dhcp_devman.h new file mode 100644 index 00000000000..2f66fa407ca --- /dev/null +++ b/src/dhcpmon/src/dhcp_devman.h @@ -0,0 +1,85 @@ +/** + * @file dhcp_devman.h + * + * Device (interface) manager + */ + +#ifndef DHCP_DEVMAN_H_ +#define DHCP_DEVMAN_H_ + +#include + +#include "dhcp_device.h" + +/** + * @code dhcp_devman_init(); + * + * @brief initializes device (interface) manager that keeps track of interfaces and assert that there is one south + * interface and as many north interfaces + * + * @return none + */ +void dhcp_devman_init(); + +/** + * @code dhcp_devman_shutdown(); + * + * @brief shuts down device (interface) manager. Also, stops packet capture on interface and cleans up any allocated + * memory + * + * @return none + */ +void dhcp_devman_shutdown(); + +/** + * @code dhcp_devman_get_vlan_intf(); + * + * @brief Accessor method + * + * @return pointer to vlan ip interface name + */ +const char* dhcp_devman_get_vlan_intf(); + +/** + * @code dhcp_devman_add_intf(name, uplink); + * + * @brief adds interface to the device manager. + * + * @param name interface name + * @param is_uplink true for uplink (north) interface + * + * @return 0 on success, nonzero otherwise + */ +int dhcp_devman_add_intf(const char *name, uint8_t is_uplink); + +/** + * @code dhcp_devman_start_capture(snaplen, base); + * + * @brief start packet capture on the devman interface list + * + * @param snaplen packet packet capture snap length + * @param base libevent base + * + * @return 0 on success, nonzero otherwise + */ +int dhcp_devman_start_capture(size_t snaplen, struct event_base *base); + +/** + * @code dhcp_devman_get_status(); + * + * @brief collects DHCP relay status info. + * + * @return DHCP_MON_STATUS_HEALTHY, DHCP_MON_STATUS_UNHEALTHY, or DHCP_MON_STATUS_INDETERMINATE + */ +dhcp_mon_status_t dhcp_devman_get_status(); + +/** + * @code dhcp_devman_print_status(); + * + * @brief prints status counters to syslog + * + * @return none + */ +void dhcp_devman_print_status(); + +#endif /* DHCP_DEVMAN_H_ */ diff --git a/src/dhcpmon/src/dhcp_mon.c b/src/dhcpmon/src/dhcp_mon.c new file mode 100644 index 00000000000..623bc46f527 --- /dev/null +++ b/src/dhcpmon/src/dhcp_mon.c @@ -0,0 +1,201 @@ +/** + * @file dhcp_mon.c + * + * @brief dhcp relay monitor module + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dhcp_mon.h" +#include "dhcp_devman.h" + +/** window_interval_sec monitoring window for dhcp relay health checks */ +static int window_interval_sec = 12; +/** dhcp_unhealthy_max_count max count of consecutive unhealthy statuses before reporting to syslog */ +static int dhcp_unhealthy_max_count = 10; +/** libevent base struct */ +static struct event_base *base; +/** libevent timeout event struct */ +static struct event *ev_timeout = NULL; +/** libevent SIGINT signal event struct */ +static struct event *ev_sigint; +/** libevent SIGTERM signal event struct */ +static struct event *ev_sigterm; + +/** + * @code signal_callback(fd, event, arg); + * + * @brief signal handler for dhcpmon. It will initiate shutdown when signal is caught + * + * @param fd libevent socket + * @param event event triggered + * @param arg pointer to user provided context (libevent base) + * + * @return none + */ +static void signal_callback(evutil_socket_t fd, short event, void *arg) +{ + syslog(LOG_ALERT, "Received signal %s\n", strsignal(fd)); + dhcp_devman_print_status(); + dhcp_mon_stop(); +} + +/** + * @code timeout_callback(fd, event, arg); + * + * @brief periodic timer call back + * + * @param fd libevent socket + * @param event event triggered + * @param arg pointer user provided context (libevent base) + * + * @return none + */ +static void timeout_callback(evutil_socket_t fd, short event, void *arg) +{ + static int count = 0; + dhcp_mon_status_t dhcp_mon_status = dhcp_devman_get_status(); + + switch (dhcp_mon_status) + { + case DHCP_MON_STATUS_UNHEALTHY: + if (++count > dhcp_unhealthy_max_count) { + syslog(LOG_ALERT, "dhcpmon detected disparity in DHCP Relay behavior. Failure count: %d for vlan: '%s'\n", + count, dhcp_devman_get_vlan_intf()); + dhcp_devman_print_status(); + } + break; + case DHCP_MON_STATUS_HEALTHY: + if (count > 0) { + count = 0; + } + break; + case DHCP_MON_STATUS_INDETERMINATE: + break; + default: + syslog(LOG_ERR, "DHCP Relay returned unknown status %d\n", dhcp_mon_status); + break; + } +} + +/** + * @code dhcp_mon_init(window_sec, max_count); + * + * initializes event base and periodic timer event that continuously collects dhcp relay health status every window_sec + * seconds. It also writes to syslog when dhcp relay has been unhealthy for consecutive max_count checks. + * + */ +int dhcp_mon_init(int window_sec, int max_count) +{ + int rv = -1; + + do { + window_interval_sec = window_sec; + dhcp_unhealthy_max_count = max_count; + + base = event_base_new(); + if (base == NULL) { + syslog(LOG_ERR, "Could not initialize libevent!\n"); + break; + } + + ev_sigint = evsignal_new(base, SIGINT, signal_callback, base); + if (ev_sigint == NULL) { + syslog(LOG_ERR, "Could not create SIGINT libevent signal!\n"); + break; + } + + ev_sigterm = evsignal_new(base, SIGTERM, signal_callback, base); + if (ev_sigterm == NULL) { + syslog(LOG_ERR, "Could not create SIGTERM libevent signal!\n"); + break; + } + + ev_timeout = event_new(base, -1, EV_PERSIST, timeout_callback, base); + if (ev_timeout == NULL) { + syslog(LOG_ERR, "Could not create libevent timer!\n"); + break; + } + + rv = 0; + } while (0); + + return rv; +} + +/** + * @code dhcp_mon_shutdown(); + * + * @brief shuts down libevent loop + */ +void dhcp_mon_shutdown() +{ + event_del(ev_timeout); + event_del(ev_sigint); + event_del(ev_sigterm); + + event_free(ev_timeout); + event_free(ev_sigint); + event_free(ev_sigterm); + + event_base_free(base); +} + +/** + * @code dhcp_mon_start(snaplen); + * + * @brief start monitoring DHCP Relay + */ +int dhcp_mon_start(size_t snaplen) +{ + int rv = -1; + + do + { + if (dhcp_devman_start_capture(snaplen, base) != 0) { + break; + } + + if (evsignal_add(ev_sigint, NULL) != 0) { + syslog(LOG_ERR, "Could not add SIGINT libevent signal!\n"); + break; + } + + if (evsignal_add(ev_sigterm, NULL) != 0) { + syslog(LOG_ERR, "Could not add SIGTERM libevent signal!\n"); + break; + } + + struct timeval event_time = {.tv_sec = window_interval_sec, .tv_usec = 0}; + if (evtimer_add(ev_timeout, &event_time) != 0) { + syslog(LOG_ERR, "Could not add event timer to libevent!\n"); + break; + } + + if (event_base_dispatch(base) != 0) { + syslog(LOG_ERR, "Could not start libevent dispatching loop!\n"); + break; + } + + rv = 0; + } while (0); + + return rv; +} + +/** + * @code dhcp_mon_stop(); + * + * @brief stop monitoring DHCP Relay + */ +void dhcp_mon_stop() +{ + event_base_loopexit(base, NULL); +} diff --git a/src/dhcpmon/src/dhcp_mon.h b/src/dhcpmon/src/dhcp_mon.h new file mode 100644 index 00000000000..ae8911ab51f --- /dev/null +++ b/src/dhcpmon/src/dhcp_mon.h @@ -0,0 +1,54 @@ +/** + * @file dhcp_mon.h + * + * @brief dhcp relay monitor module + * + */ + +#ifndef DHCP_MON_H_ +#define DHCP_MON_H_ + +/** + * @code dhcp_mon_init(window_ssec, max_count); + * + * @brief initializes event base and periodic timer event that continuously collects dhcp relay health status every + * window_sec seconds. It also writes to syslog when dhcp relay has been unhealthy for consecutive max_count + * checks. + * + * @param window_sec time interval between health checks + * @param max_count max count of consecutive unhealthy statuses before reporting to syslog + * + * @return 0 upon success, otherwise upon failure + */ +int dhcp_mon_init(int window_sec, int max_count); + +/** + * @code dhcp_mon_shutdown(); + * + * @brief shuts down libevent loop + * + * @return none + */ +void dhcp_mon_shutdown(); + +/** + * @code dhcp_mon_start(snaplen); + * + * @brief start monitoring DHCP Relay + * + * @param snaplen packet capture length + * + * @return 0 upon success, otherwise upon failure + */ +int dhcp_mon_start(size_t snaplen); + +/** + * @code dhcp_mon_stop(); + * + * @brief stop monitoring DHCP Relay + * + * @return none + */ +void dhcp_mon_stop(); + +#endif /* DHCP_MON_H_ */ diff --git a/src/dhcpmon/src/main.c b/src/dhcpmon/src/main.c new file mode 100644 index 00000000000..9d155393a6e --- /dev/null +++ b/src/dhcpmon/src/main.c @@ -0,0 +1,174 @@ +/** + * @file main.c + * + * @brief: Main entry point for dhcpmon utility. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dhcp_mon.h" +#include "dhcp_devman.h" + +/** dhcpmon_default_snaplen: default snap length of packet being captured */ +static const size_t dhcpmon_default_snaplen = 65535; +/** dhcpmon_default_health_check_window: default value for a time window, during which DHCP DORA packet counts are being + * collected */ +static const uint32_t dhcpmon_default_health_check_window = 12; +/** dhcpmon_default_unhealthy_max_count: default max consecutive unhealthy status reported before reporting an issue + * with DHCP relay */ +static const uint32_t dhcpmon_default_unhealthy_max_count = 10; + +/** + * @code usage(prog); + * + * @brief prints help message about how to use dhcpmon utility + * + * @param prog program name + * + * @return none + */ +static void usage(const char *prog) +{ + printf("Usage: %s -id {-iu }+ [-w ]" + "[-c ] [-s ] [-d]\n", prog); + printf("where\n"); + printf("\tsouth interface: is a vlan interface,\n"); + printf("\tnorth interface: is a TOR-T1 interface,\n"); + printf("\tsnapshot window: during which DHCP counters are gathered and DHCP status is validated (default %d),\n", + dhcpmon_default_health_check_window); + printf("\tunhealthy status count: count of consecutive unhealthy status before writing an alert to syslog " + "(default %d),\n", + dhcpmon_default_unhealthy_max_count); + printf("\tsnap length: snap length of packet capture (default %d),\n", dhcpmon_default_snaplen); + printf("\t-d: daemonize %s.\n", prog); + + exit(EXIT_SUCCESS); +} + +/** + * @code dhcpmon_daemonize(); + * + * @brief make this utility run as a daemon. + * + * @return none + */ +static void dhcpmon_daemonize() +{ + pid_t pid, sid; + pid = fork(); + if (pid < 0) { + syslog(LOG_ALERT, "fork: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + // this is the daemon running now + umask(0); + // Create a new SID for the child process + sid = setsid(); + if (sid < 0) { + syslog(LOG_ALERT, "setsid: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + // Change the current working directory + if ((chdir("/")) < 0) { + syslog(LOG_ALERT, "chdir: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); +} + +/** + * @code main(argc, argv); + * + * @brief main entry point of dhcpmon utility + * + * @return int 0 on success, otherwise on failure + */ +int main(int argc, char **argv) +{ + int rv = EXIT_FAILURE; + int i; + int window_interval = dhcpmon_default_health_check_window; + int max_unhealthy_count = dhcpmon_default_unhealthy_max_count; + size_t snaplen = dhcpmon_default_snaplen; + int make_daemon = 0; + + setlogmask(LOG_UPTO(LOG_INFO)); + openlog(basename(argv[0]), LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON); + + dhcp_devman_init(); + + for (i = 1; i < argc;) { + if ((argv[i] == NULL) || (argv[i][0] != '-')) { + break; + } + switch (argv[i][1]) + { + case 'h': + usage(basename(argv[0])); + break; + case 'i': + if (dhcp_devman_add_intf(argv[i + 1], argv[i][2] == 'u') != 0) { + usage(basename(argv[0])); + } + i += 2; + break; + case 'd': + make_daemon = 1; + i++; + break; + case 's': + snaplen = atoi(argv[i + 1]); + i += 2; + break; + case 'w': + window_interval = atoi(argv[i + 1]); + i += 2; + break; + case 'c': + max_unhealthy_count = atoi(argv[i + 1]); + i += 2; + break; + default: + fprintf(stderr, "%s: %c: Unknown option\n", basename(argv[0]), argv[i][1]); + usage(basename(argv[0])); + } + } + + if (make_daemon) { + dhcpmon_daemonize(); + } + + if ((dhcp_mon_init(window_interval, max_unhealthy_count) == 0) && + (dhcp_mon_start(snaplen) == 0)) { + + rv = EXIT_SUCCESS; + + dhcp_mon_shutdown(); + } + + dhcp_devman_shutdown(); + + closelog(); + + return rv; +} diff --git a/src/dhcpmon/src/subdir.mk b/src/dhcpmon/src/subdir.mk new file mode 100644 index 00000000000..324977aa39f --- /dev/null +++ b/src/dhcpmon/src/subdir.mk @@ -0,0 +1,29 @@ +# Add inputs and outputs from these tool invocations to the build variables +CC := gcc + +C_SRCS += \ +../src/dhcp_device.c \ +../src/dhcp_devman.c \ +../src/dhcp_mon.c \ +../src/main.c + +OBJS += \ +./src/dhcp_device.o \ +./src/dhcp_devman.o \ +./src/dhcp_mon.o \ +./src/main.o + +C_DEPS += \ +./src/dhcp_device.d \ +./src/dhcp_devman.d \ +./src/dhcp_mon.d \ +./src/main.d + + +# Each subdirectory must supply rules for building sources it contributes +src/%.o: ../src/%.c + @echo 'Building file: $<' + @echo 'Invoking: GCC C Compiler' + $(CC) -O3 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' diff --git a/src/libteam/patch/0011-teamd-Disregard-current-state-when-considering-port-.patch b/src/libteam/patch/0011-teamd-Disregard-current-state-when-considering-port-.patch new file mode 100644 index 00000000000..a6564614063 --- /dev/null +++ b/src/libteam/patch/0011-teamd-Disregard-current-state-when-considering-port-.patch @@ -0,0 +1,67 @@ +From 0ca470e5d32979500b0919a4cd3f8293b32c3207 Mon Sep 17 00:00:00 2001 +From: Petr Machata +Date: Wed, 13 Nov 2019 13:26:47 +0000 +Subject: [PATCH] teamd: Disregard current state when considering port + enablement + +On systems where carrier is gained very quickly, there is a race between +teamd and the kernel that sometimes leads to all team slaves being stuck in +enabled=false state. + +When a port is enslaved to a team device, the kernel sends a netlink +message marking the port as enabled. teamd's lb_event_watch_port_added() +calls team_set_port_enabled(false), because link is down at that point. The +kernel responds with a message marking the port as disabled. At this point, +there are two outstanding messages: the initial one marking port as +enabled, and the second one marking it as disabled. teamd has not processed +either of these. + +Next teamd gets the netlink message that sets enabled=true, and updates its +internal cache accordingly. If at this point ethtool link-watch wakes up, +teamd considers (in teamd_port_check_enable()) enabling the port. After +consulting the cache, it concludes the port is already up, and neglects to +do so. Only then does teamd get the netlink message informing it of setting +enabled=false. + +The problem is that the teamd cache is not synchronous with respect to the +kernel state. If the carrier takes a while to come up (as is normally the +case), this is not a problem, because teamd caches up quickly enough. But +this may not always be the case, and particularly on a simulated system, +the carrier is gained almost immediately. + +Fix this by not suppressing the enablement message. + +Signed-off-by: Petr Machata +Signed-off-by: Jiri Pirko +--- + teamd/teamd_per_port.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/teamd/teamd_per_port.c b/teamd/teamd_per_port.c +index a87e809..ae09200 100644 +--- a/teamd/teamd_per_port.c ++++ b/teamd/teamd_per_port.c +@@ -434,18 +434,14 @@ int teamd_port_check_enable(struct teamd_context *ctx, + bool should_enable, bool should_disable) + { + bool new_enabled_state; +- bool curr_enabled_state; + int err; + + if (!teamd_port_present(ctx, tdport)) + return 0; +- err = teamd_port_enabled(ctx, tdport, &curr_enabled_state); +- if (err) +- return err; + +- if (!curr_enabled_state && should_enable) ++ if (should_enable) + new_enabled_state = true; +- else if (curr_enabled_state && should_disable) ++ else if (should_disable) + new_enabled_state = false; + else + return 0; +-- +2.17.1.windows.2 + diff --git a/src/libteam/patch/series b/src/libteam/patch/series index 7be69525d9d..ad24f61cd95 100644 --- a/src/libteam/patch/series +++ b/src/libteam/patch/series @@ -8,3 +8,4 @@ 0008-libteam-Add-warm_reboot-mode.patch 0009-Fix-ifinfo_link_with_port-race-condition-with-newlink.patch 0010-When-read-of-timerfd-returned-0-don-t-consider-this-.patch +0011-teamd-Disregard-current-state-when-considering-port-.patch diff --git a/src/lldpd/patch/0004-lldpctl-put-a-lock-around-some-commands-to-avoid-rac.patch b/src/lldpd/patch/0004-lldpctl-put-a-lock-around-some-commands-to-avoid-rac.patch new file mode 100644 index 00000000000..df7f26131dd --- /dev/null +++ b/src/lldpd/patch/0004-lldpctl-put-a-lock-around-some-commands-to-avoid-rac.patch @@ -0,0 +1,169 @@ +From 46aa45d0fa3e8879ecdca1c156cb2d91194c45e9 Mon Sep 17 00:00:00 2001 +From: Pavel Shirshov +Date: Thu, 12 Dec 2019 13:47:17 -0800 +Subject: [PATCH 1/1] lldpctl: put a lock around some commands to avoid race + conditions + +--- + src/client/client.h | 3 +++ + src/client/commands.c | 58 ++++++++++++++++++++++++++++++++++++++++--- + src/client/conf.c | 4 +-- + 3 files changed, 60 insertions(+), 5 deletions(-) + +diff --git a/src/client/client.h b/src/client/client.h +index e3ee352..6c3e30d 100644 +--- a/src/client/client.h ++++ b/src/client/client.h +@@ -62,6 +62,8 @@ extern void add_history (); + #endif + #undef NEWLINE + ++extern const char *ctlname; ++ + /* commands.c */ + #define NEWLINE "" + struct cmd_node; +@@ -76,6 +78,7 @@ struct cmd_node *commands_new( + struct cmd_env*, void *), + void *); + struct cmd_node* commands_privileged(struct cmd_node *); ++struct cmd_node* commands_lock(struct cmd_node *); + struct cmd_node* commands_hidden(struct cmd_node *); + void commands_free(struct cmd_node *); + const char *cmdenv_arg(struct cmd_env*); +diff --git a/src/client/commands.c b/src/client/commands.c +index beedbf1..58df4a7 100644 +--- a/src/client/commands.c ++++ b/src/client/commands.c +@@ -18,6 +18,9 @@ + #include "client.h" + #include + #include ++#include ++#include ++#include + + /** + * An element of the environment (a key and a value). +@@ -68,6 +71,7 @@ struct cmd_node { + const char *token; /**< Token to enter this cnode */ + const char *doc; /**< Documentation string */ + int privileged; /**< Privileged command? */ ++ int lock; /**< Lock required for execution? */ + int hidden; /**< Hidden command? */ + + /** +@@ -113,6 +117,21 @@ commands_privileged(struct cmd_node *node) + return node; + } + ++/** ++ * Make a node accessible only with a lock. ++ * ++ * @param node node to use lock to execute ++ * @return the modified node ++ * ++ * The node is modified. It is returned to ease chaining. ++ */ ++struct cmd_node* ++commands_lock(struct cmd_node *node) ++{ ++ if (node) node->lock = 1; ++ return node; ++} ++ + /** + * Hide a node from help or completion. + * +@@ -344,6 +363,7 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w, + int n, rc = 0, completion = (word != NULL); + int help = 0; /* Are we asking for help? */ + int complete = 0; /* Are we asking for possible completions? */ ++ int needlock = 0; /* Do we need a lock? */ + struct cmd_env env = { + .elements = TAILQ_HEAD_INITIALIZER(env.elements), + .stack = TAILQ_HEAD_INITIALIZER(env.stack), +@@ -351,6 +371,7 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w, + .argv = argv, + .argp = 0 + }; ++ static int lockfd = -1; + cmdenv_push(&env, root); + if (!completion) + for (n = 0; n < argc; n++) +@@ -388,6 +409,7 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w, + !strcmp(candidate->token, token)) { + /* Exact match */ + best = candidate; ++ needlock = needlock || candidate->lock; + break; + } + if (!best) best = candidate; +@@ -406,6 +428,7 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w, + if (!candidate->token && + CAN_EXECUTE(candidate)) { + best = candidate; ++ needlock = needlock || candidate->lock; + break; + } + } +@@ -421,9 +444,38 @@ _commands_execute(struct lldpctl_conn_t *conn, struct writer *w, + + /* Push and execute */ + cmdenv_push(&env, best); +- if (best->execute && best->execute(conn, w, &env, best->arg) != 1) { +- rc = -1; +- goto end; ++ if (best->execute) { ++ struct sockaddr_un su; ++ if (needlock) { ++ if (lockfd == -1) { ++ log_debug("lldpctl", "reopen %s for locking", ctlname); ++ if ((lockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) { ++ log_warn("lldpctl", "cannot open for lock %s", ctlname); ++ rc = -1; ++ goto end; ++ } ++ su.sun_family = AF_UNIX; ++ strlcpy(su.sun_path, ctlname, sizeof(su.sun_path)); ++ if (connect(lockfd, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) { ++ log_warn("lldpctl", "cannot connect to socket %s", ctlname); ++ rc = -1; ++ close(lockfd); lockfd = -1; ++ goto end; ++ } ++ } ++ if (lockf(lockfd, F_LOCK, 0) == -1) { ++ log_warn("lldpctl", "cannot get lock on %s", ctlname); ++ rc = -1; ++ close(lockfd); lockfd = -1; ++ goto end; ++ } ++ } ++ rc = best->execute(conn, w, &env, best->arg) != 1 ? -1 : rc; ++ if (needlock && lockf(lockfd, F_ULOCK, 0) == -1) { ++ log_warn("lldpctl", "cannot unlock %s", ctlname); ++ close(lockfd); lockfd = -1; ++ } ++ if (rc == -1) goto end; + } + env.argp++; + } +diff --git a/src/client/conf.c b/src/client/conf.c +index 1a14981..ba5743f 100644 +--- a/src/client/conf.c ++++ b/src/client/conf.c +@@ -37,8 +37,8 @@ register_commands_configure(struct cmd_node *root) + "unconfigure", + "Unconfigure system settings", + NULL, NULL, NULL); +- commands_privileged(configure); +- commands_privileged(unconfigure); ++ commands_privileged(commands_lock(configure)); ++ commands_privileged(commands_lock(unconfigure)); + cmd_restrict_ports(configure); + cmd_restrict_ports(unconfigure); + +-- +2.17.1.windows.2 + diff --git a/src/lldpd/patch/0005-Read-all-notifications-in-lldpctl_recv.patch b/src/lldpd/patch/0005-Read-all-notifications-in-lldpctl_recv.patch new file mode 100644 index 00000000000..1c3781da67c --- /dev/null +++ b/src/lldpd/patch/0005-Read-all-notifications-in-lldpctl_recv.patch @@ -0,0 +1,27 @@ +From b8e66b52f40103fd3abea77031c4634742c31860 Mon Sep 17 00:00:00 2001 +From: Pavel Shirshov +Date: Thu, 12 Dec 2019 12:47:42 -0800 +Subject: [PATCH 1/1] Read all notifications in lldpctl_recv + +--- + src/lib/connection.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/lib/connection.c b/src/lib/connection.c +index 591d9e9..88bbc99 100644 +--- a/src/lib/connection.c ++++ b/src/lib/connection.c +@@ -253,8 +253,8 @@ lldpctl_recv(lldpctl_conn_t *conn, const uint8_t *data, size_t length) + memcpy(conn->input_buffer + conn->input_buffer_len, data, length); + conn->input_buffer_len += length; + +- /* Is it a notification? */ +- check_for_notification(conn); ++ /* Read all notifications */ ++ while(!check_for_notification(conn)); + + RESET_ERROR(conn); + +-- +2.17.1.windows.2 + diff --git a/src/lldpd/patch/0006-lib-fix-memory-leak.patch b/src/lldpd/patch/0006-lib-fix-memory-leak.patch new file mode 100644 index 00000000000..765b5fb751e --- /dev/null +++ b/src/lldpd/patch/0006-lib-fix-memory-leak.patch @@ -0,0 +1,24 @@ +From 833653dffb9be40110142af2a7cb4076a0dd24f5 Mon Sep 17 00:00:00 2001 +From: Pavel Shirshov +Date: Thu, 12 Dec 2019 12:48:47 -0800 +Subject: [PATCH 1/1] lib: fix memory leak + +--- + src/lib/connection.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/lib/connection.c b/src/lib/connection.c +index 88bbc99..aa88dad 100644 +--- a/src/lib/connection.c ++++ b/src/lib/connection.c +@@ -114,6 +114,7 @@ lldpctl_new_name(const char *ctlname, lldpctl_send_callback send, lldpctl_recv_c + } + if (!send && !recv) { + if ((data = malloc(sizeof(struct lldpctl_conn_sync_t))) == NULL) { ++ free(conn->ctlname); + free(conn); + return NULL; + } +-- +2.17.1.windows.2 + diff --git a/src/lldpd/patch/0007-lib-fix-memory-leak-when-handling-I-O.patch b/src/lldpd/patch/0007-lib-fix-memory-leak-when-handling-I-O.patch new file mode 100644 index 00000000000..cad8bf2fd48 --- /dev/null +++ b/src/lldpd/patch/0007-lib-fix-memory-leak-when-handling-I-O.patch @@ -0,0 +1,85 @@ +From f6086575e63b5e089814ca116aa637d7588bfcd3 Mon Sep 17 00:00:00 2001 +From: Pavel Shirshov +Date: Thu, 12 Dec 2019 13:52:42 -0800 +Subject: [PATCH 1/1] lib: fix memory leak when handling I/O. + +--- + src/lib/atom.c | 11 ++++++----- + src/lib/atom.h | 9 ++++----- + src/lib/atoms/port.c | 2 +- + 3 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/src/lib/atom.c b/src/lib/atom.c +index 955f434..f81d3bb 100644 +--- a/src/lib/atom.c ++++ b/src/lib/atom.c +@@ -322,10 +322,12 @@ _lldpctl_do_something(lldpctl_conn_t *conn, + return SET_ERROR(conn, LLDPCTL_ERR_SERIALIZATION); + conn->state = state_send; + if (state_data) +- conn->state_data = strdup(state_data); ++ strlcpy(conn->state_data, state_data, sizeof(conn->state_data)); ++ else ++ conn->state_data[0] = 0; + } + if (conn->state == state_send && +- (state_data == NULL || !strcmp(conn->state_data, state_data))) { ++ (state_data == NULL || !strncmp(conn->state_data, state_data, sizeof(conn->state_data)))) { + /* We need to send the currently built message */ + rc = lldpctl_send(conn); + if (rc < 0) +@@ -333,7 +335,7 @@ _lldpctl_do_something(lldpctl_conn_t *conn, + conn->state = state_recv; + } + if (conn->state == state_recv && +- (state_data == NULL || !strcmp(conn->state_data, state_data))) { ++ (state_data == NULL || !strncmp(conn->state_data, state_data, sizeof(conn->state_data)))) { + /* We need to receive the answer */ + while ((rc = ctl_msg_recv_unserialized(&conn->input_buffer, + &conn->input_buffer_len, +@@ -347,8 +349,7 @@ _lldpctl_do_something(lldpctl_conn_t *conn, + return SET_ERROR(conn, LLDPCTL_ERR_SERIALIZATION); + /* rc == 0 */ + conn->state = CONN_STATE_IDLE; +- free(conn->state_data); +- conn->state_data = NULL; ++ conn->state_data[0] = 0; + return 0; + } else + return SET_ERROR(conn, LLDPCTL_ERR_INVALID_STATE); +diff --git a/src/lib/atom.h b/src/lib/atom.h +index 265c0a7..ab7037d 100644 +--- a/src/lib/atom.h ++++ b/src/lib/atom.h +@@ -55,11 +55,10 @@ struct lldpctl_conn_t { + #define CONN_STATE_GET_DEFAULT_PORT_SEND 14 + #define CONN_STATE_GET_DEFAULT_PORT_RECV 15 + int state; /* Current state */ +- char *state_data; /* Data attached to the state. It is used to +- * check that we are using the same data as a +- * previous call until the state machine goes to +- * CONN_STATE_IDLE. */ +- ++ /* Data attached to the state. It is used to check that we are using the ++ * same data as a previous call until the state machine goes to ++ * CONN_STATE_IDLE. */ ++ char state_data[IFNAMSIZ + 64]; + /* Error handling */ + lldpctl_error_t error; /* Last error */ + +diff --git a/src/lib/atoms/port.c b/src/lib/atoms/port.c +index 545155c..d902188 100644 +--- a/src/lib/atoms/port.c ++++ b/src/lib/atoms/port.c +@@ -329,7 +329,7 @@ _lldpctl_atom_set_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key, lldpctl_ato + struct lldpd_hardware *hardware = p->hardware; + struct lldpd_port_set set = {}; + int rc; +- char *canary; ++ char *canary = NULL; + + #ifdef ENABLE_DOT3 + struct _lldpctl_atom_dot3_power_t *dpow; +-- +2.17.1.windows.2 + diff --git a/src/lldpd/patch/series b/src/lldpd/patch/series index 2ca46b57539..43422a802e1 100644 --- a/src/lldpd/patch/series +++ b/src/lldpd/patch/series @@ -1,3 +1,7 @@ # This series applies on GIT commit 396961a038a38675d46f96eaa7b430b2a1f8701b 0001-return-error-when-port-does-not-exist.patch 0002-Let-linux-kernel-to-find-appropriate-nl_pid-automa.patch +0004-lldpctl-put-a-lock-around-some-commands-to-avoid-rac.patch +0005-Read-all-notifications-in-lldpctl_recv.patch +0006-lib-fix-memory-leak.patch +0007-lib-fix-memory-leak-when-handling-I-O.patch diff --git a/src/monit/Makefile b/src/monit/Makefile new file mode 100644 index 00000000000..8c9817e5273 --- /dev/null +++ b/src/monit/Makefile @@ -0,0 +1,33 @@ +.ONESHELL: +SHELL = /bin/bash +.SHELLFLAGS += -e + +MAIN_TARGET = monit_$(MONIT_VERSION)_amd64.deb +DERIVED_TARGETS = monit-dbgsym_$(MONIT_VERSION)_amd64.deb + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # Remove any stale files + rm -rf ./monit + + # Clone monit repo + git clone https://salsa.debian.org/sk-guest/monit.git + pushd ./monit + + # Reset HEAD to the commit of the proper tag + # NOTE: Using "git checkout " here detaches our HEAD, + # which stg doesn't like, so we use this method instead + # NOTE: For some reason, tags in the Debian monit repo are prefixed with "1%" + git reset --hard debian/1\%$(MONIT_VERSION) + + # Apply patches + stg init + stg import -s ../patch/series + + # Build source and Debian packages + dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) + popd + + # Move the newly-built .deb packages to the destination directory + mv $(DERIVED_TARGETS) $* $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/src/monit/patch/0001-used_system_memory_sysdep-Use-MemAvailable-value-if-.patch b/src/monit/patch/0001-used_system_memory_sysdep-Use-MemAvailable-value-if-.patch new file mode 100644 index 00000000000..9c67d153cbb --- /dev/null +++ b/src/monit/patch/0001-used_system_memory_sysdep-Use-MemAvailable-value-if-.patch @@ -0,0 +1,70 @@ +From c392362c9c1d57256b7e8ab7c77926824677fd73 Mon Sep 17 00:00:00 2001 +From: Joe LeVeque +Date: Tue, 19 Nov 2019 01:51:13 +0000 +Subject: [PATCH] [used_system_memory_sysdep] Use 'MemAvailable' value if + available + +--- + src/process/sysdep_LINUX.c | 35 +++++++++++++++++++++++------------ + 1 file changed, 23 insertions(+), 12 deletions(-) + +diff --git a/src/process/sysdep_LINUX.c b/src/process/sysdep_LINUX.c +index 0d18f85..221e785 100644 +--- a/src/process/sysdep_LINUX.c ++++ b/src/process/sysdep_LINUX.c +@@ -335,6 +335,7 @@ int getloadavg_sysdep(double *loadv, int nelem) { + boolean_t used_system_memory_sysdep(SystemInfo_T *si) { + char *ptr; + char buf[2048]; ++ unsigned long mem_available = 0UL; + unsigned long mem_free = 0UL; + unsigned long buffers = 0UL; + unsigned long cached = 0UL; +@@ -343,22 +344,32 @@ boolean_t used_system_memory_sysdep(SystemInfo_T *si) { + unsigned long swap_free = 0UL; + + if (! file_readProc(buf, sizeof(buf), "meminfo", -1, NULL)) { +- LogError("system statistic error -- cannot get real memory free amount\n"); ++ LogError("system statistic error -- cannot read /proc/meminfo\n"); + goto error; + } + +- /* Memory */ +- if (! (ptr = strstr(buf, "MemFree:")) || sscanf(ptr + 8, "%ld", &mem_free) != 1) { +- LogError("system statistic error -- cannot get real memory free amount\n"); +- goto error; ++ /* ++ * Memory ++ * ++ * First, check if the "MemAvailable" value is available on this system. If it is, we will ++ * use it. Otherwise we will attempt to calculate the amount of available memory ourself. ++ */ ++ if ((ptr = strstr(buf, "MemAvailable:")) && sscanf(ptr + 13, "%ld", &mem_available) == 1) { ++ si->total_mem = systeminfo.mem_max - (uint64_t)mem_available * 1024; ++ } else { ++ DEBUG("'MemAvailable' value not available on this system. Attempting to calculate available memory manually...\n"); ++ if (! (ptr = strstr(buf, "MemFree:")) || sscanf(ptr + 8, "%ld", &mem_free) != 1) { ++ LogError("system statistic error -- cannot get real memory free amount\n"); ++ goto error; ++ } ++ if (! (ptr = strstr(buf, "Buffers:")) || sscanf(ptr + 8, "%ld", &buffers) != 1) ++ DEBUG("system statistic error -- cannot get real memory buffers amount\n"); ++ if (! (ptr = strstr(buf, "Cached:")) || sscanf(ptr + 7, "%ld", &cached) != 1) ++ DEBUG("system statistic error -- cannot get real memory cache amount\n"); ++ if (! (ptr = strstr(buf, "SReclaimable:")) || sscanf(ptr + 13, "%ld", &slabreclaimable) != 1) ++ DEBUG("system statistic error -- cannot get slab reclaimable memory amount\n"); ++ si->total_mem = systeminfo.mem_max - (uint64_t)(mem_free + buffers + cached + slabreclaimable) * 1024; + } +- if (! (ptr = strstr(buf, "Buffers:")) || sscanf(ptr + 8, "%ld", &buffers) != 1) +- DEBUG("system statistic error -- cannot get real memory buffers amount\n"); +- if (! (ptr = strstr(buf, "Cached:")) || sscanf(ptr + 7, "%ld", &cached) != 1) +- DEBUG("system statistic error -- cannot get real memory cache amount\n"); +- if (! (ptr = strstr(buf, "SReclaimable:")) || sscanf(ptr + 13, "%ld", &slabreclaimable) != 1) +- DEBUG("system statistic error -- cannot get slab reclaimable memory amount\n"); +- si->total_mem = systeminfo.mem_max - (uint64_t)(mem_free + buffers + cached + slabreclaimable) * 1024; + + /* Swap */ + if (! (ptr = strstr(buf, "SwapTotal:")) || sscanf(ptr + 10, "%ld", &swap_total) != 1) { +-- +2.17.1 + diff --git a/src/monit/patch/series b/src/monit/patch/series new file mode 100644 index 00000000000..15fcdd50c8a --- /dev/null +++ b/src/monit/patch/series @@ -0,0 +1,2 @@ +# This series applies on GIT commit dc9bc1c949125140d967edfc598dfad47eedc552 +0001-used_system_memory_sysdep-Use-MemAvailable-value-if-.patch diff --git a/src/snmpd/patch-5.7.3+dfsg/0004-Disable-SNMPv1.patch b/src/snmpd/patch-5.7.3+dfsg/0004-Disable-SNMPv1.patch deleted file mode 100644 index 6782a18c775..00000000000 --- a/src/snmpd/patch-5.7.3+dfsg/0004-Disable-SNMPv1.patch +++ /dev/null @@ -1,25 +0,0 @@ -From db633987abf1ea093cb1785b3cd37adfdb55e4cc Mon Sep 17 00:00:00 2001 -From: Qi Luo -Date: Mon, 15 Oct 2018 22:30:28 +0000 -Subject: [PATCH] Disable SNMPv1 - -Signed-off-by: Qi Luo ---- - debian/rules | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/debian/rules b/debian/rules -index 9eb8d2d..4c3b5b6 100755 ---- a/debian/rules -+++ b/debian/rules -@@ -42,6 +42,7 @@ endif - override_dh_auto_configure: - dh_auto_configure -- --prefix=/usr --sysconfdir=/etc --mandir=/usr/share/man \ - --with-persistent-directory=/var/lib/snmp \ -+ --disable-snmpv1 \ - --enable-ucd-snmp-compatibility \ - --enable-shared --with-cflags="$(CFLAGS) -DNETSNMP_USE_INLINE" \ - --with-ldflags="$(LDFLAGS)" \ --- -2.18.0 - diff --git a/src/snmpd/patch-5.7.3+dfsg/series b/src/snmpd/patch-5.7.3+dfsg/series index 13b28de693d..a73b4a68453 100644 --- a/src/snmpd/patch-5.7.3+dfsg/series +++ b/src/snmpd/patch-5.7.3+dfsg/series @@ -1,5 +1,4 @@ 0001-SNMP-Stop-spamming-logs-with-statfs-permission-denie.patch 0002-at.c-properly-check-return-status-from-realloc.-Than.patch 0003-CHANGES-BUG-2743-snmpd-crashes-when-receiving-a-GetN.patch -0004-Disable-SNMPv1.patch 0006-From-Jiri-Cervenka-snmpd-Fixed-agentx-crashing-and-or-freezing-on-timeout.patch diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 160e91699e9..5be705d1ead 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -230,7 +230,14 @@ def parse_dpg(dpg, hname): aclintfs = child.find(str(QName(ns, "AclInterfaces"))) acls = {} for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))): - aclname = aclintf.find(str(QName(ns, "InAcl"))).text.upper().replace(" ", "_").replace("-", "_") + if aclintf.find(str(QName(ns, "InAcl"))) is not None: + aclname = aclintf.find(str(QName(ns, "InAcl"))).text.upper().replace(" ", "_").replace("-", "_") + stage = "ingress" + elif aclintf.find(str(QName(ns, "OutAcl"))) is not None: + aclname = aclintf.find(str(QName(ns, "OutAcl"))).text.upper().replace(" ", "_").replace("-", "_") + stage = "egress" + else: + system.exit("Error: 'AclInterface' must contain either an 'InAcl' or 'OutAcl' subelement.") aclattach = aclintf.find(str(QName(ns, "AttachTo"))).text.split(';') acl_intfs = [] is_mirror = False @@ -247,7 +254,7 @@ def parse_dpg(dpg, hname): # to LAG will be applied to all the LAG members internally by SAI/SDK acl_intfs.append(member) elif vlans.has_key(member): - print >> sys.stderr, "Warning: ACL " + aclname + " is attached to a Vlan interface, which is currently not supported" + acl_intfs.append(member) elif port_alias_map.has_key(member): acl_intfs.append(port_alias_map[member]) # Give a warning if trying to attach ACL to a LAG member interface, correct way is to attach ACL to the LAG interface @@ -270,13 +277,14 @@ def parse_dpg(dpg, hname): break if acl_intfs: acls[aclname] = {'policy_desc': aclname, + 'stage': stage, 'ports': acl_intfs} if is_mirror: acls[aclname]['type'] = 'MIRROR' elif is_mirror_v6: acls[aclname]['type'] = 'MIRRORV6' else: - acls[aclname]['type'] = 'L3' + acls[aclname]['type'] = 'L3V6' if 'v6' in aclname.lower() else 'L3' else: # This ACL has no interfaces to attach to -- consider this a control plane ACL try: @@ -294,6 +302,7 @@ def parse_dpg(dpg, hname): else: acls[aclname] = {'policy_desc': aclname, 'type': 'CTRLPLANE', + 'stage': stage, 'services': [aclservice]} except: print >> sys.stderr, "Warning: Ignoring Control Plane ACL %s without type" % aclname diff --git a/src/sonic-config-engine/sonic-cfggen b/src/sonic-config-engine/sonic-cfggen index e1fbd508258..caf2095fee4 100755 --- a/src/sonic-config-engine/sonic-cfggen +++ b/src/sonic-config-engine/sonic-cfggen @@ -187,6 +187,10 @@ def main(): sys.exit(1) deep_update(data, {'PORT': ports}) + for json_file in args.json: + with open(json_file, 'r') as stream: + deep_update(data, FormatConverter.to_deserialized(json.load(stream))) + if args.minigraph != None: minigraph = args.minigraph if platform: @@ -205,10 +209,6 @@ def main(): additional_data = yaml.load(stream) deep_update(data, FormatConverter.to_deserialized(additional_data)) - for json_file in args.json: - with open(json_file, 'r') as stream: - deep_update(data, FormatConverter.to_deserialized(json.load(stream))) - if args.additional_data != None: deep_update(data, json.loads(args.additional_data)) diff --git a/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf b/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf index d285fbfc788..16ea6dda434 100644 --- a/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf +++ b/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf @@ -31,3 +31,16 @@ stdout_logfile=syslog stderr_logfile=syslog +[group:dhcpmon] +programs=dhcpmon-Vlan1000 + +[program:dhcpmon-Vlan1000] +command=/usr/sbin/dhcpmon -id Vlan1000 -iu PortChannel01 -iu PortChannel02 -iu PortChannel03 -iu PortChannel04 +priority=4 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + + + diff --git a/src/sonic-config-engine/tests/sample_output/zebra_quagga.conf b/src/sonic-config-engine/tests/sample_output/zebra_quagga.conf index aa3486b0163..5a3e37857ae 100644 --- a/src/sonic-config-engine/tests/sample_output/zebra_quagga.conf +++ b/src/sonic-config-engine/tests/sample_output/zebra_quagga.conf @@ -25,19 +25,6 @@ link-detect ! set static default route to mgmt gateway as a backup to learned default ip route 0.0.0.0/0 10.0.0.1 200 ! -! Set ip source to loopback for bgp learned routes -route-map RM_SET_SRC permit 10 - set src 10.1.0.32 -! - -route-map RM_SET_SRC6 permit 10 - set src fc00:1::32 -! -ip protocol bgp route-map RM_SET_SRC -! -ipv6 protocol bgp route-map RM_SET_SRC6 -! -! log syslog informational log facility local4 ! diff --git a/src/sonic-config-engine/tests/t0-sample-graph.xml b/src/sonic-config-engine/tests/t0-sample-graph.xml index 0c641107da0..47985f870e5 100644 --- a/src/sonic-config-engine/tests/t0-sample-graph.xml +++ b/src/sonic-config-engine/tests/t0-sample-graph.xml @@ -305,7 +305,12 @@ PortChannel01;PortChannel02;PortChannel03;PortChannel04 - DataAcl + DataAclIngress + DataPlane + + + PortChannel01;PortChannel02 + DataAclEgress DataPlane diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index c9d122aa030..15691d98ff7 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -84,13 +84,14 @@ def test_minigraph_acl(self): self.assertEqual(output.strip(), "Warning: Ignoring Control Plane ACL NTP_ACL without type\n" "Warning: ignore interface 'fortyGigE0/2' as it is not in the port_config.ini\n" "Warning: ignore interface 'fortyGigE0/2' in DEVICE_NEIGHBOR as it is not in the port_config.ini\n" - "{'DATAACL': {'type': 'L3', 'policy_desc': 'DATAACL', 'ports': ['PortChannel01', 'PortChannel02', 'PortChannel03', 'PortChannel04']}, " - "'NTP_ACL': {'services': ['NTP'], 'type': 'CTRLPLANE', 'policy_desc': 'NTP_ACL'}, " - "'EVERFLOW': {'type': 'MIRROR', 'policy_desc': 'EVERFLOW', 'ports': ['PortChannel01', 'PortChannel02', 'PortChannel03', 'PortChannel04', 'Ethernet4']}, " - "'ROUTER_PROTECT': {'services': ['SSH', 'SNMP'], 'type': 'CTRLPLANE', 'policy_desc': 'ROUTER_PROTECT'}, " - "'SNMP_ACL': {'services': ['SNMP'], 'type': 'CTRLPLANE', 'policy_desc': 'SNMP_ACL'}, " - "'SSH_ACL': {'services': ['SSH'], 'type': 'CTRLPLANE', 'policy_desc': 'SSH_ACL'}, " - "'EVERFLOWV6': {'type': 'MIRRORV6', 'policy_desc': 'EVERFLOWV6', 'ports': ['PortChannel01', 'PortChannel02', 'PortChannel03', 'PortChannel04', 'Ethernet4']}}") + "{'NTP_ACL': {'services': ['NTP'], 'type': 'CTRLPLANE', 'policy_desc': 'NTP_ACL', 'stage': 'ingress'}, " + "'EVERFLOW': {'stage': 'ingress', 'type': 'MIRROR', 'ports': ['PortChannel01', 'PortChannel02', 'PortChannel03', 'PortChannel04', 'Ethernet4'], 'policy_desc': 'EVERFLOW'}, " + "'ROUTER_PROTECT': {'services': ['SSH', 'SNMP'], 'type': 'CTRLPLANE', 'policy_desc': 'ROUTER_PROTECT', 'stage': 'ingress'}, " + "'DATAACLINGRESS': {'stage': 'ingress', 'type': 'L3', 'ports': ['PortChannel01', 'PortChannel02', 'PortChannel03', 'PortChannel04'], 'policy_desc': 'DATAACLINGRESS'}, " + "'SNMP_ACL': {'services': ['SNMP'], 'type': 'CTRLPLANE', 'policy_desc': 'SNMP_ACL', 'stage': 'ingress'}, " + "'SSH_ACL': {'services': ['SSH'], 'type': 'CTRLPLANE', 'policy_desc': 'SSH_ACL', 'stage': 'ingress'}, " + "'DATAACLEGRESS': {'stage': 'egress', 'type': 'L3', 'ports': ['PortChannel01', 'PortChannel02'], 'policy_desc': 'DATAACLEGRESS'}, " + "'EVERFLOWV6': {'stage': 'ingress', 'type': 'MIRRORV6', 'ports': ['PortChannel01', 'PortChannel02', 'PortChannel03', 'PortChannel04', 'Ethernet4'], 'policy_desc': 'EVERFLOWV6'}}") # everflow portion is not used # def test_minigraph_everflow(self): diff --git a/src/sonic-quagga b/src/sonic-quagga index 904a3501077..7101eeda1a1 160000 --- a/src/sonic-quagga +++ b/src/sonic-quagga @@ -1 +1 @@ -Subproject commit 904a350107793d44be7167500fcec9087ca3243b +Subproject commit 7101eeda1a1ccef2e951e4bea5a2f15d9a43e3b5 diff --git a/src/sonic-sairedis b/src/sonic-sairedis index 4b11836f26d..5065d7858eb 160000 --- a/src/sonic-sairedis +++ b/src/sonic-sairedis @@ -1 +1 @@ -Subproject commit 4b11836f26d3e5d112a9db07f10fc92912bfdf9b +Subproject commit 5065d7858eb28154e553a8276f349a965d6bf93b diff --git a/src/sonic-snmpagent b/src/sonic-snmpagent index 873011c6541..9258d6d9c80 160000 --- a/src/sonic-snmpagent +++ b/src/sonic-snmpagent @@ -1 +1 @@ -Subproject commit 873011c6541200c9e522eaf51a32b57d745cd337 +Subproject commit 9258d6d9c80445523c6b01620a39073b17263002 diff --git a/src/sonic-swss b/src/sonic-swss index 8ef513c88d3..c3be00bb0fa 160000 --- a/src/sonic-swss +++ b/src/sonic-swss @@ -1 +1 @@ -Subproject commit 8ef513c88d3964d2268496d21b8f633a742e356d +Subproject commit c3be00bb0faa070e1d5fab7aed75136443aeee22 diff --git a/src/sonic-utilities b/src/sonic-utilities index ae274e51c49..8c21fc151d4 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit ae274e51c49f18d1ac34b7181cdf569f2fbe8e90 +Subproject commit 8c21fc151d4dc639dd242f15f3d8f3557e25a06d diff --git a/src/telemetry/Makefile b/src/telemetry/Makefile index 91a822d4f93..faf334db0eb 100644 --- a/src/telemetry/Makefile +++ b/src/telemetry/Makefile @@ -2,9 +2,11 @@ export GOPATH=/tmp/go INSTALL := /usr/bin/install -all: sonic-telemetry +all: telemetry -sonic-telemetry: +telemetry: + mkdir -p ${GOPATH}/src/github.com/Azure/ + cp -a sonic-telemetry ${GOPATH}/src/github.com/Azure/ /usr/local/go/bin/go get -v github.com/Azure/sonic-telemetry/telemetry /usr/local/go/bin/go get -v github.com/Azure/sonic-telemetry/dialout/dialout_client_cli diff --git a/src/telemetry/sonic-telemetry b/src/telemetry/sonic-telemetry new file mode 160000 index 00000000000..d8e5adf8cb9 --- /dev/null +++ b/src/telemetry/sonic-telemetry @@ -0,0 +1 @@ +Subproject commit d8e5adf8cb9f810624f61daf6d343dfe8b3fa4b0