From fb89696e5d3457422cb539d822769ee8acacd618 Mon Sep 17 00:00:00 2001 From: "simon.ji" Date: Mon, 26 Mar 2018 02:44:41 -0700 Subject: [PATCH 1/3] Upgrade SAI to v1.2.4 --- platform/nephos/sai.mk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/nephos/sai.mk b/platform/nephos/sai.mk index ca756f392351..7c898bbada6b 100644 --- a/platform/nephos/sai.mk +++ b/platform/nephos/sai.mk @@ -1,9 +1,9 @@ -NEPHOS_SAI = libsainps_2.0.3_amd64.deb -$(NEPHOS_SAI)_URL = "https://github.com/NephosInc/SONiC/raw/master/sai/libsainps_2.0.3_amd64.deb" +NEPHOS_SAI = libsainps_2.0.4_amd64.deb +$(NEPHOS_SAI)_URL = "https://github.com/NephosInc/SONiC/raw/master/sai/libsainps_2.0.4_amd64.deb" -NEPHOS_SAI_DEV = libsainps-dev_2.0.3_sai_1.2.3_amd64.deb +NEPHOS_SAI_DEV = libsainps-dev_2.0.4_sai_1.2.4_amd64.deb $(eval $(call add_derived_package,$(NEPHOS_SAI),$(NEPHOS_SAI_DEV))) -$(NEPHOS_SAI_DEV)_URL = "https://github.com/NephosInc/SONiC/raw/master/sai/libsainps-dev_2.0.3_sai_1.2.3_amd64.deb" +$(NEPHOS_SAI_DEV)_URL = "https://github.com/NephosInc/SONiC/raw/master/sai/libsainps-dev_2.0.4_sai_1.2.4_amd64.deb" SONIC_ONLINE_DEBS += $(NEPHOS_SAI) $(NEPHOS_SAI_DEV) $(NEPHOS_SAI_DEV)_DEPENDS += $(NEPHOS_SAI) From bd14591be1ad9339f50537b0846a8592abc7640e Mon Sep 17 00:00:00 2001 From: "simon.ji" Date: Tue, 27 Mar 2018 18:51:17 -0700 Subject: [PATCH 2/3] Add a new supported device accton as7116 --- .../Accton-AS7116-54X/port_config.ini | 58 + .../Accton-AS7116-54X/port_config_as7116.ini | 55 + .../Accton-AS7116-54X/sai.profile | 2 + .../installer.conf | 3 + .../led_proc_init.nps | 20 + .../x86_64-accton_as7116_54x-r0/minigraph.xml | 1074 +++++++++++++ .../plugins/eeprom.py | 21 + .../plugins/sfputil.py | 155 ++ platform/nephos/one-image.mk | 3 +- platform/nephos/rules.mk | 1 + .../sonic-platform-modules-accton/LICENSE | 16 + .../sonic-platform-modules-accton/README.md | 1 + .../as7116-54x/classes/__init__.py | 0 .../as7116-54x/classes/fanutil.py | 0 .../as7116-54x/classes/thermalutil.py | 0 .../as7116-54x/modules/Makefile | 2 + .../modules/x86-64-accton-as7116-54x-cpld.c | 242 +++ .../modules/x86-64-accton-as7116-54x-fan.c | 494 ++++++ .../modules/x86-64-accton-as7116-54x-led.c | 448 ++++++ .../modules/x86-64-accton-as7116-54x-psu.c | 349 +++++ .../modules/x86-64-accton-as7116-54x-sfp.c | 1384 +++++++++++++++++ .../service/as7116-platform-init.service | 13 + .../as7116-54x/setup.py | 15 + .../as7116-54x/utils/README | 60 + .../as7116-54x/utils/accton_as7116_util.py | 518 ++++++ .../debian/changelog | 6 + .../debian/compat | 1 + .../debian/control | 11 + .../debian/rules | 86 + 29 files changed, 5037 insertions(+), 1 deletion(-) create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/port_config.ini create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/port_config_as7116.ini create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/sai.profile create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/installer.conf create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/led_proc_init.nps create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/minigraph.xml create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/plugins/eeprom.py create mode 100644 device/accton/x86_64-accton_as7116_54x-r0/plugins/sfputil.py create mode 100644 platform/nephos/sonic-platform-modules-accton/LICENSE create mode 100644 platform/nephos/sonic-platform-modules-accton/README.md create mode 100644 platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/__init__.py create mode 100644 platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/fanutil.py create mode 100644 platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/thermalutil.py create mode 100644 platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/Makefile create mode 100644 platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-cpld.c create mode 100644 platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-fan.c create mode 100644 platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-led.c create mode 100644 platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-psu.c create mode 100644 platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-sfp.c create mode 100755 platform/nephos/sonic-platform-modules-accton/as7116-54x/service/as7116-platform-init.service create mode 100644 platform/nephos/sonic-platform-modules-accton/as7116-54x/setup.py create mode 100755 platform/nephos/sonic-platform-modules-accton/as7116-54x/utils/README create mode 100755 platform/nephos/sonic-platform-modules-accton/as7116-54x/utils/accton_as7116_util.py create mode 100755 platform/nephos/sonic-platform-modules-accton/debian/changelog create mode 100644 platform/nephos/sonic-platform-modules-accton/debian/compat create mode 100755 platform/nephos/sonic-platform-modules-accton/debian/control create mode 100755 platform/nephos/sonic-platform-modules-accton/debian/rules diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/port_config.ini b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/port_config.ini new file mode 100644 index 000000000000..6e5276fc726b --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/port_config.ini @@ -0,0 +1,58 @@ +# name lanes alias index +Ethernet0 8 Ethernet1/1 0 +Ethernet1 9 Ethernet2/1 1 +Ethernet2 10 Ethernet3/1 2 +Ethernet3 11 Ethernet4/1 3 +Ethernet4 12 Ethernet5/1 4 +Ethernet5 13 Ethernet6/1 5 +Ethernet6 14 Ethernet7/1 6 +Ethernet7 15 Ethernet8/1 7 +Ethernet8 16 Ethernet9/1 8 +Ethernet9 17 Ethernet10/1 9 +Ethernet10 18 Ethernet11/1 10 +Ethernet11 19 Ethernet12/1 11 +Ethernet12 20 Ethernet13/1 12 +Ethernet13 21 Ethernet14/1 13 +Ethernet14 22 Ethernet15/1 14 +Ethernet15 23 Ethernet16/1 15 +Ethernet16 32 Ethernet17/1 16 +Ethernet17 33 Ethernet18/1 17 +Ethernet18 34 Ethernet19/1 18 +Ethernet19 35 Ethernet20/1 19 +Ethernet20 40 Ethernet21/1 20 +Ethernet21 41 Ethernet22/1 21 +Ethernet22 42 Ethernet23/1 22 +Ethernet23 43 Ethernet24/1 23 +Ethernet24 48 Ethernet25/1 24 +Ethernet25 49 Ethernet26/1 25 +Ethernet26 50 Ethernet27/1 26 +Ethernet27 51 Ethernet28/1 27 +Ethernet28 56 Ethernet29/1 28 +Ethernet29 57 Ethernet30/1 29 +Ethernet30 58 Ethernet31/1 30 +Ethernet31 59 Ethernet32/1 31 +Ethernet32 64 Ethernet33/1 32 +Ethernet33 65 Ethernet34/1 33 +Ethernet34 66 Ethernet35/1 34 +Ethernet35 67 Ethernet36/1 35 +Ethernet36 68 Ethernet37/1 36 +Ethernet37 69 Ethernet38/1 37 +Ethernet38 70 Ethernet39/1 38 +Ethernet39 71 Ethernet40/1 39 +Ethernet40 72 Ethernet41/1 40 +Ethernet41 73 Ethernet42/1 41 +Ethernet42 74 Ethernet43/1 42 +Ethernet43 75 Ethernet44/1 43 +Ethernet44 76 Ethernet45/1 44 +Ethernet45 77 Ethernet46/1 45 +Ethernet46 78 Ethernet47/1 46 +Ethernet47 79 Ethernet48/1 47 +Ethernet48 80 Ethernet49/1 48 +Ethernet49 81 Ethernet50/1 49 +Ethernet50 82 Ethernet51/1 50 +Ethernet51 83 Ethernet52/1 51 +Ethernet52 84,85,86,87 Ethernet53/1 52 +Ethernet53 104,105,106,107 Ethernet54/1 53 +Ethernet54 108,109,110,111 Ethernet55/1 54 +Ethernet55 112,113,114,115 Ethernet56/1 55 +Ethernet56 116,117,118,119 Ethernet57/1 56 diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/port_config_as7116.ini b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/port_config_as7116.ini new file mode 100644 index 000000000000..0c124743d9ec --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/port_config_as7116.ini @@ -0,0 +1,55 @@ +# name lanes alias index +Ethernet0 8 Ethernet1/1 0 +Ethernet1 9 Ethernet2/1 1 +Ethernet2 10 Ethernet3/1 2 +Ethernet3 11 Ethernet4/1 3 +Ethernet4 12 Ethernet5/1 4 +Ethernet5 13 Ethernet6/1 5 +Ethernet6 14 Ethernet7/1 6 +Ethernet7 15 Ethernet8/1 7 +Ethernet8 16 Ethernet9/1 8 +Ethernet9 17 Ethernet10/1 9 +Ethernet10 18 Ethernet11/1 10 +Ethernet11 19 Ethernet12/1 11 +Ethernet12 20 Ethernet13/1 12 +Ethernet13 21 Ethernet14/1 13 +Ethernet14 22 Ethernet15/1 14 +Ethernet15 23 Ethernet16/1 15 +Ethernet16 32 Ethernet17/1 16 +Ethernet17 33 Ethernet18/1 17 +Ethernet18 34 Ethernet19/1 18 +Ethernet19 35 Ethernet20/1 19 +Ethernet20 40 Ethernet21/1 20 +Ethernet21 41 Ethernet22/1 21 +Ethernet22 42 Ethernet23/1 22 +Ethernet23 43 Ethernet24/1 23 +Ethernet24 48 Ethernet25/1 24 +Ethernet25 49 Ethernet26/1 25 +Ethernet26 50 Ethernet27/1 26 +Ethernet27 51 Ethernet28/1 27 +Ethernet28 56 Ethernet29/1 28 +Ethernet29 57 Ethernet30/1 29 +Ethernet30 58 Ethernet31/1 30 +Ethernet31 59 Ethernet32/1 31 +Ethernet32 64 Ethernet33/1 32 +Ethernet33 65 Ethernet34/1 33 +Ethernet34 66 Ethernet35/1 34 +Ethernet35 67 Ethernet36/1 35 +Ethernet36 68 Ethernet37/1 36 +Ethernet37 69 Ethernet38/1 37 +Ethernet38 70 Ethernet39/1 38 +Ethernet39 71 Ethernet40/1 39 +Ethernet40 72 Ethernet41/1 40 +Ethernet41 73 Ethernet42/1 41 +Ethernet42 74 Ethernet43/1 42 +Ethernet43 75 Ethernet44/1 43 +Ethernet44 76 Ethernet45/1 44 +Ethernet45 77 Ethernet46/1 45 +Ethernet46 78 Ethernet47/1 46 +Ethernet47 79 Ethernet48/1 47 +Ethernet48 80,81,82,83 Ethernet49/1 48 +Ethernet49 84,85,86,87 Ethernet50/1 49 +Ethernet50 104,105,106,107 Ethernet51/1 50 +Ethernet51 108,109,110,111 Ethernet52/1 51 +Ethernet52 112,113,114,115 Ethernet53/1 52 +Ethernet53 116,117,118,119 Ethernet54/1 56 \ No newline at end of file diff --git a/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/sai.profile b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/sai.profile new file mode 100644 index 000000000000..d43b2a33f42d --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/Accton-AS7116-54X/sai.profile @@ -0,0 +1,2 @@ +SAI_INIT_CONFIG_FILE=/etc/nps/tau-as7116-4806.cfg +SAI_DSH_CONFIG_FILE=/etc/nps/tau-as7116-4806.dsh diff --git a/device/accton/x86_64-accton_as7116_54x-r0/installer.conf b/device/accton/x86_64-accton_as7116_54x-r0/installer.conf new file mode 100644 index 000000000000..925a32fc0c3a --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/installer.conf @@ -0,0 +1,3 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 diff --git a/device/accton/x86_64-accton_as7116_54x-r0/led_proc_init.nps b/device/accton/x86_64-accton_as7116_54x-r0/led_proc_init.nps new file mode 100644 index 000000000000..9a97d94c0b0e --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/led_proc_init.nps @@ -0,0 +1,20 @@ +#This configuration file is for customer init value feature. Please refer to mtk_cfg.h/mtk_cfg.c for detail. +#1. The lines beginning with # are comment lines. The lines beginning with number are the setting lines. +#2. There are five parameters which can be set. +# 1) the first is unit. +# 2) the second is NPS_CFG_TYPE_XXX. Refer to NPS_CFG_TYPE_T. +# 3) the 3-5 are {param0, param1, value} pairs. Refer to NPS_CFG_VALUE_T. Support HEX format. +# 4) the (unit, NPS_CFG_TYPE_XXX, param0, param1) group is the key to get the correspingding value. +# There should be no same (unit, NPS_CFG_TYPE_XXX, param0, param1) group. +#3. User must follow correct format to apply the setting. Please refer to below commentted example(#0 NPS_CFG_TYPE_L2_ADDR_MODE 0 0 1); +#4. Usage under the linux shell: +# 1) ./image-path/image-name -c cfg-path/NPS_Ari_EVB_24.cfg : mamually specify directory path if they are not in current work dirctory. +# 2) ./image-name -c NPS_Ari_EVB_24.cfg : the image and the NPS_Ari_EVB_24.cfg are in the current work directory. + +#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 3 +0 NPS_CFG_TYPE_USER_BUF_CTRL 0 0 1 +0 NPS_CFG_TYPE_CPI_PORT_MODE 129 0 1 +0 NPS_CFG_TYPE_CPI_PORT_MODE 130 0 1 diff --git a/device/accton/x86_64-accton_as7116_54x-r0/minigraph.xml b/device/accton/x86_64-accton_as7116_54x-r0/minigraph.xml new file mode 100644 index 000000000000..d538a8cbd709 --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/minigraph.xml @@ -0,0 +1,1074 @@ + + + + + + ARISTA01T0 + 10.1.1.33 + switch1 + 10.0.0.32 + 1 + 180 + 60 + + + switch1 + 10.0.0.0 + ARISTA01T2 + 10.0.0.1 + 1 + 180 + 60 + + + ARISTA02T0 + 10.0.0.35 + switch1 + 10.0.0.34 + 1 + 180 + 60 + + + switch1 + 10.0.0.2 + ARISTA02T2 + 10.0.0.3 + 1 + 180 + 60 + + + ARISTA03T0 + 10.0.0.37 + switch1 + 10.0.0.36 + 1 + 180 + 60 + + + switch1 + 10.0.0.4 + ARISTA03T2 + 10.0.0.5 + 1 + 180 + 60 + + + ARISTA04T0 + 10.0.0.39 + switch1 + 10.0.0.38 + 1 + 180 + 60 + + + switch1 + 10.0.0.6 + ARISTA04T2 + 10.0.0.7 + 1 + 180 + 60 + + + ARISTA05T0 + 10.0.0.41 + switch1 + 10.0.0.40 + 1 + 180 + 60 + + + switch1 + 10.0.0.8 + ARISTA05T2 + 10.0.0.9 + 1 + 180 + 60 + + + ARISTA06T0 + 10.0.0.43 + switch1 + 10.0.0.42 + 1 + 180 + 60 + + + switch1 + 10.0.0.10 + ARISTA06T2 + 10.0.0.11 + 1 + 180 + 60 + + + ARISTA07T0 + 10.0.0.45 + switch1 + 10.0.0.44 + 1 + 180 + 60 + + + switch1 + 10.0.0.12 + ARISTA07T2 + 10.0.0.13 + 1 + 180 + 60 + + + ARISTA08T0 + 10.0.0.47 + switch1 + 10.0.0.46 + 1 + 180 + 60 + + + switch1 + 10.0.0.14 + ARISTA08T2 + 10.0.0.15 + 1 + 180 + 60 + + + ARISTA09T0 + 10.0.0.49 + switch1 + 10.0.0.48 + 1 + 180 + 60 + + + switch1 + 10.0.0.16 + ARISTA09T2 + 10.0.0.17 + 1 + 180 + 60 + + + ARISTA10T0 + 10.0.0.51 + switch1 + 10.0.0.50 + 1 + 180 + 60 + + + switch1 + 10.0.0.18 + ARISTA10T2 + 10.0.0.19 + 1 + 180 + 60 + + + ARISTA11T0 + 10.0.0.53 + switch1 + 10.0.0.52 + 1 + 180 + 60 + + + switch1 + 10.0.0.20 + ARISTA11T2 + 10.0.0.21 + 1 + 180 + 60 + + + ARISTA12T0 + 10.0.0.55 + switch1 + 10.0.0.54 + 1 + 180 + 60 + + + switch1 + 10.0.0.22 + ARISTA12T2 + 10.0.0.23 + 1 + 180 + 60 + + + ARISTA13T0 + 10.0.0.57 + switch1 + 10.0.0.56 + 1 + 180 + 60 + + + switch1 + 10.0.0.24 + ARISTA13T2 + 10.0.0.25 + 1 + 180 + 60 + + + ARISTA14T0 + 10.0.0.59 + switch1 + 10.0.0.58 + 1 + 180 + 60 + + + switch1 + 10.0.0.26 + ARISTA14T2 + 10.0.0.27 + 1 + 180 + 60 + + + ARISTA15T0 + 10.0.0.61 + switch1 + 10.0.0.60 + 1 + 180 + 60 + + + switch1 + 10.0.0.28 + ARISTA15T2 + 10.0.0.29 + 1 + 180 + 60 + + + ARISTA16T0 + 10.0.0.63 + switch1 + 10.0.0.62 + 1 + 180 + 60 + + + switch1 + 10.0.0.30 + ARISTA16T2 + 10.0.0.31 + 1 + 180 + 60 + + + + + 65100 + switch1 + + +
10.0.0.33
+ + +
+ +
10.0.0.1
+ + +
+ +
10.0.0.35
+ + +
+ +
10.0.0.3
+ + +
+ +
10.0.0.37
+ + +
+ +
10.0.0.5
+ + +
+ +
10.0.0.39
+ + +
+ +
10.0.0.7
+ + +
+ +
10.0.0.41
+ + +
+ +
10.0.0.9
+ + +
+ +
10.0.0.43
+ + +
+ +
10.0.0.11
+ + +
+ +
10.0.0.45
+ + +
+ +
10.0.0.13
+ + +
+ +
10.0.0.47
+ + +
+ +
10.0.0.15
+ + +
+ +
10.0.0.49
+ + +
+ +
10.0.0.17
+ + +
+ +
10.0.0.51
+ + +
+ +
10.0.0.19
+ + +
+ +
10.0.0.53
+ + +
+ +
10.0.0.21
+ + +
+ +
10.0.0.55
+ + +
+ +
10.0.0.23
+ + +
+ +
10.0.0.57
+ + +
+ +
10.0.0.25
+ + +
+ +
10.0.0.59
+ + +
+ +
10.0.0.27
+ + +
+ +
10.0.0.61
+ + +
+ +
10.0.0.29
+ + +
+ +
10.0.0.63
+ + +
+ +
10.0.0.31
+ + +
+
+ +
+ + 64001 + ARISTA01T0 + + + + 65200 + ARISTA01T2 + + + + 64002 + ARISTA02T0 + + + + 65200 + ARISTA02T2 + + + + 64003 + ARISTA03T0 + + + + 65200 + ARISTA03T2 + + + + 64004 + ARISTA04T0 + + + + 65200 + ARISTA04T2 + + + + 64005 + ARISTA05T0 + + + + 65200 + ARISTA05T2 + + + + 64006 + ARISTA06T0 + + + + 65200 + ARISTA06T2 + + + + 64007 + ARISTA07T0 + + + + 65200 + ARISTA07T2 + + + + 64008 + ARISTA08T0 + + + + 65200 + ARISTA08T2 + + + + 64009 + ARISTA09T0 + + + + 65200 + ARISTA09T2 + + + + 64010 + ARISTA10T0 + + + + 65200 + ARISTA10T2 + + + + 64011 + ARISTA11T0 + + + + 65200 + ARISTA11T2 + + + + 64012 + ARISTA12T0 + + + + 65200 + ARISTA12T2 + + + + 64013 + ARISTA13T0 + + + + 65200 + ARISTA13T2 + + + + 64014 + ARISTA14T0 + + + + 65200 + ARISTA14T2 + + + + 64015 + ARISTA15T0 + + + + 65200 + ARISTA15T2 + + + + 64016 + ARISTA16T0 + + + + 65200 + ARISTA16T2 + + +
+
+ + + + + + HostIP + Loopback0 + + 10.1.0.32/32 + + 10.1.0.32/32 + + + + + + + + switch1 + + + + + + Ethernet0 + 10.0.0.0/31 + + + + Ethernet4 + 10.0.0.2/31 + + + + Ethernet8 + 10.0.0.4/31 + + + + Ethernet12 + 10.0.0.6/31 + + + + Ethernet16 + 10.0.0.8/31 + + + + Ethernet20 + 10.0.0.10/31 + + + + Ethernet24 + 10.0.0.12/31 + + + + Ethernet28 + 10.0.0.14/31 + + + + Ethernet32 + 10.0.0.16/31 + + + + Ethernet36 + 10.0.0.18/31 + + + + Ethernet40 + 10.0.0.20/31 + + + + Ethernet44 + 10.0.0.22/31 + + + + Ethernet48 + 10.0.0.24/31 + + + + Ethernet52 + 10.0.0.26/31 + + + + Ethernet56 + 10.0.0.28/31 + + + + Ethernet60 + 10.0.0.30/31 + + + + Ethernet64 + 10.0.0.32/31 + + + + Ethernet68 + 10.0.0.34/31 + + + + Ethernet72 + 10.0.0.36/31 + + + + Ethernet76 + 10.0.0.38/31 + + + + Ethernet80 + 10.0.0.40/31 + + + + Ethernet84 + 10.0.0.42/31 + + + + Ethernet88 + 10.0.0.44/31 + + + + Ethernet92 + 10.0.0.46/31 + + + + Ethernet96 + 10.0.0.48/31 + + + + Ethernet100 + 10.0.0.50/31 + + + + Ethernet104 + 10.0.0.52/31 + + + + Ethernet108 + 10.0.0.54/31 + + + + Ethernet112 + 10.0.0.56/31 + + + + Ethernet116 + 10.0.0.58/31 + + + + Ethernet120 + 10.0.0.60/31 + + + + Ethernet124 + 10.0.0.62/31 + + + + + + + + + + + + DeviceInterfaceLink + switch1 + Ethernet0 + ARISTA01T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet4 + ARISTA02T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet8 + ARISTA03T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet12 + ARISTA04T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet16 + ARISTA05T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet20 + ARISTA06T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet24 + ARISTA07T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet28 + ARISTA08T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet32 + ARISTA09T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet36 + ARISTA10T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet40 + ARISTA11T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet44 + ARISTA12T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet48 + ARISTA13T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet52 + ARISTA14T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet56 + ARISTA15T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet60 + ARISTA16T2 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet64 + ARISTA01T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet68 + ARISTA02T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet72 + ARISTA03T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet76 + ARISTA04T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet80 + ARISTA05T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet84 + ARISTA06T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet88 + ARISTA07T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet92 + ARISTA08T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet96 + ARISTA09T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet100 + ARISTA10T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet104 + ARISTA11T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet108 + ARISTA12T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet112 + ARISTA13T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet116 + ARISTA14T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet120 + ARISTA15T0 + Ethernet1 + + + DeviceInterfaceLink + switch1 + Ethernet124 + ARISTA16T0 + Ethernet1 + + + + + switch1 + Accton-AS7116-54X + + + + + + + switch1 + + + DhcpResources + + + + + NtpResources + + 0.debian.pool.ntp.org;1.debian.pool.ntp.org;2.debian.pool.ntp.org;3.debian.pool.ntp.org + + + SyslogResources + + + + + + + + + switch1 + Accton-AS7116-54X +
diff --git a/device/accton/x86_64-accton_as7116_54x-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as7116_54x-r0/plugins/eeprom.py new file mode 100644 index 000000000000..1e7d1046d93d --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-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/0-0056/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/accton/x86_64-accton_as7116_54x-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as7116_54x-r0/plugins/sfputil.py new file mode 100644 index 000000000000..974bedc4db19 --- /dev/null +++ b/device/accton/x86_64-accton_as7116_54x-r0/plugins/sfputil.py @@ -0,0 +1,155 @@ +#!/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 = 0 + _port_end = 53 + _qsfp_port_start = 48 + _ports_in_block = 54 + + _port_to_eeprom_mapping = {} + _port_to_i2c_mapping = { + 0 : 37, + 1 : 38, + 2 : 39, + 3 : 40, + 4 : 41, + 5 : 42, + 6 : 43, + 7 : 44, + 8 : 45, + 9 : 46, + 10 : 47, + 11 : 48, + 12 : 49, + 13 : 50, + 14 : 51, + 15 : 52, + 16 : 53, + 17 : 54, + 18 : 55, + 19 : 56, + 20 : 57, + 21 : 58, + 22 : 59, + 23 : 60, + 24 : 61, + 25 : 62, + 26 : 63, + 27 : 64, + 28 : 65, + 29 : 66, + 30 : 67, + 31 : 68, + 32 : 69, + 33 : 70, + 34 : 71, + 35 : 72, + 36 : 73, + 37 : 74, + 38 : 75, + 39 : 76, + 40 : 77, + 41 : 78, + 42 : 79, + 43 : 80, + 44 : 81, + 45 : 82, + 46 : 83, + 47 : 84, + 48 : 21, + 49 : 22, + 50 : 23, + 51 : 24, + 52 : 25, + 53 : 26, + } + + _qsfp_ports = range(_qsfp_port_start, _ports_in_block + 1) + + 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]) + if x == 53: + self._port_to_eeprom_mapping[56] = port_eeprom_path # ugly!!!! + else: + self._port_to_eeprom_mapping[x] = port_eeprom_path + + 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): + 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" + 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 + + reg_value = reg_file.readline().rstrip() + if reg_value == '1': + return True + + return False + + @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/platform/nephos/one-image.mk b/platform/nephos/one-image.mk index 8e9406dca89c..aa5cc1ff4324 100644 --- a/platform/nephos/one-image.mk +++ b/platform/nephos/one-image.mk @@ -5,6 +5,7 @@ $(SONIC_ONE_IMAGE)_MACHINE = nephos $(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie $(SONIC_ONE_IMAGE)_INSTALLS += $(NEPHOS_NPS_KERNEL) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(INGRASYS_S9130_32X_PLATFORM_MODULE) \ - $(INGRASYS_S9230_64X_PLATFORM_MODULE) + $(INGRASYS_S9230_64X_PLATFORM_MODULE) \ + $(ACCTON_AS7116_54X_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES) SONIC_INSTALLERS += $(SONIC_ONE_IMAGE) diff --git a/platform/nephos/rules.mk b/platform/nephos/rules.mk index 96f39ef8aad1..bf77ad0e6edf 100644 --- a/platform/nephos/rules.mk +++ b/platform/nephos/rules.mk @@ -1,6 +1,7 @@ include $(PLATFORM_PATH)/sdk.mk include $(PLATFORM_PATH)/sai.mk include $(PLATFORM_PATH)/platform-modules-ingrasys.mk +include $(PLATFORM_PATH)/platform-modules-accton.mk include $(PLATFORM_PATH)/docker-orchagent-nephos.mk include $(PLATFORM_PATH)/docker-syncd-nephos.mk include $(PLATFORM_PATH)/docker-syncd-nephos-rpc.mk diff --git a/platform/nephos/sonic-platform-modules-accton/LICENSE b/platform/nephos/sonic-platform-modules-accton/LICENSE new file mode 100644 index 000000000000..bc693f7a4c40 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/LICENSE @@ -0,0 +1,16 @@ +Copyright (C) 2016 Microsoft, Inc +Copyright (C) 2017 Accton Technology Corporation + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. diff --git a/platform/nephos/sonic-platform-modules-accton/README.md b/platform/nephos/sonic-platform-modules-accton/README.md new file mode 100644 index 000000000000..0ff20bb2d21b --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/README.md @@ -0,0 +1 @@ +platform drivers of Accton products for the SONiC project diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/__init__.py b/platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/fanutil.py b/platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/fanutil.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/thermalutil.py b/platform/nephos/sonic-platform-modules-accton/as7116-54x/classes/thermalutil.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/Makefile b/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/Makefile new file mode 100644 index 000000000000..19c7029f14a2 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/Makefile @@ -0,0 +1,2 @@ +obj-m := x86-64-accton-as7116-54x-cpld.o x86-64-accton-as7116-54x-fan.o \ + x86-64-accton-as7116-54x-led.o x86-64-accton-as7116-54x-psu.o x86-64-accton-as7116-54x-sfp.o diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-cpld.c b/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-cpld.c new file mode 100644 index 000000000000..eb52512343a8 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-cpld.c @@ -0,0 +1,242 @@ +/* + * A hwmon driver for the as7116_54x_cpld + * + * Copyright (C) 2017 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +/* Addresses scanned for as7116_54x_cpld + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static ssize_t show_cpld_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + int val = 0; + struct i2c_client *client = to_i2c_client(dev); + + val = i2c_smbus_read_byte_data(client, 0x1); + + if (val < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val); + } + + return sprintf(buf, "%d\n", val); +} + +static struct device_attribute ver = __ATTR(version, 0600, show_cpld_version, NULL); + +static void as7116_54x_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); + return; + } + + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &cpld_client_list); + mutex_unlock(&list_lock); +} + +static void as7116_54x_cpld_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(cpld_node); + } + + mutex_unlock(&list_lock); +} + +static int as7116_54x_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_dbg(&client->dev, "i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + status = sysfs_create_file(&client->dev.kobj, &ver.attr); + if (status) { + goto exit; + } + + dev_info(&client->dev, "chip found\n"); + as7116_54x_cpld_add_client(client); + + return 0; + +exit: + return status; +} + +static int as7116_54x_cpld_remove(struct i2c_client *client) +{ + sysfs_remove_file(&client->dev.kobj, &ver.attr); + as7116_54x_cpld_remove_client(client); + + return 0; +} + +enum cpld_chips +{ + as7116_54x_cpld1, + as7116_54x_cpld2, + as7116_54x_cpld3 +}; + +static const struct i2c_device_id as7116_54x_cpld_id[] = { + { "as7116_54x_cpld1", as7116_54x_cpld1 }, + { "as7116_54x_cpld2", as7116_54x_cpld2 }, + { "as7116_54x_cpld3", as7116_54x_cpld3 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as7116_54x_cpld_id); + +static struct i2c_driver as7116_54x_cpld_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "as7116_54x_cpld", + }, + .probe = as7116_54x_cpld_probe, + .remove = as7116_54x_cpld_remove, + .id_table = as7116_54x_cpld_id, + .address_list = normal_i2c, +}; + +int as7116_54x_cpld_read(unsigned short cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = i2c_smbus_read_byte_data(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as7116_54x_cpld_read); + +int as7116_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EIO; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = i2c_smbus_write_byte_data(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as7116_54x_cpld_write); + +static int __init as7116_54x_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&as7116_54x_cpld_driver); +} + +static void __exit as7116_54x_cpld_exit(void) +{ + i2c_del_driver(&as7116_54x_cpld_driver); +} + +static struct dmi_system_id as7116_54x_dmi_table[] = { + { + .ident = "Accton AS7716", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Accton"), + DMI_MATCH(DMI_PRODUCT_NAME, "AS7116"), + }, + } +}; + +int platform_accton_as7116_54x(void) +{ + //return dmi_check_system(as7116_54x_dmi_table); + return 1; +} +EXPORT_SYMBOL(platform_accton_as7116_54x); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("accton_as7116_54x driver"); +MODULE_LICENSE("GPL"); + +module_init(as7116_54x_cpld_init); +module_exit(as7116_54x_cpld_exit); + diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-fan.c b/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-fan.c new file mode 100644 index 000000000000..4fd1b91e26dc --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-fan.c @@ -0,0 +1,494 @@ +/* + * A hwmon driver for the Accton as7716 32x fan + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7116_54x_fan" + +static struct as7116_54x_fan_data *as7116_54x_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); + +/* fan related data, the index should match sysfs_fan_attributes + */ +static const u8 fan_reg[] = { + 0x02, /* fan 1-6 present status */ + 0x03, /* fan 1-6 direction(0:F2B 1:B2F) */ + 0x06, /* fan PWM(for all fan) */ + 0x04, /* front fan fault */ + 0x05, /* rear fan fault */ + 0x07, /* front fan 1 speed(rpm) */ + 0x08, /* front fan 2 speed(rpm) */ + 0x09, /* front fan 3 speed(rpm) */ + 0x0A, /* front fan 4 speed(rpm) */ + 0x0B, /* front fan 5 speed(rpm) */ + 0x0C, /* rear fan 1 speed(rpm) */ + 0x0D, /* rear fan 2 speed(rpm) */ + 0x0E, /* rear fan 3 speed(rpm) */ + 0x0f, /* rear fan 4 speed(rpm) */ + 0x10, /* rear fan 5 speed(rpm) */ +}; + +/* Each client has this additional data */ +struct as7116_54x_fan_data { + 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 */ +}; + +enum fan_id { + FAN1_ID, + FAN2_ID, + FAN3_ID, + FAN4_ID, + FAN5_ID +}; + +enum sysfs_fan_attributes { + FAN_PRESENT_REG, + FAN_DIRECTION_REG, + FAN_DUTY_CYCLE_PERCENTAGE, /* Only one CPLD register to control duty cycle for all fans */ + FAN_FRONT_FAULT_REG, + FAN_REAR_FAULT_REG, + 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, + FAN1_DIRECTION, + FAN2_DIRECTION, + FAN3_DIRECTION, + FAN4_DIRECTION, + FAN5_DIRECTION, + FAN1_PRESENT, + FAN2_PRESENT, + FAN3_PRESENT, + FAN4_PRESENT, + FAN5_PRESENT, + FAN1_FRONT_FAULT, + FAN2_FRONT_FAULT, + FAN3_FRONT_FAULT, + FAN4_FRONT_FAULT, + FAN5_FRONT_FAULT, + FAN1_REAR_FAULT, + FAN2_REAR_FAULT, + FAN3_REAR_FAULT, + FAN4_REAR_FAULT, + FAN5_REAR_FAULT +}; + +/* Define attributes + */ +#define DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_front_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FRONT_FAULT);\ + static SENSOR_DEVICE_ATTR(fan##index##_rear_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_REAR_FAULT) +#define DECLARE_FAN_FAULT_ATTR(index) &sensor_dev_attr_fan##index##_front_fault.dev_attr.attr,\ + &sensor_dev_attr_fan##index##_rear_fault.dev_attr.attr + +#define DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_direction, S_IRUGO, fan_show_value, NULL, FAN##index##_DIRECTION) +#define DECLARE_FAN_DIRECTION_ATTR(index) &sensor_dev_attr_fan##index##_direction.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_PRESENT_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, fan_show_value, NULL, FAN##index##_PRESENT) +#define DECLARE_FAN_PRESENT_ATTR(index) &sensor_dev_attr_fan##index##_present.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 + +/* 6 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); +/* 6 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); +/* 6 fan present attributes in this platform */ +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(1); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(2); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(3); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(4); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(5); +/* 6 fan direction attribute in this platform */ +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); +/* 1 fan duty cycle attribute in this platform */ +DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(); + +static struct attribute *as7116_54x_fan_attributes[] = { + /* fan related attributes */ + 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_PRESENT_ATTR(1), + DECLARE_FAN_PRESENT_ATTR(2), + DECLARE_FAN_PRESENT_ATTR(3), + DECLARE_FAN_PRESENT_ATTR(4), + DECLARE_FAN_PRESENT_ATTR(5), + 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), + DECLARE_FAN_DUTY_CYCLE_ATTR(), + NULL +}; + +#define FAN_DUTY_CYCLE_REG_MASK 0x1F +#define FAN_MIN_DUTY_CYCLE 20 +#define FAN_MAX_DUTY_CYCLE 100 +#define FAN_REG_VAL_TO_SPEED_RPM_STEP 150 + +static int as7116_54x_fan_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int as7116_54x_fan_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* fan utility functions + */ +static u32 reg_val_to_duty_cycle(u8 reg_val) +{ + return (reg_val & FAN_DUTY_CYCLE_REG_MASK) * 5; +} + +static u8 duty_cycle_to_reg_val(u8 duty_cycle) +{ + return (duty_cycle / 5); +} + +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_direction(u8 reg_val, enum fan_id id) +{ + return !!(reg_val & (1 << id)); +} + +static u8 reg_val_to_is_present(u8 reg_val, enum fan_id id) +{ + return !(reg_val & (1 << id)); +} + +static u8 is_fan_fault(u8 reg_val, enum fan_id id) +{ + return !!(reg_val & (1 << id)); +} +#if 0 +static u8 is_fan_fault(struct as7116_54x_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; +} +#endif + +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value; + struct i2c_client *client = to_i2c_client(dev); + + error = kstrtoint(buf, 10, &value); + if (error) + return error; + + if (value < FAN_MIN_DUTY_CYCLE) { + value = FAN_MIN_DUTY_CYCLE; + } + + if (value > FAN_MAX_DUTY_CYCLE) { + value = FAN_MAX_DUTY_CYCLE; + } + + as7116_54x_fan_write_value(client, fan_reg[FAN_DUTY_CYCLE_PERCENTAGE], duty_cycle_to_reg_val(value)); + 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); + struct as7116_54x_fan_data *data = as7116_54x_fan_update_device(dev); + ssize_t ret = 0; + + if (data->valid) { + switch (attr->index) { + 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: + ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_val[attr->index])); + break; + case FAN1_PRESENT: + case FAN2_PRESENT: + case FAN3_PRESENT: + case FAN4_PRESENT: + case FAN5_PRESENT: + ret = sprintf(buf, "%d\n", + reg_val_to_is_present(data->reg_val[FAN_PRESENT_REG], + attr->index - FAN1_PRESENT)); + break; + case FAN1_FRONT_FAULT: + case FAN2_FRONT_FAULT: + case FAN3_FRONT_FAULT: + case FAN4_FRONT_FAULT: + case FAN5_FRONT_FAULT: + ret = sprintf(buf, "%d\n", + is_fan_fault(data->reg_val[FAN_FRONT_FAULT_REG], + attr->index - FAN1_FRONT_FAULT)); + break; + case FAN1_REAR_FAULT: + case FAN2_REAR_FAULT: + case FAN3_REAR_FAULT: + case FAN4_REAR_FAULT: + case FAN5_REAR_FAULT: + ret = sprintf(buf, "%d\n", + is_fan_fault(data->reg_val[FAN_REAR_FAULT_REG], + attr->index - FAN1_REAR_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_direction(data->reg_val[FAN_DIRECTION_REG], + attr->index - FAN1_DIRECTION)); + break; + default: + break; + } + } + + return ret; +} + +static const struct attribute_group as7116_54x_fan_group = { + .attrs = as7116_54x_fan_attributes, +}; + +static struct as7116_54x_fan_data *as7116_54x_fan_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as7116_54x_fan_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || + !data->valid) { + int i; + + dev_dbg(&client->dev, "Starting as7116_54x_fan update\n"); + data->valid = 0; + + /* Update fan data + */ + for (i = 0; i < ARRAY_SIZE(data->reg_val); i++) { + int status = as7116_54x_fan_read_value(client, fan_reg[i]); + + if (status < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + dev_dbg(&client->dev, "reg %d, err %d\n", fan_reg[i], status); + return data; + } + else { + data->reg_val[i] = status; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int as7116_54x_fan_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct as7116_54x_fan_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as7116_54x_fan_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &as7116_54x_fan_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: fan '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &as7116_54x_fan_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int as7116_54x_fan_remove(struct i2c_client *client) +{ + struct as7116_54x_fan_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &as7116_54x_fan_group); + + return 0; +} + +/* Addresses to scan */ +static const unsigned short normal_i2c[] = { 0x66, I2C_CLIENT_END }; + +static const struct i2c_device_id as7116_54x_fan_id[] = { + { "as7116_54x_fan", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as7116_54x_fan_id); + +static struct i2c_driver as7116_54x_fan_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRVNAME, + }, + .probe = as7116_54x_fan_probe, + .remove = as7116_54x_fan_remove, + .id_table = as7116_54x_fan_id, + .address_list = normal_i2c, +}; + +static int __init as7116_54x_fan_init(void) +{ +#if 0 + extern int platform_accton_as7116_54x(void); + if (!platform_accton_as7116_54x()) { + return -ENODEV; + } +#endif + return i2c_add_driver(&as7116_54x_fan_driver); +} + +static void __exit as7116_54x_fan_exit(void) +{ + i2c_del_driver(&as7116_54x_fan_driver); +} + +module_init(as7116_54x_fan_init); +module_exit(as7116_54x_fan_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7116_54x_fan driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-led.c b/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-led.c new file mode 100644 index 000000000000..cd69f711c826 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-led.c @@ -0,0 +1,448 @@ +/* + * A LED driver for the accton_as7116_54x_led + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7116_54x_fan" + +#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 + +extern int as7116_54x_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as7116_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +struct as7116_54x_led_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_val[1]; /* LOC/DIAG LED */ +}; + +static struct as7116_54x_led_data *ledctl = NULL; + +/* LED related data + */ + +#define LED_CNTRLER_I2C_ADDRESS (0x60) + +#define LED_TYPE_DIAG_REG_MASK (0x0C) +#define LED_MODE_DIAG_GREEN_VALUE (0x08) +#define LED_MODE_DIAG_AMBER_VALUE (0x04) +#define LED_MODE_DIAG_YELLOW_VALUE (0x00) +#define LED_MODE_DIAG_OFF_VALUE (0x0C) + +#define LED_TYPE_FAN_REG_MASK (0x03) +#define LED_MODE_FAN_GREEN_VALUE (0x02) +#define LED_MODE_FAN_AMBER_VALUE (0x01) +#define LED_MODE_FAN_OFF_VALUE (0x03) +#define LED_MODE_FAN_AUTO_VALUE (0x00) + +#define LED_TYPE_PSU1_REG_MASK (0x03) +#define LED_MODE_PSU1_GREEN_VALUE (0x02) +#define LED_MODE_PSU1_AMBER_VALUE (0x01) +#define LED_MODE_PSU1_OFF_VALUE (0x03) +#define LED_MODE_PSU1_AUTO_VALUE (0x00) + +#define LED_TYPE_PSU2_REG_MASK (0x0C) +#define LED_MODE_PSU2_GREEN_VALUE (0x08) +#define LED_MODE_PSU2_AMBER_VALUE (0x04) +#define LED_MODE_PSU2_OFF_VALUE (0x0C) +#define LED_MODE_PSU2_AUTO_VALUE (0x00) + +#define LED_TYPE_LOC_REG_MASK (0x30) +#define LED_MODE_LOC_AMBER_VALUE (0x00) +#define LED_MODE_LOC_AMBER_BLINKING_VALUE1 (0x20) +#define LED_MODE_LOC_AMBER_BLINKING_VALUE2 (0x30) +#define LED_MODE_LOC_OFF_VALUE (0x10) + +static const u8 led_reg[] = { + 0x0A, /* LOC/DIAG/FAN LED */ + 0x0B, /* PSU1/PSU2 LED */ +}; + +enum led_type { + LED_TYPE_DIAG, + LED_TYPE_LOC, + LED_TYPE_FAN, + LED_TYPE_PSU1, + LED_TYPE_PSU2 +}; + +enum led_light_mode { + LED_MODE_OFF = 0, + LED_MODE_GREEN, + LED_MODE_GREEN_BLINK, + LED_MODE_AMBER, + LED_MODE_AMBER_BLINK, + LED_MODE_YELLOW, + LED_MODE_YELLOW_BLINK, + LED_MODE_BLUE, + LED_MODE_BLUE_BLINK, + LED_MODE_AUTO, + LED_MODE_UNKNOWN +}; + +struct led_type_mode { + enum led_type type; + enum led_light_mode mode; + int type_mask; + int mode_value; +}; + +static struct led_type_mode led_type_mode_data[] = { +{LED_TYPE_FAN, LED_MODE_OFF, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_OFF_VALUE}, +{LED_TYPE_FAN, LED_MODE_GREEN, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_GREEN_VALUE}, +{LED_TYPE_FAN, LED_MODE_AMBER, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_AMBER_VALUE}, +{LED_TYPE_FAN, LED_MODE_AUTO, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_AUTO_VALUE}, +{LED_TYPE_PSU1, LED_MODE_OFF, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_OFF_VALUE}, +{LED_TYPE_PSU1, LED_MODE_GREEN, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_GREEN_VALUE}, +{LED_TYPE_PSU1, LED_MODE_AMBER, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_AMBER_VALUE}, +{LED_TYPE_PSU1, LED_MODE_AUTO, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_AUTO_VALUE}, +{LED_TYPE_PSU2, LED_MODE_OFF, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_OFF_VALUE}, +{LED_TYPE_PSU2, LED_MODE_GREEN, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_GREEN_VALUE}, +{LED_TYPE_PSU2, LED_MODE_AMBER, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_AMBER_VALUE}, +{LED_TYPE_PSU2, LED_MODE_AUTO, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_AUTO_VALUE}, +{LED_TYPE_DIAG, LED_MODE_OFF, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_OFF_VALUE}, +{LED_TYPE_DIAG, LED_MODE_GREEN, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_GREEN_VALUE}, +{LED_TYPE_DIAG, LED_MODE_AMBER, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_AMBER_VALUE}, +{LED_TYPE_DIAG, LED_MODE_YELLOW, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_YELLOW_VALUE}, +{LED_TYPE_LOC, LED_MODE_OFF, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_OFF_VALUE}, +{LED_TYPE_LOC, LED_MODE_AMBER, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_AMBER_VALUE}, +{LED_TYPE_LOC, LED_MODE_AMBER_BLINK, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_AMBER_BLINKING_VALUE1}, +{LED_TYPE_LOC, LED_MODE_AMBER_BLINK, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_AMBER_BLINKING_VALUE2} +}; + +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_value) { + return led_type_mode_data[i].mode; + } + } + + return LED_MODE_UNKNOWN; +} + +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++) { + int type_mask, mode_value; + + if (type != led_type_mode_data[i].type) + continue; + + if (mode != led_type_mode_data[i].mode) + continue; + + type_mask = led_type_mode_data[i].type_mask; + mode_value = led_type_mode_data[i].mode_value; + reg_val = (reg_val & ~type_mask) | mode_value; + } + + return reg_val; +} + +static int as7116_54x_led_read_value(u8 reg) +{ + return as7116_54x_cpld_read(LED_CNTRLER_I2C_ADDRESS, reg); +} + +static int as7116_54x_led_write_value(u8 reg, u8 value) +{ + return as7116_54x_cpld_write(LED_CNTRLER_I2C_ADDRESS, reg, value); +} + +static void as7116_54x_led_update(void) +{ + mutex_lock(&ledctl->update_lock); + + if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2) + || !ledctl->valid) { + int i; + + dev_dbg(&ledctl->pdev->dev, "Starting accton_as7116_54x_led update\n"); + ledctl->valid = 0; + + /* Update LED data + */ + for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) { + int status = as7116_54x_led_read_value(led_reg[i]); + + if (status < 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 as7116_54x_led_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode, + u8 reg, enum led_type type) +{ + int reg_val; + + mutex_lock(&ledctl->update_lock); + + reg_val = as7116_54x_led_read_value(reg); + + if (reg_val < 0) { + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", reg, reg_val); + goto exit; + } + reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val); + as7116_54x_led_write_value(reg, reg_val); + + /* to prevent the slow-update issue */ + ledctl->valid = 0; + +exit: + mutex_unlock(&ledctl->update_lock); +} + + +static void as7116_54x_led_diag_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + as7116_54x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_DIAG); +} + +static enum led_brightness as7116_54x_led_diag_get(struct led_classdev *cdev) +{ + as7116_54x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_DIAG, ledctl->reg_val[0]); +} + +static void as7116_54x_led_loc_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + as7116_54x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_LOC); +} + +static enum led_brightness as7116_54x_led_loc_get(struct led_classdev *cdev) +{ + as7116_54x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_LOC, ledctl->reg_val[0]); +} + +static void as7116_54x_led_fan_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + as7116_54x_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_FAN); +} + +static enum led_brightness as7116_54x_led_fan_get(struct led_classdev *cdev) +{ + as7116_54x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[0]); +} + +static void as7116_54x_led_psu1_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + as7116_54x_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU1); +} + +static enum led_brightness as7116_54x_led_psu1_get(struct led_classdev *cdev) +{ + as7116_54x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU1, ledctl->reg_val[1]); +} + +static void as7116_54x_led_psu2_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + as7116_54x_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_PSU2); +} + +static enum led_brightness as7116_54x_led_psu2_get(struct led_classdev *cdev) +{ + as7116_54x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]); +} + +static struct led_classdev as7116_54x_leds[] = { + [LED_TYPE_DIAG] = { + .name = "as7116_54x_led::diag", + .default_trigger = "unused", + .brightness_set = as7116_54x_led_diag_set, + .brightness_get = as7116_54x_led_diag_get, + .max_brightness = LED_MODE_YELLOW, + }, + [LED_TYPE_LOC] = { + .name = "as7116_54x_led::loc", + .default_trigger = "unused", + .brightness_set = as7116_54x_led_loc_set, + .brightness_get = as7116_54x_led_loc_get, + .max_brightness = LED_MODE_AMBER_BLINK, + }, + [LED_TYPE_FAN] = { + .name = "as7116_54x_led::fan", + .default_trigger = "unused", + .brightness_set = as7116_54x_led_fan_set, + .brightness_get = as7116_54x_led_fan_get, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_PSU1] = { + .name = "as7116_54x_led::psu1", + .default_trigger = "unused", + .brightness_set = as7116_54x_led_psu1_set, + .brightness_get = as7116_54x_led_psu1_get, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_PSU2] = { + .name = "as7116_54x_led::psu2", + .default_trigger = "unused", + .brightness_set = as7116_54x_led_psu2_set, + .brightness_get = as7116_54x_led_psu2_get, + .max_brightness = LED_MODE_AUTO, + }, +}; + + +static int as7116_54x_led_probe(struct platform_device *pdev) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(as7116_54x_leds); i++) { + ret = led_classdev_register(&pdev->dev, &as7116_54x_leds[i]); + + if (ret < 0) { + break; + } + } + + /* Check if all LEDs were successfully registered */ + if (i != ARRAY_SIZE(as7116_54x_leds)){ + int j; + + /* only unregister the LEDs that were successfully registered */ + for (j = 0; j < i; j++) { + led_classdev_unregister(&as7116_54x_leds[i]); + } + } + + return ret; +} + +static int as7116_54x_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(as7116_54x_leds); i++) { + led_classdev_unregister(&as7116_54x_leds[i]); + } + + return 0; +} + +static struct platform_driver as7116_54x_led_driver = { + .probe = as7116_54x_led_probe, + .remove = as7116_54x_led_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init as7116_54x_led_init(void) +{ + int ret; + +#if 0 + extern int platform_accton_as7116_54x(void); + if (!platform_accton_as7116_54x()) { + return -ENODEV; + } +#endif + + ret = platform_driver_register(&as7116_54x_led_driver); + if (ret < 0) { + goto exit; + } + + ledctl = kzalloc(sizeof(struct as7116_54x_led_data), GFP_KERNEL); + if (!ledctl) { + ret = -ENOMEM; + goto exit_driver; + } + + 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); + goto exit_free; + } + + return 0; + +exit_free: + kfree(ledctl); +exit_driver: + platform_driver_unregister(&as7116_54x_led_driver); +exit: + return ret; +} + +static void __exit as7116_54x_led_exit(void) +{ + platform_device_unregister(ledctl->pdev); + platform_driver_unregister(&as7116_54x_led_driver); + kfree(ledctl); +} + +module_init(as7116_54x_led_init); +module_exit(as7116_54x_led_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("accton_as7116_54x_led driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-psu.c b/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-psu.c new file mode 100644 index 000000000000..b4e14297f414 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-psu.c @@ -0,0 +1,349 @@ +/* + * An hwmon driver for accton as7116_54x Power Module + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PSU_STATUS_I2C_ADDR 0x60 +#define PSU_STATUS_I2C_REG_OFFSET 0x2 + +#define MODEL_NAME_LEN 11 +#define MODEL_NAME_REG_OFFSET 0x20 + +#define SERIAL_NUM_LEN 18 +#define SERIAL_NUM_REG_OFFSET 0x35 + +#define IS_POWER_GOOD(id, value) (!!(value & BIT(id*4 + 1))) +#define IS_PRESENT(id, value) (!(value & BIT(id*4))) + +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf); +static int as7116_54x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len); +extern int as7116_54x_cpld_read(unsigned short cpld_addr, u8 reg); +static struct as7116_54x_psu_data *as7116_54x_psu_update_device(struct device *dev, u8 update_eeprom); + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +/* Each client has this additional data + */ +struct as7116_54x_psu_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 index; /* PSU index */ + u8 status; /* Status(present/power_good) register read from CPLD */ + char model_name[MODEL_NAME_LEN+1]; /* Model name, read from eeprom */ + char serial[SERIAL_NUM_LEN+1]; /* Serial number, read from eeprom*/ +}; + +enum as7116_54x_psu_sysfs_attributes { + PSU_PRESENT, + PSU_MODEL_NAME, + PSU_POWER_GOOD, + PSU_SERIAL_NUMBER +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); +static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); +static SENSOR_DEVICE_ATTR(psu_serial_numer, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER); + +static struct attribute *as7116_54x_psu_attributes[] = { + &sensor_dev_attr_psu_present.dev_attr.attr, + &sensor_dev_attr_psu_model_name.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + &sensor_dev_attr_psu_serial_numer.dev_attr.attr, + NULL +}; + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as7116_54x_psu_data *data = as7116_54x_psu_update_device(dev, 0); + u8 status = 0; + + if (!data->valid) { + return -EIO; + } + + if (attr->index == PSU_PRESENT) { + status = IS_PRESENT(data->index, data->status); + } + else { /* PSU_POWER_GOOD */ + status = IS_POWER_GOOD(data->index, data->status); + } + + return sprintf(buf, "%d\n", status); +} + +static ssize_t show_string(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as7116_54x_psu_data *data = as7116_54x_psu_update_device(dev, 1); + char *ptr = NULL; + + if (!data->valid) { + return -EIO; + } + + if (!IS_PRESENT(data->index, data->status)) { + return -ENXIO; + } + + if (attr->index == PSU_MODEL_NAME) { + ptr = data->model_name; + } + else { /* PSU_SERIAL_NUBMER */ + ptr = data->serial; + } + + return sprintf(buf, "%s\n", ptr); +} + +static const struct attribute_group as7116_54x_psu_group = { + .attrs = as7116_54x_psu_attributes, +}; + +static int as7116_54x_psu_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct as7116_54x_psu_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as7116_54x_psu_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + data->index = dev_id->driver_data; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &as7116_54x_psu_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &as7116_54x_psu_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int as7116_54x_psu_remove(struct i2c_client *client) +{ + struct as7116_54x_psu_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &as7116_54x_psu_group); + kfree(data); + + return 0; +} + +enum psu_index +{ + as7116_54x_psu1, + as7116_54x_psu2 +}; + +static const struct i2c_device_id as7116_54x_psu_id[] = { + { "as7116_54x_psu1", as7116_54x_psu1 }, + { "as7116_54x_psu2", as7116_54x_psu2 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as7116_54x_psu_id); + +static struct i2c_driver as7116_54x_psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "as7116_54x_psu", + }, + .probe = as7116_54x_psu_probe, + .remove = as7116_54x_psu_remove, + .id_table = as7116_54x_psu_id, + .address_list = normal_i2c, +}; + +static int as7116_54x_psu_read_block(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int result = 0; + int retry_count = 5; + + while (retry_count) { + retry_count--; + + result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + + if (unlikely(result < 0)) { + msleep(10); + continue; + } + + if (unlikely(result != data_len)) { + result = -EIO; + msleep(10); + continue; + } + + result = 0; + break; + } + + return result; +} + +static struct as7116_54x_psu_data *as7116_54x_psu_update_device(struct device *dev, u8 update_eeprom) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as7116_54x_psu_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int status; + + data->valid = 0; + dev_dbg(&client->dev, "Starting as7116_54x update\n"); + + /* Read psu status */ + status = as7116_54x_cpld_read(PSU_STATUS_I2C_ADDR, PSU_STATUS_I2C_REG_OFFSET); + + if (status < 0) { + dev_dbg(&client->dev, "cpld reg (0x%x) err %d\n", PSU_STATUS_I2C_ADDR, status); + goto exit; + } + else { + data->status = status; + } + + + memset(data->model_name, 0, sizeof(data->model_name)); + memset(data->serial, 0, sizeof(data->serial)); + + if (update_eeprom && IS_PRESENT(data->index, data->status)) { + /* Read model name */ + status = as7116_54x_psu_read_block(client, MODEL_NAME_REG_OFFSET, data->model_name, + ARRAY_SIZE(data->model_name)-1); + + if (status < 0) { + data->model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); + goto exit; + } + else { + /* Skip the meaningless data byte 8*/ + data->model_name[8] = data->model_name[9]; + data->model_name[9] = data->model_name[10]; + data->model_name[10] = '\0'; + } + + /* Read serial number */ + status = as7116_54x_psu_read_block(client, SERIAL_NUM_REG_OFFSET, data->serial, + ARRAY_SIZE(data->serial)-1); + + if (status < 0) { + data->serial[0] = '\0'; + dev_dbg(&client->dev, "unable to read serial number from (0x%x)\n", client->addr); + goto exit; + } + else { + data->serial[SERIAL_NUM_LEN] = '\0'; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + +exit: + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init as7116_54x_psu_init(void) +{ + //extern int platform_accton_as7116_54x(void); + //if (!platform_accton_as7116_54x()) { + // return -ENODEV; + //} + + return i2c_add_driver(&as7116_54x_psu_driver); +} + +static void __exit as7116_54x_psu_exit(void) +{ + i2c_del_driver(&as7116_54x_psu_driver); +} + +module_init(as7116_54x_psu_init); +module_exit(as7116_54x_psu_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7116_54x_psu driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-sfp.c b/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-sfp.c new file mode 100644 index 000000000000..540ceb21722f --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/modules/x86-64-accton-as7116-54x-sfp.c @@ -0,0 +1,1384 @@ +/* + * SFP driver for accton as7116_54x sfp + * + * Copyright (C) Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "as7116_54x_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 + +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 as7116_54x_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as7116_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +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 +}; + +/* 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 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, + 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 { +as7116_54x_sfp1, as7116_54x_sfp2, as7116_54x_sfp3, as7116_54x_sfp4, +as7116_54x_sfp5, as7116_54x_sfp6, as7116_54x_sfp7, as7116_54x_sfp8, +as7116_54x_sfp9, as7116_54x_sfp10, as7116_54x_sfp11, as7116_54x_sfp12, +as7116_54x_sfp13, as7116_54x_sfp14, as7116_54x_sfp15, as7116_54x_sfp16, +as7116_54x_sfp17, as7116_54x_sfp18, as7116_54x_sfp19, as7116_54x_sfp20, +as7116_54x_sfp21, as7116_54x_sfp22, as7116_54x_sfp23, as7116_54x_sfp24, +as7116_54x_sfp25, as7116_54x_sfp26, as7116_54x_sfp27, as7116_54x_sfp28, +as7116_54x_sfp29, as7116_54x_sfp30, as7116_54x_sfp31, as7116_54x_sfp32, +as7116_54x_sfp33, as7116_54x_sfp34, as7116_54x_sfp35, as7116_54x_sfp36, +as7116_54x_sfp37, as7116_54x_sfp38, as7116_54x_sfp39, as7116_54x_sfp40, +as7116_54x_sfp41, as7116_54x_sfp42, as7116_54x_sfp43, as7116_54x_sfp44, +as7116_54x_sfp45, as7116_54x_sfp46, as7116_54x_sfp47, as7116_54x_sfp48, +as7116_54x_sfp49, as7116_54x_sfp50, as7116_54x_sfp51, as7116_54x_sfp52, +as7116_54x_sfp53, as7116_54x_sfp54 +}; + +#define I2C_DEV_ID(x) { #x, x} + +static const struct i2c_device_id sfp_device_id[] = { +I2C_DEV_ID(as7116_54x_sfp1), +I2C_DEV_ID(as7116_54x_sfp2), +I2C_DEV_ID(as7116_54x_sfp3), +I2C_DEV_ID(as7116_54x_sfp4), +I2C_DEV_ID(as7116_54x_sfp5), +I2C_DEV_ID(as7116_54x_sfp6), +I2C_DEV_ID(as7116_54x_sfp7), +I2C_DEV_ID(as7116_54x_sfp8), +I2C_DEV_ID(as7116_54x_sfp9), +I2C_DEV_ID(as7116_54x_sfp10), +I2C_DEV_ID(as7116_54x_sfp11), +I2C_DEV_ID(as7116_54x_sfp12), +I2C_DEV_ID(as7116_54x_sfp13), +I2C_DEV_ID(as7116_54x_sfp14), +I2C_DEV_ID(as7116_54x_sfp15), +I2C_DEV_ID(as7116_54x_sfp16), +I2C_DEV_ID(as7116_54x_sfp17), +I2C_DEV_ID(as7116_54x_sfp18), +I2C_DEV_ID(as7116_54x_sfp19), +I2C_DEV_ID(as7116_54x_sfp20), +I2C_DEV_ID(as7116_54x_sfp21), +I2C_DEV_ID(as7116_54x_sfp22), +I2C_DEV_ID(as7116_54x_sfp23), +I2C_DEV_ID(as7116_54x_sfp24), +I2C_DEV_ID(as7116_54x_sfp25), +I2C_DEV_ID(as7116_54x_sfp26), +I2C_DEV_ID(as7116_54x_sfp27), +I2C_DEV_ID(as7116_54x_sfp28), +I2C_DEV_ID(as7116_54x_sfp29), +I2C_DEV_ID(as7116_54x_sfp30), +I2C_DEV_ID(as7116_54x_sfp31), +I2C_DEV_ID(as7116_54x_sfp32), +I2C_DEV_ID(as7116_54x_sfp33), +I2C_DEV_ID(as7116_54x_sfp34), +I2C_DEV_ID(as7116_54x_sfp35), +I2C_DEV_ID(as7116_54x_sfp36), +I2C_DEV_ID(as7116_54x_sfp37), +I2C_DEV_ID(as7116_54x_sfp38), +I2C_DEV_ID(as7116_54x_sfp39), +I2C_DEV_ID(as7116_54x_sfp40), +I2C_DEV_ID(as7116_54x_sfp41), +I2C_DEV_ID(as7116_54x_sfp42), +I2C_DEV_ID(as7116_54x_sfp43), +I2C_DEV_ID(as7116_54x_sfp44), +I2C_DEV_ID(as7116_54x_sfp45), +I2C_DEV_ID(as7116_54x_sfp46), +I2C_DEV_ID(as7116_54x_sfp47), +I2C_DEV_ID(as7116_54x_sfp48), +I2C_DEV_ID(as7116_54x_sfp49), +I2C_DEV_ID(as7116_54x_sfp50), +I2C_DEV_ID(as7116_54x_sfp51), +I2C_DEV_ID(as7116_54x_sfp52), +I2C_DEV_ID(as7116_54x_sfp53), +I2C_DEV_ID(as7116_54x_sfp54), +{ /* 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)); +} + +/* Platform dependent +++ */ +static struct sfp_port_data *sfp_update_present(struct i2c_client *client) +{ + int i = 0, j = 0, status = -1; + u8 reg; + unsigned short cpld_addr; + struct sfp_port_data *data = i2c_get_clientdata(client); + + DEBUG_PRINT("Starting sfp present status update"); + mutex_lock(&data->update_lock); + data->present = 0; + + /* Read present status of port 1~48(SFP port) */ + for (i = 0; i < 2; i++) { + for (j = 0; j < 3; j++) { + cpld_addr = 0x61+i; + reg = 0x6+j; + status = as7116_54x_cpld_read(cpld_addr, reg); + + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_addr, reg, status); + goto exit; + } + + DEBUG_PRINT("Present status = 0x%lx\r\n", data->present); + data->present |= (u64)status << ((i*24) + (j%3)*8); + } + } + + /* Read present status of port 49-54(QSFP port) */ + cpld_addr = 0x62; + reg = 0x14; + status = as7116_54x_cpld_read(cpld_addr, reg); + + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_addr, reg, status); + goto exit; + } + else { + data->present |= (u64)status << 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; + + if (time_before(jiffies, data->msa->last_updated + HZ + HZ / 2) && data->msa->valid) { + return data; + } + + DEBUG_PRINT("Starting as7116_54x sfp tx rx status update"); + mutex_lock(&data->update_lock); + data->msa->valid = 0; + memset(data->msa->status, 0, sizeof(data->msa->status)); + + /* Read status of port 1~48(SFP port) */ + for (i = 0; i < 2; i++) { + for (j = 0; j < 9; j++) { + u8 reg; + unsigned short cpld_addr; + reg = 0x9+j; + cpld_addr = 0x61+i; + + status = as7116_54x_cpld_read(cpld_addr, reg); + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_addr, reg, status); + goto exit; + } + + data->msa->status[j/3] |= (u64)status << ((i*24) + (j%3)*8); + } + } + + 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 short cpld_addr = 0; + u8 cpld_reg = 0, cpld_val = 0, cpld_bit = 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); + + if(data->port < 24) { + cpld_addr = 0x61; + cpld_reg = 0xC + data->port / 8; + cpld_bit = 1 << (data->port % 8); + } + else { /* port 24 ~ 48 */ + cpld_addr = 0x62; + cpld_reg = 0xC + (data->port - 24) / 8; + cpld_bit = 1 << (data->port % 8); + } + + /* Read current status */ + cpld_val = as7116_54x_cpld_read(cpld_addr, cpld_reg); + + /* Update tx_disable status */ + if (disable) { + data->msa->status[1] |= BIT_INDEX(data->port); + cpld_val |= cpld_bit; + } + else { + data->msa->status[1] &= ~BIT_INDEX(data->port); + cpld_val &= ~cpld_bit; + } + + as7116_54x_cpld_write(cpld_addr, cpld_reg, cpld_val); + 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 -> 54 in order */ + return sprintf(buf, "%.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", + values[0], values[1], values[2], + values[3], values[4], values[5], + values[6] & 0x3F); + } + 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 = OOM_DRIVER_PORT_TYPE_INVALID; + 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_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); + + 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 */ + as7116_54x_cpld_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 >= as7116_54x_sfp1 && dev_id->driver_data <= as7116_54x_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 { /* as7116_54x_sfp49 ~ as7116_54x_sfp54 */ + 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); + + 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 sfp_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .probe = sfp_device_probe, + .remove = sfp_device_remove, + .id_table = sfp_device_id, + .address_list = normal_i2c, +}; + +static int __init sfp_init(void) +{ + //extern int platform_accton_as7116_54x(void); + //if (!platform_accton_as7116_54x()) { + // return -ENODEV; + //} + + return i2c_add_driver(&sfp_driver); +} + +static void __exit sfp_exit(void) +{ + i2c_del_driver(&sfp_driver); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("accton as7116_54x_sfp driver"); +MODULE_LICENSE("GPL"); + +module_init(sfp_init); +module_exit(sfp_exit); + diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/service/as7116-platform-init.service b/platform/nephos/sonic-platform-modules-accton/as7116-54x/service/as7116-platform-init.service new file mode 100755 index 000000000000..be8688d2c2d2 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/service/as7116-platform-init.service @@ -0,0 +1,13 @@ +[Unit] +Description=Accton AS7116-54X Platform initialization service +Before=pmon.service +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/accton_as7116_util.py install +ExecStop=/usr/local/bin/accton_as7116_util.py clean +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/setup.py b/platform/nephos/sonic-platform-modules-accton/as7116-54x/setup.py new file mode 100644 index 000000000000..bb740409e310 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/setup.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +import os +import sys +from setuptools import setup +os.listdir + +setup( + name='as7116-54x', + version='1.0.0', + description='Module to initialize Accton AS7116-54X platforms', + + packages=['as7116-54x'], + package_dir={'as7116-54x': 'as7116-54x/classes'}, + ) diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/utils/README b/platform/nephos/sonic-platform-modules-accton/as7116-54x/utils/README new file mode 100755 index 000000000000..0b9fc1633999 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/utils/README @@ -0,0 +1,60 @@ +Copyright (C) 2016 Accton Networks, Inc. + +This program is free software: you can redistribute it and/or modify +It under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +To initialize the system, run "accton_as7712_util.py install". +To clean up the drivers & devices, run "accton_as7712_util.py clean". +To dump information of sensors, run "accton_as7712_util.py show". +To dump SFP EEPROM, run "accton_as7712_util.py sff". +To set fan speed, run "accton_as7712_util.py set fan". +To enable/disable SFP emission, run "accton_as7712_util.py set sfp". +To set system LEDs' color, run "accton_as7712_util.py set led" +For more information, run "accton_as7712_util.py --help". + +==================================================================== +Besides applying accton_as7712_util.py to access peripherals, you can +access peripherals by sysfs nodes directly after the installation is run. + +LED controls can be found under /sys/class/leds. The sysfs interface +color mappings are as follows: +Brightness: + 0 => off + 1 => green + 2 => amber + 3 => red + 4 => blue + +There are 5 system LEDs, loc, diag, fan, ps1, and ps2. +They are lit automatically by CPLD, but the loc and diag. +The loc led has only 1 color, blue. +The diag one has 3 colors: red, amber, and green. + +Fan controls can be found in /sys/bus/i2c/devices/2-0066. +There are 12 fans inside 6 fan modules. +All fans share 1 duty setting, ranged from 0~100. + +Three temperature sensors are controlled by the lm75 kernel modules. +They should already be visible under /sys/bus/i2c/drivers/lm75/. + +Two power supplies are controlled by the CPLD. +Here provide their status under +/sys/bus/i2c/devices/10-0050 and /sys/bus/i2c/devices/11-0053. + +There are 32 QSFP+ modules are equipped. +Apply "accton_as7712_util.py show" to get their status. +Apply "accton_as7712_util.py set sfp" to turn on/off light transmission. +Apply "accton_as7712_util.py sff" to dump EEPROM information. +Before operating on that QSFP+, please make sure it is well plugged. +Otherwise, operation is going to fail. + diff --git a/platform/nephos/sonic-platform-modules-accton/as7116-54x/utils/accton_as7116_util.py b/platform/nephos/sonic-platform-modules-accton/as7116-54x/utils/accton_as7116_util.py new file mode 100755 index 000000000000..17c56f7beb53 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/as7116-54x/utils/accton_as7116_util.py @@ -0,0 +1,518 @@ +#!/usr/bin/env python +# +# Copyright (C) 2016 Accton Networks, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes + show : show all systen status + sff : dump SFP eeprom + set : change board setting with fan|led|sfp +""" + +import os +import commands +import sys, getopt +import logging +import re +import time +from collections import namedtuple + + + + +PROJECT_NAME = 'as7116_54x' +version = '0.1.0' +verbose = False +DEBUG = False +args = [] +ALL_DEVICE = {} +DEVICE_NO = {'led':5, 'fan':1, 'thermal':3, 'psu':2, 'sfp':54} +FORCE = 0 +#logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG) +#logging.basicConfig(level=logging.INFO) + + +if DEBUG == True: + print sys.argv[0] + print 'ARGV :', sys.argv[1:] + + +def main(): + global DEBUG + global args + global FORCE + + if len(sys.argv)<2: + show_help() + + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', + 'debug', + 'force', + ]) + if DEBUG == True: + print options + print args + print len(sys.argv) + + for opt, arg in options: + if opt in ('-h', '--help'): + show_help() + elif opt in ('-d', '--debug'): + DEBUG = True + logging.basicConfig(level=logging.INFO) + elif opt in ('-f', '--force'): + FORCE = 1 + else: + logging.info('no option') + for arg in args: + if arg == 'install': + do_install() + elif arg == 'clean': + do_uninstall() + elif arg == 'show': + device_traversal() + elif arg == 'sff': + if len(args)!=2: + show_eeprom_help() + elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']: + show_eeprom_help() + else: + show_eeprom(args[1]) + return + elif arg == 'set': + if len(args)<3: + show_set_help() + else: + set_device(args[1:]) + return + else: + show_help() + + + return 0 + +def show_help(): + print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} + sys.exit(0) + +def show_set_help(): + cmd = sys.argv[0].split("/")[-1]+ " " + args[0] + print cmd +" [led|sfp|fan]" + print " use \""+ cmd + " led 0-4 \" to set led color" + print " use \""+ cmd + " fan 0-100\" to set fan duty percetage" + print " use \""+ cmd + " sfp 1-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(): + ret, lsmod = log_os_system("lsmod| grep accton", 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-accton-as7116-54x-cpld' , + 'modprobe x86-64-accton-as7116-54x-fan' , + 'modprobe x86-64-accton-as7116-54x-psu' , + 'modprobe x86-64-accton-as7116-54x-sfp' , + 'modprobe x86-64-accton-as7116-54x-led' ] + +def driver_install(): + global FORCE + for i in range(0,len(kos)): + status, output = log_os_system(kos[i], 1) + if status: + if FORCE == 0: + return status + return 0 + +def driver_uninstall(): + global FORCE + for i in range(0,len(kos)): + rm = kos[-(i+1)].replace("modprobe", "modprobe -rq") + rm = rm.replace("insmod", "rmmod") + status, output = log_os_system(rm, 1) + if status: + if FORCE == 0: + return status + return 0 + +led_prefix ='/sys/class/leds/'+PROJECT_NAME+'_led::' +hwmon_types = {'led': ['diag','fan','loc','psu1','psu2']} +hwmon_nodes = {'led': ['brightness'] } +hwmon_prefix ={'led': led_prefix} + +i2c_prefix = '/sys/bus/i2c/devices/' +i2c_bus = {'fan': ['1-0063'] , + 'thermal': ['17-004b','19-0049', '20-004a'] , + 'psu': ['10-0050','11-0058'], + 'sfp': ['-0050']} +i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'] , + 'thermal': ['hwmon/hwmon*/temp1_input'] , + 'psu': ['psu_present ', 'psu_power_good'] , + 'sfp': ['sfp_is_present ', 'sfp_tx_disable_all']} + +sfp_map = [37,38,39,40, + 41,42,43,44,45,46,47,48,49,50, + 51,52,53,54,55,56,57,58,59,60, + 61,62,63,64,65,66,67,68,69,70, + 71,72,73,74,75,76,77,78,79,80, + 81,82,83,84, + 21,22,23,24,25,26] + +mknod =[ + 'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-0/new_device', + 'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device', + 'echo pca9545 0x71 > /sys/bus/i2c/devices/i2c-1/new_device', + 'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-1/new_device', + 'echo as7116_54x_fan 0x63 > /sys/bus/i2c/devices/i2c-1/new_device', + 'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-17/new_device', + 'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-19/new_device', + 'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-20/new_device', + 'echo as7116_54x_cpld1 0x60 > /sys/bus/i2c/devices/i2c-2/new_device', + 'echo as7116_54x_cpld2 0x61 > /sys/bus/i2c/devices/i2c-2/new_device', + 'echo as7116_54x_cpld3 0x62 > /sys/bus/i2c/devices/i2c-2/new_device', + 'echo as7116_54x_psu1 0x50 > /sys/bus/i2c/devices/i2c-10/new_device', + 'echo ym2401 0x58 > /sys/bus/i2c/devices/i2c-10/new_device', + 'echo as7116_54x_psu2 0x53 > /sys/bus/i2c/devices/i2c-11/new_device', + 'echo ym2401 0x5b > /sys/bus/i2c/devices/i2c-11/new_device', + 'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-2/new_device', + 'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-29/new_device', + 'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-30/new_device', + 'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-31/new_device', + 'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-32/new_device', + 'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-33/new_device', + 'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-34/new_device', + 'echo 24c02 0x56 > /sys/bus/i2c/devices/i2c-0/new_device'] + +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) + + 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)): + status, output =log_os_system("echo as7116_54x_sfp"+str(i+1)+" 0x50 > /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 + + status, output =log_os_system("ls /sys/bus/i2c/devices/1-0077", 0) + + for i in range(0,len(sfp_map)): + target = "/sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/delete_device" + status, output =log_os_system("echo 0x50 > "+ target, 1) + if status: + print output + if FORCE == 0: + return status + + nodelist = mknod + + for i in range(len(nodelist)): + target = nodelist[-(i+1)] + temp = target.split() + del temp[1] + temp[-1] = temp[-1].replace('new_device', 'delete_device') + status, output = log_os_system(" ".join(temp), 1) + if status: + print output + if FORCE == 0: + return status + + return + +def system_ready(): + if driver_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 + for key in DEVICE_NO: + ALL_DEVICE[key]= {} + for i in range(0,DEVICE_NO[key]): + ALL_DEVICE[key][key+str(i+1)] = [] + + for key in i2c_bus: + buses = i2c_bus[key] + nodes = i2c_nodes[key] + for i in range(0,len(buses)): + for j in range(0,len(nodes)): + if 'fan' == key: + for k in range(0,DEVICE_NO[key]): + node = key+str(k+1) + path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + elif 'sfp' == key: + for k in range(0,DEVICE_NO[key]): + node = key+str(k+1) + path = i2c_prefix+ str(sfp_map[k])+ buses[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + else: + node = key+str(i+1) + path = i2c_prefix+ buses[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + + for key in hwmon_types: + itypes = hwmon_types[key] + nodes = hwmon_nodes[key] + for i in range(0,len(itypes)): + for j in range(0,len(nodes)): + node = key+"_"+itypes[i] + path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][ key+str(i+1)].append(path) + + #show dict all in the order + if DEBUG == True: + for i in sorted(ALL_DEVICE.keys()): + print(i+": ") + for j in sorted(ALL_DEVICE[i].keys()): + print(" "+j) + for k in (ALL_DEVICE[i][j]): + print(" "+" "+k) + return + +def show_eeprom(index): + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0] + node = node.replace(node.split("/")[-1], '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 + +#get digits inside a string. +#Ex: 31 for "sfp31" +def get_value(input): + digit = re.findall('\d+', input) + return int(digit[0]) + +def device_traversal(): + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + for i in sorted(ALL_DEVICE.keys()): + print("============================================") + print(i.upper()+": ") + print("============================================") + + for j in sorted(ALL_DEVICE[i].keys(), key=get_value): + print " "+j+":", + for k in (ALL_DEVICE[i][j]): + ret, log = log_os_system("cat "+k, 0) + func = k.split("/")[-1].strip() + func = re.sub(j+'_','',func,1) + func = re.sub(i.lower()+'_','',func,1) + if ret==0: + print func+"="+log+" ", + else: + print func+"="+"X"+" ", + print + print("----------------------------------------------------------------") + + + print + return + +def device_exist(): + ret1, log = log_os_system("ls "+i2c_prefix+"*0077", 0) + ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0) + return not(ret1 or ret2) + +if __name__ == "__main__": + main() diff --git a/platform/nephos/sonic-platform-modules-accton/debian/changelog b/platform/nephos/sonic-platform-modules-accton/debian/changelog new file mode 100755 index 000000000000..49f8f44bca48 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/debian/changelog @@ -0,0 +1,6 @@ +sonic-accton-platform-modules (1.0.0) unstable; urgency=low + + * Add support for AS7116-54X series + + -- developer Wed, 29 Mar 2017 11:00:00 +0800 + diff --git a/platform/nephos/sonic-platform-modules-accton/debian/compat b/platform/nephos/sonic-platform-modules-accton/debian/compat new file mode 100644 index 000000000000..ec635144f600 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/debian/compat @@ -0,0 +1 @@ +9 diff --git a/platform/nephos/sonic-platform-modules-accton/debian/control b/platform/nephos/sonic-platform-modules-accton/debian/control new file mode 100755 index 000000000000..92ce226ac11b --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/debian/control @@ -0,0 +1,11 @@ +Source: sonic-accton-platform-modules +Section: main +Priority: extra +Maintainer: +Build-Depends: debhelper (>= 8.0.0), bzip2 +Standards-Version: 3.9.3 + +Package: sonic-platform-accton-as7116-54x +Architecture: amd64 +Depends: linux-image-3.16.0-5-amd64 +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/nephos/sonic-platform-modules-accton/debian/rules b/platform/nephos/sonic-platform-modules-accton/debian/rules new file mode 100755 index 000000000000..cb232bd42425 --- /dev/null +++ b/platform/nephos/sonic-platform-modules-accton/debian/rules @@ -0,0 +1,86 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +include /usr/share/dpkg/pkg-info.mk + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +export INSTALL_MOD_DIR:=extra + +PYTHON ?= python2 + +PACKAGE_PRE_NAME := sonic-platform-accton +KVERSION ?= $(shell uname -r) +KERNEL_SRC := /lib/modules/$(KVERSION) +MOD_SRC_DIR:= $(shell pwd) +MODULE_DIRS:= as7116-54x +MODULE_DIR := modules +UTILS_DIR := utils +SERVICE_DIR := service +CLASSES_DIR := classes +CONF_DIR := conf + +%: + dh $@ --with systemd,python2,python3 --buildsystem=pybuild + +clean: + dh_testdir + dh_testroot + dh_clean + +build: + #make modules -C $(KERNEL_SRC)/build M=$(MODULE_SRC) + (for mod in $(MODULE_DIRS); do \ + make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ + $(PYTHON) $${mod}/setup.py build; \ + done) + +binary: binary-arch binary-indep + # Nothing to do + +binary-arch: + # Nothing to do + +#install: build + #dh_testdir + #dh_testroot + #dh_clean -k + #dh_installdirs + +binary-indep: + dh_testdir + dh_installdirs + + # Custom package commands + (for mod in $(MODULE_DIRS); do \ + 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; \ + 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}/$(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) + # Resuming debhelper scripts + dh_testroot + dh_install + dh_installchangelogs + dh_installdocs + dh_systemd_enable + dh_installinit + dh_systemd_start + dh_link + dh_fixperms + dh_compress + dh_strip + dh_installdeb + dh_gencontrol + dh_md5sums + dh_builddeb +.PHONY: build binary binary-arch binary-indep clean From 199777f7372eb1af0a493d0e6e8fe3a9d43dd257 Mon Sep 17 00:00:00 2001 From: "simon.ji" Date: Thu, 29 Mar 2018 03:04:04 -0700 Subject: [PATCH 3/3] Add maintainer info for deb --- platform/nephos/sonic-platform-modules-accton/debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/nephos/sonic-platform-modules-accton/debian/control b/platform/nephos/sonic-platform-modules-accton/debian/control index 92ce226ac11b..e1a403b3a719 100755 --- a/platform/nephos/sonic-platform-modules-accton/debian/control +++ b/platform/nephos/sonic-platform-modules-accton/debian/control @@ -1,7 +1,7 @@ Source: sonic-accton-platform-modules Section: main Priority: extra -Maintainer: +Maintainer: simon.ji@nephosinc.com Build-Depends: debhelper (>= 8.0.0), bzip2 Standards-Version: 3.9.3