diff --git a/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/buffers.json.j2 b/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/buffers.json.j2
new file mode 100644
index 0000000000..08e21e428b
--- /dev/null
+++ b/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/buffers.json.j2
@@ -0,0 +1,70 @@
+{# Default values which will be used if no actual configura available #}
+{% set default_cable = '40m' %}
+{% set default_ports_num = 54 -%}
+
+{# Port configuration to cable length look-up table #}
+{# Each record describes mapping of DUT (DUT port) role and neighbor role to cable length #}
+{# Roles described in the minigraph #}
+{% set ports2cable = {
+ 'torrouter_server' : '5m',
+ 'leafrouter_torrouter' : '40m',
+ 'spinerouter_leafrouter' : '300m'
+ }
+%}
+
+{%- macro cable_length(port_name) -%}
+ {%- set cable_len = [] -%}
+ {%- for local_port in DEVICE_NEIGHBOR -%}
+ {%- if local_port == port_name -%}
+ {%- if DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%}
+ {%- set neighbor = DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%}
+ {%- set neighbor_role = neighbor.type -%}
+ {%- set roles1 = switch_role + '_' + neighbor_role %}
+ {%- set roles2 = neighbor_role + '_' + switch_role -%}
+ {%- set roles1 = roles1 | lower -%}
+ {%- set roles2 = roles2 | lower -%}
+ {%- if roles1 in ports2cable -%}
+ {%- if cable_len.append(ports2cable[roles1]) -%}{%- endif -%}
+ {%- elif roles2 in ports2cable -%}
+ {%- if cable_len.append(ports2cable[roles2]) -%}{%- endif -%}
+ {%- endif -%}
+ {%- endif -%}
+ {%- endif -%}
+ {%- endfor -%}
+ {%- if cable_len -%}
+ {{ cable_len.0 }}
+ {%- else -%}
+ {{ default_cable }}
+ {%- endif -%}
+{% endmacro %}
+
+{%- if DEVICE_METADATA is defined %}
+{%- set switch_role = DEVICE_METADATA['localhost']['type'] %}
+{%- endif -%}
+
+{# Generate list of ports if not defined #}
+{% if PORT is not defined %}
+ {% set PORT = [] %}
+ {% for port_idx in range(1,default_ports_num+1) %}
+ {% if PORT.append("Ethernet%d" % (port_idx)) %}{% endif %}
+ {% endfor %}
+{% endif -%}
+
+{% set port_names_list = [] %}
+{% for port in PORT %}
+ {%- if port_names_list.append(port) %}{% endif %}
+{% endfor %}
+{% set port_names = port_names_list | join(',') -%}
+
+{
+ "CABLE_LENGTH": {
+ "AZURE": {
+ {% for port in PORT %}
+ {% set cable = cable_length(port) -%}
+ "{{ port }}": "{{ cable }}"{%- if not loop.last -%},{% endif %}
+
+ {% endfor %}
+ }
+ }
+}
+
diff --git a/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/pg_profile_lookup.ini b/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/pg_profile_lookup.ini
new file mode 100644
index 0000000000..a65244e69b
--- /dev/null
+++ b/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/pg_profile_lookup.ini
@@ -0,0 +1,21 @@
+# PG lossless profiles.
+# speed cable size xon xoff threshold
+ 1000 5m 34816 18432 16384 0
+ 10000 5m 34816 18432 16384 0
+ 25000 5m 34816 18432 16384 0
+ 40000 5m 34816 18432 16384 0
+ 50000 5m 34816 18432 16384 0
+ 100000 5m 36864 18432 18432 0
+ 1000 40m 36864 18432 18432 0
+ 10000 40m 36864 18432 18432 0
+ 25000 40m 39936 18432 21504 0
+ 40000 40m 41984 18432 23552 0
+ 50000 40m 41984 18432 23552 0
+ 100000 40m 54272 18432 35840 0
+ 1000 300m 49152 18432 30720 0
+ 10000 300m 49152 18432 30720 0
+ 25000 300m 71680 18432 53248 0
+ 40000 300m 94208 18432 75776 0
+ 50000 300m 94208 18432 75776 0
+ 100000 300m 184320 18432 165888 0
+
diff --git a/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/port_config.ini b/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/port_config.ini
index b9a831f22e..95190282b2 100644
--- a/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/port_config.ini
+++ b/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/port_config.ini
@@ -1,33 +1,55 @@
# name lanes
-Ethernet0 1
-Ethernet4 2
-Ethernet8 3
-Ethernet12 4
-Ethernet16 5
-Ethernet20 6
-Ethernet24 7
-Ethernet28 8
-Ethernet32 9
-Ethernet36 10
-Ethernet40 11
-Ethernet44 12
-Ethernet48 13
-Ethernet52 14
-Ethernet56 15
-Ethernet60 16
-Ethernet64 17
-Ethernet68 18
-Ethernet72 19
-Ethernet76 20
-Ethernet80 21
-Ethernet84 22
-Ethernet88 23
-Ethernet92 24
-Ethernet96 25
-Ethernet100 26
-Ethernet104 27
-Ethernet108 28
-Ethernet112 29
-Ethernet116 30
-Ethernet120 31
-Ethernet124 32
+Ethernet1 4
+Ethernet2 5
+Ethernet3 6
+Ethernet4 8
+Ethernet5 9
+Ethernet6 10
+Ethernet7 12
+Ethernet8 13
+Ethernet9 14
+Ethernet10 16
+Ethernet11 17
+Ethernet12 18
+Ethernet13 20
+Ethernet14 21
+Ethernet15 22
+Ethernet16 24
+Ethernet17 25
+Ethernet18 26
+Ethernet19 28
+Ethernet20 30
+Ethernet21 31
+Ethernet22 32
+Ethernet23 34
+Ethernet24 35
+Ethernet25 40
+Ethernet26 41
+Ethernet27 43
+Ethernet28 36
+Ethernet29 37
+Ethernet30 39
+Ethernet31 44
+Ethernet32 45
+Ethernet33 46
+Ethernet34 47
+Ethernet35 80
+Ethernet36 81
+Ethernet37 82
+Ethernet38 88
+Ethernet39 89
+Ethernet40 90
+Ethernet41 84
+Ethernet42 85
+Ethernet43 86
+Ethernet44 87
+Ethernet45 92
+Ethernet46 93
+Ethernet47 94
+Ethernet48 95
+Ethernet49 52,53,54,55
+Ethernet50 56,57,58,59
+Ethernet51 60,61,62,63
+Ethernet52 68,69,70,71
+Ethernet53 72,73,74,75
+Ethernet54 76,77,78,79
diff --git a/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/qos.json b/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/qos.json
new file mode 100644
index 0000000000..b9dc80abb0
--- /dev/null
+++ b/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/qos.json
@@ -0,0 +1,133 @@
+{
+ "DSCP_TO_TC_MAP": {
+ "AZURE": {
+ "0":"0",
+ "1":"0",
+ "2":"0",
+ "3":"0",
+ "4":"0",
+ "5":"0",
+ "6":"0",
+ "7":"0",
+ "8":"1",
+ "9":"1",
+ "10":"1",
+ "11":"1",
+ "12":"1",
+ "13":"1",
+ "14":"1",
+ "15":"1",
+ "16":"2",
+ "17":"2",
+ "18":"2",
+ "19":"2",
+ "20":"2",
+ "21":"2",
+ "22":"2",
+ "23":"2",
+ "24":"3",
+ "25":"3",
+ "26":"3",
+ "27":"3",
+ "28":"3",
+ "29":"3",
+ "30":"3",
+ "31":"3",
+ "32":"4",
+ "33":"4",
+ "34":"4",
+ "35":"4",
+ "36":"4",
+ "37":"4",
+ "38":"4",
+ "39":"4",
+ "40":"5",
+ "41":"5",
+ "42":"5",
+ "43":"5",
+ "44":"5",
+ "45":"5",
+ "46":"5",
+ "47":"5",
+ "48":"6",
+ "49":"6",
+ "50":"6",
+ "51":"6",
+ "52":"6",
+ "53":"6",
+ "54":"6",
+ "55":"6",
+ "56":"7",
+ "57":"7",
+ "58":"7",
+ "59":"7",
+ "60":"7",
+ "61":"7",
+ "62":"7",
+ "63":"7"
+ }
+ },
+ "SCHEDULER": {
+ "scheduler.0": {
+ "type":"DWRR",
+ "weight": "25"
+ },
+ "scheduler.1": {
+ "type":"DWRR",
+ "weight": "30"
+ },
+ "scheduler.2": {
+ "type":"DWRR",
+ "weight": "20"
+ }
+ },
+ "PORT_QOS_MAP": {
+ "Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet49,Ethernet50,Ethernet51,Ethernet52,Ethernet53,Ethernet54": {
+ "dscp_to_tc_map" : "[DSCP_TO_TC_MAP|AZURE]",
+ "pfc_enable": "3,4"
+ }
+ },
+ "WRED_PROFILE": {
+ "AZURE_LOSSY": {
+ "wred_green_enable":"true",
+ "wred_yellow_enable":"true",
+ "red_max_threshold":"32760",
+ "red_min_threshold":"4095",
+ "yellow_max_threshold":"32760",
+ "yellow_min_threshold":"4095",
+ "green_max_threshold": "32760",
+ "green_min_threshold": "4095"
+ },
+ "AZURE_LOSSLESS": {
+ "wred_green_enable":"true",
+ "wred_yellow_enable":"true",
+ "red_max_threshold":"32760",
+ "red_min_threshold":"4095",
+ "yellow_max_threshold":"32760",
+ "yellow_min_threshold":"4095",
+ "green_max_threshold": "32760",
+ "green_min_threshold": "4095"
+ }
+ },
+ "QUEUE": {
+ "Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet49,Ethernet50,Ethernet51,Ethernet52,Ethernet53,Ethernet54|0-2": {
+ "scheduler" : "[SCHEDULER|scheduler.1]"
+ },
+ "Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet49,Ethernet50,Ethernet51,Ethernet52,Ethernet53,Ethernet54|5-7": {
+ "scheduler" : "[SCHEDULER|scheduler.2]"
+ },
+ "Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet49,Ethernet50,Ethernet51,Ethernet52,Ethernet53,Ethernet54|0-2": {
+ "wred_profile" : "[WRED_PROFILE|AZURE_LOSSY]"
+ },
+
+ "Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet49,Ethernet50,Ethernet51,Ethernet52,Ethernet53,Ethernet54|5-7": {
+ "wred_profile" : "[WRED_PROFILE|AZURE_LOSSY]"
+ },
+ "Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet49,Ethernet50,Ethernet51,Ethernet52,Ethernet53,Ethernet54|3-4": {
+ "scheduler" : "[SCHEDULER|scheduler.0]",
+ "wred_profile" : "[WRED_PROFILE|AZURE_LOSSLESS]"
+ }
+ }
+}
+
+
diff --git a/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/sai.profile b/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/sai.profile
index 2eb3ce5f61..9842dcf57f 100644
--- a/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/sai.profile
+++ b/device/centec/x86_64-centec_e582_48x6q-r0/E582-48x6q/sai.profile
@@ -1 +1,3 @@
BOARD_CONFIG_FILE_PATH=/etc/centec/E582-48x6q.json
+SAI_INIT_CONFIG_FILE=/etc/centec/E582-48x6q-chip-profile.txt
+SAI_HW_PORT_PROFILE_ID_CONFIG_FILE=/etc/centec/E582-48x6q-datapath-cfg.txt
diff --git a/device/centec/x86_64-centec_e582_48x6q-r0/fancontrol b/device/centec/x86_64-centec_e582_48x6q-r0/fancontrol
new file mode 100644
index 0000000000..886a4bc6c0
--- /dev/null
+++ b/device/centec/x86_64-centec_e582_48x6q-r0/fancontrol
@@ -0,0 +1,11 @@
+# Configuration file generated by pwmconfig, changes will be lost
+INTERVAL=10
+DEVPATH=hwmon0= hwmon5=devices/pci0000:00/0000:00:1f.3/i2c-0/i2c-15/15-002f
+DEVNAME=hwmon0=acpitz hwmon5=adt7470
+FCTEMPS=hwmon5/device/pwm4=hwmon0/temp1_input hwmon5/device/pwm3=hwmon0/temp1_input hwmon5/device/pwm2=hwmon0/temp1_input hwmon5/device/pwm1=hwmon0/temp1_input
+FCFANS=hwmon5/device/pwm4=hwmon5/device/fan4_input hwmon5/device/pwm3=hwmon5/device/fan3_input hwmon5/device/pwm2=hwmon5/device/fan2_input hwmon5/device/pwm1=hwmon5/device/fan1_input
+MINTEMP=hwmon5/device/pwm4=20 hwmon5/device/pwm3=20 hwmon5/device/pwm2=20 hwmon5/device/pwm1=20
+MAXTEMP=hwmon5/device/pwm4=60 hwmon5/device/pwm3=60 hwmon5/device/pwm2=60 hwmon5/device/pwm1=60
+MINSTART=hwmon5/device/pwm4=150 hwmon5/device/pwm3=12 hwmon5/device/pwm2=12 hwmon5/device/pwm1=150
+MINSTOP=hwmon5/device/pwm4=0 hwmon5/device/pwm3=12 hwmon5/device/pwm2=12 hwmon5/device/pwm1=0
+MAXPWM= hwmon5/device/pwm4=150
diff --git a/device/centec/x86_64-centec_e582_48x6q-r0/installer.conf b/device/centec/x86_64-centec_e582_48x6q-r0/installer.conf
index 5e62742c11..7d60bf73d3 100644
--- a/device/centec/x86_64-centec_e582_48x6q-r0/installer.conf
+++ b/device/centec/x86_64-centec_e582_48x6q-r0/installer.conf
@@ -1 +1,2 @@
CONSOLE_SPEED=115200
+ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="acpi_enforce_resources=no"
diff --git a/device/centec/x86_64-centec_e582_48x6q-r0/minigraph.xml b/device/centec/x86_64-centec_e582_48x6q-r0/minigraph.xml
deleted file mode 100644
index 950c52a641..0000000000
--- a/device/centec/x86_64-centec_e582_48x6q-r0/minigraph.xml
+++ /dev/null
@@ -1,1049 +0,0 @@
-
-
-
-
-
- ARISTA01T0
- 10.0.0.33
- sonic
- 10.0.0.32
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.0
- ARISTA01T2
- 10.0.0.1
- 1
- 180
- 60
-
-
- ARISTA02T0
- 10.0.0.35
- sonic
- 10.0.0.34
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.2
- ARISTA02T2
- 10.0.0.3
- 1
- 180
- 60
-
-
- ARISTA03T0
- 10.0.0.37
- sonic
- 10.0.0.36
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.4
- ARISTA03T2
- 10.0.0.5
- 1
- 180
- 60
-
-
- ARISTA04T0
- 10.0.0.39
- sonic
- 10.0.0.38
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.6
- ARISTA04T2
- 10.0.0.7
- 1
- 180
- 60
-
-
- ARISTA05T0
- 10.0.0.41
- sonic
- 10.0.0.40
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.8
- ARISTA05T2
- 10.0.0.9
- 1
- 180
- 60
-
-
- ARISTA06T0
- 10.0.0.43
- sonic
- 10.0.0.42
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.10
- ARISTA06T2
- 10.0.0.11
- 1
- 180
- 60
-
-
- ARISTA07T0
- 10.0.0.45
- sonic
- 10.0.0.44
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.12
- ARISTA07T2
- 10.0.0.13
- 1
- 180
- 60
-
-
- ARISTA08T0
- 10.0.0.47
- sonic
- 10.0.0.46
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.14
- ARISTA08T2
- 10.0.0.15
- 1
- 180
- 60
-
-
- ARISTA09T0
- 10.0.0.49
- sonic
- 10.0.0.48
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.16
- ARISTA09T2
- 10.0.0.17
- 1
- 180
- 60
-
-
- ARISTA10T0
- 10.0.0.51
- sonic
- 10.0.0.50
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.18
- ARISTA10T2
- 10.0.0.19
- 1
- 180
- 60
-
-
- ARISTA11T0
- 10.0.0.53
- sonic
- 10.0.0.52
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.20
- ARISTA11T2
- 10.0.0.21
- 1
- 180
- 60
-
-
- ARISTA12T0
- 10.0.0.55
- sonic
- 10.0.0.54
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.22
- ARISTA12T2
- 10.0.0.23
- 1
- 180
- 60
-
-
- ARISTA13T0
- 10.0.0.57
- sonic
- 10.0.0.56
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.24
- ARISTA13T2
- 10.0.0.25
- 1
- 180
- 60
-
-
- ARISTA14T0
- 10.0.0.59
- sonic
- 10.0.0.58
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.26
- ARISTA14T2
- 10.0.0.27
- 1
- 180
- 60
-
-
- ARISTA15T0
- 10.0.0.61
- sonic
- 10.0.0.60
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.28
- ARISTA15T2
- 10.0.0.29
- 1
- 180
- 60
-
-
- ARISTA16T0
- 10.0.0.63
- sonic
- 10.0.0.62
- 1
- 180
- 60
-
-
- sonic
- 10.0.0.30
- ARISTA16T2
- 10.0.0.31
- 1
- 180
- 60
-
-
-
-
- 65100
- sonic
-
-
- 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
-
-
-
-
-
-
-
- sonic
-
-
-
-
-
- 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
- sonic
- Ethernet0
- ARISTA01T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet4
- ARISTA02T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet8
- ARISTA03T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet12
- ARISTA04T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet16
- ARISTA05T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet20
- ARISTA06T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet24
- ARISTA07T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet28
- ARISTA08T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet32
- ARISTA09T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet36
- ARISTA10T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet40
- ARISTA11T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet44
- ARISTA12T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet48
- ARISTA13T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet52
- ARISTA14T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet56
- ARISTA15T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet60
- ARISTA16T2
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet64
- ARISTA01T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet68
- ARISTA02T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet72
- ARISTA03T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet76
- ARISTA04T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet80
- ARISTA05T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet84
- ARISTA06T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet88
- ARISTA07T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet92
- ARISTA08T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet96
- ARISTA09T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet100
- ARISTA10T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet104
- ARISTA11T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet108
- ARISTA12T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet112
- ARISTA13T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet116
- ARISTA14T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet120
- ARISTA15T0
- Ethernet1
-
-
- DeviceInterfaceLink
- sonic
- Ethernet124
- ARISTA16T0
- Ethernet1
-
-
-
-
- sonic
- E582-48x6q
-
-
-
- sonic
- E582-48x6q
-
diff --git a/device/centec/x86_64-centec_e582_48x6q-r0/plugins/eeprom.py b/device/centec/x86_64-centec_e582_48x6q-r0/plugins/eeprom.py
new file mode 100644
index 0000000000..3fd55c63d8
--- /dev/null
+++ b/device/centec/x86_64-centec_e582_48x6q-r0/plugins/eeprom.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+#############################################################################
+# Centec E582-48X6Q
+#
+# Platform and model specific eeprom subclass, inherits from the base class,
+# and provides the followings:
+# - the eeprom format definition
+# - specific encoder/decoder if there is special need
+#############################################################################
+
+try:
+ import exceptions
+ import binascii
+ import time
+ import optparse
+ import warnings
+ import os
+ import sys
+ import subprocess
+ from sonic_eeprom import eeprom_base
+ from sonic_eeprom import eeprom_tlvinfo
+except ImportError, e:
+ raise ImportError (str(e) + "- required module not found")
+
+
+class board(eeprom_tlvinfo.TlvInfoDecoder):
+
+ def __init__(self, name, path, cpld_root, ro):
+ self.eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0057/eeprom"
+ super(board, self).__init__(self.eeprom_path, 0, '', True)
diff --git a/device/centec/x86_64-centec_e582_48x6q-r0/plugins/led_control.py b/device/centec/x86_64-centec_e582_48x6q-r0/plugins/led_control.py
new file mode 100644
index 0000000000..d25bf6f8b4
--- /dev/null
+++ b/device/centec/x86_64-centec_e582_48x6q-r0/plugins/led_control.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python
+#
+# led_control.py
+#
+# Platform-specific LED control functionality for SONiC
+#
+
+try:
+ from sonic_led.led_control_base import LedControlBase
+ import swsssdk
+ import threading
+ import os
+ import logging
+ import struct
+ import time
+ import syslog
+ from socket import *
+ from select import *
+except ImportError, e:
+ raise ImportError(str(e) + " - required module not found")
+
+
+def DBG_PRINT(str):
+ syslog.openlog("centec-led")
+ syslog.syslog(syslog.LOG_INFO, str)
+ syslog.closelog()
+
+class LedControl(LedControlBase):
+ """Platform specific LED control class"""
+ SONIC_PORT_NAME_PREFIX = "Ethernet"
+ LED_MODE_UP = [11, 1]
+ LED_MODE_DOWN = [7, 2]
+
+ def _initSystemLed(self):
+ try:
+ with open(self.f_led.format("system"), 'w') as led_file:
+ led_file.write("5")
+ DBG_PRINT("init system led to normal")
+ with open(self.f_led.format("idn"), 'w') as led_file:
+ led_file.write("1")
+ DBG_PRINT("init idn led to off")
+ except IOError as e:
+ DBG_PRINT(str(e))
+
+ def _initPanelLed(self):
+ with open(self.f_led.format("port1"), 'r') as led_file:
+ shouldInit = (int(led_file.read()) == 0)
+
+ if shouldInit == True:
+ for (port, ctlid, defmode) in self.led_mapping[1:59]:
+ data = struct.pack('=HHHBBH', 0, 7, 4, ctlid, defmode, port)
+ self.udpClient.sendto(data, ('localhost', 8101))
+
+ data = struct.pack('=HHHBB34B', 0, 3, 36, 34, 0, *[x[0] for x in self.led_mapping[1:35]])
+ self.udpClient.sendto(data, ('localhost', 8101))
+ data = struct.pack('=HHHBB24B', 0, 3, 26, 24, 1, *[x[0] for x in self.led_mapping[35:59]])
+ self.udpClient.sendto(data, ('localhost', 8101))
+
+ data = struct.pack('=HHHB', 0, 5, 1, 1)
+ self.udpClient.sendto(data, ('localhost', 8101))
+
+ for idx in range(1, 55):
+ (port, ctlid, defmode) = self.led_mapping[idx]
+ with open(self.f_led.format("port{}".format(idx)), 'w') as led_file:
+ led_file.write(str(defmode))
+ DBG_PRINT("init port{} led to mode={}".format(idx, defmode))
+
+ for idx in range(1, 55):
+ (port, ctlid, defmode) = self.led_mapping[idx]
+ with open(self.f_led.format("port{}".format(idx)), 'r') as led_file:
+ defmode = int(led_file.read())
+ data = struct.pack('=HHHBBH', 0, 7, 4, ctlid, defmode, port)
+ self.udpClient.sendto(data, ('localhost', 8101))
+ DBG_PRINT("init port{} led to mode={}".format(idx, defmode))
+
+ def _initDefaultConfig(self):
+ DBG_PRINT("start init led")
+ while True:
+ try:
+ r_sel = [self.udpClient]
+ echo_req = struct.pack('=HHH', 0, 1, 0)
+ self.udpClient.sendto(echo_req, ('localhost', 8101))
+ result = select(r_sel, [], [], 1)
+ if self.udpClient in result[0]:
+ echo_rsp, srv_addr = self.udpClient.recvfrom(1024)
+ if echo_rsp:
+ break
+ DBG_PRINT("connect to sdk rpc server timeout, try again.")
+ except IOError as e:
+ DBG_PRINT(str(e))
+
+ DBG_PRINT("connect to sdk rpc server success.")
+
+ self._initSystemLed()
+ self._initPanelLed()
+
+ DBG_PRINT("init led done")
+
+
+ # Helper method to map SONiC port name to index
+ def _port_name_to_index(self, port_name):
+ # Strip "Ethernet" off port name
+ if not port_name.startswith(self.SONIC_PORT_NAME_PREFIX):
+ return -1
+
+ port_idx = int(port_name[len(self.SONIC_PORT_NAME_PREFIX):])
+ return port_idx
+
+ def _port_state_to_mode(self, port_idx, state):
+ if state == "up":
+ return self.LED_MODE_UP[0] if (port_idx < 49) else self.LED_MODE_UP[1]
+ else:
+ return self.LED_MODE_DOWN[0] if (port_idx < 49) else self.LED_MODE_DOWN[1]
+
+ def _port_led_mode_update(self, port_idx, ledMode):
+ with open(self.f_led.format("port{}".format(port_idx)), 'w') as led_file:
+ led_file.write(str(ledMode))
+ (port, ctlid) = (self.led_mapping[port_idx][0], self.led_mapping[port_idx][1])
+ data = struct.pack('=HHHBBH', 0, 7, 4, ctlid, ledMode, port)
+ self.udpClient.sendto(data, ('localhost', 8101))
+
+ # Concrete implementation of port_link_state_change() method
+ def port_link_state_change(self, portname, state):
+ port_idx = self._port_name_to_index(portname)
+ ledMode = self._port_state_to_mode(port_idx, state)
+ with open(self.f_led.format("port{}".format(port_idx)), 'r') as led_file:
+ saveMode = int(led_file.read())
+
+ if ledMode == saveMode:
+ return
+
+ self._port_led_mode_update(port_idx, ledMode)
+ DBG_PRINT("update {} led mode from {} to {}".format(portname, saveMode, ledMode))
+
+ # Constructor
+ def __init__(self):
+ # [macid, ctlid, defaultmode]
+ self.led_mapping = [(0, 0, 0)] # resv
+ self.led_mapping.extend([(4, 0, 7), (5, 0, 7), (6, 0, 7), (8, 0, 7), (9, 0, 7), (10, 0, 7), (12, 0, 7), (13, 0, 7)]) # panel port 1~8
+ self.led_mapping.extend([(14, 0, 7), (16, 0, 7), (17, 0, 7), (18, 0, 7), (20, 0, 7), (21, 0, 7), (22, 0, 7), (24, 0, 7)]) # panel port 9~16
+ self.led_mapping.extend([(25, 0, 7), (26, 0, 7), (28, 0, 7), (30, 0, 7), (31, 0, 7), (32, 0, 7), (34, 0, 7), (35, 0, 7)]) # panel port 17~24
+ self.led_mapping.extend([(48, 0, 7), (49, 0, 7), (51, 0, 7), (36, 0, 7), (37, 0, 7), (39, 0, 7), (55, 0, 7), (54, 0, 7)]) # panel port 25~32
+ self.led_mapping.extend([(53, 0, 7), (52, 0, 7), (52, 1, 7), (53, 1, 7), (54, 1, 7), (55, 1, 7), (38, 1, 7), (37, 1, 7)]) # panel port 33~40
+ self.led_mapping.extend([(36, 1, 7), (51, 1, 7), (50, 1, 7), (49, 1, 7), (48, 1, 7), (34, 1, 7), (33, 1, 7), (32, 1, 7)]) # panel port 41~48
+ self.led_mapping.extend([(28, 1, 2), (24, 1, 2), (20, 1, 2), (12, 1, 2), (8, 1, 2), (4, 1, 2)]) # panel port 49~54
+ self.led_mapping.extend([(0, 1, 2), (0, 1, 2), (0, 1, 2), (0, 1, 2), (0, 1, 2), (0, 1, 2)])
+
+ self.f_led = "/sys/class/leds/{}/brightness"
+
+ self.udpClient = socket(AF_INET, SOCK_DGRAM)
+
+ self._initDefaultConfig()
+
diff --git a/device/centec/x86_64-centec_e582_48x6q-r0/plugins/psuutil.py b/device/centec/x86_64-centec_e582_48x6q-r0/plugins/psuutil.py
new file mode 100644
index 0000000000..5f8ba030c1
--- /dev/null
+++ b/device/centec/x86_64-centec_e582_48x6q-r0/plugins/psuutil.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+
+#############################################################################
+# Mellanox
+#
+# Module contains an implementation of SONiC PSU Base API and
+# provides the PSUs status which are available in the platform
+#
+#############################################################################
+
+import os.path
+
+try:
+ from sonic_psu.psu_base import PsuBase
+except ImportError as e:
+ raise ImportError (str(e) + "- required module not found")
+
+class PsuUtil(PsuBase):
+ """Platform-specific PSUutil class"""
+
+ def __init__(self):
+ PsuBase.__init__(self)
+
+ self.psu_path = "/sys/class/psu/psu{}/"
+ self.psu_presence = "psu_presence"
+ self.psu_oper_status = "psu_status"
+
+ def get_num_psus(self):
+ """
+ Retrieves the number of PSUs available on the device
+
+ :return: An integer, the number of PSUs available on the device
+ """
+ return 2
+
+ def get_psu_status(self, index):
+ """
+ Retrieves the oprational status of power supply unit (PSU) defined
+ by 1-based index
+
+ :param index: An integer, 1-based index of the PSU of which to query status
+ :return: Boolean, True if PSU is operating properly, False if PSU is faulty
+ """
+ if index is None:
+ return False
+
+ status = 0
+ try:
+ with open(self.psu_path.format(index) + self.psu_oper_status, 'r') as power_status:
+ status = int(power_status.read())
+ except IOError:
+ return False
+
+ return status == 0
+
+ def get_psu_presence(self, index):
+ """
+ Retrieves the presence status of power supply unit (PSU) defined
+ by 1-based index
+
+ :param index: An integer, 1-based index of the PSU of which to query status
+ :return: Boolean, True if PSU is plugged, False if not
+ """
+ if index is None:
+ return False
+
+ status = 0
+ try:
+ with open(self.psu_path.format(index) + self.psu_presence, 'r') as presence_status:
+ status = int(presence_status.read())
+ except IOError:
+ return False
+
+ return status == 0
diff --git a/device/centec/x86_64-centec_e582_48x6q-r0/plugins/sfputil.py b/device/centec/x86_64-centec_e582_48x6q-r0/plugins/sfputil.py
new file mode 100644
index 0000000000..7bb1ac0d41
--- /dev/null
+++ b/device/centec/x86_64-centec_e582_48x6q-r0/plugins/sfputil.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+
+# sfputil.py
+#
+# Platform-specific SFP transceiver interface for SONiC
+#
+
+try:
+ import time
+ import os
+ import logging
+ import struct
+ import syslog
+ from socket import *
+ from select import *
+ from sonic_sfp.sfputilbase import SfpUtilBase
+except ImportError as e:
+ raise ImportError("%s - required module not found" % str(e))
+
+
+
+def DBG_PRINT(str):
+ print str + "\n"
+
+
+class SfpUtil(SfpUtilBase):
+ """Platform-specific SfpUtil class"""
+ SONIC_PORT_NAME_PREFIX = "Ethernet"
+ PORT_START = 1
+ PORT_END = 54
+ PORTS_IN_BLOCK = 54
+
+ @property
+ def port_start(self):
+ return self.PORT_START
+
+ @property
+ def port_end(self):
+ return self.PORT_END
+
+ @property
+ def qsfp_ports(self):
+ return range(49, self.PORTS_IN_BLOCK + 1)
+
+ @property
+ def port_to_eeprom_mapping(self):
+ return self.eeprom_mapping
+
+ def is_logical_port(self, port_name):
+ return True
+
+ def get_logical_to_physical(self, port_name):
+ if not port_name.startswith(self.SONIC_PORT_NAME_PREFIX):
+ return None
+
+ port_idx = int(port_name[len(self.SONIC_PORT_NAME_PREFIX):])
+
+ return [port_idx]
+
+ def get_eeprom_data(self, port):
+ (ctlid, devid) = self.fiber_mapping[port]
+ offset = (128 if port in self.qsfp_ports else 0)
+ r_sel = [self.udpClient]
+ req = struct.pack('=HHHBBHIBBBBI',
+ 0, 9, 16, # lchip/msgtype/msglen
+ ctlid, # uint8 ctl_id
+ devid, # uint8 slave_dev_id
+ 0x50, # uint16 dev_addr
+ (1< self.port_end:
+ return False
+ try:
+ with open(self.f_sfp_present.format(port_num), 'r') as sfp_file:
+ return 1 == int(sfp_file.read())
+ except IOError as e:
+ DBG_PRINT(str(e))
+
+ return False
+
+ def get_low_power_mode(self, port_num):
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+
+ return False
+
+ def set_low_power_mode(self, port_num, lpmode):
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+
+ return False
+
+ def reset(self, port_num):
+ # Check for invalid port_num
+ if port_num < self.port_start or port_num > self.port_end:
+ return False
+
+ return False
+
diff --git a/dockers/docker-orchagent/orchagent.sh b/dockers/docker-orchagent/orchagent.sh
index af9e5b0766..7758ceeed5 100755
--- a/dockers/docker-orchagent/orchagent.sh
+++ b/dockers/docker-orchagent/orchagent.sh
@@ -20,6 +20,11 @@ elif [ "$platform" == "cavium" ]; then
ORCHAGENT_ARGS+="-m $MAC_ADDRESS"
elif [ "$platform" == "nephos" ]; then
ORCHAGENT_ARGS+="-m $MAC_ADDRESS"
+elif [ "$platform" == "centec" ]; then
+ last_byte=$(python -c "print '$MAC_ADDRESS'[-2:]")
+ aligned_last_byte=$(python -c "print format(int(int('$last_byte', 16) + 1), '02x')") # put mask and take away the 0x prefix
+ ALIGNED_MAC_ADDRESS=$(python -c "print '$MAC_ADDRESS'[:-2] + '$aligned_last_byte'") # put aligned byte into the end of MAC
+ ORCHAGENT_ARGS+="-m $ALIGNED_MAC_ADDRESS"
elif [ "$platform" == "barefoot" ]; then
ORCHAGENT_ARGS+="-m $MAC_ADDRESS"
fi
diff --git a/platform/centec/one-image.mk b/platform/centec/one-image.mk
index 7ad205dce5..42e78ab4df 100644
--- a/platform/centec/one-image.mk
+++ b/platform/centec/one-image.mk
@@ -3,6 +3,6 @@
SONIC_ONE_IMAGE = sonic-centec.bin
$(SONIC_ONE_IMAGE)_MACHINE = centec
$(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie
-$(SONIC_ONE_IMAGE)_INSTALLS += $(CENTEC_SDK_KERNEL)
+$(SONIC_ONE_IMAGE)_INSTALLS += $(CENTEC_E582_48X6Q_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_IMAGES)
SONIC_INSTALLERS += $(SONIC_ONE_IMAGE)
diff --git a/platform/centec/platform-modules-centec-e582.mk b/platform/centec/platform-modules-centec-e582.mk
new file mode 100644
index 0000000000..e86c428a74
--- /dev/null
+++ b/platform/centec/platform-modules-centec-e582.mk
@@ -0,0 +1,19 @@
+# Centec E582-48X6Q Platform modules
+
+
+CENTEC_E582_48X6Q_PLATFORM_MODULE_VERSION =1.1
+CENTEC_E582_48X2Q4Z_PLATFORM_MODULE_VERSION =1.1
+
+export CENTEC_E582_48X6Q_PLATFORM_MODULE_VERSION
+export CENTEC_E582_48X2Q4Z_PLATFORM_MODULE_VERSION
+
+CENTEC_E582_48X6Q_PLATFORM_MODULE = platform-modules-e582-48x6q_$(CENTEC_E582_48X6Q_PLATFORM_MODULE_VERSION)_amd64.deb
+
+$(CENTEC_E582_48X6Q_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-e582
+$(CENTEC_E582_48X6Q_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON)
+$(CENTEC_E582_48X6Q_PLATFORM_MODULE)_PLATFORM = x86_64-centec_e582_48x6q-r0
+SONIC_DPKG_DEBS += $(CENTEC_E582_48X6Q_PLATFORM_MODULE)
+
+CENTEC_E582_48X2Q4Z_PLATFORM_MODULE = platform-modules-e582-48x2q4z_$(CENTEC_E582_48X2Q4Z_PLATFORM_MODULE_VERSION)_amd64.deb
+$(CENTEC_E582_48X2Q4Z_PLATFORM_MODULE)_PLATFORM = x86_64-centec_e582_48x2q4z-r0
+$(eval $(call add_extra_package,$(CENTEC_E582_48X6Q_PLATFORM_MODULE),$(CENTEC_E582_48X2Q4Z_PLATFORM_MODULE)))
diff --git a/platform/centec/rules.mk b/platform/centec/rules.mk
index 8b676f87ec..823144dc25 100644
--- a/platform/centec/rules.mk
+++ b/platform/centec/rules.mk
@@ -1,5 +1,5 @@
+include $(PLATFORM_PATH)/platform-modules-centec-e582.mk
include $(PLATFORM_PATH)/sdk.mk
-include $(PLATFORM_PATH)/sai.mk
include $(PLATFORM_PATH)/docker-orchagent-centec.mk
include $(PLATFORM_PATH)/docker-syncd-centec.mk
include $(PLATFORM_PATH)/docker-syncd-centec-rpc.mk
diff --git a/platform/centec/sai.mk b/platform/centec/sai.mk
deleted file mode 100644
index 299b36a69e..0000000000
--- a/platform/centec/sai.mk
+++ /dev/null
@@ -1,5 +0,0 @@
-# Centec SAI
-CENTEC_SAI = libsai_1.0.0_amd64.deb
-$(CENTEC_SAI)_URL = https://github.com/CentecNetworks/goldengate-sai/raw/master/lib/SONiC_1.0/libsai_1.0.0_amd64.deb
-
-SONIC_ONLINE_DEBS += $(CENTEC_SAI)
diff --git a/platform/centec/sdk.mk b/platform/centec/sdk.mk
index e3ce05f6b7..ba2d1adbe6 100644
--- a/platform/centec/sdk.mk
+++ b/platform/centec/sdk.mk
@@ -1,4 +1,5 @@
-CENTEC_SDK_KERNEL = centec-gg-sdk3.5-modules-3.16.0-4-amd64.deb
-$(CENTEC_SDK_KERNEL)_URL = "https://github.com/CentecNetworks/goldengate-sai/raw/master/lib/SONiC_1.0/centec-gg-sdk3.5-modules-3.16.0-4-amd64.deb"
+# Centec SAI
+CENTEC_SAI = libsai_1.2.4_amd64.deb
+$(CENTEC_SAI)_URL = https://github.com/CentecNetworks/goldengate-sai/raw/master/lib/SONiC_1.2.4/libsai_1.2.4-1.0_amd64.deb
-SONIC_ONLINE_DEBS += $(CENTEC_SDK_KERNEL)
+SONIC_ONLINE_DEBS += $(CENTEC_SAI)
diff --git a/platform/centec/sonic-platform-modules-e582/48x2q4z/cfg/48x2q4z-modules.conf b/platform/centec/sonic-platform-modules-e582/48x2q4z/cfg/48x2q4z-modules.conf
new file mode 100644
index 0000000000..5becd702a7
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x2q4z/cfg/48x2q4z-modules.conf
@@ -0,0 +1,17 @@
+# /etc/modules: kernel modules to load at boot time.
+#
+# This file contains the names of kernel modules that should be loaded
+# at boot time, one per line. Lines beginning with "#" are ignored.
+
+i2c-i801
+i2c-dev
+i2c-mux
+i2c-smbus
+
+i2c-mux-pca954x
+lm77
+adt7470
+tun
+centec_e582_48x6q_platform
+dal
+centec_at24c64
diff --git a/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/Makefile b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/Makefile
new file mode 100644
index 0000000000..d1ca9824aa
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/Makefile
@@ -0,0 +1,2 @@
+obj-m := centec_e582_48x2q4z_platform.o dal.o centec_at24c64.o
+dal-y := dal_kernel.o dal_mpool.o
diff --git a/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/centec_at24c64.c b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/centec_at24c64.c
new file mode 100644
index 0000000000..52b8d536d0
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/centec_at24c64.c
@@ -0,0 +1,657 @@
+/*
+ * at24.c - handle most I2C EEPROMs
+ *
+ * Copyright (C) 2005-2007 David Brownell
+ * Copyright (C) 2008 Wolfram Sang, Pengutronix
+ *
+ * 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.
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
+ * Differences between different vendor product lines (like Atmel AT24C or
+ * MicroChip 24LC, etc) won't much matter for typical read/write access.
+ * There are also I2C RAM chips, likewise interchangeable. One example
+ * would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes).
+ *
+ * However, misconfiguration can lose data. "Set 16-bit memory address"
+ * to a part with 8-bit addressing will overwrite data. Writing with too
+ * big a page size also loses data. And it's not safe to assume that the
+ * conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC
+ * uses 0x51, for just one example.
+ *
+ * Accordingly, explicit board-specific configuration data should be used
+ * in almost all cases. (One partial exception is an SMBus used to access
+ * "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.)
+ *
+ * So this driver uses "new style" I2C driver binding, expecting to be
+ * told what devices exist. That may be in arch/X/mach-Y/board-Z.c or
+ * similar kernel-resident tables; or, configuration data coming from
+ * a bootloader.
+ *
+ * Other than binding model, current differences from "eeprom" driver are
+ * that this one handles write access and isn't restricted to 24c02 devices.
+ * It also handles larger devices (32 kbit and up) with two-byte addresses,
+ * which won't work on pure SMBus systems.
+ */
+
+struct at24_data {
+ struct at24_platform_data chip;
+ struct memory_accessor macc;
+ int use_smbus;
+
+ /*
+ * Lock protects against activities from other Linux tasks,
+ * but not from changes by other I2C masters.
+ */
+ struct mutex lock;
+ struct bin_attribute bin;
+
+ u8 *writebuf;
+ unsigned write_max;
+ unsigned num_addresses;
+
+ /*
+ * Some chips tie up multiple I2C addresses; dummy devices reserve
+ * them for us, and we'll use them with SMBus calls.
+ */
+ struct i2c_client *client[];
+};
+
+/*
+ * This parameter is to help this driver avoid blocking other drivers out
+ * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C
+ * clock, one 256 byte read takes about 1/43 second which is excessive;
+ * but the 1/170 second it takes at 400 kHz may be quite reasonable; and
+ * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible.
+ *
+ * This value is forced to be a power of two so that writes align on pages.
+ */
+static unsigned io_limit = 128;
+module_param(io_limit, uint, 0);
+MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 128)");
+
+/*
+ * Specs often allow 5 msec for a page write, sometimes 20 msec;
+ * it's important to recover from write timeouts.
+ */
+static unsigned write_timeout = 25;
+module_param(write_timeout, uint, 0);
+MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
+
+#define AT24_SIZE_BYTELEN 5
+#define AT24_SIZE_FLAGS 8
+
+#define AT24_BITMASK(x) (BIT(x) - 1)
+
+/* create non-zero magic value for given eeprom parameters */
+#define AT24_DEVICE_MAGIC(_len, _flags) \
+ ((1 << AT24_SIZE_FLAGS | (_flags)) \
+ << AT24_SIZE_BYTELEN | ilog2(_len))
+
+static const struct i2c_device_id at24_ctc_ids[] = {
+ { "24c64-ctc", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16 | AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
+ { /* END OF LIST */ }
+};
+MODULE_DEVICE_TABLE(i2c, at24_ctc_ids);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This routine supports chips which consume multiple I2C addresses. It
+ * computes the addressing information to be used for a given r/w request.
+ * Assumes that sanity checks for offset happened at sysfs-layer.
+ */
+static struct i2c_client *at24_translate_offset(struct at24_data *at24,
+ unsigned *offset)
+{
+ unsigned i;
+
+ if (at24->chip.flags & AT24_FLAG_ADDR16) {
+ i = *offset >> 16;
+ *offset &= 0xffff;
+ } else {
+ i = *offset >> 8;
+ *offset &= 0xff;
+ }
+
+ return at24->client[i];
+}
+
+static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
+ unsigned offset, size_t count)
+{
+ struct i2c_msg msg[2];
+ struct i2c_client *client;
+ unsigned long timeout, read_time;
+ int status;
+
+ memset(msg, 0, sizeof(msg));
+
+ /*
+ * REVISIT some multi-address chips don't rollover page reads to
+ * the next slave address, so we may need to truncate the count.
+ * Those chips might need another quirk flag.
+ *
+ * If the real hardware used four adjacent 24c02 chips and that
+ * were misconfigured as one 24c08, that would be a similar effect:
+ * one "eeprom" file not four, but larger reads would fail when
+ * they crossed certain pages.
+ */
+
+ /*
+ * Slave address and byte offset derive from the offset. Always
+ * set the byte address; on a multi-master board, another master
+ * may have changed the chip's "current" address pointer.
+ */
+ client = at24_translate_offset(at24, &offset);
+
+ if (count > io_limit)
+ count = io_limit;
+
+ count = 1;
+
+ /*
+ * Reads fail if the previous write didn't complete yet. We may
+ * loop a few times until this one succeeds, waiting at least
+ * long enough for one entire page write to work.
+ */
+ timeout = jiffies + msecs_to_jiffies(write_timeout);
+ do {
+ read_time = jiffies;
+
+ status = i2c_smbus_write_byte_data(client, (offset >> 8) & 0x0ff, offset & 0x0ff );
+ status = i2c_smbus_read_byte(client);
+ if (status >= 0) {
+ buf[0] = status;
+ status = count;
+ }
+
+ dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
+ count, offset, status, jiffies);
+
+ if (status == count)
+ return count;
+
+ /* REVISIT: at HZ=100, this is sloooow */
+ msleep(1);
+ } while (time_before(read_time, timeout));
+
+ return -ETIMEDOUT;
+}
+
+static ssize_t at24_read(struct at24_data *at24,
+ char *buf, loff_t off, size_t count)
+{
+ ssize_t retval = 0;
+
+ if (unlikely(!count))
+ return count;
+
+ memset(buf, 0, count);
+
+ /*
+ * Read data from chip, protecting against concurrent updates
+ * from this host, but not from other I2C masters.
+ */
+ mutex_lock(&at24->lock);
+
+ while (count) {
+ ssize_t status;
+
+ status = at24_eeprom_read(at24, buf, off, count);
+ if (status <= 0) {
+ if (retval == 0)
+ retval = status;
+ break;
+ }
+ buf += status;
+ off += status;
+ count -= status;
+ retval += status;
+ }
+
+ //printk(KERN_ALERT "at24_read buf = %s, retval = %zu\n", buf, retval);
+
+ mutex_unlock(&at24->lock);
+
+ return retval;
+}
+
+static ssize_t at24_bin_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct at24_data *at24;
+
+ at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
+ return at24_read(at24, buf, off, count);
+}
+
+
+/*
+ * Note that if the hardware write-protect pin is pulled high, the whole
+ * chip is normally write protected. But there are plenty of product
+ * variants here, including OTP fuses and partial chip protect.
+ *
+ * We only use page mode writes; the alternative is sloooow. This routine
+ * writes at most one page.
+ */
+static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
+ unsigned offset, size_t count)
+{
+ struct i2c_client *client;
+ ssize_t status;
+ unsigned long timeout, write_time;
+ unsigned next_page;
+
+ /* Get corresponding I2C address and adjust offset */
+ client = at24_translate_offset(at24, &offset);
+
+ /* write_max is at most a page */
+ if (count > at24->write_max)
+ count = at24->write_max;
+
+ /* Never roll over backwards, to the start of this page */
+ next_page = roundup(offset + 1, at24->chip.page_size);
+ if (offset + count > next_page)
+ count = next_page - offset;
+
+ /*
+ * Writes fail if the previous one didn't complete yet. We may
+ * loop a few times until this one succeeds, waiting at least
+ * long enough for one entire page write to work.
+ */
+ timeout = jiffies + msecs_to_jiffies(write_timeout);
+ do {
+ write_time = jiffies;
+
+ status = i2c_smbus_write_word_data(client,
+ (offset >> 8) & 0x0ff, (offset & 0xFF) | buf[0]);
+ if (status == 0)
+ status = count;
+
+ dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
+ count, offset, status, jiffies);
+
+ if (status == count)
+ return count;
+
+ /* REVISIT: at HZ=100, this is sloooow */
+ msleep(1);
+ } while (time_before(write_time, timeout));
+
+ return -ETIMEDOUT;
+}
+
+static ssize_t at24_write(struct at24_data *at24, 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(&at24->lock);
+
+ while (count) {
+ ssize_t status;
+
+ status = at24_eeprom_write(at24, buf, off, 1); /* only one-byte to write; TODO page wirte */
+ if (status <= 0) {
+ if (retval == 0)
+ retval = status;
+ break;
+ }
+ buf += status;
+ off += status;
+ count -= status;
+ retval += status;
+ }
+
+ mutex_unlock(&at24->lock);
+
+ return retval;
+}
+
+static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct at24_data *at24;
+
+ if (unlikely(off >= attr->size))
+ return -EFBIG;
+
+ at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
+ return at24_write(at24, buf, off, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This lets other kernel code access the eeprom data. For example, it
+ * might hold a board's Ethernet address, or board-specific calibration
+ * data generated on the manufacturing floor.
+ */
+
+static ssize_t at24_macc_read(struct memory_accessor *macc, char *buf,
+ off_t offset, size_t count)
+{
+ struct at24_data *at24 = container_of(macc, struct at24_data, macc);
+
+ return at24_read(at24, buf, offset, count);
+}
+
+static ssize_t at24_macc_write(struct memory_accessor *macc, const char *buf,
+ off_t offset, size_t count)
+{
+ struct at24_data *at24 = container_of(macc, struct at24_data, macc);
+
+ return at24_write(at24, buf, offset, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_OF
+static void at24_get_ofdata(struct i2c_client *client,
+ struct at24_platform_data *chip)
+{
+ const __be32 *val;
+ struct device_node *node = client->dev.of_node;
+
+ if (node) {
+ if (of_get_property(node, "read-only", NULL))
+ chip->flags |= AT24_FLAG_READONLY;
+ val = of_get_property(node, "pagesize", NULL);
+ if (val)
+ chip->page_size = be32_to_cpup(val);
+ }
+}
+#else
+static void at24_get_ofdata(struct i2c_client *client,
+ struct at24_platform_data *chip)
+{ }
+#endif /* CONFIG_OF */
+
+static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct at24_platform_data chip;
+ bool writable;
+ int use_smbus = 0;
+ struct at24_data *at24;
+ int err;
+ unsigned i, num_addresses;
+ kernel_ulong_t magic;
+
+ if (client->dev.platform_data) {
+ chip = *(struct at24_platform_data *)client->dev.platform_data;
+ } else {
+ if (!id->driver_data)
+ return -ENODEV;
+
+ magic = id->driver_data;
+ chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
+ magic >>= AT24_SIZE_BYTELEN;
+ chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
+
+ /*
+ * This is slow, but we can't know all eeproms, so we better
+ * play safe. Specifying custom eeprom-types via platform_data
+ * is recommended anyhow.
+ */
+ chip.page_size = 1;
+
+ /* update chipdata if OF is present */
+ at24_get_ofdata(client, &chip);
+
+ printk(KERN_ALERT "at24_probe chip.byte_len = 0x%x\n", chip.byte_len);
+ printk(KERN_ALERT "at24_probe chip.flags = 0x%x\n", chip.flags);
+ printk(KERN_ALERT "at24_probe chip.magic = 0x%lx\n", id->driver_data);
+
+ chip.setup = NULL;
+ chip.context = NULL;
+ }
+
+ if (!is_power_of_2(chip.byte_len))
+ dev_warn(&client->dev,
+ "byte_len looks suspicious (no power of 2)!\n");
+ if (!chip.page_size) {
+ dev_err(&client->dev, "page_size must not be 0!\n");
+ return -EINVAL;
+ }
+ if (!is_power_of_2(chip.page_size))
+ dev_warn(&client->dev,
+ "page_size looks suspicious (no power of 2)!\n");
+
+ /* Use I2C operations unless we're stuck with SMBus extensions. */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ use_smbus = I2C_SMBUS_I2C_BLOCK_DATA;
+ } else if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+ use_smbus = I2C_SMBUS_WORD_DATA;
+ } else if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
+ use_smbus = I2C_SMBUS_BYTE_DATA;
+ } else {
+ return -EPFNOSUPPORT;
+ }
+ use_smbus = I2C_SMBUS_BYTE_DATA;
+ printk(KERN_ALERT "at24_probe use_smbus --> %d\n",
+ use_smbus);
+ }
+
+ if (chip.flags & AT24_FLAG_TAKE8ADDR)
+ num_addresses = 8;
+ else
+ num_addresses = DIV_ROUND_UP(chip.byte_len,
+ (chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);
+
+ at24 = devm_kzalloc(&client->dev, sizeof(struct at24_data) +
+ num_addresses * sizeof(struct i2c_client *), GFP_KERNEL);
+ if (!at24)
+ return -ENOMEM;
+
+ mutex_init(&at24->lock);
+ at24->use_smbus = use_smbus;
+ at24->chip = chip;
+ at24->num_addresses = num_addresses;
+
+ /*
+ * Export the EEPROM bytes through sysfs, since that's convenient.
+ * By default, only root should see the data (maybe passwords etc)
+ */
+ sysfs_bin_attr_init(&at24->bin);
+ at24->bin.attr.name = "eeprom";
+ at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR;
+ at24->bin.read = at24_bin_read;
+ at24->bin.size = chip.byte_len;
+
+ at24->macc.read = at24_macc_read;
+
+ writable = !(chip.flags & AT24_FLAG_READONLY);
+ if (writable) {
+ if (!use_smbus || i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
+
+ unsigned write_max = chip.page_size;
+
+ at24->macc.write = at24_macc_write;
+
+ at24->bin.write = at24_bin_write;
+ at24->bin.attr.mode |= S_IWUSR;
+
+ if (write_max > io_limit)
+ write_max = io_limit;
+ if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX)
+ write_max = I2C_SMBUS_BLOCK_MAX;
+ at24->write_max = write_max;
+
+ /* buffer (data + address at the beginning) */
+ at24->writebuf = devm_kzalloc(&client->dev,
+ write_max + 2, GFP_KERNEL);
+ if (!at24->writebuf)
+ return -ENOMEM;
+ } else {
+ dev_warn(&client->dev,
+ "cannot write due to controller restrictions.");
+ }
+ }
+
+ at24->client[0] = client;
+
+ /* use dummy devices for multiple-address chips */
+ for (i = 1; i < num_addresses; i++) {
+ at24->client[i] = i2c_new_dummy(client->adapter,
+ client->addr + i);
+ if (!at24->client[i]) {
+ dev_err(&client->dev, "address 0x%02x unavailable\n",
+ client->addr + i);
+ err = -EADDRINUSE;
+ goto err_clients;
+ }
+ }
+
+ err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin);
+ if (err)
+ goto err_clients;
+
+ i2c_set_clientdata(client, at24);
+
+ dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/write\n",
+ at24->bin.size, client->name,
+ writable ? "writable" : "read-only", at24->write_max);
+ if (use_smbus == I2C_SMBUS_WORD_DATA ||
+ use_smbus == I2C_SMBUS_BYTE_DATA) {
+ dev_notice(&client->dev, "Falling back to %s reads, "
+ "performance will suffer\n", use_smbus ==
+ I2C_SMBUS_WORD_DATA ? "word" : "byte");
+ }
+
+ /* export data to kernel code */
+ if (chip.setup)
+ chip.setup(&at24->macc, chip.context);
+
+ return 0;
+
+err_clients:
+ for (i = 1; i < num_addresses; i++)
+ if (at24->client[i])
+ i2c_unregister_device(at24->client[i]);
+
+ return err;
+}
+
+static int at24_remove(struct i2c_client *client)
+{
+ struct at24_data *at24;
+ int i;
+
+ at24 = i2c_get_clientdata(client);
+ sysfs_remove_bin_file(&client->dev.kobj, &at24->bin);
+
+ for (i = 1; i < at24->num_addresses; i++)
+ i2c_unregister_device(at24->client[i]);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct i2c_board_info i2c_devs = {
+ I2C_BOARD_INFO("24c64-ctc", 0x57),
+};
+
+static struct i2c_adapter *adapter = NULL;
+static struct i2c_client *client = NULL;
+
+static int ctc_at24c64_init(void)
+{
+ printk(KERN_ALERT "ctc_at24c64_init\n");
+
+ adapter = i2c_get_adapter(0);
+ if(adapter == NULL){
+ printk(KERN_ALERT "i2c_get_adapter == NULL\n");
+ return -1;
+ }
+
+ client = i2c_new_device(adapter, &i2c_devs);
+ if(client == NULL){
+ printk(KERN_ALERT "i2c_new_device == NULL\n");
+ i2c_put_adapter(adapter);
+ adapter = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static void ctc_at24c64_exit(void)
+{
+ printk(KERN_ALERT "ctc_at24c64_exit\n");
+ if(client){
+ i2c_unregister_device(client);
+ }
+ if(adapter){
+ i2c_put_adapter(adapter);
+ }
+}
+
+static struct i2c_driver at24_ctc_driver = {
+ .driver = {
+ .name = "at24-ctc",
+ .owner = THIS_MODULE,
+ },
+ .probe = at24_probe,
+ .remove = at24_remove,
+ .id_table = at24_ctc_ids,
+};
+
+static int __init at24_ctc_init(void)
+{
+ if (!io_limit) {
+ pr_err("at24_ctc: io_limit must not be 0!\n");
+ return -EINVAL;
+ }
+
+ io_limit = rounddown_pow_of_two(io_limit);
+
+ ctc_at24c64_init();
+
+ return i2c_add_driver(&at24_ctc_driver);
+}
+module_init(at24_ctc_init);
+
+static void __exit at24_ctc_exit(void)
+{
+ ctc_at24c64_exit();
+ i2c_del_driver(&at24_ctc_driver);
+}
+module_exit(at24_ctc_exit);
+
+MODULE_DESCRIPTION("Driver for most I2C EEPROMs");
+MODULE_AUTHOR("David Brownell and Wolfram Sang");
+MODULE_LICENSE("GPL");
diff --git a/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/centec_e582_48x2q4z_platform.c b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/centec_e582_48x2q4z_platform.c
new file mode 100644
index 0000000000..003f9a80ca
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/centec_e582_48x2q4z_platform.c
@@ -0,0 +1,142 @@
+#include
+#include
+#include
+#include
+
+#define PCA9548_CHANNEL_NUM 8
+#define PCA9548_ADAPT_ID_START 10
+
+static struct pca954x_platform_mode i2c_dev_pca9548_platform_mode[PCA9548_CHANNEL_NUM] = {
+ [0] = {
+ .adap_id = PCA9548_ADAPT_ID_START,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [1] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 1,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [2] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 2,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [3] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 3,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [4] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 4,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [5] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 5,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [6] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 6,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [7] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 7,
+ .deselect_on_exit = 1,
+ .class = 0,
+ }
+};
+
+static struct pca954x_platform_data i2c_dev_pca9548_platform_data = {
+ .modes = i2c_dev_pca9548_platform_mode,
+ .num_modes = PCA9548_CHANNEL_NUM,
+};
+
+static struct i2c_board_info i2c_dev_pca9548 = {
+ I2C_BOARD_INFO("pca9548", 0x70),
+ .platform_data = &i2c_dev_pca9548_platform_data,
+};
+
+static struct i2c_board_info i2c_dev_adt7475 = {
+ I2C_BOARD_INFO("adt7470", 0x2F),
+};
+
+struct i2c_adapter *i2c_core_master = NULL; /* i2c-0-cpu */
+struct i2c_adapter *i2c_mux_channel_4 = NULL; /* pca9548x-channel 5 */
+struct i2c_client *i2c_client_pca9548x = NULL;
+struct i2c_client *i2c_client_adt7475 = NULL;
+
+static int e582_48x6q_init(void)
+{
+ printk(KERN_INFO "install e582_48x6q board dirver...\n");
+
+ /* find i2c-core master */
+ i2c_core_master = i2c_get_adapter(0);
+ if(i2c_core_master == NULL)
+ {
+ printk(KERN_CRIT "can't find i2c-core bus\n");
+ goto err_i2c_core_master;
+ }
+
+ /* install i2c-mux */
+ i2c_client_pca9548x = i2c_new_device(i2c_core_master, &i2c_dev_pca9548);
+ if(i2c_client_pca9548x == NULL)
+ {
+ printk(KERN_INFO "install e582_48x6q board pca9548 failed\n");
+ goto install_at24c64;
+ }
+
+ /* install adt7475 */
+ /* find i2c-mux-channel 15 */
+ i2c_mux_channel_4 = i2c_get_adapter(PCA9548_ADAPT_ID_START + 4);
+ if(i2c_mux_channel_4 == NULL)
+ {
+ printk(KERN_INFO "install e582_48x6q board adt7470 failed\n");
+ goto install_at24c64;
+ }
+
+ i2c_client_adt7475 = i2c_new_device(i2c_mux_channel_4, &i2c_dev_adt7475);
+ if(i2c_client_adt7475 == NULL){
+ printk(KERN_INFO "install e582_48x6q board adt7470 failed\n");
+ goto install_at24c64;
+ }
+
+install_at24c64:
+
+ printk(KERN_INFO "install e582_48x6q board dirver...ok\n");
+ return 0;
+
+err_i2c_core_master:
+ return -1;
+}
+
+static void e582_48x6q_exit(void)
+{
+ printk(KERN_INFO "uninstall e582_48x6q board dirver...\n");
+
+ /* uninstall adt7475 master */
+ if(i2c_client_adt7475) {
+ i2c_unregister_device(i2c_client_adt7475);
+ }
+ if(i2c_mux_channel_4) {
+ i2c_put_adapter(i2c_mux_channel_4);
+ }
+
+ /* uninstall i2c-core master */
+ if(i2c_client_pca9548x) {
+ i2c_unregister_device(i2c_client_pca9548x);
+ }
+
+ /* uninstall i2c-core master */
+ if(i2c_core_master) {
+ i2c_put_adapter(i2c_core_master);
+ }
+}
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("xuwj centecNetworks, Inc");
+MODULE_DESCRIPTION("e582-48x6q board driver");
+module_init(e582_48x6q_init);
+module_exit(e582_48x6q_exit);
diff --git a/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/dal_kernel.c b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/dal_kernel.c
new file mode 100644
index 0000000000..4c9a3da64e
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/dal_kernel.c
@@ -0,0 +1,1814 @@
+/**
+ @file dal_kernal.c
+
+ @date 2012-10-18
+
+ @version v2.0
+
+
+*/
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
+#include
+#endif
+#include "dal_kernel.h"
+#include "dal_mpool.h"
+
+MODULE_AUTHOR("Centec Networks Inc.");
+MODULE_DESCRIPTION("DAL kernel module");
+MODULE_LICENSE("GPL");
+
+/* DMA memory pool size */
+static char* dma_pool_size;
+module_param(dma_pool_size, charp, 0);
+MODULE_PARM_DESC(dma_pool_size,
+ "Specify DMA memory pool size (default 4MB)");
+
+/*****************************************************************************
+ * defines
+ *****************************************************************************/
+#define MB_SIZE 0x100000
+#define CTC_MAX_INTR_NUM 8
+
+#define MEM_MAP_RESERVE SetPageReserved
+#define MEM_MAP_UNRESERVE ClearPageReserved
+
+#define CTC_VENDOR_VID 0xc001
+#define CTC_HUMBER_DEVICE_ID 0x6048
+#define CTC_GOLDENGATE_DEVICE_ID 0xcb10
+
+#define MEM_MAP_RESERVE SetPageReserved
+#define MEM_MAP_UNRESERVE ClearPageReserved
+
+#define CTC_GREATBELT_DEVICE_ID 0x03e8 /* TBD */
+#define DAL_MAX_CHIP_NUM 8 /* [GB] used */
+#define VIRT_TO_PAGE(p) virt_to_page((p))
+#define DAL_UNTAG_BLOCK 0
+#define DAL_DISCARD_BLOCK 1
+#define DAL_MATCHED_BLOCK 2
+#define DAL_CUR_MATCH_BLOCk 3
+/*****************************************************************************
+ * typedef
+ *****************************************************************************/
+/* Control Data */
+typedef struct dal_isr_s
+{
+ int irq;
+ void (* isr)(void*);
+ void* isr_data;
+ int trigger;
+ int count;
+ wait_queue_head_t wqh;
+} dal_isr_t;
+
+typedef struct dal_kernel_dev_s
+{
+ struct list_head list;
+ struct pci_dev* pci_dev;
+
+ /* PCI I/O mapped base address */
+ uintptr logic_address;
+
+ /* Physical address */
+ uintptr phys_address;
+} dal_kern_dev_t;
+
+typedef struct _dma_segment
+{
+ struct list_head list;
+ unsigned long req_size; /* Requested DMA segment size */
+ unsigned long blk_size; /* DMA block size */
+ unsigned long blk_order; /* DMA block size in alternate format */
+ unsigned long seg_size; /* Current DMA segment size */
+ unsigned long seg_begin; /* Logical address of segment */
+ unsigned long seg_end; /* Logical end address of segment */
+ unsigned long* blk_ptr; /* Array of logical DMA block addresses */
+ int blk_cnt_max; /* Maximum number of block to allocate */
+ int blk_cnt; /* Current number of blocks allocated */
+} dma_segment_t;
+
+typedef irqreturn_t (*p_func) (int irq, void* dev_id);
+
+/***************************************************************************
+ *declared
+ ***************************************************************************/
+static unsigned int linux_dal_poll0(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll1(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll2(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll3(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll4(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll5(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll6(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll7(struct file* filp, struct poll_table_struct* p);
+
+/*****************************************************************************
+ * global variables
+ *****************************************************************************/
+static dal_kern_dev_t dal_dev[DAL_MAX_CHIP_NUM];
+static dal_isr_t dal_isr[CTC_MAX_INTR_NUM];
+static int dal_chip_num = 0;
+static int dal_version = 0;
+static int dal_intr_num = 0;
+static int use_high_memory = 0;
+static unsigned int* dma_virt_base[DAL_MAX_CHIP_NUM];
+#ifndef DMA_MEM_MODE_PLATFORM
+static unsigned int* dma_virt_base_tmp[DAL_MAX_CHIP_NUM];
+#endif
+static uintptr dma_phy_base[DAL_MAX_CHIP_NUM];
+static unsigned int dma_mem_size = 0x800000;
+static unsigned int msi_irq_base[DAL_MAX_CHIP_NUM];
+static unsigned int msi_irq_num[DAL_MAX_CHIP_NUM];
+static unsigned int msi_used = 0;
+static struct class *dal_class;
+
+static LIST_HEAD(_dma_seg);
+static int dal_debug = 0;
+module_param(dal_debug, int, 0);
+MODULE_PARM_DESC(dal_debug, "Set debug level (default 0)");
+
+static struct pci_device_id dal_id_table[] =
+{
+ {PCI_DEVICE(CTC_VENDOR_VID, CTC_GREATBELT_DEVICE_ID)},
+ {PCI_DEVICE(0xcb10, 0xc010)},
+ {0, },
+};
+
+static wait_queue_head_t poll_intr[CTC_MAX_INTR_NUM];
+
+p_func intr_handler_fun[CTC_MAX_INTR_NUM];
+
+static int poll_intr_trigger[CTC_MAX_INTR_NUM];
+
+static struct file_operations dal_intr_fops[CTC_MAX_INTR_NUM] =
+{
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll0,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll1,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll2,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll3,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll4,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll5,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll6,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll7,
+ },
+};
+
+/*****************************************************************************
+ * macros
+ *****************************************************************************/
+#define VERIFY_CHIP_INDEX(n) (n < dal_chip_num)
+
+#define _KERNEL_INTERUPT_PROCESS
+static irqreturn_t
+intr0_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+
+ if(poll_intr_trigger[0])
+ {
+ return IRQ_HANDLED;
+ }
+
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[0] = 1;
+ wake_up(&poll_intr[0]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr1_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[1])
+ {
+ return IRQ_HANDLED;
+ }
+
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[1] = 1;
+ wake_up(&poll_intr[1]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr2_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[2])
+ {
+ return IRQ_HANDLED;
+ }
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[2] = 1;
+ wake_up(&poll_intr[2]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr3_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[3])
+ {
+ return IRQ_HANDLED;
+ }
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[3] = 1;
+ wake_up(&poll_intr[3]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr4_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[4])
+ {
+ return IRQ_HANDLED;
+ }
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[4] = 1;
+ wake_up(&poll_intr[4]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr5_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[5])
+ {
+ return IRQ_HANDLED;
+ }
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[5] = 1;
+ wake_up(&poll_intr[5]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr6_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[6])
+ {
+ return IRQ_HANDLED;
+ }
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[6] = 1;
+ wake_up(&poll_intr[6]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr7_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[7])
+ {
+ return IRQ_HANDLED;
+ }
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[7] = 1;
+ wake_up(&poll_intr[7]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+int
+dal_interrupt_register(unsigned int irq, int prio, void (* isr)(void*), void* data)
+{
+ int ret;
+ unsigned char str[16];
+ unsigned char* int_name = NULL;
+ unsigned int intr_num_tmp = 0;
+ unsigned int intr_num = CTC_MAX_INTR_NUM;
+ unsigned long irq_flags = 0;
+
+ if (dal_intr_num >= CTC_MAX_INTR_NUM)
+ {
+ printk("Interrupt numbers exceeds max.\n");
+ return -1;
+ }
+
+ if (msi_used)
+ {
+ int_name = "dal_msi";
+ }
+ else
+ {
+ int_name = "dal_intr";
+ }
+
+
+ for (intr_num_tmp=0;intr_num_tmp < CTC_MAX_INTR_NUM; intr_num_tmp++)
+ {
+ if (irq == dal_isr[intr_num_tmp].irq)
+ {
+ dal_isr[intr_num_tmp].count++;
+ printk("Interrupt irq %d register count %d.\n", irq, dal_isr[intr_num_tmp].count);
+ return 0;
+ }
+ if ((0 == dal_isr[intr_num_tmp].irq) && (CTC_MAX_INTR_NUM == intr_num))
+ {
+ intr_num = intr_num_tmp;
+ dal_isr[intr_num].count = 0;
+ }
+ }
+ dal_isr[intr_num].irq = irq;
+ dal_isr[intr_num].isr = isr;
+ dal_isr[intr_num].isr_data = data;
+ dal_isr[intr_num].count++;
+
+ init_waitqueue_head(&poll_intr[intr_num]);
+
+ /* only user mode */
+ if ((NULL == isr) && (NULL == data))
+ {
+ snprintf(str, 16, "%s%d", "dal_intr", intr_num);
+ ret = register_chrdev(DAL_DEV_INTR_MAJOR_BASE + intr_num,
+ str, &dal_intr_fops[intr_num]);
+ if (ret < 0)
+ {
+ printk("Register character device for irq %d failed, ret= %d", irq, ret);
+ return ret;
+ }
+ }
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
+ irq_flags = 0;
+#else
+ irq_flags = IRQF_DISABLED;
+#endif
+ if ((ret = request_irq(irq,
+ intr_handler_fun[intr_num],
+ irq_flags,
+ int_name,
+ &dal_isr[intr_num])) < 0)
+ {
+ printk("Cannot request irq %d, ret %d.\n", irq, ret);
+ unregister_chrdev(DAL_DEV_INTR_MAJOR_BASE + intr_num, str);
+ }
+
+ if (0 == ret)
+ {
+ dal_intr_num++;
+ }
+
+ return ret;
+}
+
+int
+dal_interrupt_unregister(unsigned int irq)
+{
+ unsigned char str[16];
+ int intr_idx = 0;
+ int find_flag = 0;
+
+ /* get intr device index */
+ for (intr_idx = 0; intr_idx < CTC_MAX_INTR_NUM; intr_idx++)
+ {
+ if (dal_isr[intr_idx].irq == irq)
+ {
+ find_flag = 1;
+ break;
+ }
+ }
+
+ if (find_flag == 0)
+ {
+ printk ("irq%d is not registered! unregister failed \n", irq);
+ return -1;
+ }
+
+ dal_isr[intr_idx].count--;
+ if (0 != dal_isr[intr_idx].count)
+ {
+ printk("Interrupt irq %d unregister count %d.\n", irq, dal_isr[intr_idx].count);
+ return -1;
+ }
+ snprintf(str, 16, "%s%d", "dal_intr", intr_idx);
+
+ unregister_chrdev(DAL_DEV_INTR_MAJOR_BASE + intr_idx, str);
+
+ free_irq(irq, &dal_isr[intr_idx]);
+
+ dal_isr[intr_idx].irq = 0;
+
+ dal_intr_num--;
+
+ return 0;
+}
+
+int
+dal_interrupt_set_en(unsigned int irq, unsigned int enable)
+{
+ enable ? enable_irq(irq) : disable_irq_nosync(irq);
+ return 0;
+}
+
+static int
+_dal_set_msi_enabe(unsigned int lchip, unsigned int irq_num)
+{
+ int ret = 0;
+
+ if (irq_num == 1)
+ {
+ ret = pci_enable_msi(dal_dev[lchip].pci_dev);
+ if (ret)
+ {
+ printk ("msi enable failed!!! lchip = %d, irq_num = %d\n", lchip, irq_num);
+ pci_disable_msi(dal_dev[lchip].pci_dev);
+ msi_used = 0;
+ }
+
+ msi_irq_base[lchip] = dal_dev[lchip].pci_dev->irq;
+ msi_irq_num[lchip] = 1;
+ }
+ else
+ {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 79))
+ ret = pci_enable_msi_exact(dal_dev[lchip].pci_dev, irq_num);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 26, 32))
+ ret = pci_enable_msi_block(dal_dev[lchip].pci_dev, irq_num);
+#else
+ ret = -1;
+#endif
+ if (ret)
+ {
+ printk ("msi enable failed!!! lchip = %d, irq_num = %d\n", lchip, irq_num);
+ pci_disable_msi(dal_dev[lchip].pci_dev);
+ msi_used = 0;
+ }
+
+ msi_irq_base[lchip] = dal_dev[lchip].pci_dev->irq;
+ msi_irq_num[lchip] = irq_num;
+ }
+
+ return ret;
+}
+
+static int
+_dal_set_msi_disable(unsigned int lchip)
+{
+
+ pci_disable_msi(dal_dev[lchip].pci_dev);
+
+ msi_irq_base[lchip] = 0;
+ msi_irq_num[lchip] = 0;
+
+ return 0;
+}
+
+int
+dal_set_msi_cap(unsigned long arg)
+{
+ int ret = 0;
+ dal_msi_info_t msi_info;
+
+ if (copy_from_user(&msi_info, (void*)arg, sizeof(dal_msi_info_t)))
+ {
+ return -EFAULT;
+ }
+
+ printk("####dal_set_msi_cap lchip %d base %d num:%d\n", msi_info.lchip, msi_info.irq_base, msi_info.irq_num);
+ if (msi_info.irq_num > 0)
+ {
+ msi_used = 1;
+ ret = _dal_set_msi_enabe(msi_info.lchip, msi_info.irq_num);
+ }
+ else
+ {
+ msi_used = 0;
+ ret = _dal_set_msi_disable(msi_info.lchip);
+ }
+
+ return ret;
+}
+
+int
+dal_user_interrupt_register(unsigned long arg)
+{
+ int irq = 0;
+ if (copy_from_user(&irq, (void*)arg, sizeof(int)))
+ {
+ return -EFAULT;
+ }
+ printk("####register interrupt irq:%d\n", irq);
+ return dal_interrupt_register(irq, 0, NULL, NULL);
+}
+
+int
+dal_user_interrupt_unregister(unsigned long arg)
+{
+ int irq = 0;
+ if (copy_from_user(&irq, (void*)arg, sizeof(int)))
+ {
+ return -EFAULT;
+ }
+ printk("####unregister interrupt irq:%d\n", irq);
+ return dal_interrupt_unregister(irq);
+}
+
+int
+dal_user_interrupt_set_en(unsigned long arg)
+{
+ dal_intr_parm_t dal_intr_parm;
+
+ if (copy_from_user(&dal_intr_parm, (void*)arg, sizeof(dal_intr_parm_t)))
+ {
+ return -EFAULT;
+ }
+
+ return dal_interrupt_set_en(dal_intr_parm.irq, dal_intr_parm.enable);
+}
+
+/*
+ * Function: _dal_dma_segment_free
+ */
+
+/*
+ * Function: _find_largest_segment
+ *
+ * Purpose:
+ * Find largest contiguous segment from a pool of DMA blocks.
+ * Parameters:
+ * dseg - DMA segment descriptor
+ * Returns:
+ * 0 on success, < 0 on error.
+ * Notes:
+ * Assembly stops if a segment of the requested segment size
+ * has been obtained.
+ *
+ * Lower address bits of the DMA blocks are used as follows:
+ * 0: Untagged
+ * 1: Discarded block
+ * 2: Part of largest contiguous segment
+ * 3: Part of current contiguous segment
+ */
+#ifndef DMA_MEM_MODE_PLATFORM
+static int
+_dal_find_largest_segment(dma_segment_t* dseg)
+{
+ int i, j, blks, found;
+ unsigned long seg_begin;
+ unsigned long seg_end;
+ unsigned long seg_tmp;
+
+ blks = dseg->blk_cnt;
+
+ /* Clear all block tags */
+ for (i = 0; i < blks; i++)
+ {
+ dseg->blk_ptr[i] &= ~3;
+ }
+
+ for (i = 0; i < blks && dseg->seg_size < dseg->req_size; i++)
+ {
+ /* First block must be an untagged block */
+ if ((dseg->blk_ptr[i] & 3) == DAL_UNTAG_BLOCK)
+ {
+ /* Initial segment size is the block size */
+ seg_begin = dseg->blk_ptr[i];
+ seg_end = seg_begin + dseg->blk_size;
+ dseg->blk_ptr[i] |= DAL_CUR_MATCH_BLOCk;
+
+ /* Loop looking for adjacent blocks */
+ do
+ {
+ found = 0;
+
+ for (j = i + 1; j < blks && (seg_end - seg_begin) < dseg->req_size; j++)
+ {
+ seg_tmp = dseg->blk_ptr[j];
+ /* Check untagged blocks only */
+ if ((seg_tmp & 3) == DAL_UNTAG_BLOCK)
+ {
+ if (seg_tmp == (seg_begin - dseg->blk_size))
+ {
+ /* Found adjacent block below current segment */
+ dseg->blk_ptr[j] |= DAL_CUR_MATCH_BLOCk;
+ seg_begin = seg_tmp;
+ found = 1;
+ }
+ else if (seg_tmp == seg_end)
+ {
+ /* Found adjacent block above current segment */
+ dseg->blk_ptr[j] |= DAL_CUR_MATCH_BLOCk;
+ seg_end += dseg->blk_size;
+ found = 1;
+ }
+ }
+ }
+ }
+ while (found);
+
+ if ((seg_end - seg_begin) > dseg->seg_size)
+ {
+ /* The current block is largest so far */
+ dseg->seg_begin = seg_begin;
+ dseg->seg_end = seg_end;
+ dseg->seg_size = seg_end - seg_begin;
+
+ /* Re-tag current and previous largest segment */
+ for (j = 0; j < blks; j++)
+ {
+ if ((dseg->blk_ptr[j] & 3) == DAL_CUR_MATCH_BLOCk)
+ {
+ /* Tag current segment as the largest */
+ dseg->blk_ptr[j] &= ~1;
+ }
+ else if ((dseg->blk_ptr[j] & 3) == DAL_MATCHED_BLOCK)
+ {
+ /* Discard previous largest segment */
+ dseg->blk_ptr[j] ^= 3;
+ }
+ }
+ }
+ else
+ {
+ /* Discard all blocks in current segment */
+ for (j = 0; j < blks; j++)
+ {
+ if ((dseg->blk_ptr[j] & 3) == DAL_CUR_MATCH_BLOCk)
+ {
+ dseg->blk_ptr[j] &= ~2;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Function: _alloc_dma_blocks
+ */
+static int
+_dal_alloc_dma_blocks(dma_segment_t* dseg, int blks)
+{
+ int i, start;
+ unsigned long addr;
+
+ if (dseg->blk_cnt + blks > dseg->blk_cnt_max)
+ {
+ printk("No more DMA blocks\n");
+ return -1;
+ }
+
+ start = dseg->blk_cnt;
+ dseg->blk_cnt += blks;
+
+ for (i = start; i < dseg->blk_cnt; i++)
+ {
+ addr = __get_free_pages(GFP_ATOMIC, dseg->blk_order);
+ if (addr)
+ {
+ dseg->blk_ptr[i] = addr;
+ }
+ else
+ {
+ printk("DMA allocation failed\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Function: _dal_dma_segment_alloc
+ */
+static dma_segment_t*
+_dal_dma_segment_alloc(unsigned int size, unsigned int blk_size)
+{
+ dma_segment_t* dseg;
+ int i, blk_ptr_size;
+ unsigned long page_addr;
+ struct sysinfo si;
+
+ /* Sanity check */
+ if (size == 0 || blk_size == 0)
+ {
+ return NULL;
+ }
+
+ /* Allocate an initialize DMA segment descriptor */
+ if ((dseg = kmalloc(sizeof(dma_segment_t), GFP_ATOMIC)) == NULL)
+ {
+ return NULL;
+ }
+
+ memset(dseg, 0, sizeof(dma_segment_t));
+ dseg->req_size = size;
+ dseg->blk_size = PAGE_ALIGN(blk_size);
+
+ while ((PAGE_SIZE << dseg->blk_order) < dseg->blk_size)
+ {
+ dseg->blk_order++;
+ }
+
+ si_meminfo(&si);
+ dseg->blk_cnt_max = (si.totalram << PAGE_SHIFT) / dseg->blk_size;
+ blk_ptr_size = dseg->blk_cnt_max * sizeof(unsigned long);
+ /* Allocate an initialize DMA block pool */
+ dseg->blk_ptr = kmalloc(blk_ptr_size, GFP_KERNEL);
+ if (dseg->blk_ptr == NULL)
+ {
+ kfree(dseg);
+ return NULL;
+ }
+
+ memset(dseg->blk_ptr, 0, blk_ptr_size);
+ /* Allocate minimum number of blocks */
+ _dal_alloc_dma_blocks(dseg, dseg->req_size / dseg->blk_size);
+
+ /* Allocate more blocks until we have a complete segment */
+ do
+ {
+ _dal_find_largest_segment(dseg);
+ if (dseg->seg_size >= dseg->req_size)
+ {
+ break;
+ }
+ }
+ while (_dal_alloc_dma_blocks(dseg, 8) == 0);
+
+ /* Reserve all pages in the DMA segment and free unused blocks */
+ for (i = 0; i < dseg->blk_cnt; i++)
+ {
+ if ((dseg->blk_ptr[i] & 3) == 2)
+ {
+ dseg->blk_ptr[i] &= ~3;
+
+ for (page_addr = dseg->blk_ptr[i];
+ page_addr < dseg->blk_ptr[i] + dseg->blk_size;
+ page_addr += PAGE_SIZE)
+ {
+ MEM_MAP_RESERVE(VIRT_TO_PAGE((void*)page_addr));
+ }
+ }
+ else if (dseg->blk_ptr[i])
+ {
+ dseg->blk_ptr[i] &= ~3;
+ free_pages(dseg->blk_ptr[i], dseg->blk_order);
+ dseg->blk_ptr[i] = 0;
+ }
+ }
+
+ return dseg;
+}
+
+/*
+ * Function: _dal_dma_segment_free
+ */
+static void
+_dal_dma_segment_free(dma_segment_t* dseg)
+{
+ int i;
+ unsigned long page_addr;
+
+ if (dseg->blk_ptr)
+ {
+ for (i = 0; i < dseg->blk_cnt; i++)
+ {
+ if (dseg->blk_ptr[i])
+ {
+ for (page_addr = dseg->blk_ptr[i];
+ page_addr < dseg->blk_ptr[i] + dseg->blk_size;
+ page_addr += PAGE_SIZE)
+ {
+ MEM_MAP_UNRESERVE(VIRT_TO_PAGE(page_addr));
+ }
+
+ free_pages(dseg->blk_ptr[i], dseg->blk_order);
+ }
+ }
+
+ kfree(dseg->blk_ptr);
+ kfree(dseg);
+ }
+}
+
+/*
+ * Function: -dal_pgalloc
+ */
+static void*
+_dal_pgalloc(unsigned int size)
+{
+ dma_segment_t* dseg;
+ unsigned int blk_size;
+
+ blk_size = (size < DMA_BLOCK_SIZE) ? size : DMA_BLOCK_SIZE;
+ if ((dseg = _dal_dma_segment_alloc(size, blk_size)) == NULL)
+ {
+ return NULL;
+ }
+
+ if (dseg->seg_size < size)
+ {
+ /* If we didn't get the full size then forget it */
+ printk("Notice: Can not get enough memory for requset!!\n");
+ printk("actual size:0x%lx, request size:0x%x\n", dseg->seg_size, size);
+ //-_dal_dma_segment_free(dseg);
+ //-return NULL;
+ }
+
+ list_add(&dseg->list, &_dma_seg);
+ return (void*)dseg->seg_begin;
+}
+
+/*
+ * Function: _dal_pgfree
+ */
+static int
+_dal_pgfree(void* ptr)
+{
+ struct list_head* pos;
+
+ list_for_each(pos, &_dma_seg)
+ {
+ dma_segment_t* dseg = list_entry(pos, dma_segment_t, list);
+ if (ptr == (void*)dseg->seg_begin)
+ {
+ list_del(&dseg->list);
+ _dal_dma_segment_free(dseg);
+ return 0;
+ }
+ }
+ return -1;
+}
+#endif
+static void
+dal_alloc_dma_pool(int lchip, int size)
+{
+ if (use_high_memory)
+ {
+ dma_phy_base[lchip] = virt_to_bus(high_memory);
+ dma_virt_base[lchip] = ioremap_nocache(dma_phy_base[lchip], size);
+ }
+ else
+ {
+#ifdef DMA_MEM_MODE_PLATFORM
+ dma_virt_base[lchip] = dma_alloc_coherent(&(dal_dev[lchip].pci_dev->dev), dma_mem_size,
+ &dma_phy_base[lchip], GFP_KERNEL);
+
+ printk(KERN_WARNING "########Using DMA_MEM_MODE_PLATFORM \n");
+#endif
+
+#ifndef DMA_MEM_MODE_PLATFORM
+ /* Get DMA memory from kernel */
+ dma_virt_base_tmp[lchip] = _dal_pgalloc(size);
+ dma_phy_base[lchip] = virt_to_bus(dma_virt_base_tmp[lchip]);
+ dma_virt_base [lchip]= ioremap_nocache(dma_phy_base[lchip], size);
+#endif
+ }
+}
+
+static void
+dal_free_dma_pool(int lchip)
+{
+ int ret = 0;
+ ret = ret;
+ if (use_high_memory)
+ {
+ iounmap(dma_virt_base[lchip]);
+ }
+ else
+ {
+#ifdef DMA_MEM_MODE_PLATFORM
+ dma_free_coherent(&(dal_dev[lchip].pci_dev->dev), dma_mem_size,
+ dma_virt_base[lchip], dma_phy_base[lchip]);
+#endif
+
+#ifndef DMA_MEM_MODE_PLATFORM
+ iounmap(dma_virt_base[lchip]);
+ ret = _dal_pgfree(dma_virt_base_tmp[lchip]);
+ if(ret<0)
+ {
+ printk("Dma free memory fail !!!!!! \n");
+ }
+#endif
+ }
+}
+
+#define _KERNEL_DAL_IO
+static int
+_dal_pci_read(unsigned char lchip, unsigned int offset, unsigned int* value)
+{
+ if (!VERIFY_CHIP_INDEX(lchip))
+ {
+ return -1;
+ }
+
+ *value = *(volatile unsigned int*)(dal_dev[lchip].logic_address + offset);
+ return 0;
+}
+
+int
+dal_create_irq_mapping(unsigned long arg)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
+ dal_irq_mapping_t irq_map;
+
+ if (copy_from_user(&irq_map, (void*)arg, sizeof(dal_irq_mapping_t)))
+ {
+ return -EFAULT;
+ }
+
+ irq_map.sw_irq = irq_create_mapping(NULL, irq_map.hw_irq);
+ if (irq_map.sw_irq == NO_IRQ)
+ {
+ printk("IRQ mapping fail !!!!!! \n");
+ return -1;
+ }
+
+ if (copy_to_user((dal_irq_mapping_t*)arg, (void*)&irq_map, sizeof(dal_irq_mapping_t)))
+ {
+ return -EFAULT;
+ }
+#endif
+ return 0;
+}
+
+int
+dal_pci_read(unsigned long arg)
+{
+ dal_chip_parm_t cmdpara_chip;
+
+ if (copy_from_user(&cmdpara_chip, (void*)arg, sizeof(dal_chip_parm_t)))
+ {
+ return -EFAULT;
+ }
+
+ _dal_pci_read((unsigned char)cmdpara_chip.chip_id, (unsigned int)cmdpara_chip.reg_addr,
+ (unsigned int*)(&(cmdpara_chip.value)));
+
+ if (copy_to_user((dal_chip_parm_t*)arg, (void*)&cmdpara_chip, sizeof(dal_chip_parm_t)))
+ {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int
+_dal_pci_write(unsigned char lchip, unsigned int offset, unsigned int value)
+{
+ if (!VERIFY_CHIP_INDEX(lchip))
+ {
+ return -1;
+ }
+
+ *(volatile unsigned int*)(dal_dev[lchip].logic_address + offset) = value;
+ return 0;
+}
+
+int
+dal_pci_write(unsigned long arg)
+{
+ dal_chip_parm_t cmdpara_chip;
+
+ if (copy_from_user(&cmdpara_chip, (void*)arg, sizeof(dal_chip_parm_t)))
+ {
+ return -EFAULT;
+ }
+
+ _dal_pci_write((unsigned char)cmdpara_chip.chip_id, (unsigned int)cmdpara_chip.reg_addr,
+ (unsigned int)cmdpara_chip.value);
+
+ return 0;
+}
+
+int
+dal_pci_conf_read(unsigned char lchip, unsigned int offset, unsigned int* value)
+{
+ if (!VERIFY_CHIP_INDEX(lchip))
+ {
+ return -1;
+ }
+
+ pci_read_config_dword(dal_dev[lchip].pci_dev, offset, value);
+ return 0;
+}
+
+int
+dal_pci_conf_write(unsigned char lchip, unsigned int offset, unsigned int value)
+{
+ if (!VERIFY_CHIP_INDEX(lchip))
+ {
+ return -1;
+ }
+
+ pci_write_config_dword(dal_dev[lchip].pci_dev, offset, value);
+ return 0;
+}
+int
+dal_user_read_pci_conf(unsigned long arg)
+{
+ dal_pci_cfg_ioctl_t dal_cfg;
+
+ if (copy_from_user(&dal_cfg, (void*)arg, sizeof(dal_pci_cfg_ioctl_t)))
+ {
+ return -EFAULT;
+ }
+
+ if (dal_pci_conf_read(dal_cfg.chip_id, dal_cfg.offset, &dal_cfg.value))
+ {
+ printk("dal_pci_conf_read failed.\n");
+ return -EFAULT;
+ }
+
+ if (copy_to_user((dal_pci_cfg_ioctl_t*)arg, (void*)&dal_cfg, sizeof(dal_pci_cfg_ioctl_t)))
+ {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int
+dal_user_write_pci_conf(unsigned long arg)
+{
+ dal_pci_cfg_ioctl_t dal_cfg;
+
+ if (copy_from_user(&dal_cfg, (void*)arg, sizeof(dal_pci_cfg_ioctl_t)))
+ {
+ return -EFAULT;
+ }
+
+ return dal_pci_conf_write(dal_cfg.chip_id, dal_cfg.offset, dal_cfg.value);
+}
+
+static int
+linux_get_device(unsigned long arg)
+{
+ dal_user_dev_t user_dev;
+ int chip_id = 0;
+
+ if (copy_from_user(&user_dev, (void*)arg, sizeof(user_dev)))
+ {
+ return -EFAULT;
+ }
+
+ user_dev.chip_num = dal_chip_num;
+ chip_id = user_dev.chip_id;
+
+ if (chip_id < dal_chip_num)
+ {
+ user_dev.phy_base0 = (unsigned int)dal_dev[chip_id].phys_address;
+ #ifdef PHYS_ADDR_IS_64BIT
+ user_dev.phy_base1 = (unsigned int)(dal_dev[chip_id].phys_address >> 32);
+ #else
+ user_dev.phy_base1 = 0;
+ #endif
+
+ user_dev.bus_no = dal_dev[chip_id].pci_dev->bus->number;
+ user_dev.dev_no = dal_dev[chip_id].pci_dev->device;
+ user_dev.fun_no = dal_dev[chip_id].pci_dev->devfn;
+ }
+
+ if (copy_to_user((dal_user_dev_t*)arg, (void*)&user_dev, sizeof(user_dev)))
+ {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/* set dal version, copy to user */
+static int
+linux_get_dal_version(unsigned long arg)
+{
+ int dal_ver = VERSION_1DOT2; /* set dal version */
+
+ if (copy_to_user((int*)arg, (void*)&dal_ver, sizeof(dal_ver)))
+ {
+ return -EFAULT;
+ }
+
+ dal_version = dal_ver; /* up sw */
+
+ return 0;
+}
+
+static int
+linux_get_dma_info(unsigned long arg)
+{
+ dma_info_t dma_para;
+
+ if (copy_from_user(&dma_para, (void*)arg, sizeof(dma_info_t)))
+ {
+ return -EFAULT;
+ }
+
+ dma_para.phy_base = (unsigned int)dma_phy_base[dma_para.lchip];
+ #ifdef PHYS_ADDR_IS_64BIT
+ dma_para.phy_base_hi = dma_phy_base[dma_para.lchip] >> 32;
+ #else
+ dma_para.phy_base_hi = 0;
+ #endif
+ dma_para.size = dma_mem_size;
+
+ if (copy_to_user((dma_info_t*)arg, (void*)&dma_para, sizeof(dma_info_t)))
+ {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int
+dal_get_msi_info(unsigned long arg)
+{
+ dal_msi_info_t msi_para;
+ unsigned int lchip = 0;
+
+ /* get lchip form user mode */
+ if (copy_from_user(&msi_para, (void*)arg, sizeof(dal_msi_info_t)))
+ {
+ return -EFAULT;
+ }
+ lchip = msi_para.lchip;
+
+ msi_para.irq_base = msi_irq_base[lchip];
+ msi_para.irq_num = msi_irq_num[lchip];
+
+ /* send msi info to user mode */
+ if (copy_to_user((dal_msi_info_t*)arg, (void*)&msi_para, sizeof(dal_msi_info_t)))
+ {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+
+static int
+dal_get_intr_info(unsigned long arg)
+{
+ dal_intr_info_t intr_para;
+ unsigned int intr_num = 0;
+
+ /* get lchip form user mode */
+ if (copy_from_user(&intr_para, (void*)arg, sizeof(dal_intr_info_t)))
+ {
+ return -EFAULT;
+ }
+
+ intr_para.irq_idx = CTC_MAX_INTR_NUM;
+ for (intr_num=0; intr_num< CTC_MAX_INTR_NUM; intr_num++)
+ {
+ if (intr_para.irq == dal_isr[intr_num].irq)
+ {
+ intr_para.irq_idx = intr_num;
+ break;
+ }
+ }
+
+ if (CTC_MAX_INTR_NUM == intr_para.irq_idx)
+ {
+ printk("Interrupt %d cann't find.\n", intr_para.irq);
+ }
+ /* send msi info to user mode */
+ if (copy_to_user((dal_intr_info_t*)arg, (void*)&intr_para, sizeof(dal_intr_info_t)))
+ {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int
+dal_cache_inval(unsigned long arg)
+{
+ dal_dma_cache_info_t intr_para;
+
+ if (copy_from_user(&intr_para, (void*)arg, sizeof(dal_dma_cache_info_t)))
+ {
+ return -EFAULT;
+ }
+
+#if 0
+ dma_cache_wback_inv((unsigned long)intr_para.ptr, intr_para.length);
+#endif
+
+#if 0
+ dma_sync_single_for_cpu(NULL, intr_para.ptr, intr_para.length, DMA_BIDIRECTIONAL);
+#endif
+
+ dma_cache_sync(NULL, (void*)intr_para.ptr, intr_para.length, DMA_BIDIRECTIONAL);
+
+ return 0;
+}
+
+static int
+dal_cache_flush(unsigned long arg)
+{
+ dal_dma_cache_info_t intr_para;
+
+ if (copy_from_user(&intr_para, (void*)arg, sizeof(dal_dma_cache_info_t)))
+ {
+ return -EFAULT;
+ }
+
+#if 0
+ dma_cache_wback_inv(intr_para.ptr, intr_para.length);
+#endif
+
+#if 0
+ dma_sync_single_for_cpu(NULL, intr_para.ptr, intr_para.length, DMA_BIDIRECTIONAL);
+#endif
+
+ dma_cache_sync(NULL, (void*)intr_para.ptr, intr_para.length, DMA_BIDIRECTIONAL);
+
+ return 0;
+}
+
+int
+linux_dal_probe(struct pci_dev* pdev, const struct pci_device_id* id)
+{
+ dal_kern_dev_t* dev = NULL;
+ int bar = 0;
+ int ret = 0;
+ unsigned int temp = 0;
+ unsigned int lchip = 0;
+ unsigned int chip_id = 0;
+
+ printk(KERN_WARNING "********found dal device*****\n");
+
+ for (chip_id = 0; chip_id < DAL_MAX_CHIP_NUM; chip_id ++)
+ {
+ if (NULL == dal_dev[chip_id].pci_dev)
+ {
+ break;
+ }
+ }
+
+ if (chip_id >= DAL_MAX_CHIP_NUM)
+ {
+ printk("Exceed max local chip num\n");
+ return -1;
+ }
+
+ dev = &dal_dev[chip_id];
+ if (NULL == dev)
+ {
+ printk("Cannot obtain PCI resources\n");
+ }
+
+ lchip = chip_id;
+ dal_chip_num += 1;
+
+ dev->pci_dev = pdev;
+
+ if (pci_enable_device(pdev) < 0)
+ {
+ printk("Cannot enable PCI device: vendor id = %x, device id = %x\n",
+ pdev->vendor, pdev->device);
+ }
+
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (ret)
+ {
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret)
+ {
+ printk("Could not set PCI DMA Mask\n");
+ return ret;
+ }
+ }
+
+ if (pci_request_regions(pdev, DAL_NAME) < 0)
+ {
+ printk("Cannot obtain PCI resources\n");
+ }
+
+ dev->phys_address = pci_resource_start(pdev, bar);
+ dev->logic_address = (uintptr)ioremap_nocache(dev->phys_address,
+ pci_resource_len(dev->pci_dev, bar));
+
+ _dal_pci_read(lchip, 0x48, &temp);
+ if (((temp >> 8) & 0xffff) == 0x3412)
+ {
+ printk("Little endian Cpu detected!!! \n");
+ _dal_pci_write(lchip, 0x48, 0xFFFFFFFF);
+ }
+
+ pci_set_master(pdev);
+
+ /* alloc dma_mem_size for every chip */
+ if (dma_mem_size)
+ {
+ dal_alloc_dma_pool(lchip, dma_mem_size);
+ #ifdef PHYS_ADDR_IS_64BIT
+
+ /*add check Dma memory pool cannot cross 4G space*/
+ if ((0==(dma_phy_base[lchip]>>32)) && (0!=((dma_phy_base[lchip]+dma_mem_size)>>32)))
+ {
+ printk("Dma malloc memory cross 4G space!!!!!! \n");
+ return -1;
+ }
+ #endif
+ }
+
+ printk(KERN_WARNING "linux_dal_probe end*****\n");
+
+ return 0;
+}
+
+void
+linux_dal_remove(struct pci_dev* pdev)
+{
+ unsigned int chip_id = 0;
+ unsigned int flag = 0;
+
+ for (chip_id = 0; chip_id < DAL_MAX_CHIP_NUM; chip_id ++)
+ {
+ if (pdev == dal_dev[chip_id].pci_dev)
+ {
+ flag = 1;
+ break;
+ }
+ }
+
+ if (1 == flag)
+ {
+ dal_free_dma_pool(chip_id);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+
+ dal_dev[chip_id].pci_dev = NULL;
+ dal_chip_num--;
+ }
+
+
+}
+
+#ifdef CONFIG_COMPAT
+static long
+linux_dal_ioctl(struct file* file,
+ unsigned int cmd, unsigned long arg)
+#else
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 13))
+static int
+linux_dal_ioctl(struct file* file,
+ unsigned int cmd, unsigned long arg)
+#else
+static int
+linux_dal_ioctl(struct inode* inode, struct file* file,
+ unsigned int cmd, unsigned long arg)
+#endif
+
+#endif
+{
+ switch (cmd)
+ {
+
+ case CMD_READ_CHIP:
+ return dal_pci_read(arg);
+
+ case CMD_WRITE_CHIP:
+ return dal_pci_write(arg);
+
+ case CMD_GET_DEVICES:
+ return linux_get_device(arg);
+
+ case CMD_GET_DAL_VERSION:
+ return linux_get_dal_version(arg);
+
+ case CMD_GET_DMA_INFO:
+ return linux_get_dma_info(arg);
+
+ case CMD_PCI_CONFIG_READ:
+ return dal_user_read_pci_conf(arg);
+
+ case CMD_PCI_CONFIG_WRITE:
+ return dal_user_write_pci_conf(arg);
+
+ case CMD_REG_INTERRUPTS:
+ return dal_user_interrupt_register(arg);
+
+ case CMD_UNREG_INTERRUPTS:
+ return dal_user_interrupt_unregister(arg);
+
+ case CMD_EN_INTERRUPTS:
+ return dal_user_interrupt_set_en(arg);
+
+ case CMD_SET_MSI_CAP:
+ return dal_set_msi_cap(arg);
+
+ case CMD_GET_MSI_INFO:
+ return dal_get_msi_info(arg);
+
+ case CMD_IRQ_MAPPING:
+ return dal_create_irq_mapping(arg);
+
+ case CMD_GET_INTR_INFO:
+ return dal_get_intr_info(arg);
+
+ case CMD_CACHE_INVAL:
+ return dal_cache_inval(arg);
+
+ case CMD_CACHE_FLUSH:
+ return dal_cache_flush(arg);
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static unsigned int
+linux_dal_poll0(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[0], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[0])
+ {
+ poll_intr_trigger[0] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll1(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[1], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[1])
+ {
+ poll_intr_trigger[1] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll2(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[2], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[2])
+ {
+ poll_intr_trigger[2] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll3(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[3], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[3])
+ {
+ poll_intr_trigger[3] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll4(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[4], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[4])
+ {
+ poll_intr_trigger[4] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll5(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[5], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[5])
+ {
+ poll_intr_trigger[5] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll6(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[6], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[6])
+ {
+ poll_intr_trigger[6] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll7(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[7], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[7])
+ {
+ poll_intr_trigger[7] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static struct pci_driver linux_dal_driver =
+{
+ .name = DAL_NAME,
+ .id_table = dal_id_table,
+ .probe = linux_dal_probe,
+ .remove = linux_dal_remove,
+};
+
+static struct file_operations fops =
+{
+ .owner = THIS_MODULE,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = linux_dal_ioctl,
+ .unlocked_ioctl = linux_dal_ioctl,
+#else
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))
+ .unlocked_ioctl = linux_dal_ioctl,
+#else
+ .ioctl = linux_dal_ioctl,
+#endif
+#endif
+};
+
+
+static int __init
+linux_dal_init(void)
+{
+ int ret = 0;
+
+ /* Get DMA memory pool size form dal.ok input param, or use default dma_mem_size */
+ if (dma_pool_size)
+ {
+ if ((dma_pool_size[strlen(dma_pool_size) - 1] & ~0x20) == 'M')
+ {
+ dma_mem_size = simple_strtoul(dma_pool_size, NULL, 0);
+ printk("dma_mem_size: 0x%x \n", dma_mem_size);
+
+ dma_mem_size *= MB_SIZE;
+ }
+ else
+ {
+ printk("DMA memory pool size must be specified as e.g. dma_pool_size=8M\n");
+ }
+
+ if (dma_mem_size & (dma_mem_size - 1))
+ {
+ printk("dma_mem_size must be a power of 2 (1M, 2M, 4M, 8M etc.)\n");
+ dma_mem_size = 0;
+ }
+ }
+
+ ret = register_chrdev(DAL_DEV_MAJOR, DAL_NAME, &fops);
+ if (ret < 0)
+ {
+ printk(KERN_WARNING "Register linux_dal device, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = pci_register_driver(&linux_dal_driver);
+ if (ret < 0)
+ {
+ printk(KERN_WARNING "Register ASIC PCI driver failed, ret %d\n", ret);
+ return ret;
+ }
+
+ /* alloc /dev/linux_dal node */
+ dal_class = class_create(THIS_MODULE, DAL_NAME);
+ device_create(dal_class, NULL, MKDEV(DAL_DEV_MAJOR, 0), NULL, DAL_NAME);
+
+ /* init interrupt function */
+ intr_handler_fun[0] = intr0_handler;
+ intr_handler_fun[1] = intr1_handler;
+ intr_handler_fun[2] = intr2_handler;
+ intr_handler_fun[3] = intr3_handler;
+ intr_handler_fun[4] = intr4_handler;
+ intr_handler_fun[5] = intr5_handler;
+ intr_handler_fun[6] = intr6_handler;
+ intr_handler_fun[7] = intr7_handler;
+
+ return ret;
+}
+
+static void __exit
+linux_dal_exit(void)
+{
+ device_destroy(dal_class, MKDEV(DAL_DEV_MAJOR, 0));
+ class_destroy(dal_class);
+ unregister_chrdev(DAL_DEV_MAJOR, "linux_dal");
+ pci_unregister_driver(&linux_dal_driver);
+}
+
+module_init(linux_dal_init);
+module_exit(linux_dal_exit);
+
diff --git a/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/dal_kernel.h b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/dal_kernel.h
new file mode 100644
index 0000000000..de39af6777
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/dal_kernel.h
@@ -0,0 +1,170 @@
+/**
+ @file dal_kernel_io.h
+
+ @author Copyright (C) 2012 Centec Networks Inc. All rights reserved.
+
+ @date 2012-4-9
+
+ @version v2.0
+
+*/
+#ifndef _DAL_KERNEL_H_
+#define _DAL_KERNEL_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(CONFIG_RESOURCES_64BIT) || defined(CONFIG_PHYS_ADDR_T_64BIT)
+#define PHYS_ADDR_IS_64BIT
+#endif
+
+#ifndef SDK_IN_USERMODE
+#ifdef PHYS_ADDR_IS_64BIT
+typedef long long intptr;
+typedef unsigned long long uintptr;
+#else
+typedef int intptr;
+typedef unsigned int uintptr;
+#endif
+#endif
+
+#define DAL_PCI_READ_ADDR 0x0
+#define DAL_PCI_READ_DATA 0xc
+#define DAL_PCI_WRITE_ADDR 0x8
+#define DAL_PCI_WRITE_DATA 0x4
+#define DAL_PCI_STATUS 0x10
+
+#define DAL_PCI_STATUS_IN_PROCESS 31
+#define DAL_PCI_STATUS_BAD_PARITY 5
+#define DAL_PCI_STATUS_CPU_ACCESS_ERR 4
+#define DAL_PCI_STATUS_READ_CMD 3
+#define DAL_PCI_STATUS_REGISTER_ERR 1
+#define DAL_PCI_STATUS_REGISTER_ACK 0
+
+#define DAL_PCI_ACCESS_TIMEOUT 0x64
+
+#define DAL_NAME "linux_dal" /* "linux_dal" */
+
+#define DAL_DEV_MAJOR 198
+
+#define DAL_DEV_INTR_MAJOR_BASE 200
+
+#define DAL_DEV_NAME "/dev/" DAL_NAME
+#define DAL_ONE_KB 1024
+#define DAL_ONE_MB (1024*1024)
+struct dal_chip_parm_s
+{
+ unsigned int chip_id; /*tmp should be uint8*/
+ unsigned int fpga_id; /*tmp add*/
+ unsigned int reg_addr;
+ unsigned int value;
+};
+typedef struct dal_chip_parm_s dal_chip_parm_t;
+
+struct dal_intr_parm_s
+{
+ unsigned int irq;
+ unsigned int enable;
+};
+typedef struct dal_intr_parm_s dal_intr_parm_t;
+
+struct dal_irq_mapping_s
+{
+ unsigned int hw_irq;
+ unsigned int sw_irq;
+};
+typedef struct dal_irq_mapping_s dal_irq_mapping_t;
+
+struct dal_user_dev_s
+{
+ unsigned int chip_num; /*output: local chip number*/
+ unsigned int chip_id; /*input: local chip id*/
+ unsigned int phy_base0; /* low 32bits physical base address */
+ unsigned int phy_base1; /* high 32bits physical base address */
+ unsigned int bus_no;
+ unsigned int dev_no;
+ unsigned int fun_no;
+ void* virt_base[2]; /* Virtual base address; this must be last member */
+};
+typedef struct dal_user_dev_s dal_user_dev_t;
+
+struct dma_info_s
+{
+ unsigned int lchip;
+ unsigned int phy_base;
+ unsigned int phy_base_hi;
+ unsigned int size;
+ unsigned int* virt_base;
+};
+typedef struct dma_info_s dma_info_t;
+
+struct dal_pci_cfg_ioctl_s
+{
+ unsigned int chip_id; /* Device ID */
+ unsigned int offset;
+ unsigned int value;
+};
+typedef struct dal_pci_cfg_ioctl_s dal_pci_cfg_ioctl_t;
+
+struct dal_msi_info_s
+{
+ unsigned int lchip;
+ unsigned int irq_base;
+ unsigned int irq_num;
+};
+typedef struct dal_msi_info_s dal_msi_info_t;
+
+struct dal_intr_info_s
+{
+ unsigned int irq;
+ unsigned int irq_idx;
+};
+typedef struct dal_intr_info_s dal_intr_info_t;
+
+struct dal_dma_cache_info_s
+{
+ unsigned long ptr;
+ unsigned int length;
+};
+typedef struct dal_dma_cache_info_s dal_dma_cache_info_t;
+
+#define CMD_MAGIC 'C'
+#define CMD_WRITE_CHIP _IO(CMD_MAGIC, 0) /* for humber ioctrol*/
+#define CMD_READ_CHIP _IO(CMD_MAGIC, 1) /* for humber ioctrol*/
+#define CMD_GET_DEVICES _IO(CMD_MAGIC, 2)
+#define CMD_GET_DAL_VERSION _IO(CMD_MAGIC, 3)
+#define CMD_PCI_CONFIG_WRITE _IO(CMD_MAGIC, 4)
+#define CMD_PCI_CONFIG_READ _IO(CMD_MAGIC, 5)
+#define CMD_GET_DMA_INFO _IO(CMD_MAGIC, 6)
+#define CMD_REG_INTERRUPTS _IO(CMD_MAGIC, 7)
+#define CMD_UNREG_INTERRUPTS _IO(CMD_MAGIC, 8)
+#define CMD_EN_INTERRUPTS _IO(CMD_MAGIC, 9)
+#define CMD_I2C_READ _IO(CMD_MAGIC, 10)
+#define CMD_I2C_WRITE _IO(CMD_MAGIC, 11)
+#define CMD_GET_MSI_INFO _IO(CMD_MAGIC, 12)
+#define CMD_SET_MSI_CAP _IO(CMD_MAGIC, 13)
+#define CMD_IRQ_MAPPING _IO(CMD_MAGIC, 14)
+#define CMD_GET_INTR_INFO _IO(CMD_MAGIC, 15)
+#define CMD_CACHE_INVAL _IO(CMD_MAGIC, 16)
+#define CMD_CACHE_FLUSH _IO(CMD_MAGIC, 17)
+
+enum dal_version_e
+{
+ VERSION_MIN,
+ VERSION_1DOT0,
+ VERSION_1DOT1,
+ VERSION_1DOT2,
+
+ VERSION_MAX
+};
+typedef enum dal_version_e dal_version_t;
+
+/* We try to assemble a contiguous segment from chunks of this size */
+#define DMA_BLOCK_SIZE (512 * DAL_ONE_KB)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/dal_mpool.c b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/dal_mpool.c
new file mode 100644
index 0000000000..82d3b7a917
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/dal_mpool.c
@@ -0,0 +1,343 @@
+
+#include "dal_mpool.h"
+
+#ifdef __KERNEL__
+#include
+#include
+
+#define DAL_MALLOC(x) kmalloc(x, GFP_ATOMIC)
+#define DAL_FREE(x) kfree(x)
+
+static spinlock_t dal_mpool_lock;
+#define MPOOL_LOCK_INIT() spin_lock_init(&dal_mpool_lock)
+#define MPOOL_LOCK() unsigned long flags; spin_lock_irqsave(&dal_mpool_lock, flags)
+#define MPOOL_UNLOCK() spin_unlock_irqrestore(&dal_mpool_lock, flags)
+#define DAL_PRINT(fmt,arg...) printk(fmt,##arg)
+#else /* !__KERNEL__*/
+
+#include
+#include "sal.h"
+#define DAL_MALLOC(x) malloc(x)
+#define DAL_FREE(x) free(x)
+static sal_mutex_t* dal_mpool_lock;
+#define MPOOL_LOCK_INIT() sal_mutex_create(&dal_mpool_lock)
+#define MPOOL_LOCK() sal_mutex_lock(dal_mpool_lock)
+#define MPOOL_UNLOCK() sal_mutex_unlock(dal_mpool_lock)
+#define DAL_PRINT(fmt,arg...) sal_printf(fmt,##arg)
+
+#endif /* __KERNEL__ */
+
+dal_mpool_mem_t* g_free_block_ptr = NULL;
+
+/* System cache line size */
+#ifndef DAL_CACHE_LINE_BYTES
+#define DAL_CACHE_LINE_BYTES 256
+#endif
+
+static dal_mpool_mem_t* p_desc_pool = NULL;
+static dal_mpool_mem_t* p_data_pool = NULL;
+
+int
+dal_mpool_init(void)
+{
+ MPOOL_LOCK_INIT();
+ return 0;
+}
+
+dal_mpool_mem_t*
+_dal_mpool_create(void* base, int size, int type)
+{
+ dal_mpool_mem_t* head = NULL;
+ dal_mpool_mem_t* tail = NULL;
+
+ head = (dal_mpool_mem_t*)DAL_MALLOC(sizeof(dal_mpool_mem_t));
+ if (head == NULL)
+ {
+ return NULL;
+ }
+
+ tail = (dal_mpool_mem_t*)DAL_MALLOC(sizeof(dal_mpool_mem_t));
+ if (tail == NULL)
+ {
+ DAL_FREE(head);
+ return NULL;
+ }
+
+ head->size = tail->size = 0;
+ head->type = type;
+ head->address = base;
+ tail->address = head->address + size;
+ head->next = tail;
+ tail->next = NULL;
+
+ return head;
+}
+
+dal_mpool_mem_t*
+dal_mpool_create(void* base, int size)
+{
+ dal_mpool_mem_t* head = NULL;
+ int mod = (int)(((unsigned long)base) & (DAL_CACHE_LINE_BYTES - 1));
+
+ MPOOL_LOCK();
+
+ if (mod)
+ {
+ base = (char*)base + (DAL_CACHE_LINE_BYTES - mod);
+ size -= (DAL_CACHE_LINE_BYTES - mod);
+ }
+
+ size &= ~(DAL_CACHE_LINE_BYTES - 1);
+
+ /* init for common linkptr, only used for GB */
+ head = _dal_mpool_create(base, size, DAL_MPOOL_TYPE_USELESS);
+ if (NULL == head)
+ {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+
+ /* init for desc linkptr */
+ p_desc_pool = _dal_mpool_create(base, DAL_MPOOL_MAX_DESX_SIZE, DAL_MPOOL_TYPE_DESC);
+ if (NULL == p_desc_pool)
+ {
+ MPOOL_UNLOCK();
+ DAL_FREE(head->next);
+ DAL_FREE(head);
+ return NULL;
+ }
+
+ /* init for data linkptr */
+ p_data_pool = _dal_mpool_create(((char*)base+DAL_MPOOL_MAX_DESX_SIZE), (size - DAL_MPOOL_MAX_DESX_SIZE), DAL_MPOOL_TYPE_DATA);
+ if (NULL == p_data_pool)
+ {
+ MPOOL_UNLOCK();
+ DAL_FREE(head->next);
+ DAL_FREE(head);
+ DAL_FREE(p_desc_pool->next);
+ DAL_FREE(p_desc_pool);
+ return NULL;
+ }
+
+ MPOOL_UNLOCK();
+
+ return head;
+}
+
+dal_mpool_mem_t*
+_dal_mpool_alloc_comon(dal_mpool_mem_t* ptr, int size, int type)
+{
+ dal_mpool_mem_t* new_ptr = NULL;
+
+ while (ptr && ptr->next)
+ {
+ if (ptr->next->address - (ptr->address + ptr->size) >= size)
+ {
+ break;
+ }
+
+ ptr = ptr->next;
+ }
+
+ if (!(ptr && ptr->next))
+ {
+ return NULL;
+ }
+
+ new_ptr = DAL_MALLOC(sizeof(dal_mpool_mem_t));
+ if (!new_ptr)
+ {
+ return NULL;
+ }
+
+ new_ptr->type = type;
+ new_ptr->address = ptr->address + ptr->size;
+ new_ptr->size = size;
+ new_ptr->next = ptr->next;
+ ptr->next = new_ptr;
+
+ return new_ptr;
+}
+
+void*
+dal_mpool_alloc(dal_mpool_mem_t* pool, int size, int type)
+{
+ dal_mpool_mem_t* ptr = NULL;
+ dal_mpool_mem_t* new_ptr = NULL;
+ int mod;
+
+ MPOOL_LOCK();
+
+ mod = size & (DAL_CACHE_LINE_BYTES - 1);
+ if (mod != 0)
+ {
+ size += (DAL_CACHE_LINE_BYTES - mod);
+ }
+
+ switch(type)
+ {
+ case DAL_MPOOL_TYPE_USELESS:
+ ptr = pool;
+ new_ptr = _dal_mpool_alloc_comon(ptr, size, type);
+ if (NULL == new_ptr)
+ {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+ break;
+ case DAL_MPOOL_TYPE_DESC:
+ ptr = p_desc_pool;
+ new_ptr = _dal_mpool_alloc_comon(ptr, size, type);
+ if (NULL == new_ptr)
+ {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+ break;
+ case DAL_MPOOL_TYPE_DATA:
+ ptr = p_data_pool;
+ new_ptr = _dal_mpool_alloc_comon(ptr, size, type);
+ if (NULL == new_ptr)
+ {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+ break;
+ default:
+ MPOOL_UNLOCK();
+ return NULL;
+ break;
+ }
+
+ MPOOL_UNLOCK();
+
+ return new_ptr->address;
+}
+
+void
+_dal_mpool_free(dal_mpool_mem_t* ptr, void* addr, int type)
+{
+ unsigned char* address = (unsigned char*)addr;
+ dal_mpool_mem_t* prev = NULL;
+
+ while (ptr && ptr->next)
+ {
+ if (ptr->next->address == address)
+ {
+ break;
+ }
+
+ ptr = ptr->next;
+ }
+
+ if (ptr && ptr->next)
+ {
+ prev = ptr;
+ ptr = ptr->next;
+ prev->next = ptr->next;
+ DAL_FREE(ptr);
+ }
+
+ return;
+}
+
+void
+dal_mpool_free(dal_mpool_mem_t* pool, void* addr)
+{
+ dal_mpool_mem_t* ptr = pool;
+
+ MPOOL_LOCK();
+
+ switch(pool->type)
+ {
+ case DAL_MPOOL_TYPE_USELESS:
+ ptr = pool;
+ _dal_mpool_free(ptr, addr, DAL_MPOOL_TYPE_USELESS);
+ break;
+ case DAL_MPOOL_TYPE_DESC:
+ ptr = p_desc_pool;
+ _dal_mpool_free(ptr, addr, DAL_MPOOL_TYPE_DESC);
+ break;
+ case DAL_MPOOL_TYPE_DATA:
+ ptr = p_data_pool;
+ _dal_mpool_free(ptr, addr, DAL_MPOOL_TYPE_DATA);
+ break;
+ default:
+ break;
+ }
+
+ MPOOL_UNLOCK();
+ return;
+}
+
+int
+dal_mpool_destroy(dal_mpool_mem_t* pool)
+{
+ dal_mpool_mem_t* ptr, * next;
+
+ MPOOL_LOCK();
+
+ for (ptr = pool; ptr; ptr = next)
+ {
+ next = ptr->next;
+ DAL_FREE(ptr);
+ }
+
+ for (ptr = p_desc_pool; ptr; ptr = next)
+ {
+ next = ptr->next;
+ DAL_FREE(ptr);
+ }
+
+ for (ptr = p_data_pool; ptr; ptr = next)
+ {
+ next = ptr->next;
+ DAL_FREE(ptr);
+ }
+
+ MPOOL_UNLOCK();
+
+ return 0;
+}
+
+int
+dal_mpool_usage(dal_mpool_mem_t* pool, int type)
+{
+ int usage = 0;
+ dal_mpool_mem_t* ptr;
+
+ MPOOL_LOCK();
+
+ for (ptr = pool; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == type || ptr->type == -1)
+ {
+ usage += ptr->size;
+ }
+ }
+
+ MPOOL_UNLOCK();
+
+ return usage;
+}
+
+int
+dal_mpool_debug(dal_mpool_mem_t* pool)
+{
+ dal_mpool_mem_t* ptr;
+ int index = 0;
+
+ MPOOL_LOCK();
+
+ for (ptr = pool; ptr; ptr = ptr->next)
+ {
+// DAL_PRINT("%2dst mpool block: address=0x%8x, size=0x%x \n", index, (unsigned int)ptr->address, ptr->size);
+ DAL_PRINT("%2dst mpool block: address=%p, size=0x%x \n", index, ptr->address, ptr->size); // note
+ index++;
+ }
+
+ MPOOL_UNLOCK();
+
+ return 0;
+}
+
diff --git a/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/dal_mpool.h b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/dal_mpool.h
new file mode 100644
index 0000000000..a1fa37d05f
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x2q4z/modules/dal_mpool.h
@@ -0,0 +1,71 @@
+/**
+ @file dal_mpool.h
+
+ @author Copyright (C) 2011 Centec Networks Inc. All rights reserved.
+
+ @date 2012-5-10
+
+ @version v2.0
+
+ This file contains the dma memory init, allocation and free APIs
+*/
+
+#ifndef _DMA_MPOOL_H
+#define _DMA_MPOOL_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DAL_MPOOL_MAX_DESX_SIZE (1024*1024)
+
+enum dal_mpool_type_e
+{
+ DAL_MPOOL_TYPE_USELESS, /* just compatible with GB */
+ DAL_MPOOL_TYPE_DESC, /* dma mpool op for desc */
+ DAL_MPOOL_TYPE_DATA /* dma mpool op for data */
+};
+typedef enum dal_mpool_type_e dal_mpool_type_t;
+
+struct dal_mpool_mem_s
+{
+ unsigned char* address;
+ int size;
+ int type;
+ struct dal_mpool_mem_s* next;
+};
+typedef struct dal_mpool_mem_s dal_mpool_mem_t;
+
+/**
+ @brief This function is to alloc dma memory
+
+ @param[in] size size of memory
+
+ @return NULL
+
+*/
+extern int
+dal_mpool_init(void);
+
+extern dal_mpool_mem_t*
+dal_mpool_create(void* base_ptr, int size);
+
+extern void*
+dal_mpool_alloc(dal_mpool_mem_t* pool, int size, int type);
+
+extern void
+dal_mpool_free(dal_mpool_mem_t* pool, void* addr);
+
+extern int
+dal_mpool_destroy(dal_mpool_mem_t* pool);
+
+extern int
+dal_mpool_usage(dal_mpool_mem_t* pool, int type);
+
+extern int
+dal_mpool_debug(dal_mpool_mem_t* pool);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_DMA_MPOOL_H */
+
diff --git a/platform/centec/sonic-platform-modules-e582/48x2q4z/scripts/48x2q4z_platform.sh b/platform/centec/sonic-platform-modules-e582/48x2q4z/scripts/48x2q4z_platform.sh
new file mode 100755
index 0000000000..2caae94f03
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x2q4z/scripts/48x2q4z_platform.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+#platform init script for centec e582-48x2q4z
+
+init_devnum() {
+ found=0
+ for devnum in 0 1; do
+ devname=`cat /sys/bus/i2c/devices/i2c-${devnum}/name`
+ # I801 adapter can be at either dffd0000 or dfff0000
+ if [[ $devname == 'SMBus I801 adapter at '* ]]; then
+ found=1
+ break
+ fi
+ done
+
+ [ $found -eq 0 ] && echo "cannot find I801" && exit 1
+}
+
+init_devnum
+
+if [ "$1" == "init" ]; then
+ depmod -a
+ modprobe i2c-dev
+ modprobe i2c-mux-pca954x force_deselect_on_exit=1
+ modprobe centec_e582_48x2q4z_platform
+ modprobe dal
+ modprobe centec_at24c64
+elif [ "$1" == "deinit" ]; then
+ modprobe -r centec_at24c64
+ modprobe -r dal
+ modprobe -r centec_e582_48x2q4z_platform
+ modprobe -r i2c-mux-pca954x
+ modprobe -r i2c-dev
+else
+ echo "e582-48x2q4z_platform : Invalid option !"
+fi
diff --git a/platform/centec/sonic-platform-modules-e582/48x6q/cfg/48x6q-modules.conf b/platform/centec/sonic-platform-modules-e582/48x6q/cfg/48x6q-modules.conf
new file mode 100644
index 0000000000..7a7881c8c0
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x6q/cfg/48x6q-modules.conf
@@ -0,0 +1,14 @@
+# /etc/modules: kernel modules to load at boot time.
+#
+# This file contains the names of kernel modules that should be loaded
+# at boot time, one per line. Lines beginning with "#" are ignored.
+
+i2c-i801
+i2c-dev
+i2c-mux
+i2c-smbus
+
+i2c-mux-pca954x
+lm77
+adt7470
+tun
diff --git a/platform/centec/sonic-platform-modules-e582/48x6q/cfg/config_db.json b/platform/centec/sonic-platform-modules-e582/48x6q/cfg/config_db.json
new file mode 100644
index 0000000000..c75eb1284f
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x6q/cfg/config_db.json
@@ -0,0 +1,303 @@
+{
+ "DEVICE_METADATA": {
+ "localhost": {
+ "bgp_asn": 65100,
+ "deployment_id": null,
+ "hostname": "switch1",
+ "type": "LeafRouter",
+ "hwsku": "E582-48x6q"
+
+ }
+ },
+ "BGP_PEER_RANGE": {},
+ "VLAN": {},
+ "PORT": {
+ "Ethernet1": {
+ "alias": "Ethernet1",
+ "lanes": "4",
+ "speed": "1000"
+ },
+ "Ethernet2": {
+ "alias": "Ethernet2",
+ "lanes": "5",
+ "speed": "1000"
+ },
+ "Ethernet3": {
+ "alias": "Ethernet3",
+ "lanes": "6",
+ "speed": "1000"
+ },
+ "Ethernet4": {
+ "alias": "Ethernet4",
+ "lanes": "8",
+ "speed": "1000"
+ },
+ "Ethernet5": {
+ "alias": "Ethernet5",
+ "lanes": "9",
+ "speed": "1000"
+ },
+ "Ethernet6": {
+ "alias": "Ethernet6",
+ "lanes": "10",
+ "speed": "1000"
+ },
+ "Ethernet7": {
+ "alias": "Ethernet7",
+ "lanes": "12",
+ "speed": "1000"
+ },
+ "Ethernet8": {
+ "alias": "Ethernet8",
+ "lanes": "13",
+ "speed": "1000"
+ },
+ "Ethernet9": {
+ "alias": "Ethernet9",
+ "lanes": "14",
+ "speed": "1000"
+ },
+ "Ethernet10": {
+ "alias": "Ethernet10",
+ "lanes": "16",
+ "speed": "1000"
+ },
+ "Ethernet11": {
+ "alias": "Ethernet11",
+ "lanes": "17",
+ "speed": "1000"
+ },
+ "Ethernet12": {
+ "alias": "Ethernet12",
+ "lanes": "18",
+ "speed": "1000"
+ },
+ "Ethernet13": {
+ "alias": "Ethernet13",
+ "lanes": "20",
+ "speed": "10000"
+ },
+ "Ethernet14": {
+ "alias": "Ethernet14",
+ "lanes": "21",
+ "speed": "10000"
+ },
+ "Ethernet15": {
+ "alias": "Ethernet15",
+ "lanes": "22",
+ "speed": "10000"
+ },
+ "Ethernet16": {
+ "alias": "Ethernet16",
+ "lanes": "24",
+ "speed": "10000"
+ },
+ "Ethernet17": {
+ "alias": "Ethernet17",
+ "lanes": "25",
+ "speed": "10000"
+ },
+ "Ethernet18": {
+ "alias": "Ethernet18",
+ "lanes": "26",
+ "speed": "10000"
+ },
+ "Ethernet19": {
+ "alias": "Ethernet19",
+ "lanes": "28",
+ "speed": "10000"
+ },
+ "Ethernet20": {
+ "alias": "Ethernet20",
+ "lanes": "30",
+ "speed": "10000"
+ },
+ "Ethernet21": {
+ "alias": "Ethernet21",
+ "lanes": "31",
+ "speed": "10000"
+ },
+ "Ethernet22": {
+ "alias": "Ethernet22",
+ "lanes": "32",
+ "speed": "10000"
+ },
+ "Ethernet23": {
+ "alias": "Ethernet23",
+ "lanes": "34",
+ "speed": "10000"
+ },
+ "Ethernet24": {
+ "alias": "Ethernet24",
+ "lanes": "35",
+ "speed": "10000"
+ },
+ "Ethernet25": {
+ "alias": "Ethernet25",
+ "lanes": "40",
+ "speed": "10000"
+ },
+ "Ethernet26": {
+ "alias": "Ethernet26",
+ "lanes": "41",
+ "speed": "10000"
+ },
+ "Ethernet27": {
+ "alias": "Ethernet27",
+ "lanes": "43",
+ "speed": "10000"
+ },
+ "Ethernet28": {
+ "alias": "Ethernet28",
+ "lanes": "36",
+ "speed": "10000"
+ },
+ "Ethernet29": {
+ "alias": "Ethernet29",
+ "lanes": "37",
+ "speed": "10000"
+ },
+ "Ethernet30": {
+ "alias": "Ethernet30",
+ "lanes": "39",
+ "speed": "10000"
+ },
+ "Ethernet31": {
+ "alias": "Ethernet31",
+ "lanes": "44",
+ "speed": "10000"
+ },
+ "Ethernet32": {
+ "alias": "Ethernet32",
+ "lanes": "45",
+ "speed": "10000"
+ },
+ "Ethernet33": {
+ "alias": "Ethernet33",
+ "lanes": "46",
+ "speed": "10000"
+ },
+ "Ethernet34": {
+ "alias": "Ethernet34",
+ "lanes": "47",
+ "speed": "10000"
+ },
+ "Ethernet35": {
+ "alias": "Ethernet35",
+ "lanes": "80",
+ "speed": "10000"
+ },
+ "Ethernet36": {
+ "alias": "Ethernet36",
+ "lanes": "81",
+ "speed": "10000"
+ },
+ "Ethernet37": {
+ "alias": "Ethernet37",
+ "lanes": "82",
+ "speed": "10000"
+ },
+ "Ethernet38": {
+ "alias": "Ethernet38",
+ "lanes": "88",
+ "speed": "10000"
+ },
+ "Ethernet39": {
+ "alias": "Ethernet39",
+ "lanes": "89",
+ "speed": "10000"
+ },
+ "Ethernet40": {
+ "alias": "Ethernet40",
+ "lanes": "90",
+ "speed": "10000"
+ },
+ "Ethernet41": {
+ "alias": "Ethernet41",
+ "lanes": "84",
+ "speed": "10000"
+ },
+ "Ethernet42": {
+ "alias": "Ethernet42",
+ "lanes": "85",
+ "speed": "10000"
+ },
+ "Ethernet43": {
+ "alias": "Ethernet43",
+ "lanes": "86",
+ "speed": "10000"
+ },
+ "Ethernet44": {
+ "alias": "Ethernet44",
+ "lanes": "87",
+ "speed": "10000"
+ },
+ "Ethernet45": {
+ "alias": "Ethernet45",
+ "lanes": "92",
+ "speed": "10000"
+ },
+ "Ethernet46": {
+ "alias": "Ethernet46",
+ "lanes": "93",
+ "speed": "10000"
+ },
+ "Ethernet47": {
+ "alias": "Ethernet47",
+ "lanes": "94",
+ "speed": "10000"
+ },
+ "Ethernet48": {
+ "alias": "Ethernet48",
+ "lanes": "95",
+ "speed": "10000"
+ },
+ "Ethernet49": {
+ "alias": "Ethernet49",
+ "lanes": "52,53,54,55",
+ "speed": "40000"
+ },
+ "Ethernet50": {
+ "alias": "Ethernet50",
+ "lanes": "56,57,58,59",
+ "speed": "40000"
+ },
+ "Ethernet51": {
+ "alias": "Ethernet51",
+ "lanes": "60,61,62,63",
+ "speed": "40000"
+ },
+ "Ethernet52": {
+ "alias": "Ethernet52",
+ "lanes": "68,69,70,71",
+ "speed": "40000"
+ },
+ "Ethernet53": {
+ "alias": "Ethernet53",
+ "lanes": "72,73,74,75",
+ "speed": "40000"
+ },
+ "Ethernet54": {
+ "alias": "Ethernet54",
+ "lanes": "76,77,78,79",
+ "speed": "40000"
+ }
+ },
+ "SYSLOG_SERVER": {},
+ "VLAN_INTERFACE": {},
+ "PORTCHANNEL_INTERFACE": {},
+ "PORTCHANNEL": {},
+ "MGMT_INTERFACE": {},
+ "DHCP_SERVER": {},
+ "LOOPBACK_INTERFACE": {
+ "Loopback0|127.0.0.1/8": {}
+ },
+ "ACL_TABLE": {},
+ "INTERFACE": {
+ "Ethernet1|192.168.1.1/24": {},
+ "Ethernet2|192.168.2.1/24": {},
+ "Ethernet3|192.168.3.1/24": {},
+ "Ethernet4|192.168.4.1/24": {}
+ }
+}
+
diff --git a/platform/centec/sonic-platform-modules-e582/48x6q/cfg/config_db_l2l3.json b/platform/centec/sonic-platform-modules-e582/48x6q/cfg/config_db_l2l3.json
new file mode 100644
index 0000000000..e9d9a3bb5e
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x6q/cfg/config_db_l2l3.json
@@ -0,0 +1,610 @@
+{
+ "QUEUE": {
+ "Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet49,Ethernet50,Ethernet51,Ethernet52,Ethernet53,Ethernet54|0-2": {
+ "wred_profile": "[WRED_PROFILE|AZURE_LOSSY]"
+ },
+ "Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet49,Ethernet50,Ethernet51,Ethernet52,Ethernet53,Ethernet54|3-4": {
+ "wred_profile": "[WRED_PROFILE|AZURE_LOSSLESS]",
+ "scheduler": "[SCHEDULER|scheduler.0]"
+ },
+ "Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet49,Ethernet50,Ethernet51,Ethernet52,Ethernet53,Ethernet54|5-7": {
+ "wred_profile": "[WRED_PROFILE|AZURE_LOSSY]"
+ }
+ },
+ "WRED_PROFILE": {
+ "AZURE_LOSSLESS": {
+ "red_max_threshold": "32760",
+ "yellow_max_threshold": "32760",
+ "green_min_threshold": "4095",
+ "red_min_threshold": "4095",
+ "yellow_min_threshold": "4095",
+ "green_max_threshold": "32760",
+ "wred_yellow_enable": "true",
+ "wred_green_enable": "true"
+ },
+ "AZURE_LOSSY": {
+ "red_max_threshold": "32760",
+ "yellow_max_threshold": "32760",
+ "green_min_threshold": "4095",
+ "red_min_threshold": "4095",
+ "yellow_min_threshold": "4095",
+ "green_max_threshold": "32760",
+ "wred_yellow_enable": "true",
+ "wred_green_enable": "true"
+ }
+ },
+ "DSCP_TO_TC_MAP": {
+ "AZURE": {
+ "56": "7",
+ "54": "6",
+ "28": "3",
+ "48": "6",
+ "29": "3",
+ "60": "7",
+ "61": "7",
+ "62": "7",
+ "63": "7",
+ "49": "6",
+ "34": "4",
+ "24": "3",
+ "25": "3",
+ "26": "3",
+ "27": "3",
+ "20": "2",
+ "21": "2",
+ "22": "2",
+ "23": "2",
+ "46": "5",
+ "47": "5",
+ "44": "5",
+ "45": "5",
+ "42": "5",
+ "43": "5",
+ "40": "5",
+ "41": "5",
+ "1": "0",
+ "0": "0",
+ "3": "0",
+ "2": "0",
+ "5": "0",
+ "4": "0",
+ "7": "0",
+ "6": "0",
+ "9": "1",
+ "8": "1",
+ "35": "4",
+ "13": "1",
+ "12": "1",
+ "15": "1",
+ "58": "7",
+ "11": "1",
+ "10": "1",
+ "39": "4",
+ "38": "4",
+ "59": "7",
+ "14": "1",
+ "17": "2",
+ "16": "2",
+ "19": "2",
+ "18": "2",
+ "31": "3",
+ "30": "3",
+ "51": "6",
+ "36": "4",
+ "53": "6",
+ "52": "6",
+ "33": "4",
+ "55": "6",
+ "37": "4",
+ "32": "4",
+ "57": "7",
+ "50": "6"
+ }
+ },
+ "DEVICE_METADATA": {
+ "localhost": {
+ "hwsku": "E582-48x6q",
+ "hostname": "switch1",
+ "bgp_asn": "None",
+ "deployment_id": "None",
+ "type": "LeafRouter"
+ }
+ },
+ "PORT": {
+ "Ethernet1": {
+ "alias": "Ethernet1",
+ "lanes": "4",
+ "speed": "1000"
+ },
+ "Ethernet2": {
+ "alias": "Ethernet2",
+ "lanes": "5",
+ "speed": "1000"
+ },
+ "Ethernet3": {
+ "alias": "Ethernet3",
+ "lanes": "6",
+ "speed": "1000"
+ },
+ "Ethernet4": {
+ "alias": "Ethernet4",
+ "lanes": "8",
+ "speed": "1000"
+ },
+ "Ethernet5": {
+ "alias": "Ethernet5",
+ "lanes": "9",
+ "speed": "1000"
+ },
+ "Ethernet6": {
+ "alias": "Ethernet6",
+ "lanes": "10",
+ "speed": "1000"
+ },
+ "Ethernet7": {
+ "alias": "Ethernet7",
+ "lanes": "12",
+ "speed": "1000"
+ },
+ "Ethernet8": {
+ "alias": "Ethernet8",
+ "lanes": "13",
+ "speed": "1000"
+ },
+ "Ethernet9": {
+ "alias": "Ethernet9",
+ "lanes": "14",
+ "speed": "1000"
+ },
+ "Ethernet10": {
+ "alias": "Ethernet10",
+ "lanes": "16",
+ "speed": "1000"
+ },
+ "Ethernet11": {
+ "alias": "Ethernet11",
+ "lanes": "17",
+ "speed": "1000"
+ },
+ "Ethernet12": {
+ "alias": "Ethernet12",
+ "lanes": "18",
+ "speed": "1000"
+ },
+ "Ethernet13": {
+ "alias": "Ethernet13",
+ "lanes": "20",
+ "speed": "10000"
+ },
+ "Ethernet14": {
+ "alias": "Ethernet14",
+ "lanes": "21",
+ "speed": "10000"
+ },
+ "Ethernet15": {
+ "alias": "Ethernet15",
+ "lanes": "22",
+ "speed": "10000"
+ },
+ "Ethernet16": {
+ "alias": "Ethernet16",
+ "lanes": "24",
+ "speed": "10000"
+ },
+ "Ethernet17": {
+ "alias": "Ethernet17",
+ "lanes": "25",
+ "speed": "10000"
+ },
+ "Ethernet18": {
+ "alias": "Ethernet18",
+ "lanes": "26",
+ "speed": "10000"
+ },
+ "Ethernet19": {
+ "alias": "Ethernet19",
+ "lanes": "28",
+ "speed": "10000"
+ },
+ "Ethernet20": {
+ "alias": "Ethernet20",
+ "lanes": "30",
+ "speed": "10000"
+ },
+ "Ethernet21": {
+ "alias": "Ethernet21",
+ "lanes": "31",
+ "speed": "10000"
+ },
+ "Ethernet22": {
+ "alias": "Ethernet22",
+ "lanes": "32",
+ "speed": "10000"
+ },
+ "Ethernet23": {
+ "alias": "Ethernet23",
+ "lanes": "34",
+ "speed": "10000"
+ },
+ "Ethernet24": {
+ "alias": "Ethernet24",
+ "lanes": "35",
+ "speed": "10000"
+ },
+ "Ethernet25": {
+ "alias": "Ethernet25",
+ "lanes": "40",
+ "speed": "10000"
+ },
+ "Ethernet26": {
+ "alias": "Ethernet26",
+ "lanes": "41",
+ "speed": "10000"
+ },
+ "Ethernet27": {
+ "alias": "Ethernet27",
+ "lanes": "43",
+ "speed": "10000"
+ },
+ "Ethernet28": {
+ "alias": "Ethernet28",
+ "lanes": "36",
+ "speed": "10000"
+ },
+ "Ethernet29": {
+ "alias": "Ethernet29",
+ "lanes": "37",
+ "speed": "10000"
+ },
+ "Ethernet30": {
+ "alias": "Ethernet30",
+ "lanes": "39",
+ "speed": "10000"
+ },
+ "Ethernet31": {
+ "alias": "Ethernet31",
+ "lanes": "44",
+ "speed": "10000"
+ },
+ "Ethernet32": {
+ "alias": "Ethernet32",
+ "lanes": "45",
+ "speed": "10000"
+ },
+ "Ethernet33": {
+ "alias": "Ethernet33",
+ "lanes": "46",
+ "speed": "10000"
+ },
+ "Ethernet34": {
+ "alias": "Ethernet34",
+ "lanes": "47",
+ "speed": "10000"
+ },
+ "Ethernet35": {
+ "alias": "Ethernet35",
+ "lanes": "80",
+ "speed": "10000"
+ },
+ "Ethernet36": {
+ "alias": "Ethernet36",
+ "lanes": "81",
+ "speed": "10000"
+ },
+ "Ethernet37": {
+ "alias": "Ethernet37",
+ "lanes": "82",
+ "speed": "10000"
+ },
+ "Ethernet38": {
+ "alias": "Ethernet38",
+ "lanes": "88",
+ "speed": "10000"
+ },
+ "Ethernet39": {
+ "alias": "Ethernet39",
+ "lanes": "89",
+ "speed": "10000"
+ },
+ "Ethernet40": {
+ "alias": "Ethernet40",
+ "lanes": "90",
+ "speed": "10000"
+ },
+ "Ethernet41": {
+ "alias": "Ethernet41",
+ "lanes": "84",
+ "speed": "10000"
+ },
+ "Ethernet42": {
+ "alias": "Ethernet42",
+ "lanes": "85",
+ "speed": "10000"
+ },
+ "Ethernet43": {
+ "alias": "Ethernet43",
+ "lanes": "86",
+ "speed": "10000"
+ },
+ "Ethernet44": {
+ "alias": "Ethernet44",
+ "lanes": "87",
+ "speed": "10000"
+ },
+ "Ethernet45": {
+ "alias": "Ethernet45",
+ "lanes": "92",
+ "speed": "10000"
+ },
+ "Ethernet46": {
+ "alias": "Ethernet46",
+ "lanes": "93",
+ "speed": "10000"
+ },
+ "Ethernet47": {
+ "alias": "Ethernet47",
+ "lanes": "94",
+ "speed": "10000"
+ },
+ "Ethernet48": {
+ "alias": "Ethernet48",
+ "lanes": "95",
+ "speed": "10000"
+ },
+ "Ethernet49": {
+ "alias": "Ethernet49",
+ "lanes": "52,53,54,55",
+ "speed": "40000"
+ },
+ "Ethernet50": {
+ "alias": "Ethernet50",
+ "lanes": "56,57,58,59",
+ "speed": "40000"
+ },
+ "Ethernet51": {
+ "alias": "Ethernet51",
+ "lanes": "60,61,62,63",
+ "speed": "40000"
+ },
+ "Ethernet52": {
+ "alias": "Ethernet52",
+ "lanes": "68,69,70,71",
+ "speed": "40000"
+ },
+ "Ethernet53": {
+ "alias": "Ethernet53",
+ "lanes": "72,73,74,75",
+ "speed": "40000"
+ },
+ "Ethernet54": {
+ "alias": "Ethernet54",
+ "lanes": "76,77,78,79",
+ "speed": "40000"
+ }
+ },
+ "PORT_QOS_MAP": {
+ "Ethernet1,Ethernet2,Ethernet3,Ethernet4,Ethernet5,Ethernet6,Ethernet7,Ethernet8,Ethernet9,Ethernet10,Ethernet11,Ethernet12,Ethernet13,Ethernet14,Ethernet15,Ethernet16,Ethernet17,Ethernet18,Ethernet19,Ethernet20,Ethernet21,Ethernet22,Ethernet23,Ethernet24,Ethernet25,Ethernet26,Ethernet27,Ethernet28,Ethernet29,Ethernet30,Ethernet31,Ethernet32,Ethernet33,Ethernet34,Ethernet35,Ethernet36,Ethernet37,Ethernet38,Ethernet39,Ethernet40,Ethernet41,Ethernet42,Ethernet43,Ethernet44,Ethernet45,Ethernet46,Ethernet47,Ethernet48,Ethernet49,Ethernet50,Ethernet51,Ethernet52,Ethernet53,Ethernet54": {
+ "pfc_enable": "3,4",
+ "dscp_to_tc_map": "[DSCP_TO_TC_MAP|AZURE]"
+ }
+ },
+ "SCHEDULER": {
+ "scheduler.0": {
+ "type": "DWRR",
+ "weight": "25"
+ },
+ "scheduler.1": {
+ "type": "DWRR",
+ "weight": "30"
+ },
+ "scheduler.2": {
+ "type": "DWRR",
+ "weight": "20"
+ }
+ },
+ "VLAN": {
+ "Vlan500": {
+ "dhcp_servers": [
+ "192.168.5.1",
+ "192.168.5.2",
+ "192.168.5.3",
+ "192.168.5.4"
+ ],
+ "members": [
+ "Ethernet5",
+ "Ethernet6",
+ "Ethernet7",
+ "Ethernet8"
+ ],
+ "vlanid": "500"
+ },
+ "Vlan600": {
+ "dhcp_servers": [
+ "192.168.6.1",
+ "192.168.6.2",
+ "192.168.6.3",
+ "192.168.6.4"
+ ],
+ "members": [
+ "Ethernet5",
+ "Ethernet6"
+ ],
+ "vlanid": "600"
+ },
+ "Vlan700": {
+ "dhcp_servers": [
+ "192.168.7.1",
+ "192.168.7.2",
+ "192.168.7.3",
+ "192.168.7.4"
+ ],
+ "members": [
+ "Ethernet5",
+ "Ethernet7"
+ ],
+ "vlanid": "700"
+ },
+ "Vlan800": {
+ "dhcp_servers": [
+ "192.168.8.1",
+ "192.168.8.2",
+ "192.168.8.3",
+ "192.168.8.4"
+ ],
+ "members": [
+ "Ethernet5",
+ "Ethernet8"
+ ],
+ "vlanid": "800"
+ }
+ },
+ "VLAN_MEMBER": {
+ "Vlan500|Ethernet5": {
+ "tagging_mode": "tagged"
+ },
+ "Vlan500|Ethernet6": {
+ "tagging_mode": "untagged"
+ },
+ "Vlan500|Ethernet7": {
+ "tagging_mode": "untagged"
+ },
+ "Vlan500|Ethernet8": {
+ "tagging_mode": "untagged"
+ },
+ "Vlan600|Ethernet5": {
+ "tagging_mode": "tagged"
+ },
+ "Vlan600|Ethernet6": {
+ "tagging_mode": "tagged"
+ },
+ "Vlan700|Ethernet5": {
+ "tagging_mode": "tagged"
+ },
+ "Vlan700|Ethernet7": {
+ "tagging_mode": "tagged"
+ },
+ "Vlan800|Ethernet5": {
+ "tagging_mode": "tagged"
+ },
+ "Vlan800|Ethernet8": {
+ "tagging_mode": "tagged"
+ }
+ },
+ "INTERFACE": {
+ "Ethernet1|192.168.1.1/24": {},
+ "Ethernet2|192.168.2.1/24": {},
+ "Ethernet3|192.168.3.1/24": {},
+ "Ethernet4|192.168.4.1/24": {}
+ },
+ "VLAN_INTERFACE": {
+ "Vlan500|192.168.5.1/24": {},
+ "Vlan600|192.168.6.1/24": {},
+ "Vlan700|192.168.7.1/24": {},
+ "Vlan800|192.168.8.1/24": {}
+ },
+ "LOOPBACK_INTERFACE": {
+ "Loopback0|127.0.0.1/8": {}
+ },
+ "CABLE_LENGTH": {
+ "AZURE": {
+ "Ethernet8": "40m",
+ "Ethernet9": "40m",
+ "Ethernet2": "40m",
+ "Ethernet3": "40m",
+ "Ethernet1": "40m",
+ "Ethernet6": "40m",
+ "Ethernet7": "40m",
+ "Ethernet4": "40m",
+ "Ethernet5": "40m",
+ "Ethernet22": "40m",
+ "Ethernet50": "40m",
+ "Ethernet51": "40m",
+ "Ethernet52": "40m",
+ "Ethernet53": "40m",
+ "Ethernet54": "40m",
+ "Ethernet38": "40m",
+ "Ethernet39": "40m",
+ "Ethernet18": "40m",
+ "Ethernet19": "40m",
+ "Ethernet14": "40m",
+ "Ethernet15": "40m",
+ "Ethernet16": "40m",
+ "Ethernet17": "40m",
+ "Ethernet10": "40m",
+ "Ethernet11": "40m",
+ "Ethernet12": "40m",
+ "Ethernet35": "40m",
+ "Ethernet37": "40m",
+ "Ethernet32": "40m",
+ "Ethernet33": "40m",
+ "Ethernet30": "40m",
+ "Ethernet31": "40m",
+ "Ethernet49": "40m",
+ "Ethernet48": "40m",
+ "Ethernet47": "40m",
+ "Ethernet36": "40m",
+ "Ethernet45": "40m",
+ "Ethernet44": "40m",
+ "Ethernet43": "40m",
+ "Ethernet42": "40m",
+ "Ethernet41": "40m",
+ "Ethernet40": "40m",
+ "Ethernet29": "40m",
+ "Ethernet28": "40m",
+ "Ethernet34": "40m",
+ "Ethernet46": "40m",
+ "Ethernet21": "40m",
+ "Ethernet20": "40m",
+ "Ethernet23": "40m",
+ "Ethernet13": "40m",
+ "Ethernet25": "40m",
+ "Ethernet24": "40m",
+ "Ethernet27": "40m",
+ "Ethernet26": "40m"
+ }
+ },
+ "CRM": {
+ "Config": {
+ "acl_table_threshold_type": "percentage",
+ "nexthop_group_threshold_type": "percentage",
+ "fdb_entry_high_threshold": "85",
+ "acl_entry_threshold_type": "percentage",
+ "ipv6_neighbor_low_threshold": "70",
+ "nexthop_group_member_low_threshold": "70",
+ "acl_group_high_threshold": "85",
+ "ipv4_route_high_threshold": "85",
+ "acl_counter_high_threshold": "85",
+ "ipv4_route_low_threshold": "70",
+ "ipv4_route_threshold_type": "percentage",
+ "ipv4_neighbor_low_threshold": "70",
+ "acl_group_threshold_type": "percentage",
+ "ipv4_nexthop_high_threshold": "85",
+ "ipv6_route_threshold_type": "percentage",
+ "nexthop_group_low_threshold": "70",
+ "ipv4_neighbor_high_threshold": "85",
+ "ipv6_route_high_threshold": "85",
+ "ipv6_nexthop_threshold_type": "percentage",
+ "polling_interval": "300",
+ "ipv4_nexthop_threshold_type": "percentage",
+ "acl_group_low_threshold": "70",
+ "acl_entry_low_threshold": "70",
+ "nexthop_group_member_threshold_type": "percentage",
+ "ipv4_nexthop_low_threshold": "70",
+ "acl_counter_threshold_type": "percentage",
+ "ipv6_neighbor_high_threshold": "85",
+ "nexthop_group_member_high_threshold": "85",
+ "acl_table_low_threshold": "70",
+ "fdb_entry_threshold_type": "percentage",
+ "ipv6_neighbor_threshold_type": "percentage",
+ "acl_table_high_threshold": "85",
+ "ipv6_nexthop_low_threshold": "70",
+ "acl_counter_low_threshold": "70",
+ "ipv4_neighbor_threshold_type": "percentage",
+ "nexthop_group_high_threshold": "85",
+ "ipv6_route_low_threshold": "70",
+ "acl_entry_high_threshold": "85",
+ "fdb_entry_low_threshold": "70",
+ "ipv6_nexthop_high_threshold": "85"
+ }
+ }
+}
diff --git a/platform/centec/sonic-platform-modules-e582/48x6q/cfg/minigraph.xml b/platform/centec/sonic-platform-modules-e582/48x6q/cfg/minigraph.xml
new file mode 100644
index 0000000000..fc313eb846
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x6q/cfg/minigraph.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ switch1
+
+
+
+
+
+
+
+
+
+
+
+
+ switch1
+ E582-48x6q
+
+
+
+ switch1
+ E582-48x6q
+
+
diff --git a/platform/centec/sonic-platform-modules-e582/48x6q/modules/Makefile b/platform/centec/sonic-platform-modules-e582/48x6q/modules/Makefile
new file mode 100644
index 0000000000..25df81bba4
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x6q/modules/Makefile
@@ -0,0 +1,2 @@
+obj-m := centec_e582_48x6q_platform.o dal.o centec_at24c64.o
+dal-y := dal_kernel.o dal_mpool.o
diff --git a/platform/centec/sonic-platform-modules-e582/48x6q/modules/centec_at24c64.c b/platform/centec/sonic-platform-modules-e582/48x6q/modules/centec_at24c64.c
new file mode 100644
index 0000000000..7b551e71f7
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x6q/modules/centec_at24c64.c
@@ -0,0 +1,658 @@
+/*
+ * at24.c - handle most I2C EEPROMs
+ *
+ * Copyright (C) 2005-2007 David Brownell
+ * Copyright (C) 2008 Wolfram Sang, Pengutronix
+ *
+ * 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.
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
+ * Differences between different vendor product lines (like Atmel AT24C or
+ * MicroChip 24LC, etc) won't much matter for typical read/write access.
+ * There are also I2C RAM chips, likewise interchangeable. One example
+ * would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes).
+ *
+ * However, misconfiguration can lose data. "Set 16-bit memory address"
+ * to a part with 8-bit addressing will overwrite data. Writing with too
+ * big a page size also loses data. And it's not safe to assume that the
+ * conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC
+ * uses 0x51, for just one example.
+ *
+ * Accordingly, explicit board-specific configuration data should be used
+ * in almost all cases. (One partial exception is an SMBus used to access
+ * "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.)
+ *
+ * So this driver uses "new style" I2C driver binding, expecting to be
+ * told what devices exist. That may be in arch/X/mach-Y/board-Z.c or
+ * similar kernel-resident tables; or, configuration data coming from
+ * a bootloader.
+ *
+ * Other than binding model, current differences from "eeprom" driver are
+ * that this one handles write access and isn't restricted to 24c02 devices.
+ * It also handles larger devices (32 kbit and up) with two-byte addresses,
+ * which won't work on pure SMBus systems.
+ */
+
+struct at24_data {
+ struct at24_platform_data chip;
+ struct memory_accessor macc;
+ int use_smbus;
+
+ /*
+ * Lock protects against activities from other Linux tasks,
+ * but not from changes by other I2C masters.
+ */
+ struct mutex lock;
+ struct bin_attribute bin;
+
+ u8 *writebuf;
+ unsigned write_max;
+ unsigned num_addresses;
+
+ /*
+ * Some chips tie up multiple I2C addresses; dummy devices reserve
+ * them for us, and we'll use them with SMBus calls.
+ */
+ struct i2c_client *client[];
+};
+
+/*
+ * This parameter is to help this driver avoid blocking other drivers out
+ * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C
+ * clock, one 256 byte read takes about 1/43 second which is excessive;
+ * but the 1/170 second it takes at 400 kHz may be quite reasonable; and
+ * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible.
+ *
+ * This value is forced to be a power of two so that writes align on pages.
+ */
+static unsigned io_limit = 128;
+module_param(io_limit, uint, 0);
+MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 128)");
+
+/*
+ * Specs often allow 5 msec for a page write, sometimes 20 msec;
+ * it's important to recover from write timeouts.
+ */
+static unsigned write_timeout = 25;
+module_param(write_timeout, uint, 0);
+MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
+
+#define AT24_SIZE_BYTELEN 5
+#define AT24_SIZE_FLAGS 8
+
+#define AT24_BITMASK(x) (BIT(x) - 1)
+
+/* create non-zero magic value for given eeprom parameters */
+#define AT24_DEVICE_MAGIC(_len, _flags) \
+ ((1 << AT24_SIZE_FLAGS | (_flags)) \
+ << AT24_SIZE_BYTELEN | ilog2(_len))
+
+static const struct i2c_device_id at24_ctc_ids[] = {
+ { "24c64-ctc", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16 | AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
+ { /* END OF LIST */ }
+};
+MODULE_DEVICE_TABLE(i2c, at24_ctc_ids);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This routine supports chips which consume multiple I2C addresses. It
+ * computes the addressing information to be used for a given r/w request.
+ * Assumes that sanity checks for offset happened at sysfs-layer.
+ */
+static struct i2c_client *at24_translate_offset(struct at24_data *at24,
+ unsigned *offset)
+{
+ unsigned i;
+
+ if (at24->chip.flags & AT24_FLAG_ADDR16) {
+ i = *offset >> 16;
+ *offset &= 0xffff;
+ } else {
+ i = *offset >> 8;
+ *offset &= 0xff;
+ }
+
+ return at24->client[i];
+}
+
+static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
+ unsigned offset, size_t count)
+{
+ struct i2c_msg msg[2];
+ struct i2c_client *client;
+ unsigned long timeout, read_time;
+ int status;
+
+ memset(msg, 0, sizeof(msg));
+
+ /*
+ * REVISIT some multi-address chips don't rollover page reads to
+ * the next slave address, so we may need to truncate the count.
+ * Those chips might need another quirk flag.
+ *
+ * If the real hardware used four adjacent 24c02 chips and that
+ * were misconfigured as one 24c08, that would be a similar effect:
+ * one "eeprom" file not four, but larger reads would fail when
+ * they crossed certain pages.
+ */
+
+ /*
+ * Slave address and byte offset derive from the offset. Always
+ * set the byte address; on a multi-master board, another master
+ * may have changed the chip's "current" address pointer.
+ */
+ client = at24_translate_offset(at24, &offset);
+
+ if (count > io_limit)
+ count = io_limit;
+
+ count = 1;
+
+ /*
+ * Reads fail if the previous write didn't complete yet. We may
+ * loop a few times until this one succeeds, waiting at least
+ * long enough for one entire page write to work.
+ */
+ timeout = jiffies + msecs_to_jiffies(write_timeout);
+ do {
+ read_time = jiffies;
+
+ status = i2c_smbus_write_byte_data(client, (offset >> 8) & 0x0ff, offset & 0x0ff );
+ status = i2c_smbus_read_byte(client);
+ if (status >= 0) {
+ buf[0] = status;
+ status = count;
+ }
+
+ dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
+ count, offset, status, jiffies);
+
+ if (status == count)
+ return count;
+
+ /* REVISIT: at HZ=100, this is sloooow */
+ msleep(1);
+ } while (time_before(read_time, timeout));
+
+ return -ETIMEDOUT;
+}
+
+static ssize_t at24_read(struct at24_data *at24,
+ char *buf, loff_t off, size_t count)
+{
+ ssize_t retval = 0;
+
+ if (unlikely(!count))
+ return count;
+
+ memset(buf, 0, count);
+
+ /*
+ * Read data from chip, protecting against concurrent updates
+ * from this host, but not from other I2C masters.
+ */
+ mutex_lock(&at24->lock);
+
+ while (count) {
+ ssize_t status;
+
+ status = at24_eeprom_read(at24, buf, off, count);
+ if (status <= 0) {
+ if (retval == 0)
+ retval = status;
+ break;
+ }
+ buf += status;
+ off += status;
+ count -= status;
+ retval += status;
+ }
+
+ //printk(KERN_ALERT "at24_read buf = %s, retval = %zu\n", buf, retval);
+
+ mutex_unlock(&at24->lock);
+
+ return retval;
+}
+
+static ssize_t at24_bin_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct at24_data *at24;
+
+ at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
+ return at24_read(at24, buf, off, count);
+}
+
+
+/*
+ * Note that if the hardware write-protect pin is pulled high, the whole
+ * chip is normally write protected. But there are plenty of product
+ * variants here, including OTP fuses and partial chip protect.
+ *
+ * We only use page mode writes; the alternative is sloooow. This routine
+ * writes at most one page.
+ */
+static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
+ unsigned offset, size_t count)
+{
+ struct i2c_client *client;
+ ssize_t status;
+ unsigned long timeout, write_time;
+ unsigned next_page;
+
+ /* Get corresponding I2C address and adjust offset */
+ client = at24_translate_offset(at24, &offset);
+
+ /* write_max is at most a page */
+ if (count > at24->write_max)
+ count = at24->write_max;
+
+ /* Never roll over backwards, to the start of this page */
+ next_page = roundup(offset + 1, at24->chip.page_size);
+ if (offset + count > next_page)
+ count = next_page - offset;
+
+ /*
+ * Writes fail if the previous one didn't complete yet. We may
+ * loop a few times until this one succeeds, waiting at least
+ * long enough for one entire page write to work.
+ */
+ timeout = jiffies + msecs_to_jiffies(write_timeout);
+ do {
+ write_time = jiffies;
+
+ status = i2c_smbus_write_word_data(client,
+ (offset >> 8) & 0x0ff, (offset & 0xFF) | buf[0]);
+ if (status == 0)
+ status = count;
+
+ dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
+ count, offset, status, jiffies);
+
+ if (status == count)
+ return count;
+
+ /* REVISIT: at HZ=100, this is sloooow */
+ msleep(1);
+ } while (time_before(write_time, timeout));
+
+ return -ETIMEDOUT;
+}
+
+static ssize_t at24_write(struct at24_data *at24, 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(&at24->lock);
+
+ while (count) {
+ ssize_t status;
+
+ status = at24_eeprom_write(at24, buf, off, 1); /* only one-byte to write; TODO page wirte */
+ if (status <= 0) {
+ if (retval == 0)
+ retval = status;
+ break;
+ }
+ buf += status;
+ off += status;
+ count -= status;
+ retval += status;
+ }
+
+ mutex_unlock(&at24->lock);
+
+ return retval;
+}
+
+static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct at24_data *at24;
+
+ if (unlikely(off >= attr->size))
+ return -EFBIG;
+
+ at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
+ return at24_write(at24, buf, off, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This lets other kernel code access the eeprom data. For example, it
+ * might hold a board's Ethernet address, or board-specific calibration
+ * data generated on the manufacturing floor.
+ */
+
+static ssize_t at24_macc_read(struct memory_accessor *macc, char *buf,
+ off_t offset, size_t count)
+{
+ struct at24_data *at24 = container_of(macc, struct at24_data, macc);
+
+ return at24_read(at24, buf, offset, count);
+}
+
+static ssize_t at24_macc_write(struct memory_accessor *macc, const char *buf,
+ off_t offset, size_t count)
+{
+ struct at24_data *at24 = container_of(macc, struct at24_data, macc);
+
+ return at24_write(at24, buf, offset, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_OF
+static void at24_get_ofdata(struct i2c_client *client,
+ struct at24_platform_data *chip)
+{
+ const __be32 *val;
+ struct device_node *node = client->dev.of_node;
+
+ if (node) {
+ if (of_get_property(node, "read-only", NULL))
+ chip->flags |= AT24_FLAG_READONLY;
+ val = of_get_property(node, "pagesize", NULL);
+ if (val)
+ chip->page_size = be32_to_cpup(val);
+ }
+}
+#else
+static void at24_get_ofdata(struct i2c_client *client,
+ struct at24_platform_data *chip)
+{ }
+#endif /* CONFIG_OF */
+
+static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct at24_platform_data chip;
+ bool writable;
+ int use_smbus = 0;
+ struct at24_data *at24;
+ int err;
+ unsigned i, num_addresses;
+ kernel_ulong_t magic;
+
+ if (client->dev.platform_data) {
+ chip = *(struct at24_platform_data *)client->dev.platform_data;
+ } else {
+ if (!id->driver_data)
+ return -ENODEV;
+
+ magic = id->driver_data;
+ chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
+ magic >>= AT24_SIZE_BYTELEN;
+ chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
+
+ /*
+ * This is slow, but we can't know all eeproms, so we better
+ * play safe. Specifying custom eeprom-types via platform_data
+ * is recommended anyhow.
+ */
+ chip.page_size = 1;
+
+ /* update chipdata if OF is present */
+ at24_get_ofdata(client, &chip);
+
+ printk(KERN_ALERT "at24_probe chip.byte_len = 0x%x\n", chip.byte_len);
+ printk(KERN_ALERT "at24_probe chip.flags = 0x%x\n", chip.flags);
+ printk(KERN_ALERT "at24_probe chip.magic = 0x%lx\n", id->driver_data);
+
+ chip.setup = NULL;
+ chip.context = NULL;
+ }
+
+ if (!is_power_of_2(chip.byte_len))
+ dev_warn(&client->dev,
+ "byte_len looks suspicious (no power of 2)!\n");
+ if (!chip.page_size) {
+ dev_err(&client->dev, "page_size must not be 0!\n");
+ return -EINVAL;
+ }
+ if (!is_power_of_2(chip.page_size))
+ dev_warn(&client->dev,
+ "page_size looks suspicious (no power of 2)!\n");
+
+ /* Use I2C operations unless we're stuck with SMBus extensions. */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ use_smbus = I2C_SMBUS_I2C_BLOCK_DATA;
+ } else if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+ use_smbus = I2C_SMBUS_WORD_DATA;
+ } else if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
+ use_smbus = I2C_SMBUS_BYTE_DATA;
+ } else {
+ return -EPFNOSUPPORT;
+ }
+ use_smbus = I2C_SMBUS_BYTE_DATA;
+ printk(KERN_ALERT "at24_probe use_smbus --> %d\n",
+ use_smbus);
+ }
+
+ if (chip.flags & AT24_FLAG_TAKE8ADDR)
+ num_addresses = 8;
+ else
+ num_addresses = DIV_ROUND_UP(chip.byte_len,
+ (chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);
+
+ at24 = devm_kzalloc(&client->dev, sizeof(struct at24_data) +
+ num_addresses * sizeof(struct i2c_client *), GFP_KERNEL);
+ if (!at24)
+ return -ENOMEM;
+
+ mutex_init(&at24->lock);
+ at24->use_smbus = use_smbus;
+ at24->chip = chip;
+ at24->num_addresses = num_addresses;
+
+ /*
+ * Export the EEPROM bytes through sysfs, since that's convenient.
+ * By default, only root should see the data (maybe passwords etc)
+ */
+ sysfs_bin_attr_init(&at24->bin);
+ at24->bin.attr.name = "eeprom";
+ at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR;
+ at24->bin.read = at24_bin_read;
+ at24->bin.size = chip.byte_len;
+
+ at24->macc.read = at24_macc_read;
+
+ writable = !(chip.flags & AT24_FLAG_READONLY);
+ if (writable) {
+ if (!use_smbus || i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
+
+ unsigned write_max = chip.page_size;
+
+ at24->macc.write = at24_macc_write;
+
+ at24->bin.write = at24_bin_write;
+ at24->bin.attr.mode |= S_IWUSR;
+
+ if (write_max > io_limit)
+ write_max = io_limit;
+ if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX)
+ write_max = I2C_SMBUS_BLOCK_MAX;
+ at24->write_max = write_max;
+
+ /* buffer (data + address at the beginning) */
+ at24->writebuf = devm_kzalloc(&client->dev,
+ write_max + 2, GFP_KERNEL);
+ if (!at24->writebuf)
+ return -ENOMEM;
+ } else {
+ dev_warn(&client->dev,
+ "cannot write due to controller restrictions.");
+ }
+ }
+
+ at24->client[0] = client;
+
+ /* use dummy devices for multiple-address chips */
+ for (i = 1; i < num_addresses; i++) {
+ at24->client[i] = i2c_new_dummy(client->adapter,
+ client->addr + i);
+ if (!at24->client[i]) {
+ dev_err(&client->dev, "address 0x%02x unavailable\n",
+ client->addr + i);
+ err = -EADDRINUSE;
+ goto err_clients;
+ }
+ }
+
+ err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin);
+ if (err)
+ goto err_clients;
+
+ i2c_set_clientdata(client, at24);
+
+ dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/write\n",
+ at24->bin.size, client->name,
+ writable ? "writable" : "read-only", at24->write_max);
+ if (use_smbus == I2C_SMBUS_WORD_DATA ||
+ use_smbus == I2C_SMBUS_BYTE_DATA) {
+ dev_notice(&client->dev, "Falling back to %s reads, "
+ "performance will suffer\n", use_smbus ==
+ I2C_SMBUS_WORD_DATA ? "word" : "byte");
+ }
+
+ /* export data to kernel code */
+ if (chip.setup)
+ chip.setup(&at24->macc, chip.context);
+
+ return 0;
+
+err_clients:
+ for (i = 1; i < num_addresses; i++)
+ if (at24->client[i])
+ i2c_unregister_device(at24->client[i]);
+
+ return err;
+}
+
+static int at24_remove(struct i2c_client *client)
+{
+ struct at24_data *at24;
+ int i;
+
+ at24 = i2c_get_clientdata(client);
+ sysfs_remove_bin_file(&client->dev.kobj, &at24->bin);
+
+ for (i = 1; i < at24->num_addresses; i++)
+ i2c_unregister_device(at24->client[i]);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct i2c_board_info i2c_devs = {
+ I2C_BOARD_INFO("24c64-ctc", 0x57),
+};
+
+static struct i2c_adapter *adapter = NULL;
+static struct i2c_client *client = NULL;
+
+static int ctc_at24c64_init(void)
+{
+ printk(KERN_ALERT "ctc_at24c64_init\n");
+
+ adapter = i2c_get_adapter(0);
+ if(adapter == NULL){
+ printk(KERN_ALERT "i2c_get_adapter == NULL\n");
+ return -1;
+ }
+
+ client = i2c_new_device(adapter, &i2c_devs);
+ if(client == NULL){
+ printk(KERN_ALERT "i2c_new_device == NULL\n");
+ i2c_put_adapter(adapter);
+ adapter = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static void ctc_at24c64_exit(void)
+{
+ printk(KERN_ALERT "ctc_at24c64_exit\n");
+ if(client){
+ i2c_unregister_device(client);
+ }
+ if(adapter){
+ i2c_put_adapter(adapter);
+ }
+}
+
+static struct i2c_driver at24_ctc_driver = {
+ .driver = {
+ .name = "at24-ctc",
+ .owner = THIS_MODULE,
+ },
+ .probe = at24_probe,
+ .remove = at24_remove,
+ .id_table = at24_ctc_ids,
+};
+
+static int __init at24_ctc_init(void)
+{
+ if (!io_limit) {
+ pr_err("at24_ctc: io_limit must not be 0!\n");
+ return -EINVAL;
+ }
+
+ io_limit = rounddown_pow_of_two(io_limit);
+
+ ctc_at24c64_init();
+
+ return i2c_add_driver(&at24_ctc_driver);
+}
+module_init(at24_ctc_init);
+
+static void __exit at24_ctc_exit(void)
+{
+ ctc_at24c64_exit();
+ i2c_del_driver(&at24_ctc_driver);
+}
+module_exit(at24_ctc_exit);
+
+MODULE_DESCRIPTION("Driver for most I2C EEPROMs");
+MODULE_AUTHOR("David Brownell and Wolfram Sang");
+MODULE_LICENSE("GPL");
+/* XXX */
diff --git a/platform/centec/sonic-platform-modules-e582/48x6q/modules/centec_e582_48x6q_platform.c b/platform/centec/sonic-platform-modules-e582/48x6q/modules/centec_e582_48x6q_platform.c
new file mode 100644
index 0000000000..4837335872
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x6q/modules/centec_e582_48x6q_platform.c
@@ -0,0 +1,1380 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define SEP(XXX) 1
+#define IS_INVALID_PTR(_PTR_) ((_PTR_ == NULL) || IS_ERR(_PTR_))
+#define IS_VALID_PTR(_PTR_) (!IS_INVALID_PTR(_PTR_))
+
+#if SEP("defines")
+#define PCA9548_CHANNEL_NUM 8
+#define PCA9548_ADAPT_ID_START 10
+#define SFP_NUM 48
+#define QSFP_NUM 6
+#define PORT_NUM (SFP_NUM+QSFP_NUM)
+#endif
+
+#if SEP("i2c:master")
+static struct i2c_adapter *i2c_adp_master = NULL; /* i2c-0-cpu */
+
+static int e582_48x6q_init_i2c_master(void)
+{
+ /* find i2c-core master */
+ i2c_adp_master = i2c_get_adapter(0);
+ if(IS_INVALID_PTR(i2c_adp_master))
+ {
+ i2c_adp_master = NULL;
+ printk(KERN_CRIT "e582_48x6q_init_i2c_master can't find i2c-core bus\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int e582_48x6q_exit_i2c_master(void)
+{
+ /* uninstall i2c-core master */
+ if(IS_VALID_PTR(i2c_adp_master)) {
+ i2c_put_adapter(i2c_adp_master);
+ i2c_adp_master = NULL;
+ }
+
+ return 0;
+}
+#endif
+
+#if SEP("i2c:pca9548")
+static struct pca954x_platform_mode i2c_dev_pca9548_platform_mode[PCA9548_CHANNEL_NUM] = {
+ [0] = {
+ .adap_id = PCA9548_ADAPT_ID_START,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [1] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 1,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [2] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 2,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [3] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 3,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [4] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 4,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [5] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 5,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [6] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 6,
+ .deselect_on_exit = 1,
+ .class = 0,
+ },
+ [7] = {
+ .adap_id = PCA9548_ADAPT_ID_START + 7,
+ .deselect_on_exit = 1,
+ .class = 0,
+ }
+};
+static struct pca954x_platform_data i2c_dev_pca9548_platform_data = {
+ .modes = i2c_dev_pca9548_platform_mode,
+ .num_modes = PCA9548_CHANNEL_NUM,
+};
+static struct i2c_board_info i2c_dev_pca9548 = {
+ I2C_BOARD_INFO("pca9548", 0x70),
+ .platform_data = &i2c_dev_pca9548_platform_data,
+};
+static struct i2c_client *i2c_client_pca9548x = NULL;
+
+static int e582_48x6q_init_i2c_pca9548(void)
+{
+ if(IS_INVALID_PTR(i2c_adp_master))
+ {
+ i2c_adp_master = NULL;
+ printk(KERN_CRIT "e582_48x6q_init_i2c_pca9548 can't find i2c-core bus\n");
+ return -1;
+ }
+
+ /* install i2c-mux */
+ i2c_client_pca9548x = i2c_new_device(i2c_adp_master, &i2c_dev_pca9548);
+ if(IS_INVALID_PTR(i2c_client_pca9548x))
+ {
+ i2c_client_pca9548x = NULL;
+ printk(KERN_CRIT "install e582_48x6q board pca9548 failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int e582_48x6q_exit_i2c_pca9548(void)
+{
+ /* uninstall i2c-core master */
+ if(IS_VALID_PTR(i2c_client_pca9548x)) {
+ i2c_unregister_device(i2c_client_pca9548x);
+ i2c_client_pca9548x = NULL;
+ }
+
+ return 0;
+}
+#endif
+
+#if SEP("i2c:adt7470")
+static struct i2c_board_info i2c_dev_adt7470 = {
+ I2C_BOARD_INFO("adt7470", 0x2F),
+};
+static struct i2c_adapter *i2c_adp_adt7470 = NULL; /* pca9548x-channel 5 */
+static struct i2c_client *i2c_client_adt7470 = NULL;
+
+static int e582_48x6q_init_i2c_adt7470(void)
+{
+ i2c_adp_adt7470 = i2c_get_adapter(PCA9548_ADAPT_ID_START + 5);
+ if(IS_INVALID_PTR(i2c_adp_adt7470))
+ {
+ i2c_adp_adt7470 = NULL;
+ printk(KERN_CRIT "install e582_48x6q board adt7470 failed\n");
+ return -1;
+ }
+
+ i2c_client_adt7470 = i2c_new_device(i2c_adp_adt7470, &i2c_dev_adt7470);
+ if(IS_INVALID_PTR(i2c_client_adt7470)){
+ i2c_client_adt7470 = NULL;
+ printk(KERN_CRIT "install e582_48x6q board adt7470 failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int e582_48x6q_exit_i2c_adt7470(void)
+{
+ if(IS_VALID_PTR(i2c_client_adt7470)) {
+ i2c_unregister_device(i2c_client_adt7470);
+ i2c_client_adt7470 = NULL;
+ }
+
+ if(IS_VALID_PTR(i2c_adp_adt7470)) {
+ i2c_put_adapter(i2c_adp_adt7470);
+ i2c_adp_adt7470 = NULL;
+ }
+
+ return 0;
+}
+#endif
+
+#if SEP("i2c:psu")
+static struct i2c_adapter *i2c_adp_psu1 = NULL; /* psu1 channel 3 */
+static struct i2c_adapter *i2c_adp_psu2 = NULL; /* psu2 channel 1 */
+static struct i2c_board_info i2c_dev_psu1 = {
+ I2C_BOARD_INFO("i2c-psu1", 0x38),
+};
+static struct i2c_board_info i2c_dev_psu2 = {
+ I2C_BOARD_INFO("i2c-psu2", 0x38),
+};
+static struct i2c_client *i2c_client_psu1 = NULL;
+static struct i2c_client *i2c_client_psu2 = NULL;
+
+static int e582_48x6q_init_i2c_psu(void)
+{
+ i2c_adp_psu1 = i2c_get_adapter(PCA9548_ADAPT_ID_START + 3);
+ if(IS_INVALID_PTR(i2c_adp_psu1))
+ {
+ i2c_adp_psu1 = NULL;
+ printk(KERN_CRIT "get e582_48x6q psu1 i2c-adp failed\n");
+ return -1;
+ }
+
+ i2c_adp_psu2 = i2c_get_adapter(PCA9548_ADAPT_ID_START + 1);
+ if(IS_INVALID_PTR(i2c_adp_psu2))
+ {
+ i2c_adp_psu2 = NULL;
+ printk(KERN_CRIT "get e582_48x6q psu2 i2c-adp failed\n");
+ return -1;
+ }
+
+ i2c_client_psu1 = i2c_new_device(i2c_adp_psu1, &i2c_dev_psu1);
+ if(IS_INVALID_PTR(i2c_client_psu1)){
+ i2c_client_psu1 = NULL;
+ printk(KERN_CRIT "create e582_48x6q board i2c client psu1 failed\n");
+ return -1;
+ }
+
+ i2c_client_psu2 = i2c_new_device(i2c_adp_psu2, &i2c_dev_psu2);
+ if(IS_INVALID_PTR(i2c_client_psu2)){
+ i2c_client_psu2 = NULL;
+ printk(KERN_CRIT "create e582_48x6q board i2c client psu2 failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int e582_48x6q_exit_i2c_psu(void)
+{
+ if(IS_VALID_PTR(i2c_client_psu1)) {
+ i2c_unregister_device(i2c_client_psu1);
+ i2c_client_psu1 = NULL;
+ }
+
+ if(IS_VALID_PTR(i2c_client_psu2)) {
+ i2c_unregister_device(i2c_client_psu2);
+ i2c_client_psu2 = NULL;
+ }
+
+ if(IS_VALID_PTR(i2c_adp_psu1))
+ {
+ i2c_put_adapter(i2c_adp_psu1);
+ i2c_adp_psu1 = NULL;
+ }
+
+ if(IS_VALID_PTR(i2c_adp_psu2))
+ {
+ i2c_put_adapter(i2c_adp_psu2);
+ i2c_adp_psu2 = NULL;
+ }
+
+ return 0;
+}
+#endif
+
+#if SEP("i2c:epld")
+static struct i2c_board_info i2c_dev_epld = {
+ I2C_BOARD_INFO("i2c-epld", 0x58),
+};
+static struct i2c_client *i2c_client_epld = NULL;
+
+static int e582_48x6q_init_i2c_epld(void)
+{
+ if (IS_INVALID_PTR(i2c_adp_master))
+ {
+ printk(KERN_CRIT "e582_48x6q_init_i2c_epld can't find i2c-core bus\n");
+ return -1;
+ }
+
+ i2c_client_epld = i2c_new_device(i2c_adp_master, &i2c_dev_epld);
+ if(IS_INVALID_PTR(i2c_client_epld))
+ {
+ i2c_client_epld = NULL;
+ printk(KERN_CRIT "create e582_48x6q board i2c client epld failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int e582_48x6q_exit_i2c_epld(void)
+{
+ if(IS_VALID_PTR(i2c_client_epld)) {
+ i2c_unregister_device(i2c_client_epld);
+ i2c_client_epld = NULL;
+ }
+
+ return 0;
+}
+#endif
+
+#if SEP("i2c:gpio")
+static struct i2c_board_info i2c_dev_gpio0 = {
+ I2C_BOARD_INFO("i2c-gpio0", 0x20),
+};
+static struct i2c_board_info i2c_dev_gpio1 = {
+ I2C_BOARD_INFO("i2c-gpio1", 0x21),
+};
+static struct i2c_board_info i2c_dev_gpio2 = {
+ I2C_BOARD_INFO("i2c-gpio2", 0x22),
+};
+static struct i2c_board_info i2c_dev_gpio3 = {
+ I2C_BOARD_INFO("i2c-gpio3", 0x23),
+};
+static struct i2c_board_info i2c_dev_gpio4 = {
+ I2C_BOARD_INFO("i2c-gpio4", 0x24),
+};
+static struct i2c_client *i2c_client_gpio0 = NULL;
+static struct i2c_client *i2c_client_gpio1 = NULL;
+static struct i2c_client *i2c_client_gpio2 = NULL;
+static struct i2c_client *i2c_client_gpio3 = NULL;
+static struct i2c_client *i2c_client_gpio4 = NULL;
+
+static int e582_48x6q_init_i2c_gpio(void)
+{
+ if (IS_INVALID_PTR(i2c_adp_master))
+ {
+ printk(KERN_CRIT "e582_48x6q_init_i2c_gpio can't find i2c-core bus\n");
+ return -1;
+ }
+
+ i2c_client_gpio0 = i2c_new_device(i2c_adp_master, &i2c_dev_gpio0);
+ if(IS_INVALID_PTR(i2c_client_gpio0))
+ {
+ i2c_client_gpio0 = NULL;
+ printk(KERN_CRIT "create e582_48x6q board i2c client gpio0 failed\n");
+ return -1;
+ }
+
+ i2c_client_gpio1 = i2c_new_device(i2c_adp_master, &i2c_dev_gpio1);
+ if(IS_INVALID_PTR(i2c_client_gpio1))
+ {
+ i2c_client_gpio1 = NULL;
+ printk(KERN_CRIT "create e582_48x6q board i2c client gpio1 failed\n");
+ return -1;
+ }
+
+ i2c_client_gpio2 = i2c_new_device(i2c_adp_master, &i2c_dev_gpio2);
+ if(IS_INVALID_PTR(i2c_client_gpio2))
+ {
+ i2c_client_gpio2 = NULL;
+ printk(KERN_CRIT "create e582_48x6q board i2c client gpio2 failed\n");
+ return -1;
+ }
+
+ i2c_client_gpio3 = i2c_new_device(i2c_adp_master, &i2c_dev_gpio3);
+ if(IS_INVALID_PTR(i2c_client_gpio3))
+ {
+ i2c_client_gpio3 = NULL;
+ printk(KERN_CRIT "create e582_48x6q board i2c client gpio3 failed\n");
+ return -1;
+ }
+
+ i2c_client_gpio4 = i2c_new_device(i2c_adp_master, &i2c_dev_gpio4);
+ if(IS_INVALID_PTR(i2c_client_gpio4))
+ {
+ i2c_client_gpio4 = NULL;
+ printk(KERN_CRIT "create e582_48x6q board i2c client gpio4 failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int e582_48x6q_exit_i2c_gpio(void)
+{
+ if(IS_VALID_PTR(i2c_client_gpio0)) {
+ i2c_unregister_device(i2c_client_gpio0);
+ i2c_client_gpio0 = NULL;
+ }
+
+ if((i2c_client_gpio1)) {
+ i2c_unregister_device(i2c_client_gpio1);
+ i2c_client_gpio1 = NULL;
+ }
+
+ if(IS_VALID_PTR(i2c_client_gpio2)) {
+ i2c_unregister_device(i2c_client_gpio2);
+ i2c_client_gpio2 = NULL;
+ }
+
+ if(IS_VALID_PTR(i2c_client_gpio3)) {
+ i2c_unregister_device(i2c_client_gpio3);
+ i2c_client_gpio3 = NULL;
+ }
+
+ if(IS_VALID_PTR(i2c_client_gpio4)) {
+ i2c_unregister_device(i2c_client_gpio4);
+ i2c_client_gpio4 = NULL;
+ }
+
+ return 0;
+}
+#endif
+
+#if SEP("i2c:smbus")
+static int e582_48x6q_smbus_read_reg(struct i2c_client *client, unsigned char reg, unsigned char* value)
+{
+ int ret = 0;
+
+ if (IS_INVALID_PTR(client))
+ {
+ printk(KERN_CRIT "invalid i2c client");
+ return -1;
+ }
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret >= 0) {
+ *value = (unsigned char)ret;
+ }
+ else
+ {
+ *value = 0;
+ printk(KERN_CRIT "i2c_smbus op failed: ret=%d reg=%d\n",ret ,reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int e582_48x6q_smbus_write_reg(struct i2c_client *client, unsigned char reg, unsigned char value)
+{
+ int ret = 0;
+
+ if (IS_INVALID_PTR(client))
+ {
+ printk(KERN_CRIT "invalid i2c client");
+ return -1;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, reg, value);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "i2c_smbus op failed: ret=%d reg=%d\n",ret ,reg);
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+#if SEP("drivers:psu")
+static struct class* psu_class = NULL;
+static struct device* psu_dev_psu1 = NULL;
+static struct device* psu_dev_psu2 = NULL;
+
+static ssize_t e582_48x6q_psu_read_presence(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int ret = 0;
+ unsigned char present_no = 0;
+ unsigned char present = 0;
+ unsigned char value = 0;
+ struct i2c_client *i2c_psu_client = NULL;
+
+ if (psu_dev_psu1 == dev)
+ {
+ i2c_psu_client = i2c_client_gpio0;
+ present_no = 17;
+ }
+ else if (psu_dev_psu2 == dev)
+ {
+ i2c_psu_client = i2c_client_gpio0;
+ present_no = 9;
+ }
+ else
+ {
+ return sprintf(buf, "Error: unknown psu device\n");
+ }
+
+ if (IS_INVALID_PTR(i2c_psu_client))
+ {
+ return sprintf(buf, "Error: psu i2c-adapter invalid\n");
+ }
+
+ ret = e582_48x6q_smbus_read_reg(i2c_psu_client, present_no/8, &present);
+ if (ret != 0)
+ {
+ return sprintf(buf, "Error: read psu data:%s failed\n", attr->attr.name);
+ }
+
+ value = ((present & (1<<(present_no%8))) ? 1 : 0 );
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t e582_48x6q_psu_read_status(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int ret = 0;
+ unsigned char workstate_no = 0;
+ unsigned char workstate = 0;
+ unsigned char value = 0;
+ struct i2c_client *i2c_psu_client = NULL;
+
+ if (psu_dev_psu1 == dev)
+ {
+ i2c_psu_client = i2c_client_gpio0;
+ workstate_no = 21;
+ }
+ else if (psu_dev_psu2 == dev)
+ {
+ i2c_psu_client = i2c_client_gpio0;
+ workstate_no = 13;
+ }
+ else
+ {
+ return sprintf(buf, "Error: unknown psu device\n");
+ }
+
+ if (IS_INVALID_PTR(i2c_psu_client))
+ {
+ return sprintf(buf, "Error: psu i2c-adapter invalid\n");
+ }
+
+ ret = e582_48x6q_smbus_read_reg(i2c_psu_client, workstate_no/8, &workstate);
+ if (ret != 0)
+ {
+ return sprintf(buf, "Error: read psu data:%s failed\n", attr->attr.name);
+ }
+
+ if (ret != 0)
+ {
+ return sprintf(buf, "Error: read psu data:%s failed\n", attr->attr.name);
+ }
+
+ value = ((workstate & (1<<(workstate_no%8))) ? 1 : 0 );
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static DEVICE_ATTR(psu_presence, S_IRUGO, e582_48x6q_psu_read_presence, NULL);
+static DEVICE_ATTR(psu_status, S_IRUGO, e582_48x6q_psu_read_status, NULL);
+
+static int e582_48x6q_init_psu(void)
+{
+ int ret = 0;
+
+ psu_class = class_create(THIS_MODULE, "psu");
+ if (IS_INVALID_PTR(psu_class))
+ {
+ psu_class = NULL;
+ printk(KERN_CRIT "create e582_48x6q class psu failed\n");
+ return -1;
+ }
+
+ psu_dev_psu1 = device_create(psu_class, NULL, MKDEV(222,0), NULL, "psu1");
+ if (IS_INVALID_PTR(psu_dev_psu1))
+ {
+ psu_dev_psu1 = NULL;
+ printk(KERN_CRIT "create e582_48x6q psu1 device failed\n");
+ return -1;
+ }
+
+ psu_dev_psu2 = device_create(psu_class, NULL, MKDEV(222,1), NULL, "psu2");
+ if (IS_INVALID_PTR(psu_dev_psu2))
+ {
+ psu_dev_psu2 = NULL;
+ printk(KERN_CRIT "create e582_48x6q psu2 device failed\n");
+ return -1;
+ }
+
+ ret = device_create_file(psu_dev_psu1, &dev_attr_psu_presence);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q psu1 device attr:presence failed\n");
+ return -1;
+ }
+
+ ret = device_create_file(psu_dev_psu1, &dev_attr_psu_status);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q psu1 device attr:status failed\n");
+ return -1;
+ }
+
+ ret = device_create_file(psu_dev_psu2, &dev_attr_psu_presence);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q psu2 device attr:presence failed\n");
+ return -1;
+ }
+
+ ret = device_create_file(psu_dev_psu2, &dev_attr_psu_status);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q psu2 device attr:status failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int e582_48x6q_exit_psu(void)
+{
+ if (IS_VALID_PTR(psu_dev_psu1))
+ {
+ device_remove_file(psu_dev_psu1, &dev_attr_psu_presence);
+ device_remove_file(psu_dev_psu1, &dev_attr_psu_status);
+ device_destroy(psu_class, MKDEV(222,0));
+ }
+
+ if (IS_VALID_PTR(psu_dev_psu2))
+ {
+ device_remove_file(psu_dev_psu2, &dev_attr_psu_presence);
+ device_remove_file(psu_dev_psu2, &dev_attr_psu_status);
+ device_destroy(psu_class, MKDEV(222,1));
+ }
+
+ if (IS_VALID_PTR(psu_class))
+ {
+ class_destroy(psu_class);
+ psu_class = NULL;
+ }
+
+ return 0;
+}
+#endif
+
+#if SEP("drivers:leds")
+extern void e582_48x6q_led_set(struct led_classdev *led_cdev, enum led_brightness set_value);
+extern enum led_brightness e582_48x6q_led_get(struct led_classdev *led_cdev);
+extern void e582_48x6q_led_port_set(struct led_classdev *led_cdev, enum led_brightness set_value);
+extern enum led_brightness e582_48x6q_led_port_get(struct led_classdev *led_cdev);
+
+static struct led_classdev led_dev_system = {
+ .name = "system",
+ .brightness_set = e582_48x6q_led_set,
+ .brightness_get = e582_48x6q_led_get,
+};
+static struct led_classdev led_dev_idn = {
+ .name = "idn",
+ .brightness_set = e582_48x6q_led_set,
+ .brightness_get = e582_48x6q_led_get,
+};
+static struct led_classdev led_dev_fan1 = {
+ .name = "fan1",
+ .brightness_set = e582_48x6q_led_set,
+ .brightness_get = e582_48x6q_led_get,
+};
+static struct led_classdev led_dev_fan2 = {
+ .name = "fan2",
+ .brightness_set = e582_48x6q_led_set,
+ .brightness_get = e582_48x6q_led_get,
+};
+static struct led_classdev led_dev_fan3 = {
+ .name = "fan3",
+ .brightness_set = e582_48x6q_led_set,
+ .brightness_get = e582_48x6q_led_get,
+};
+static struct led_classdev led_dev_fan4 = {
+ .name = "fan4",
+ .brightness_set = e582_48x6q_led_set,
+ .brightness_get = e582_48x6q_led_get,
+};
+static struct led_classdev led_dev_psu1 = {
+ .name = "psu1",
+ .brightness_set = e582_48x6q_led_set,
+ .brightness_get = e582_48x6q_led_get,
+};
+static struct led_classdev led_dev_psu2 = {
+ .name = "psu2",
+ .brightness_set = e582_48x6q_led_set,
+ .brightness_get = e582_48x6q_led_get,
+};
+static struct led_classdev led_dev_port[PORT_NUM] = {
+{ .name = "port1", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port2", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port3", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port4", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port5", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port6", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port7", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port8", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port9", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port10", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port11", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port12", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port13", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port14", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port15", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port16", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port17", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port18", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port19", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port20", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port21", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port22", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port23", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port24", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port25", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port26", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port27", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port28", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port29", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port30", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port31", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port32", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port33", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port34", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port35", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port36", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port37", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port38", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port39", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port40", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port41", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port42", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port43", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port44", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port45", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port46", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port47", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port48", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port49", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port50", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port51", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port52", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port53", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,},
+{ .name = "port54", .brightness_set = e582_48x6q_led_port_set, .brightness_get = e582_48x6q_led_port_get,}
+};
+static unsigned char port_led_mode[PORT_NUM] = {0};
+
+void e582_48x6q_led_set(struct led_classdev *led_cdev, enum led_brightness set_value)
+{
+ int ret = 0;
+ unsigned char reg = 0;
+ unsigned char mask = 0;
+ unsigned char shift = 0;
+ unsigned char led_value = 0;
+ struct i2c_client *i2c_led_client = i2c_client_epld;
+
+ if (0 == strcmp(led_dev_system.name, led_cdev->name))
+ {
+ reg = 0x2;
+ mask = 0x0F;
+ shift = 4;
+ }
+ else if (0 == strcmp(led_dev_idn.name, led_cdev->name))
+ {
+ reg = 0x3;
+ mask = 0xFE;
+ shift = 0;
+ }
+ else if (0 == strcmp(led_dev_fan1.name, led_cdev->name))
+ {
+ goto not_support;
+ }
+ else if (0 == strcmp(led_dev_fan2.name, led_cdev->name))
+ {
+ goto not_support;
+ }
+ else if (0 == strcmp(led_dev_fan3.name, led_cdev->name))
+ {
+ goto not_support;
+ }
+ else if (0 == strcmp(led_dev_fan4.name, led_cdev->name))
+ {
+ goto not_support;
+ }
+ else if (0 == strcmp(led_dev_psu1.name, led_cdev->name))
+ {
+ goto not_support;
+ }
+ else if (0 == strcmp(led_dev_psu2.name, led_cdev->name))
+ {
+ goto not_support;
+ }
+ else
+ {
+ goto not_support;
+ }
+
+ ret = e582_48x6q_smbus_read_reg(i2c_led_client, reg, &led_value);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "Error: read %s led attr failed\n", led_cdev->name);
+ return;
+ }
+
+ led_value = ((led_value & mask) | ((set_value << shift) & (~mask)));
+
+ ret = e582_48x6q_smbus_write_reg(i2c_led_client, reg, led_value);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "Error: write %s led attr failed\n", led_cdev->name);
+ return;
+ }
+
+ return;
+
+not_support:
+
+ printk(KERN_INFO "Error: not support device:%s\n", led_cdev->name);
+ return;
+}
+
+enum led_brightness e582_48x6q_led_get(struct led_classdev *led_cdev)
+{
+ int ret = 0;
+ unsigned char reg = 0;
+ unsigned char mask = 0;
+ unsigned char shift = 0;
+ unsigned char led_value = 0;
+ struct i2c_client *i2c_led_client = i2c_client_epld;
+
+ if (0 == strcmp(led_dev_system.name, led_cdev->name))
+ {
+ reg = 0x2;
+ mask = 0xF0;
+ shift = 4;
+ }
+ else if (0 == strcmp(led_dev_idn.name, led_cdev->name))
+ {
+ reg = 0x3;
+ mask = 0x01;
+ shift = 0;
+ }
+ else if (0 == strcmp(led_dev_fan1.name, led_cdev->name))
+ {
+ goto not_support;
+ }
+ else if (0 == strcmp(led_dev_fan2.name, led_cdev->name))
+ {
+ goto not_support;
+ }
+ else if (0 == strcmp(led_dev_fan3.name, led_cdev->name))
+ {
+ goto not_support;
+ }
+ else if (0 == strcmp(led_dev_fan4.name, led_cdev->name))
+ {
+ goto not_support;
+ }
+ else if (0 == strcmp(led_dev_psu1.name, led_cdev->name))
+ {
+ goto not_support;
+ }
+ else if (0 == strcmp(led_dev_psu2.name, led_cdev->name))
+ {
+ goto not_support;
+ }
+ else
+ {
+ goto not_support;
+ }
+
+ ret = e582_48x6q_smbus_read_reg(i2c_led_client, reg, &led_value);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "Error: read %s led attr failed\n", led_cdev->name);
+ return;
+ }
+
+ led_value = ((led_value & mask) >> shift);
+
+ return led_value;
+
+not_support:
+
+ printk(KERN_INFO "Error: not support device:%s\n", led_cdev->name);
+ return 0;
+}
+
+void e582_48x6q_led_port_set(struct led_classdev *led_cdev, enum led_brightness set_value)
+{
+ int portNum = 0;
+
+ sscanf(led_cdev->name, "port%d", &portNum);
+
+ port_led_mode[portNum-1] = set_value;
+
+ return;
+}
+
+enum led_brightness e582_48x6q_led_port_get(struct led_classdev *led_cdev)
+{
+ int portNum = 0;
+
+ sscanf(led_cdev->name, "port%d", &portNum);
+
+ return port_led_mode[portNum-1];
+}
+
+static int e582_48x6q_init_led(void)
+{
+ int ret = 0;
+ int i = 0;
+
+ ret = led_classdev_register(NULL, &led_dev_system);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q led_dev_system device failed\n");
+ return -1;
+ }
+
+ ret = led_classdev_register(NULL, &led_dev_idn);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q led_dev_idn device failed\n");
+ return -1;
+ }
+
+ ret = led_classdev_register(NULL, &led_dev_fan1);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q led_dev_fan1 device failed\n");
+ return -1;
+ }
+
+ ret = led_classdev_register(NULL, &led_dev_fan2);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q led_dev_fan2 device failed\n");
+ return -1;
+ }
+
+ ret = led_classdev_register(NULL, &led_dev_fan3);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q led_dev_fan3 device failed\n");
+ return -1;
+ }
+
+ ret = led_classdev_register(NULL, &led_dev_fan4);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q led_dev_fan4 device failed\n");
+ return -1;
+ }
+
+ ret = led_classdev_register(NULL, &led_dev_psu1);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q led_dev_psu1 device failed\n");
+ return -1;
+ }
+
+ ret = led_classdev_register(NULL, &led_dev_psu2);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q led_dev_psu2 device failed\n");
+ return -1;
+ }
+
+ for (i=0; i PORT_NUM))
+ {
+ printk(KERN_CRIT "sfp read presence, invalid port number!\n");
+ value = 0;
+ }
+
+ if ((portNum >= 1) && (portNum <= 8))
+ {
+ reg_no = portNum + 31;/*32-39*/
+ i2c_sfp_client = i2c_client_gpio0;
+ }
+ else if ((portNum >= 9) && (portNum <= 16))
+ {
+ reg_no = portNum + 7;/*16-23*/
+ i2c_sfp_client = i2c_client_gpio1;
+ }
+ else if ((portNum >= 17) && (portNum <= 24))
+ {
+ reg_no = portNum - 17;/*0-7*/
+ i2c_sfp_client = i2c_client_gpio2;
+ }
+ else if ((portNum >= 25) && (portNum <= 32))
+ {
+ reg_no = portNum - 1;/*24-31*/
+ i2c_sfp_client = i2c_client_gpio2;
+ }
+ else if ((portNum >= 33) && (portNum <= 40))
+ {
+ reg_no = portNum - 25;/*8-15*/
+ i2c_sfp_client = i2c_client_gpio3;
+ }
+ else if ((portNum >= 41) && (portNum <= 48))
+ {
+ reg_no = portNum - 9;/*32-39*/
+ i2c_sfp_client = i2c_client_gpio3;
+ }
+ else if ((portNum >= 49) && (portNum <= 54))
+ {
+ reg_no = portNum - 25;/*24-29*/
+ i2c_sfp_client = i2c_client_gpio4;
+ }
+
+ dir_bank = (reg_no/8) + 0x18;
+ ret = e582_48x6q_smbus_write_reg(i2c_sfp_client, dir_bank, 0xff);
+ if (ret != 0)
+ {
+ return sprintf(buf, "Error: read sfp data:%s set dir-ctl failed\n", attr->attr.name);
+ }
+
+ input_bank = (reg_no/8) + 0x0;
+ ret = e582_48x6q_smbus_read_reg(i2c_sfp_client, input_bank, &value);
+ if (ret != 0)
+ {
+ return sprintf(buf, "Error: read sfp data:%s failed\n", attr->attr.name);
+ }
+
+ value = ((value & (1<<(reg_no%8))) ? 0 : 1 );/*1:PRESENT 0:ABSENT*/
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t e582_48x6q_sfp_read_enable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int ret = 0;
+ unsigned char value = 0;
+ unsigned char reg_no = 0;
+ unsigned char dir_bank = 0;
+ unsigned char input_bank = 0;
+ int portNum = 0;
+ const char *name = dev_name(dev);
+ struct i2c_client *i2c_sfp_client = NULL;
+
+ sscanf(name, "sfp%d", &portNum);
+
+ if ((portNum < 1) || (portNum > PORT_NUM))
+ {
+ printk(KERN_CRIT "sfp read presence, invalid port number!\n");
+ value = 0;
+ }
+
+ if ((portNum >= 1) && (portNum <= 8))
+ {
+ reg_no = portNum + 23;/*24-31*/
+ i2c_sfp_client = i2c_client_gpio0;
+ }
+ else if ((portNum >= 9) && (portNum <= 16))
+ {
+ reg_no = portNum - 1;/*8-15*/
+ i2c_sfp_client = i2c_client_gpio1;
+ }
+ else if ((portNum >= 17) && (portNum <= 24))
+ {
+ reg_no = portNum + 15;/*32-39*/
+ i2c_sfp_client = i2c_client_gpio1;
+ }
+ else if ((portNum >= 25) && (portNum <= 32))
+ {
+ reg_no = portNum - 9;/*16-23*/
+ i2c_sfp_client = i2c_client_gpio2;
+ }
+ else if ((portNum >= 33) && (portNum <= 40))
+ {
+ reg_no = portNum - 33;/*0-7*/
+ i2c_sfp_client = i2c_client_gpio3;
+ }
+ else if ((portNum >= 41) && (portNum <= 48))
+ {
+ reg_no = portNum - 17;/*24-31*/
+ i2c_sfp_client = i2c_client_gpio3;
+ }
+ else if ((portNum >= 49) && (portNum <= 54))
+ {
+ printk(KERN_INFO "%s not supported!\n", name);
+ return sprintf(buf, "%d\n", 0);
+ }
+
+ dir_bank = (reg_no/8) + 0x18;
+ ret = e582_48x6q_smbus_write_reg(i2c_sfp_client, dir_bank, 0xff);
+ if (ret != 0)
+ {
+ return sprintf(buf, "Error: read sfp data:%s set dir-ctl failed\n", attr->attr.name);
+ }
+
+ input_bank = (reg_no/8) + 0x8;
+ ret = e582_48x6q_smbus_read_reg(i2c_sfp_client, input_bank, &value);
+ if (ret != 0)
+ {
+ return sprintf(buf, "Error: read sfp data:%s failed\n", attr->attr.name);
+ }
+
+ value = ((value & (1<<(reg_no%8))) ? 0 : 1 );
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t e582_48x6q_sfp_write_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ int ret = 0;
+ unsigned char value = 0;
+ unsigned char set_value = simple_strtol(buf, NULL, 10);
+ unsigned char reg_no = 0;
+ unsigned char dir_bank = 0;
+ unsigned char input_bank = 0;
+ unsigned char output_bank = 0;
+ int portNum = 0;
+ const char *name = dev_name(dev);
+ struct i2c_client *i2c_sfp_client = NULL;
+
+ sscanf(name, "sfp%d", &portNum);
+
+ if ((portNum < 1) || (portNum > PORT_NUM))
+ {
+ printk(KERN_CRIT "sfp read presence, invalid port number!\n");
+ return size;
+ }
+
+ if ((portNum >= 1) && (portNum <= 8))
+ {
+ reg_no = portNum + 23;/*24-31*/
+ i2c_sfp_client = i2c_client_gpio0;
+ }
+ else if ((portNum >= 9) && (portNum <= 16))
+ {
+ reg_no = portNum - 1;/*8-15*/
+ i2c_sfp_client = i2c_client_gpio1;
+ }
+ else if ((portNum >= 17) && (portNum <= 24))
+ {
+ reg_no = portNum + 15;/*32-39*/
+ i2c_sfp_client = i2c_client_gpio1;
+ }
+ else if ((portNum >= 25) && (portNum <= 32))
+ {
+ reg_no = portNum - 9;/*16-23*/
+ i2c_sfp_client = i2c_client_gpio2;
+ }
+ else if ((portNum >= 33) && (portNum <= 40))
+ {
+ reg_no = portNum - 33;/*0-7*/
+ i2c_sfp_client = i2c_client_gpio3;
+ }
+ else if ((portNum >= 41) && (portNum <= 48))
+ {
+ reg_no = portNum - 17;/*24-31*/
+ i2c_sfp_client = i2c_client_gpio3;
+ }
+ else if ((portNum >= 49) && (portNum <= 54))
+ {
+ printk(KERN_INFO "%s not supported!\n", name);
+ return size;
+ }
+
+ set_value = ((set_value > 0) ? 0 : 1 );
+
+ dir_bank = (reg_no/8) + 0x18;
+ ret = e582_48x6q_smbus_write_reg(i2c_sfp_client, dir_bank, 0x0);
+ if (ret != 0)
+ {
+ return sprintf(buf, "Error: read sfp data:%s set dir-ctl failed\n", attr->attr.name);
+ }
+
+ input_bank = (reg_no/8) + 0x8;
+ ret = e582_48x6q_smbus_read_reg(i2c_sfp_client, input_bank, &value);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "Error: read %s presence failed\n", name);
+ return size;
+ }
+
+ if (set_value)
+ {
+ value = (value | (1<<(reg_no % 8)));
+ }
+ else
+ {
+ value = (value & (~(1<<(reg_no % 8))));
+ }
+
+ output_bank = (reg_no/8) + 0x8;
+ ret = e582_48x6q_smbus_write_reg(i2c_sfp_client, output_bank, value);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "Error: write %s presence failed\n", name);
+ return size;
+ }
+
+ return size;
+}
+
+static DEVICE_ATTR(sfp_presence, S_IRUGO, e582_48x6q_sfp_read_presence, NULL);
+static DEVICE_ATTR(sfp_enable, S_IRUGO|S_IWUGO, e582_48x6q_sfp_read_enable, e582_48x6q_sfp_write_enable);
+static int e582_48x6q_init_sfp(void)
+{
+ int ret = 0;
+ int i = 0;
+
+ sfp_class = class_create(THIS_MODULE, "sfp");
+ if (IS_INVALID_PTR(sfp_class))
+ {
+ sfp_class = NULL;
+ printk(KERN_CRIT "create e582_48x6q class sfp failed\n");
+ return -1;
+ }
+
+ for (i=1; i<=PORT_NUM; i++)
+ {
+ sfp_dev[i] = device_create(sfp_class, NULL, MKDEV(223,i), NULL, "sfp%d", i);
+ if (IS_INVALID_PTR(sfp_dev[i]))
+ {
+ sfp_dev[i] = NULL;
+ printk(KERN_CRIT "create e582_48x6q sfp[%d] device failed\n", i);
+ continue;
+ }
+
+ ret = device_create_file(sfp_dev[i], &dev_attr_sfp_presence);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q sfp[%d] device attr:presence failed\n", i);
+ continue;
+ }
+
+ ret = device_create_file(sfp_dev[i], &dev_attr_sfp_enable);
+ if (ret != 0)
+ {
+ printk(KERN_CRIT "create e582_48x6q sfp[%d] device attr:enable failed\n", i);
+ continue;
+ }
+ }
+
+ return ret;
+}
+
+static int e582_48x6q_exit_sfp(void)
+{
+ int i = 0;
+
+ for (i=1; i<=PORT_NUM; i++)
+ {
+ if (IS_VALID_PTR(sfp_dev[i]))
+ {
+ device_remove_file(sfp_dev[i], &dev_attr_sfp_presence);
+ device_remove_file(sfp_dev[i], &dev_attr_sfp_enable);
+ device_destroy(sfp_class, MKDEV(223,i));
+ sfp_dev[i] = NULL;
+ }
+ }
+
+ if (IS_VALID_PTR(sfp_class))
+ {
+ class_destroy(sfp_class);
+ sfp_class = NULL;
+ }
+
+ return 0;
+}
+#endif
+
+static int e582_48x6q_init(void)
+{
+ int ret = 0;
+ int failed = 0;
+
+ printk(KERN_ALERT "install e582_48x6q board dirver...\n");
+
+ ret = e582_48x6q_init_i2c_master();
+ if (ret != 0)
+ {
+ failed = 1;
+ }
+
+ ret = e582_48x6q_init_i2c_pca9548();
+ if (ret != 0)
+ {
+ failed = 1;
+ }
+
+ ret = e582_48x6q_init_i2c_adt7470();
+ if (ret != 0)
+ {
+ failed = 1;
+ }
+
+ ret = e582_48x6q_init_i2c_psu();
+ if (ret != 0)
+ {
+ failed = 1;
+ }
+
+ ret = e582_48x6q_init_i2c_epld();
+ if (ret != 0)
+ {
+ failed = 1;
+ }
+
+ ret = e582_48x6q_init_i2c_gpio();
+ if (ret != 0)
+ {
+ failed = 1;
+ }
+
+ ret = e582_48x6q_init_psu();
+ if (ret != 0)
+ {
+ failed = 1;
+ }
+
+ ret = e582_48x6q_init_led();
+ if (ret != 0)
+ {
+ failed = 1;
+ }
+
+ ret = e582_48x6q_init_sfp();
+ if (ret != 0)
+ {
+ failed = 1;
+ }
+
+ if (failed)
+ printk(KERN_INFO "install e582_48x6q board driver failed\n");
+ else
+ printk(KERN_ALERT "install e582_48x6q board dirver...ok\n");
+
+ return 0;
+}
+
+static void e582_48x6q_exit(void)
+{
+ printk(KERN_INFO "uninstall e582_48x6q board dirver...\n");
+
+ e582_48x6q_exit_sfp();
+ e582_48x6q_exit_led();
+ e582_48x6q_exit_psu();
+ e582_48x6q_exit_i2c_gpio();
+ e582_48x6q_exit_i2c_epld();
+ e582_48x6q_exit_i2c_psu();
+ e582_48x6q_exit_i2c_adt7470();
+ e582_48x6q_exit_i2c_pca9548();
+ e582_48x6q_exit_i2c_master();
+}
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("yangbs centecNetworks, Inc");
+MODULE_DESCRIPTION("e582-48x6q board driver");
+module_init(e582_48x6q_init);
+module_exit(e582_48x6q_exit);
+
diff --git a/platform/centec/sonic-platform-modules-e582/48x6q/modules/dal_kernel.c b/platform/centec/sonic-platform-modules-e582/48x6q/modules/dal_kernel.c
new file mode 100644
index 0000000000..a1315a9715
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x6q/modules/dal_kernel.c
@@ -0,0 +1,1822 @@
+/**
+ @file dal_kernal.c
+
+ @date 2012-10-18
+
+ @version v2.0
+
+
+*/
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
+#include
+#endif
+#include "dal_kernel.h"
+#include "dal_mpool.h"
+
+MODULE_AUTHOR("Centec Networks Inc.");
+MODULE_DESCRIPTION("DAL kernel module");
+MODULE_LICENSE("GPL");
+
+/* DMA memory pool size */
+static char* dma_pool_size;
+module_param(dma_pool_size, charp, 0);
+MODULE_PARM_DESC(dma_pool_size,
+ "Specify DMA memory pool size (default 4MB)");
+
+/*****************************************************************************
+ * defines
+ *****************************************************************************/
+#define MB_SIZE 0x100000
+#define CTC_MAX_INTR_NUM 8
+
+#define MEM_MAP_RESERVE SetPageReserved
+#define MEM_MAP_UNRESERVE ClearPageReserved
+
+#define CTC_VENDOR_VID 0xc001
+#define CTC_HUMBER_DEVICE_ID 0x6048
+#define CTC_GOLDENGATE_DEVICE_ID 0xcb10
+
+#define MEM_MAP_RESERVE SetPageReserved
+#define MEM_MAP_UNRESERVE ClearPageReserved
+
+#define CTC_GREATBELT_DEVICE_ID 0x03e8 /* TBD */
+#define DAL_MAX_CHIP_NUM 8 /* [GB] used */
+#define VIRT_TO_PAGE(p) virt_to_page((p))
+#define DAL_UNTAG_BLOCK 0
+#define DAL_DISCARD_BLOCK 1
+#define DAL_MATCHED_BLOCK 2
+#define DAL_CUR_MATCH_BLOCk 3
+/*****************************************************************************
+ * typedef
+ *****************************************************************************/
+/* Control Data */
+typedef struct dal_isr_s
+{
+ int irq;
+ void (* isr)(void*);
+ void* isr_data;
+ int trigger;
+ int count;
+ wait_queue_head_t wqh;
+} dal_isr_t;
+
+typedef struct dal_kernel_dev_s
+{
+ struct list_head list;
+ struct pci_dev* pci_dev;
+
+ /* PCI I/O mapped base address */
+ uintptr logic_address;
+
+ /* Physical address */
+ uintptr phys_address;
+} dal_kern_dev_t;
+
+typedef struct _dma_segment
+{
+ struct list_head list;
+ unsigned long req_size; /* Requested DMA segment size */
+ unsigned long blk_size; /* DMA block size */
+ unsigned long blk_order; /* DMA block size in alternate format */
+ unsigned long seg_size; /* Current DMA segment size */
+ unsigned long seg_begin; /* Logical address of segment */
+ unsigned long seg_end; /* Logical end address of segment */
+ unsigned long* blk_ptr; /* Array of logical DMA block addresses */
+ int blk_cnt_max; /* Maximum number of block to allocate */
+ int blk_cnt; /* Current number of blocks allocated */
+} dma_segment_t;
+
+typedef irqreturn_t (*p_func) (int irq, void* dev_id);
+
+/***************************************************************************
+ *declared
+ ***************************************************************************/
+static unsigned int linux_dal_poll0(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll1(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll2(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll3(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll4(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll5(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll6(struct file* filp, struct poll_table_struct* p);
+static unsigned int linux_dal_poll7(struct file* filp, struct poll_table_struct* p);
+
+/*****************************************************************************
+ * global variables
+ *****************************************************************************/
+static dal_kern_dev_t dal_dev[DAL_MAX_CHIP_NUM];
+static dal_isr_t dal_isr[CTC_MAX_INTR_NUM];
+static int dal_chip_num = 0;
+static int dal_version = 0;
+static int dal_intr_num = 0;
+static int use_high_memory = 0;
+static unsigned int* dma_virt_base[DAL_MAX_CHIP_NUM];
+#ifndef DMA_MEM_MODE_PLATFORM
+static unsigned int* dma_virt_base_tmp[DAL_MAX_CHIP_NUM];
+#endif
+static uintptr dma_phy_base[DAL_MAX_CHIP_NUM];
+static unsigned int dma_mem_size = 0x800000;
+static unsigned int msi_irq_base[DAL_MAX_CHIP_NUM];
+static unsigned int msi_irq_num[DAL_MAX_CHIP_NUM];
+static unsigned int msi_used = 0;
+static struct class *dal_class;
+
+static LIST_HEAD(_dma_seg);
+static int dal_debug = 0;
+module_param(dal_debug, int, 0);
+MODULE_PARM_DESC(dal_debug, "Set debug level (default 0)");
+
+static struct pci_device_id dal_id_table[] =
+{
+ {PCI_DEVICE(CTC_VENDOR_VID, CTC_GREATBELT_DEVICE_ID)},
+ {PCI_DEVICE(0xcb10, 0xc010)},
+ {0, },
+};
+
+static wait_queue_head_t poll_intr[CTC_MAX_INTR_NUM];
+
+p_func intr_handler_fun[CTC_MAX_INTR_NUM];
+
+static int poll_intr_trigger[CTC_MAX_INTR_NUM];
+
+static struct file_operations dal_intr_fops[CTC_MAX_INTR_NUM] =
+{
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll0,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll1,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll2,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll3,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll4,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll5,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll6,
+ },
+ {
+ .owner = THIS_MODULE,
+ .poll = linux_dal_poll7,
+ },
+};
+
+/*****************************************************************************
+ * macros
+ *****************************************************************************/
+#define VERIFY_CHIP_INDEX(n) (n < dal_chip_num)
+
+#define _KERNEL_INTERUPT_PROCESS
+static irqreturn_t
+intr0_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+
+ if(poll_intr_trigger[0])
+ {
+ return IRQ_HANDLED;
+ }
+
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[0] = 1;
+ wake_up(&poll_intr[0]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr1_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[1])
+ {
+ return IRQ_HANDLED;
+ }
+
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[1] = 1;
+ wake_up(&poll_intr[1]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr2_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[2])
+ {
+ return IRQ_HANDLED;
+ }
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[2] = 1;
+ wake_up(&poll_intr[2]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr3_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[3])
+ {
+ return IRQ_HANDLED;
+ }
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[3] = 1;
+ wake_up(&poll_intr[3]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr4_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[4])
+ {
+ return IRQ_HANDLED;
+ }
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[4] = 1;
+ wake_up(&poll_intr[4]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr5_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[5])
+ {
+ return IRQ_HANDLED;
+ }
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[5] = 1;
+ wake_up(&poll_intr[5]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr6_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[6])
+ {
+ return IRQ_HANDLED;
+ }
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[6] = 1;
+ wake_up(&poll_intr[6]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+intr7_handler(int irq, void* dev_id)
+{
+ dal_isr_t* p_dal_isr = (dal_isr_t*)dev_id;
+ if(poll_intr_trigger[7])
+ {
+ return IRQ_HANDLED;
+ }
+ disable_irq_nosync(irq);
+
+ if (p_dal_isr)
+ {
+ if (p_dal_isr->isr)
+ {
+ /* kernel mode interrupt handler */
+ p_dal_isr->isr(p_dal_isr->isr_data);
+ }
+ else if ((NULL == p_dal_isr->isr) && (NULL == p_dal_isr->isr_data))
+ {
+ /* user mode interrupt handler */
+ poll_intr_trigger[7] = 1;
+ wake_up(&poll_intr[7]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+int
+dal_interrupt_register(unsigned int irq, int prio, void (* isr)(void*), void* data)
+{
+ int ret;
+ unsigned char str[16];
+ unsigned char* int_name = NULL;
+ unsigned int intr_num_tmp = 0;
+ unsigned int intr_num = CTC_MAX_INTR_NUM;
+ unsigned long irq_flags = 0;
+
+ if (dal_intr_num >= CTC_MAX_INTR_NUM)
+ {
+ printk("Interrupt numbers exceeds max.\n");
+ return -1;
+ }
+
+ if (msi_used)
+ {
+ int_name = "dal_msi";
+ }
+ else
+ {
+ int_name = "dal_intr";
+ }
+
+
+ for (intr_num_tmp=0;intr_num_tmp < CTC_MAX_INTR_NUM; intr_num_tmp++)
+ {
+ if (irq == dal_isr[intr_num_tmp].irq)
+ {
+ dal_isr[intr_num_tmp].count++;
+ printk("Interrupt irq %d register count %d.\n", irq, dal_isr[intr_num_tmp].count);
+ return 0;
+ }
+ if ((0 == dal_isr[intr_num_tmp].irq) && (CTC_MAX_INTR_NUM == intr_num))
+ {
+ intr_num = intr_num_tmp;
+ dal_isr[intr_num].count = 0;
+ }
+ }
+ dal_isr[intr_num].irq = irq;
+ dal_isr[intr_num].isr = isr;
+ dal_isr[intr_num].isr_data = data;
+ dal_isr[intr_num].count++;
+
+ init_waitqueue_head(&poll_intr[intr_num]);
+
+ /* only user mode */
+ if ((NULL == isr) && (NULL == data))
+ {
+ snprintf(str, 16, "%s%d", "dal_intr", intr_num);
+ ret = register_chrdev(DAL_DEV_INTR_MAJOR_BASE + intr_num,
+ str, &dal_intr_fops[intr_num]);
+ if (ret < 0)
+ {
+ printk("Register character device for irq %d failed, ret= %d", irq, ret);
+ return ret;
+ }
+ }
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
+ irq_flags = 0;
+#else
+ irq_flags = IRQF_DISABLED;
+#endif
+ if ((ret = request_irq(irq,
+ intr_handler_fun[intr_num],
+ irq_flags,
+ int_name,
+ &dal_isr[intr_num])) < 0)
+ {
+ printk("Cannot request irq %d, ret %d.\n", irq, ret);
+ unregister_chrdev(DAL_DEV_INTR_MAJOR_BASE + intr_num, str);
+ }
+
+ if (0 == ret)
+ {
+ dal_intr_num++;
+ }
+
+ return ret;
+}
+
+int
+dal_interrupt_unregister(unsigned int irq)
+{
+ unsigned char str[16];
+ int intr_idx = 0;
+ int find_flag = 0;
+
+ /* get intr device index */
+ for (intr_idx = 0; intr_idx < CTC_MAX_INTR_NUM; intr_idx++)
+ {
+ if (dal_isr[intr_idx].irq == irq)
+ {
+ find_flag = 1;
+ break;
+ }
+ }
+
+ if (find_flag == 0)
+ {
+ printk ("irq%d is not registered! unregister failed \n", irq);
+ return -1;
+ }
+
+ dal_isr[intr_idx].count--;
+ if (0 != dal_isr[intr_idx].count)
+ {
+ printk("Interrupt irq %d unregister count %d.\n", irq, dal_isr[intr_idx].count);
+ return -1;
+ }
+ snprintf(str, 16, "%s%d", "dal_intr", intr_idx);
+
+ unregister_chrdev(DAL_DEV_INTR_MAJOR_BASE + intr_idx, str);
+
+ free_irq(irq, &dal_isr[intr_idx]);
+
+ dal_isr[intr_idx].irq = 0;
+
+ dal_intr_num--;
+
+ return 0;
+}
+
+int
+dal_interrupt_set_en(unsigned int irq, unsigned int enable)
+{
+ enable ? enable_irq(irq) : disable_irq_nosync(irq);
+ return 0;
+}
+
+static int
+_dal_set_msi_enabe(unsigned int lchip, unsigned int irq_num)
+{
+ int ret = 0;
+
+ if (irq_num == 1)
+ {
+ if (msi_irq_base[lchip])
+ {
+ dal_interrupt_unregister(msi_irq_base[lchip]);
+ pci_disable_msi(dal_dev[lchip].pci_dev);
+ msi_used = 0;
+ msi_irq_base[lchip] = 0;
+ msi_irq_num[lchip] = 0;
+ }
+ ret = pci_enable_msi(dal_dev[lchip].pci_dev);
+ if (ret)
+ {
+ printk ("msi enable failed!!! lchip = %d, irq_num = %d\n", lchip, irq_num);
+ pci_disable_msi(dal_dev[lchip].pci_dev);
+ msi_used = 0;
+ }
+
+ msi_irq_base[lchip] = dal_dev[lchip].pci_dev->irq;
+ msi_irq_num[lchip] = 1;
+ }
+ else
+ {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 79))
+ ret = pci_enable_msi_exact(dal_dev[lchip].pci_dev, irq_num);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 26, 32))
+ ret = pci_enable_msi_block(dal_dev[lchip].pci_dev, irq_num);
+#else
+ ret = -1;
+#endif
+ if (ret)
+ {
+ printk ("msi enable failed!!! lchip = %d, irq_num = %d\n", lchip, irq_num);
+ pci_disable_msi(dal_dev[lchip].pci_dev);
+ msi_used = 0;
+ }
+
+ msi_irq_base[lchip] = dal_dev[lchip].pci_dev->irq;
+ msi_irq_num[lchip] = irq_num;
+ }
+
+ return ret;
+}
+
+static int
+_dal_set_msi_disable(unsigned int lchip)
+{
+
+ pci_disable_msi(dal_dev[lchip].pci_dev);
+
+ msi_irq_base[lchip] = 0;
+ msi_irq_num[lchip] = 0;
+
+ return 0;
+}
+
+int
+dal_set_msi_cap(unsigned long arg)
+{
+ int ret = 0;
+ dal_msi_info_t msi_info;
+
+ if (copy_from_user(&msi_info, (void*)arg, sizeof(dal_msi_info_t)))
+ {
+ return -EFAULT;
+ }
+
+ printk("####dal_set_msi_cap lchip %d base %d num:%d\n", msi_info.lchip, msi_info.irq_base, msi_info.irq_num);
+ if (msi_info.irq_num > 0)
+ {
+ msi_used = 1;
+ ret = _dal_set_msi_enabe(msi_info.lchip, msi_info.irq_num);
+ }
+ else
+ {
+ msi_used = 0;
+ ret = _dal_set_msi_disable(msi_info.lchip);
+ }
+
+ return ret;
+}
+
+int
+dal_user_interrupt_register(unsigned long arg)
+{
+ int irq = 0;
+ if (copy_from_user(&irq, (void*)arg, sizeof(int)))
+ {
+ return -EFAULT;
+ }
+ printk("####register interrupt irq:%d\n", irq);
+ return dal_interrupt_register(irq, 0, NULL, NULL);
+}
+
+int
+dal_user_interrupt_unregister(unsigned long arg)
+{
+ int irq = 0;
+ if (copy_from_user(&irq, (void*)arg, sizeof(int)))
+ {
+ return -EFAULT;
+ }
+ printk("####unregister interrupt irq:%d\n", irq);
+ return dal_interrupt_unregister(irq);
+}
+
+int
+dal_user_interrupt_set_en(unsigned long arg)
+{
+ dal_intr_parm_t dal_intr_parm;
+
+ if (copy_from_user(&dal_intr_parm, (void*)arg, sizeof(dal_intr_parm_t)))
+ {
+ return -EFAULT;
+ }
+
+ return dal_interrupt_set_en(dal_intr_parm.irq, dal_intr_parm.enable);
+}
+
+/*
+ * Function: _dal_dma_segment_free
+ */
+
+/*
+ * Function: _find_largest_segment
+ *
+ * Purpose:
+ * Find largest contiguous segment from a pool of DMA blocks.
+ * Parameters:
+ * dseg - DMA segment descriptor
+ * Returns:
+ * 0 on success, < 0 on error.
+ * Notes:
+ * Assembly stops if a segment of the requested segment size
+ * has been obtained.
+ *
+ * Lower address bits of the DMA blocks are used as follows:
+ * 0: Untagged
+ * 1: Discarded block
+ * 2: Part of largest contiguous segment
+ * 3: Part of current contiguous segment
+ */
+#ifndef DMA_MEM_MODE_PLATFORM
+static int
+_dal_find_largest_segment(dma_segment_t* dseg)
+{
+ int i, j, blks, found;
+ unsigned long seg_begin;
+ unsigned long seg_end;
+ unsigned long seg_tmp;
+
+ blks = dseg->blk_cnt;
+
+ /* Clear all block tags */
+ for (i = 0; i < blks; i++)
+ {
+ dseg->blk_ptr[i] &= ~3;
+ }
+
+ for (i = 0; i < blks && dseg->seg_size < dseg->req_size; i++)
+ {
+ /* First block must be an untagged block */
+ if ((dseg->blk_ptr[i] & 3) == DAL_UNTAG_BLOCK)
+ {
+ /* Initial segment size is the block size */
+ seg_begin = dseg->blk_ptr[i];
+ seg_end = seg_begin + dseg->blk_size;
+ dseg->blk_ptr[i] |= DAL_CUR_MATCH_BLOCk;
+
+ /* Loop looking for adjacent blocks */
+ do
+ {
+ found = 0;
+
+ for (j = i + 1; j < blks && (seg_end - seg_begin) < dseg->req_size; j++)
+ {
+ seg_tmp = dseg->blk_ptr[j];
+ /* Check untagged blocks only */
+ if ((seg_tmp & 3) == DAL_UNTAG_BLOCK)
+ {
+ if (seg_tmp == (seg_begin - dseg->blk_size))
+ {
+ /* Found adjacent block below current segment */
+ dseg->blk_ptr[j] |= DAL_CUR_MATCH_BLOCk;
+ seg_begin = seg_tmp;
+ found = 1;
+ }
+ else if (seg_tmp == seg_end)
+ {
+ /* Found adjacent block above current segment */
+ dseg->blk_ptr[j] |= DAL_CUR_MATCH_BLOCk;
+ seg_end += dseg->blk_size;
+ found = 1;
+ }
+ }
+ }
+ }
+ while (found);
+
+ if ((seg_end - seg_begin) > dseg->seg_size)
+ {
+ /* The current block is largest so far */
+ dseg->seg_begin = seg_begin;
+ dseg->seg_end = seg_end;
+ dseg->seg_size = seg_end - seg_begin;
+
+ /* Re-tag current and previous largest segment */
+ for (j = 0; j < blks; j++)
+ {
+ if ((dseg->blk_ptr[j] & 3) == DAL_CUR_MATCH_BLOCk)
+ {
+ /* Tag current segment as the largest */
+ dseg->blk_ptr[j] &= ~1;
+ }
+ else if ((dseg->blk_ptr[j] & 3) == DAL_MATCHED_BLOCK)
+ {
+ /* Discard previous largest segment */
+ dseg->blk_ptr[j] ^= 3;
+ }
+ }
+ }
+ else
+ {
+ /* Discard all blocks in current segment */
+ for (j = 0; j < blks; j++)
+ {
+ if ((dseg->blk_ptr[j] & 3) == DAL_CUR_MATCH_BLOCk)
+ {
+ dseg->blk_ptr[j] &= ~2;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Function: _alloc_dma_blocks
+ */
+static int
+_dal_alloc_dma_blocks(dma_segment_t* dseg, int blks)
+{
+ int i, start;
+ unsigned long addr;
+
+ if (dseg->blk_cnt + blks > dseg->blk_cnt_max)
+ {
+ printk("No more DMA blocks\n");
+ return -1;
+ }
+
+ start = dseg->blk_cnt;
+ dseg->blk_cnt += blks;
+
+ for (i = start; i < dseg->blk_cnt; i++)
+ {
+ addr = __get_free_pages(GFP_ATOMIC, dseg->blk_order);
+ if (addr)
+ {
+ dseg->blk_ptr[i] = addr;
+ }
+ else
+ {
+ printk("DMA allocation failed\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Function: _dal_dma_segment_alloc
+ */
+static dma_segment_t*
+_dal_dma_segment_alloc(unsigned int size, unsigned int blk_size)
+{
+ dma_segment_t* dseg;
+ int i, blk_ptr_size;
+ unsigned long page_addr;
+ struct sysinfo si;
+
+ /* Sanity check */
+ if (size == 0 || blk_size == 0)
+ {
+ return NULL;
+ }
+
+ /* Allocate an initialize DMA segment descriptor */
+ if ((dseg = kmalloc(sizeof(dma_segment_t), GFP_ATOMIC)) == NULL)
+ {
+ return NULL;
+ }
+
+ memset(dseg, 0, sizeof(dma_segment_t));
+ dseg->req_size = size;
+ dseg->blk_size = PAGE_ALIGN(blk_size);
+
+ while ((PAGE_SIZE << dseg->blk_order) < dseg->blk_size)
+ {
+ dseg->blk_order++;
+ }
+
+ si_meminfo(&si);
+ dseg->blk_cnt_max = (si.totalram << PAGE_SHIFT) / dseg->blk_size;
+ blk_ptr_size = dseg->blk_cnt_max * sizeof(unsigned long);
+ /* Allocate an initialize DMA block pool */
+ dseg->blk_ptr = kmalloc(blk_ptr_size, GFP_KERNEL);
+ if (dseg->blk_ptr == NULL)
+ {
+ kfree(dseg);
+ return NULL;
+ }
+
+ memset(dseg->blk_ptr, 0, blk_ptr_size);
+ /* Allocate minimum number of blocks */
+ _dal_alloc_dma_blocks(dseg, dseg->req_size / dseg->blk_size);
+
+ /* Allocate more blocks until we have a complete segment */
+ do
+ {
+ _dal_find_largest_segment(dseg);
+ if (dseg->seg_size >= dseg->req_size)
+ {
+ break;
+ }
+ }
+ while (_dal_alloc_dma_blocks(dseg, 8) == 0);
+
+ /* Reserve all pages in the DMA segment and free unused blocks */
+ for (i = 0; i < dseg->blk_cnt; i++)
+ {
+ if ((dseg->blk_ptr[i] & 3) == 2)
+ {
+ dseg->blk_ptr[i] &= ~3;
+
+ for (page_addr = dseg->blk_ptr[i];
+ page_addr < dseg->blk_ptr[i] + dseg->blk_size;
+ page_addr += PAGE_SIZE)
+ {
+ MEM_MAP_RESERVE(VIRT_TO_PAGE((void*)page_addr));
+ }
+ }
+ else if (dseg->blk_ptr[i])
+ {
+ dseg->blk_ptr[i] &= ~3;
+ free_pages(dseg->blk_ptr[i], dseg->blk_order);
+ dseg->blk_ptr[i] = 0;
+ }
+ }
+
+ return dseg;
+}
+
+/*
+ * Function: _dal_dma_segment_free
+ */
+static void
+_dal_dma_segment_free(dma_segment_t* dseg)
+{
+ int i;
+ unsigned long page_addr;
+
+ if (dseg->blk_ptr)
+ {
+ for (i = 0; i < dseg->blk_cnt; i++)
+ {
+ if (dseg->blk_ptr[i])
+ {
+ for (page_addr = dseg->blk_ptr[i];
+ page_addr < dseg->blk_ptr[i] + dseg->blk_size;
+ page_addr += PAGE_SIZE)
+ {
+ MEM_MAP_UNRESERVE(VIRT_TO_PAGE(page_addr));
+ }
+
+ free_pages(dseg->blk_ptr[i], dseg->blk_order);
+ }
+ }
+
+ kfree(dseg->blk_ptr);
+ kfree(dseg);
+ }
+}
+
+/*
+ * Function: -dal_pgalloc
+ */
+static void*
+_dal_pgalloc(unsigned int size)
+{
+ dma_segment_t* dseg;
+ unsigned int blk_size;
+
+ blk_size = (size < DMA_BLOCK_SIZE) ? size : DMA_BLOCK_SIZE;
+ if ((dseg = _dal_dma_segment_alloc(size, blk_size)) == NULL)
+ {
+ return NULL;
+ }
+
+ if (dseg->seg_size < size)
+ {
+ /* If we didn't get the full size then forget it */
+ printk("Notice: Can not get enough memory for requset!!\n");
+ printk("actual size:0x%lx, request size:0x%x\n", dseg->seg_size, size);
+ //-_dal_dma_segment_free(dseg);
+ //-return NULL;
+ }
+
+ list_add(&dseg->list, &_dma_seg);
+ return (void*)dseg->seg_begin;
+}
+
+/*
+ * Function: _dal_pgfree
+ */
+static int
+_dal_pgfree(void* ptr)
+{
+ struct list_head* pos;
+
+ list_for_each(pos, &_dma_seg)
+ {
+ dma_segment_t* dseg = list_entry(pos, dma_segment_t, list);
+ if (ptr == (void*)dseg->seg_begin)
+ {
+ list_del(&dseg->list);
+ _dal_dma_segment_free(dseg);
+ return 0;
+ }
+ }
+ return -1;
+}
+#endif
+static void
+dal_alloc_dma_pool(int lchip, int size)
+{
+ if (use_high_memory)
+ {
+ dma_phy_base[lchip] = virt_to_bus(high_memory);
+ dma_virt_base[lchip] = ioremap_nocache(dma_phy_base[lchip], size);
+ }
+ else
+ {
+#ifdef DMA_MEM_MODE_PLATFORM
+ dma_virt_base[lchip] = dma_alloc_coherent(&(dal_dev[lchip].pci_dev->dev), dma_mem_size,
+ &dma_phy_base[lchip], GFP_KERNEL);
+
+ printk(KERN_WARNING "########Using DMA_MEM_MODE_PLATFORM \n");
+#endif
+
+#ifndef DMA_MEM_MODE_PLATFORM
+ /* Get DMA memory from kernel */
+ dma_virt_base_tmp[lchip] = _dal_pgalloc(size);
+ dma_phy_base[lchip] = virt_to_bus(dma_virt_base_tmp[lchip]);
+ dma_virt_base [lchip]= ioremap_nocache(dma_phy_base[lchip], size);
+#endif
+ }
+}
+
+static void
+dal_free_dma_pool(int lchip)
+{
+ int ret = 0;
+ ret = ret;
+ if (use_high_memory)
+ {
+ iounmap(dma_virt_base[lchip]);
+ }
+ else
+ {
+#ifdef DMA_MEM_MODE_PLATFORM
+ dma_free_coherent(&(dal_dev[lchip].pci_dev->dev), dma_mem_size,
+ dma_virt_base[lchip], dma_phy_base[lchip]);
+#endif
+
+#ifndef DMA_MEM_MODE_PLATFORM
+ iounmap(dma_virt_base[lchip]);
+ ret = _dal_pgfree(dma_virt_base_tmp[lchip]);
+ if(ret<0)
+ {
+ printk("Dma free memory fail !!!!!! \n");
+ }
+#endif
+ }
+}
+
+#define _KERNEL_DAL_IO
+static int
+_dal_pci_read(unsigned char lchip, unsigned int offset, unsigned int* value)
+{
+ if (!VERIFY_CHIP_INDEX(lchip))
+ {
+ return -1;
+ }
+
+ *value = *(volatile unsigned int*)(dal_dev[lchip].logic_address + offset);
+ return 0;
+}
+
+int
+dal_create_irq_mapping(unsigned long arg)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
+ dal_irq_mapping_t irq_map;
+
+ if (copy_from_user(&irq_map, (void*)arg, sizeof(dal_irq_mapping_t)))
+ {
+ return -EFAULT;
+ }
+
+ irq_map.sw_irq = irq_create_mapping(NULL, irq_map.hw_irq);
+ if (irq_map.sw_irq == NO_IRQ)
+ {
+ printk("IRQ mapping fail !!!!!! \n");
+ return -1;
+ }
+
+ if (copy_to_user((dal_irq_mapping_t*)arg, (void*)&irq_map, sizeof(dal_irq_mapping_t)))
+ {
+ return -EFAULT;
+ }
+#endif
+ return 0;
+}
+
+int
+dal_pci_read(unsigned long arg)
+{
+ dal_chip_parm_t cmdpara_chip;
+
+ if (copy_from_user(&cmdpara_chip, (void*)arg, sizeof(dal_chip_parm_t)))
+ {
+ return -EFAULT;
+ }
+
+ _dal_pci_read((unsigned char)cmdpara_chip.chip_id, (unsigned int)cmdpara_chip.reg_addr,
+ (unsigned int*)(&(cmdpara_chip.value)));
+
+ if (copy_to_user((dal_chip_parm_t*)arg, (void*)&cmdpara_chip, sizeof(dal_chip_parm_t)))
+ {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int
+_dal_pci_write(unsigned char lchip, unsigned int offset, unsigned int value)
+{
+ if (!VERIFY_CHIP_INDEX(lchip))
+ {
+ return -1;
+ }
+
+ *(volatile unsigned int*)(dal_dev[lchip].logic_address + offset) = value;
+ return 0;
+}
+
+int
+dal_pci_write(unsigned long arg)
+{
+ dal_chip_parm_t cmdpara_chip;
+
+ if (copy_from_user(&cmdpara_chip, (void*)arg, sizeof(dal_chip_parm_t)))
+ {
+ return -EFAULT;
+ }
+
+ _dal_pci_write((unsigned char)cmdpara_chip.chip_id, (unsigned int)cmdpara_chip.reg_addr,
+ (unsigned int)cmdpara_chip.value);
+
+ return 0;
+}
+
+int
+dal_pci_conf_read(unsigned char lchip, unsigned int offset, unsigned int* value)
+{
+ if (!VERIFY_CHIP_INDEX(lchip))
+ {
+ return -1;
+ }
+
+ pci_read_config_dword(dal_dev[lchip].pci_dev, offset, value);
+ return 0;
+}
+
+int
+dal_pci_conf_write(unsigned char lchip, unsigned int offset, unsigned int value)
+{
+ if (!VERIFY_CHIP_INDEX(lchip))
+ {
+ return -1;
+ }
+
+ pci_write_config_dword(dal_dev[lchip].pci_dev, offset, value);
+ return 0;
+}
+int
+dal_user_read_pci_conf(unsigned long arg)
+{
+ dal_pci_cfg_ioctl_t dal_cfg;
+
+ if (copy_from_user(&dal_cfg, (void*)arg, sizeof(dal_pci_cfg_ioctl_t)))
+ {
+ return -EFAULT;
+ }
+
+ if (dal_pci_conf_read(dal_cfg.chip_id, dal_cfg.offset, &dal_cfg.value))
+ {
+ printk("dal_pci_conf_read failed.\n");
+ return -EFAULT;
+ }
+
+ if (copy_to_user((dal_pci_cfg_ioctl_t*)arg, (void*)&dal_cfg, sizeof(dal_pci_cfg_ioctl_t)))
+ {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int
+dal_user_write_pci_conf(unsigned long arg)
+{
+ dal_pci_cfg_ioctl_t dal_cfg;
+
+ if (copy_from_user(&dal_cfg, (void*)arg, sizeof(dal_pci_cfg_ioctl_t)))
+ {
+ return -EFAULT;
+ }
+
+ return dal_pci_conf_write(dal_cfg.chip_id, dal_cfg.offset, dal_cfg.value);
+}
+
+static int
+linux_get_device(unsigned long arg)
+{
+ dal_user_dev_t user_dev;
+ int chip_id = 0;
+
+ if (copy_from_user(&user_dev, (void*)arg, sizeof(user_dev)))
+ {
+ return -EFAULT;
+ }
+
+ user_dev.chip_num = dal_chip_num;
+ chip_id = user_dev.chip_id;
+
+ if (chip_id < dal_chip_num)
+ {
+ user_dev.phy_base0 = (unsigned int)dal_dev[chip_id].phys_address;
+ #ifdef PHYS_ADDR_IS_64BIT
+ user_dev.phy_base1 = (unsigned int)(dal_dev[chip_id].phys_address >> 32);
+ #else
+ user_dev.phy_base1 = 0;
+ #endif
+
+ user_dev.bus_no = dal_dev[chip_id].pci_dev->bus->number;
+ user_dev.dev_no = dal_dev[chip_id].pci_dev->device;
+ user_dev.fun_no = dal_dev[chip_id].pci_dev->devfn;
+ }
+
+ if (copy_to_user((dal_user_dev_t*)arg, (void*)&user_dev, sizeof(user_dev)))
+ {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/* set dal version, copy to user */
+static int
+linux_get_dal_version(unsigned long arg)
+{
+ int dal_ver = VERSION_1DOT2; /* set dal version */
+
+ if (copy_to_user((int*)arg, (void*)&dal_ver, sizeof(dal_ver)))
+ {
+ return -EFAULT;
+ }
+
+ dal_version = dal_ver; /* up sw */
+
+ return 0;
+}
+
+static int
+linux_get_dma_info(unsigned long arg)
+{
+ dma_info_t dma_para;
+
+ if (copy_from_user(&dma_para, (void*)arg, sizeof(dma_info_t)))
+ {
+ return -EFAULT;
+ }
+
+ dma_para.phy_base = (unsigned int)dma_phy_base[dma_para.lchip];
+ #ifdef PHYS_ADDR_IS_64BIT
+ dma_para.phy_base_hi = dma_phy_base[dma_para.lchip] >> 32;
+ #else
+ dma_para.phy_base_hi = 0;
+ #endif
+ dma_para.size = dma_mem_size;
+
+ if (copy_to_user((dma_info_t*)arg, (void*)&dma_para, sizeof(dma_info_t)))
+ {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int
+dal_get_msi_info(unsigned long arg)
+{
+ dal_msi_info_t msi_para;
+ unsigned int lchip = 0;
+
+ /* get lchip form user mode */
+ if (copy_from_user(&msi_para, (void*)arg, sizeof(dal_msi_info_t)))
+ {
+ return -EFAULT;
+ }
+ lchip = msi_para.lchip;
+
+ msi_para.irq_base = msi_irq_base[lchip];
+ msi_para.irq_num = msi_irq_num[lchip];
+
+ /* send msi info to user mode */
+ if (copy_to_user((dal_msi_info_t*)arg, (void*)&msi_para, sizeof(dal_msi_info_t)))
+ {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+
+static int
+dal_get_intr_info(unsigned long arg)
+{
+ dal_intr_info_t intr_para;
+ unsigned int intr_num = 0;
+
+ /* get lchip form user mode */
+ if (copy_from_user(&intr_para, (void*)arg, sizeof(dal_intr_info_t)))
+ {
+ return -EFAULT;
+ }
+
+ intr_para.irq_idx = CTC_MAX_INTR_NUM;
+ for (intr_num=0; intr_num< CTC_MAX_INTR_NUM; intr_num++)
+ {
+ if (intr_para.irq == dal_isr[intr_num].irq)
+ {
+ intr_para.irq_idx = intr_num;
+ break;
+ }
+ }
+
+ if (CTC_MAX_INTR_NUM == intr_para.irq_idx)
+ {
+ printk("Interrupt %d cann't find.\n", intr_para.irq);
+ }
+ /* send msi info to user mode */
+ if (copy_to_user((dal_intr_info_t*)arg, (void*)&intr_para, sizeof(dal_intr_info_t)))
+ {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int
+dal_cache_inval(unsigned long arg)
+{
+ dal_dma_cache_info_t intr_para;
+
+ if (copy_from_user(&intr_para, (void*)arg, sizeof(dal_dma_cache_info_t)))
+ {
+ return -EFAULT;
+ }
+
+#if 0
+ dma_cache_wback_inv((unsigned long)intr_para.ptr, intr_para.length);
+#endif
+
+#if 0
+ dma_sync_single_for_cpu(NULL, intr_para.ptr, intr_para.length, DMA_BIDIRECTIONAL);
+#endif
+
+ dma_cache_sync(NULL, (void*)intr_para.ptr, intr_para.length, DMA_BIDIRECTIONAL);
+
+ return 0;
+}
+
+static int
+dal_cache_flush(unsigned long arg)
+{
+ dal_dma_cache_info_t intr_para;
+
+ if (copy_from_user(&intr_para, (void*)arg, sizeof(dal_dma_cache_info_t)))
+ {
+ return -EFAULT;
+ }
+
+#if 0
+ dma_cache_wback_inv(intr_para.ptr, intr_para.length);
+#endif
+
+#if 0
+ dma_sync_single_for_cpu(NULL, intr_para.ptr, intr_para.length, DMA_BIDIRECTIONAL);
+#endif
+
+ dma_cache_sync(NULL, (void*)intr_para.ptr, intr_para.length, DMA_BIDIRECTIONAL);
+
+ return 0;
+}
+
+int
+linux_dal_probe(struct pci_dev* pdev, const struct pci_device_id* id)
+{
+ dal_kern_dev_t* dev = NULL;
+ int bar = 0;
+ int ret = 0;
+ unsigned int temp = 0;
+ unsigned int lchip = 0;
+ unsigned int chip_id = 0;
+
+ printk(KERN_WARNING "********found dal device*****\n");
+
+ for (chip_id = 0; chip_id < DAL_MAX_CHIP_NUM; chip_id ++)
+ {
+ if (NULL == dal_dev[chip_id].pci_dev)
+ {
+ break;
+ }
+ }
+
+ if (chip_id >= DAL_MAX_CHIP_NUM)
+ {
+ printk("Exceed max local chip num\n");
+ return -1;
+ }
+
+ dev = &dal_dev[chip_id];
+ if (NULL == dev)
+ {
+ printk("Cannot obtain PCI resources\n");
+ }
+
+ lchip = chip_id;
+ dal_chip_num += 1;
+
+ dev->pci_dev = pdev;
+
+ if (pci_enable_device(pdev) < 0)
+ {
+ printk("Cannot enable PCI device: vendor id = %x, device id = %x\n",
+ pdev->vendor, pdev->device);
+ }
+
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (ret)
+ {
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret)
+ {
+ printk("Could not set PCI DMA Mask\n");
+ return ret;
+ }
+ }
+
+ if (pci_request_regions(pdev, DAL_NAME) < 0)
+ {
+ printk("Cannot obtain PCI resources\n");
+ }
+
+ dev->phys_address = pci_resource_start(pdev, bar);
+ dev->logic_address = (uintptr)ioremap_nocache(dev->phys_address,
+ pci_resource_len(dev->pci_dev, bar));
+
+ _dal_pci_read(lchip, 0x48, &temp);
+ if (((temp >> 8) & 0xffff) == 0x3412)
+ {
+ printk("Little endian Cpu detected!!! \n");
+ _dal_pci_write(lchip, 0x48, 0xFFFFFFFF);
+ }
+
+ pci_set_master(pdev);
+
+ /* alloc dma_mem_size for every chip */
+ if (dma_mem_size)
+ {
+ dal_alloc_dma_pool(lchip, dma_mem_size);
+ #ifdef PHYS_ADDR_IS_64BIT
+
+ /*add check Dma memory pool cannot cross 4G space*/
+ if ((0==(dma_phy_base[lchip]>>32)) && (0!=((dma_phy_base[lchip]+dma_mem_size)>>32)))
+ {
+ printk("Dma malloc memory cross 4G space!!!!!! \n");
+ return -1;
+ }
+ #endif
+ }
+
+ printk(KERN_WARNING "linux_dal_probe end*****\n");
+
+ return 0;
+}
+
+void
+linux_dal_remove(struct pci_dev* pdev)
+{
+ unsigned int chip_id = 0;
+ unsigned int flag = 0;
+
+ for (chip_id = 0; chip_id < DAL_MAX_CHIP_NUM; chip_id ++)
+ {
+ if (pdev == dal_dev[chip_id].pci_dev)
+ {
+ flag = 1;
+ break;
+ }
+ }
+
+ if (1 == flag)
+ {
+ dal_free_dma_pool(chip_id);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+
+ dal_dev[chip_id].pci_dev = NULL;
+ dal_chip_num--;
+ }
+
+
+}
+
+#ifdef CONFIG_COMPAT
+static long
+linux_dal_ioctl(struct file* file,
+ unsigned int cmd, unsigned long arg)
+#else
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 13))
+static int
+linux_dal_ioctl(struct file* file,
+ unsigned int cmd, unsigned long arg)
+#else
+static int
+linux_dal_ioctl(struct inode* inode, struct file* file,
+ unsigned int cmd, unsigned long arg)
+#endif
+
+#endif
+{
+ switch (cmd)
+ {
+
+ case CMD_READ_CHIP:
+ return dal_pci_read(arg);
+
+ case CMD_WRITE_CHIP:
+ return dal_pci_write(arg);
+
+ case CMD_GET_DEVICES:
+ return linux_get_device(arg);
+
+ case CMD_GET_DAL_VERSION:
+ return linux_get_dal_version(arg);
+
+ case CMD_GET_DMA_INFO:
+ return linux_get_dma_info(arg);
+
+ case CMD_PCI_CONFIG_READ:
+ return dal_user_read_pci_conf(arg);
+
+ case CMD_PCI_CONFIG_WRITE:
+ return dal_user_write_pci_conf(arg);
+
+ case CMD_REG_INTERRUPTS:
+ return dal_user_interrupt_register(arg);
+
+ case CMD_UNREG_INTERRUPTS:
+ return dal_user_interrupt_unregister(arg);
+
+ case CMD_EN_INTERRUPTS:
+ return dal_user_interrupt_set_en(arg);
+
+ case CMD_SET_MSI_CAP:
+ return dal_set_msi_cap(arg);
+
+ case CMD_GET_MSI_INFO:
+ return dal_get_msi_info(arg);
+
+ case CMD_IRQ_MAPPING:
+ return dal_create_irq_mapping(arg);
+
+ case CMD_GET_INTR_INFO:
+ return dal_get_intr_info(arg);
+
+ case CMD_CACHE_INVAL:
+ return dal_cache_inval(arg);
+
+ case CMD_CACHE_FLUSH:
+ return dal_cache_flush(arg);
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static unsigned int
+linux_dal_poll0(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[0], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[0])
+ {
+ poll_intr_trigger[0] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll1(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[1], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[1])
+ {
+ poll_intr_trigger[1] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll2(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[2], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[2])
+ {
+ poll_intr_trigger[2] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll3(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[3], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[3])
+ {
+ poll_intr_trigger[3] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll4(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[4], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[4])
+ {
+ poll_intr_trigger[4] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll5(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[5], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[5])
+ {
+ poll_intr_trigger[5] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll6(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[6], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[6])
+ {
+ poll_intr_trigger[6] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static unsigned int
+linux_dal_poll7(struct file* filp, struct poll_table_struct* p)
+{
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ poll_wait(filp, &poll_intr[7], p);
+ local_irq_save(flags);
+ if (poll_intr_trigger[7])
+ {
+ poll_intr_trigger[7] = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ local_irq_restore(flags);
+
+ return mask;
+}
+
+static struct pci_driver linux_dal_driver =
+{
+ .name = DAL_NAME,
+ .id_table = dal_id_table,
+ .probe = linux_dal_probe,
+ .remove = linux_dal_remove,
+};
+
+static struct file_operations fops =
+{
+ .owner = THIS_MODULE,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = linux_dal_ioctl,
+ .unlocked_ioctl = linux_dal_ioctl,
+#else
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))
+ .unlocked_ioctl = linux_dal_ioctl,
+#else
+ .ioctl = linux_dal_ioctl,
+#endif
+#endif
+};
+
+
+static int __init
+linux_dal_init(void)
+{
+ int ret = 0;
+
+ /* Get DMA memory pool size form dal.ok input param, or use default dma_mem_size */
+ if (dma_pool_size)
+ {
+ if ((dma_pool_size[strlen(dma_pool_size) - 1] & ~0x20) == 'M')
+ {
+ dma_mem_size = simple_strtoul(dma_pool_size, NULL, 0);
+ printk("dma_mem_size: 0x%x \n", dma_mem_size);
+
+ dma_mem_size *= MB_SIZE;
+ }
+ else
+ {
+ printk("DMA memory pool size must be specified as e.g. dma_pool_size=8M\n");
+ }
+
+ if (dma_mem_size & (dma_mem_size - 1))
+ {
+ printk("dma_mem_size must be a power of 2 (1M, 2M, 4M, 8M etc.)\n");
+ dma_mem_size = 0;
+ }
+ }
+
+ ret = register_chrdev(DAL_DEV_MAJOR, DAL_NAME, &fops);
+ if (ret < 0)
+ {
+ printk(KERN_WARNING "Register linux_dal device, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = pci_register_driver(&linux_dal_driver);
+ if (ret < 0)
+ {
+ printk(KERN_WARNING "Register ASIC PCI driver failed, ret %d\n", ret);
+ return ret;
+ }
+
+ /* alloc /dev/linux_dal node */
+ dal_class = class_create(THIS_MODULE, DAL_NAME);
+ device_create(dal_class, NULL, MKDEV(DAL_DEV_MAJOR, 0), NULL, DAL_NAME);
+
+ /* init interrupt function */
+ intr_handler_fun[0] = intr0_handler;
+ intr_handler_fun[1] = intr1_handler;
+ intr_handler_fun[2] = intr2_handler;
+ intr_handler_fun[3] = intr3_handler;
+ intr_handler_fun[4] = intr4_handler;
+ intr_handler_fun[5] = intr5_handler;
+ intr_handler_fun[6] = intr6_handler;
+ intr_handler_fun[7] = intr7_handler;
+
+ return ret;
+}
+
+static void __exit
+linux_dal_exit(void)
+{
+ device_destroy(dal_class, MKDEV(DAL_DEV_MAJOR, 0));
+ class_destroy(dal_class);
+ unregister_chrdev(DAL_DEV_MAJOR, "linux_dal");
+ pci_unregister_driver(&linux_dal_driver);
+}
+
+module_init(linux_dal_init);
+module_exit(linux_dal_exit);
+
diff --git a/platform/centec/sonic-platform-modules-e582/48x6q/modules/dal_kernel.h b/platform/centec/sonic-platform-modules-e582/48x6q/modules/dal_kernel.h
new file mode 100644
index 0000000000..de39af6777
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x6q/modules/dal_kernel.h
@@ -0,0 +1,170 @@
+/**
+ @file dal_kernel_io.h
+
+ @author Copyright (C) 2012 Centec Networks Inc. All rights reserved.
+
+ @date 2012-4-9
+
+ @version v2.0
+
+*/
+#ifndef _DAL_KERNEL_H_
+#define _DAL_KERNEL_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(CONFIG_RESOURCES_64BIT) || defined(CONFIG_PHYS_ADDR_T_64BIT)
+#define PHYS_ADDR_IS_64BIT
+#endif
+
+#ifndef SDK_IN_USERMODE
+#ifdef PHYS_ADDR_IS_64BIT
+typedef long long intptr;
+typedef unsigned long long uintptr;
+#else
+typedef int intptr;
+typedef unsigned int uintptr;
+#endif
+#endif
+
+#define DAL_PCI_READ_ADDR 0x0
+#define DAL_PCI_READ_DATA 0xc
+#define DAL_PCI_WRITE_ADDR 0x8
+#define DAL_PCI_WRITE_DATA 0x4
+#define DAL_PCI_STATUS 0x10
+
+#define DAL_PCI_STATUS_IN_PROCESS 31
+#define DAL_PCI_STATUS_BAD_PARITY 5
+#define DAL_PCI_STATUS_CPU_ACCESS_ERR 4
+#define DAL_PCI_STATUS_READ_CMD 3
+#define DAL_PCI_STATUS_REGISTER_ERR 1
+#define DAL_PCI_STATUS_REGISTER_ACK 0
+
+#define DAL_PCI_ACCESS_TIMEOUT 0x64
+
+#define DAL_NAME "linux_dal" /* "linux_dal" */
+
+#define DAL_DEV_MAJOR 198
+
+#define DAL_DEV_INTR_MAJOR_BASE 200
+
+#define DAL_DEV_NAME "/dev/" DAL_NAME
+#define DAL_ONE_KB 1024
+#define DAL_ONE_MB (1024*1024)
+struct dal_chip_parm_s
+{
+ unsigned int chip_id; /*tmp should be uint8*/
+ unsigned int fpga_id; /*tmp add*/
+ unsigned int reg_addr;
+ unsigned int value;
+};
+typedef struct dal_chip_parm_s dal_chip_parm_t;
+
+struct dal_intr_parm_s
+{
+ unsigned int irq;
+ unsigned int enable;
+};
+typedef struct dal_intr_parm_s dal_intr_parm_t;
+
+struct dal_irq_mapping_s
+{
+ unsigned int hw_irq;
+ unsigned int sw_irq;
+};
+typedef struct dal_irq_mapping_s dal_irq_mapping_t;
+
+struct dal_user_dev_s
+{
+ unsigned int chip_num; /*output: local chip number*/
+ unsigned int chip_id; /*input: local chip id*/
+ unsigned int phy_base0; /* low 32bits physical base address */
+ unsigned int phy_base1; /* high 32bits physical base address */
+ unsigned int bus_no;
+ unsigned int dev_no;
+ unsigned int fun_no;
+ void* virt_base[2]; /* Virtual base address; this must be last member */
+};
+typedef struct dal_user_dev_s dal_user_dev_t;
+
+struct dma_info_s
+{
+ unsigned int lchip;
+ unsigned int phy_base;
+ unsigned int phy_base_hi;
+ unsigned int size;
+ unsigned int* virt_base;
+};
+typedef struct dma_info_s dma_info_t;
+
+struct dal_pci_cfg_ioctl_s
+{
+ unsigned int chip_id; /* Device ID */
+ unsigned int offset;
+ unsigned int value;
+};
+typedef struct dal_pci_cfg_ioctl_s dal_pci_cfg_ioctl_t;
+
+struct dal_msi_info_s
+{
+ unsigned int lchip;
+ unsigned int irq_base;
+ unsigned int irq_num;
+};
+typedef struct dal_msi_info_s dal_msi_info_t;
+
+struct dal_intr_info_s
+{
+ unsigned int irq;
+ unsigned int irq_idx;
+};
+typedef struct dal_intr_info_s dal_intr_info_t;
+
+struct dal_dma_cache_info_s
+{
+ unsigned long ptr;
+ unsigned int length;
+};
+typedef struct dal_dma_cache_info_s dal_dma_cache_info_t;
+
+#define CMD_MAGIC 'C'
+#define CMD_WRITE_CHIP _IO(CMD_MAGIC, 0) /* for humber ioctrol*/
+#define CMD_READ_CHIP _IO(CMD_MAGIC, 1) /* for humber ioctrol*/
+#define CMD_GET_DEVICES _IO(CMD_MAGIC, 2)
+#define CMD_GET_DAL_VERSION _IO(CMD_MAGIC, 3)
+#define CMD_PCI_CONFIG_WRITE _IO(CMD_MAGIC, 4)
+#define CMD_PCI_CONFIG_READ _IO(CMD_MAGIC, 5)
+#define CMD_GET_DMA_INFO _IO(CMD_MAGIC, 6)
+#define CMD_REG_INTERRUPTS _IO(CMD_MAGIC, 7)
+#define CMD_UNREG_INTERRUPTS _IO(CMD_MAGIC, 8)
+#define CMD_EN_INTERRUPTS _IO(CMD_MAGIC, 9)
+#define CMD_I2C_READ _IO(CMD_MAGIC, 10)
+#define CMD_I2C_WRITE _IO(CMD_MAGIC, 11)
+#define CMD_GET_MSI_INFO _IO(CMD_MAGIC, 12)
+#define CMD_SET_MSI_CAP _IO(CMD_MAGIC, 13)
+#define CMD_IRQ_MAPPING _IO(CMD_MAGIC, 14)
+#define CMD_GET_INTR_INFO _IO(CMD_MAGIC, 15)
+#define CMD_CACHE_INVAL _IO(CMD_MAGIC, 16)
+#define CMD_CACHE_FLUSH _IO(CMD_MAGIC, 17)
+
+enum dal_version_e
+{
+ VERSION_MIN,
+ VERSION_1DOT0,
+ VERSION_1DOT1,
+ VERSION_1DOT2,
+
+ VERSION_MAX
+};
+typedef enum dal_version_e dal_version_t;
+
+/* We try to assemble a contiguous segment from chunks of this size */
+#define DMA_BLOCK_SIZE (512 * DAL_ONE_KB)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/platform/centec/sonic-platform-modules-e582/48x6q/modules/dal_mpool.c b/platform/centec/sonic-platform-modules-e582/48x6q/modules/dal_mpool.c
new file mode 100644
index 0000000000..82d3b7a917
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x6q/modules/dal_mpool.c
@@ -0,0 +1,343 @@
+
+#include "dal_mpool.h"
+
+#ifdef __KERNEL__
+#include
+#include
+
+#define DAL_MALLOC(x) kmalloc(x, GFP_ATOMIC)
+#define DAL_FREE(x) kfree(x)
+
+static spinlock_t dal_mpool_lock;
+#define MPOOL_LOCK_INIT() spin_lock_init(&dal_mpool_lock)
+#define MPOOL_LOCK() unsigned long flags; spin_lock_irqsave(&dal_mpool_lock, flags)
+#define MPOOL_UNLOCK() spin_unlock_irqrestore(&dal_mpool_lock, flags)
+#define DAL_PRINT(fmt,arg...) printk(fmt,##arg)
+#else /* !__KERNEL__*/
+
+#include
+#include "sal.h"
+#define DAL_MALLOC(x) malloc(x)
+#define DAL_FREE(x) free(x)
+static sal_mutex_t* dal_mpool_lock;
+#define MPOOL_LOCK_INIT() sal_mutex_create(&dal_mpool_lock)
+#define MPOOL_LOCK() sal_mutex_lock(dal_mpool_lock)
+#define MPOOL_UNLOCK() sal_mutex_unlock(dal_mpool_lock)
+#define DAL_PRINT(fmt,arg...) sal_printf(fmt,##arg)
+
+#endif /* __KERNEL__ */
+
+dal_mpool_mem_t* g_free_block_ptr = NULL;
+
+/* System cache line size */
+#ifndef DAL_CACHE_LINE_BYTES
+#define DAL_CACHE_LINE_BYTES 256
+#endif
+
+static dal_mpool_mem_t* p_desc_pool = NULL;
+static dal_mpool_mem_t* p_data_pool = NULL;
+
+int
+dal_mpool_init(void)
+{
+ MPOOL_LOCK_INIT();
+ return 0;
+}
+
+dal_mpool_mem_t*
+_dal_mpool_create(void* base, int size, int type)
+{
+ dal_mpool_mem_t* head = NULL;
+ dal_mpool_mem_t* tail = NULL;
+
+ head = (dal_mpool_mem_t*)DAL_MALLOC(sizeof(dal_mpool_mem_t));
+ if (head == NULL)
+ {
+ return NULL;
+ }
+
+ tail = (dal_mpool_mem_t*)DAL_MALLOC(sizeof(dal_mpool_mem_t));
+ if (tail == NULL)
+ {
+ DAL_FREE(head);
+ return NULL;
+ }
+
+ head->size = tail->size = 0;
+ head->type = type;
+ head->address = base;
+ tail->address = head->address + size;
+ head->next = tail;
+ tail->next = NULL;
+
+ return head;
+}
+
+dal_mpool_mem_t*
+dal_mpool_create(void* base, int size)
+{
+ dal_mpool_mem_t* head = NULL;
+ int mod = (int)(((unsigned long)base) & (DAL_CACHE_LINE_BYTES - 1));
+
+ MPOOL_LOCK();
+
+ if (mod)
+ {
+ base = (char*)base + (DAL_CACHE_LINE_BYTES - mod);
+ size -= (DAL_CACHE_LINE_BYTES - mod);
+ }
+
+ size &= ~(DAL_CACHE_LINE_BYTES - 1);
+
+ /* init for common linkptr, only used for GB */
+ head = _dal_mpool_create(base, size, DAL_MPOOL_TYPE_USELESS);
+ if (NULL == head)
+ {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+
+ /* init for desc linkptr */
+ p_desc_pool = _dal_mpool_create(base, DAL_MPOOL_MAX_DESX_SIZE, DAL_MPOOL_TYPE_DESC);
+ if (NULL == p_desc_pool)
+ {
+ MPOOL_UNLOCK();
+ DAL_FREE(head->next);
+ DAL_FREE(head);
+ return NULL;
+ }
+
+ /* init for data linkptr */
+ p_data_pool = _dal_mpool_create(((char*)base+DAL_MPOOL_MAX_DESX_SIZE), (size - DAL_MPOOL_MAX_DESX_SIZE), DAL_MPOOL_TYPE_DATA);
+ if (NULL == p_data_pool)
+ {
+ MPOOL_UNLOCK();
+ DAL_FREE(head->next);
+ DAL_FREE(head);
+ DAL_FREE(p_desc_pool->next);
+ DAL_FREE(p_desc_pool);
+ return NULL;
+ }
+
+ MPOOL_UNLOCK();
+
+ return head;
+}
+
+dal_mpool_mem_t*
+_dal_mpool_alloc_comon(dal_mpool_mem_t* ptr, int size, int type)
+{
+ dal_mpool_mem_t* new_ptr = NULL;
+
+ while (ptr && ptr->next)
+ {
+ if (ptr->next->address - (ptr->address + ptr->size) >= size)
+ {
+ break;
+ }
+
+ ptr = ptr->next;
+ }
+
+ if (!(ptr && ptr->next))
+ {
+ return NULL;
+ }
+
+ new_ptr = DAL_MALLOC(sizeof(dal_mpool_mem_t));
+ if (!new_ptr)
+ {
+ return NULL;
+ }
+
+ new_ptr->type = type;
+ new_ptr->address = ptr->address + ptr->size;
+ new_ptr->size = size;
+ new_ptr->next = ptr->next;
+ ptr->next = new_ptr;
+
+ return new_ptr;
+}
+
+void*
+dal_mpool_alloc(dal_mpool_mem_t* pool, int size, int type)
+{
+ dal_mpool_mem_t* ptr = NULL;
+ dal_mpool_mem_t* new_ptr = NULL;
+ int mod;
+
+ MPOOL_LOCK();
+
+ mod = size & (DAL_CACHE_LINE_BYTES - 1);
+ if (mod != 0)
+ {
+ size += (DAL_CACHE_LINE_BYTES - mod);
+ }
+
+ switch(type)
+ {
+ case DAL_MPOOL_TYPE_USELESS:
+ ptr = pool;
+ new_ptr = _dal_mpool_alloc_comon(ptr, size, type);
+ if (NULL == new_ptr)
+ {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+ break;
+ case DAL_MPOOL_TYPE_DESC:
+ ptr = p_desc_pool;
+ new_ptr = _dal_mpool_alloc_comon(ptr, size, type);
+ if (NULL == new_ptr)
+ {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+ break;
+ case DAL_MPOOL_TYPE_DATA:
+ ptr = p_data_pool;
+ new_ptr = _dal_mpool_alloc_comon(ptr, size, type);
+ if (NULL == new_ptr)
+ {
+ MPOOL_UNLOCK();
+ return NULL;
+ }
+ break;
+ default:
+ MPOOL_UNLOCK();
+ return NULL;
+ break;
+ }
+
+ MPOOL_UNLOCK();
+
+ return new_ptr->address;
+}
+
+void
+_dal_mpool_free(dal_mpool_mem_t* ptr, void* addr, int type)
+{
+ unsigned char* address = (unsigned char*)addr;
+ dal_mpool_mem_t* prev = NULL;
+
+ while (ptr && ptr->next)
+ {
+ if (ptr->next->address == address)
+ {
+ break;
+ }
+
+ ptr = ptr->next;
+ }
+
+ if (ptr && ptr->next)
+ {
+ prev = ptr;
+ ptr = ptr->next;
+ prev->next = ptr->next;
+ DAL_FREE(ptr);
+ }
+
+ return;
+}
+
+void
+dal_mpool_free(dal_mpool_mem_t* pool, void* addr)
+{
+ dal_mpool_mem_t* ptr = pool;
+
+ MPOOL_LOCK();
+
+ switch(pool->type)
+ {
+ case DAL_MPOOL_TYPE_USELESS:
+ ptr = pool;
+ _dal_mpool_free(ptr, addr, DAL_MPOOL_TYPE_USELESS);
+ break;
+ case DAL_MPOOL_TYPE_DESC:
+ ptr = p_desc_pool;
+ _dal_mpool_free(ptr, addr, DAL_MPOOL_TYPE_DESC);
+ break;
+ case DAL_MPOOL_TYPE_DATA:
+ ptr = p_data_pool;
+ _dal_mpool_free(ptr, addr, DAL_MPOOL_TYPE_DATA);
+ break;
+ default:
+ break;
+ }
+
+ MPOOL_UNLOCK();
+ return;
+}
+
+int
+dal_mpool_destroy(dal_mpool_mem_t* pool)
+{
+ dal_mpool_mem_t* ptr, * next;
+
+ MPOOL_LOCK();
+
+ for (ptr = pool; ptr; ptr = next)
+ {
+ next = ptr->next;
+ DAL_FREE(ptr);
+ }
+
+ for (ptr = p_desc_pool; ptr; ptr = next)
+ {
+ next = ptr->next;
+ DAL_FREE(ptr);
+ }
+
+ for (ptr = p_data_pool; ptr; ptr = next)
+ {
+ next = ptr->next;
+ DAL_FREE(ptr);
+ }
+
+ MPOOL_UNLOCK();
+
+ return 0;
+}
+
+int
+dal_mpool_usage(dal_mpool_mem_t* pool, int type)
+{
+ int usage = 0;
+ dal_mpool_mem_t* ptr;
+
+ MPOOL_LOCK();
+
+ for (ptr = pool; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == type || ptr->type == -1)
+ {
+ usage += ptr->size;
+ }
+ }
+
+ MPOOL_UNLOCK();
+
+ return usage;
+}
+
+int
+dal_mpool_debug(dal_mpool_mem_t* pool)
+{
+ dal_mpool_mem_t* ptr;
+ int index = 0;
+
+ MPOOL_LOCK();
+
+ for (ptr = pool; ptr; ptr = ptr->next)
+ {
+// DAL_PRINT("%2dst mpool block: address=0x%8x, size=0x%x \n", index, (unsigned int)ptr->address, ptr->size);
+ DAL_PRINT("%2dst mpool block: address=%p, size=0x%x \n", index, ptr->address, ptr->size); // note
+ index++;
+ }
+
+ MPOOL_UNLOCK();
+
+ return 0;
+}
+
diff --git a/platform/centec/sonic-platform-modules-e582/48x6q/modules/dal_mpool.h b/platform/centec/sonic-platform-modules-e582/48x6q/modules/dal_mpool.h
new file mode 100644
index 0000000000..a1fa37d05f
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x6q/modules/dal_mpool.h
@@ -0,0 +1,71 @@
+/**
+ @file dal_mpool.h
+
+ @author Copyright (C) 2011 Centec Networks Inc. All rights reserved.
+
+ @date 2012-5-10
+
+ @version v2.0
+
+ This file contains the dma memory init, allocation and free APIs
+*/
+
+#ifndef _DMA_MPOOL_H
+#define _DMA_MPOOL_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DAL_MPOOL_MAX_DESX_SIZE (1024*1024)
+
+enum dal_mpool_type_e
+{
+ DAL_MPOOL_TYPE_USELESS, /* just compatible with GB */
+ DAL_MPOOL_TYPE_DESC, /* dma mpool op for desc */
+ DAL_MPOOL_TYPE_DATA /* dma mpool op for data */
+};
+typedef enum dal_mpool_type_e dal_mpool_type_t;
+
+struct dal_mpool_mem_s
+{
+ unsigned char* address;
+ int size;
+ int type;
+ struct dal_mpool_mem_s* next;
+};
+typedef struct dal_mpool_mem_s dal_mpool_mem_t;
+
+/**
+ @brief This function is to alloc dma memory
+
+ @param[in] size size of memory
+
+ @return NULL
+
+*/
+extern int
+dal_mpool_init(void);
+
+extern dal_mpool_mem_t*
+dal_mpool_create(void* base_ptr, int size);
+
+extern void*
+dal_mpool_alloc(dal_mpool_mem_t* pool, int size, int type);
+
+extern void
+dal_mpool_free(dal_mpool_mem_t* pool, void* addr);
+
+extern int
+dal_mpool_destroy(dal_mpool_mem_t* pool);
+
+extern int
+dal_mpool_usage(dal_mpool_mem_t* pool, int type);
+
+extern int
+dal_mpool_debug(dal_mpool_mem_t* pool);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_DMA_MPOOL_H */
+
diff --git a/platform/centec/sonic-platform-modules-e582/48x6q/scripts/48x6q_platform.sh b/platform/centec/sonic-platform-modules-e582/48x6q/scripts/48x6q_platform.sh
new file mode 100755
index 0000000000..e8f81a20d9
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x6q/scripts/48x6q_platform.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+#platform init script for centec e582-48x6q
+
+init_devnum() {
+ found=0
+ for devnum in 0 1; do
+ devname=`cat /sys/bus/i2c/devices/i2c-${devnum}/name`
+ # I801 adapter can be at either dffd0000 or dfff0000
+ if [[ $devname == 'SMBus I801 adapter at '* ]]; then
+ found=1
+ break
+ fi
+ done
+
+ [ $found -eq 0 ] && echo "cannot find I801" && exit 1
+}
+
+init_devnum
+
+if [ "$1" == "init" ]; then
+ #install drivers and dependencies
+ depmod -a
+ modprobe i2c-i801
+ modprobe i2c-dev
+ modprobe i2c-mux
+ modprobe i2c-smbus
+ modprobe i2c-mux-pca954x force_deselect_on_exit=1
+ i2cset -y 0 0x58 0x8 0x3f
+ i2cset -y 0 0x20 0x1b 0x0
+ i2cset -y 0 0x20 0xb 0x0
+ i2cset -y 0 0x21 0x19 0x0
+ i2cset -y 0 0x21 0x9 0x0
+ i2cset -y 0 0x21 0x1c 0x0
+ i2cset -y 0 0x21 0xc 0x0
+ i2cset -y 0 0x22 0x1a 0x0
+ i2cset -y 0 0x22 0xa 0x0
+ i2cset -y 0 0x23 0x18 0x0
+ i2cset -y 0 0x23 0x8 0x0
+ i2cset -y 0 0x23 0x1b 0x0
+ i2cset -y 0 0x23 0xb 0x0
+ modprobe lm77
+ modprobe tun
+ modprobe dal
+ modprobe centec_at24c64
+ modprobe centec_e582_48x6q_platform
+
+ #start platform monitor
+ rm -rf /usr/bin/platform_monitor
+ ln -s /usr/bin/48x6q_platform_monitor.py /usr/bin/platform_monitor
+ python /usr/bin/platform_monitor &
+elif [ "$1" == "deinit" ]; then
+ kill -9 $(pidof platform_monitor) > /dev/null 2>&1
+ rm -rf /usr/bin/platform_monitor
+ modprobe -r centec_e582_48x6q_platform
+ modprobe -r centec_at24c64
+ modprobe -r dal
+ modprobe -r i2c-mux-pca954x
+ modprobe -r i2c-dev
+else
+ echo "e582-48x6q_platform : Invalid option !"
+fi
diff --git a/platform/centec/sonic-platform-modules-e582/48x6q/scripts/48x6q_platform_monitor.py b/platform/centec/sonic-platform-modules-e582/48x6q/scripts/48x6q_platform_monitor.py
new file mode 100644
index 0000000000..d08802a35f
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/48x6q/scripts/48x6q_platform_monitor.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python
+
+#############################################################################
+# Centec
+#
+# Module contains an implementation of sfp presence scan logic
+#
+#############################################################################
+
+try:
+ import os
+ import os.path
+ import threading
+ import time
+ import logging
+ import struct
+ import syslog
+ import swsssdk
+ from socket import *
+ from select import *
+except ImportError, e:
+ raise ImportError(str(e) + " - required module not found")
+
+
+def DBG_PRINT(str):
+ syslog.openlog("centec-pmon")
+ syslog.syslog(syslog.LOG_INFO, str)
+ syslog.closelog()
+
+PORT_NUMBER = (48+6)
+
+class PlatformMonitor:
+
+ """init board platform default config"""
+ def __init__(self):
+ """[ctlid, slavedevid]"""
+ self.fiber_mapping = [(0, 0)] # res
+ self.fiber_mapping.extend([(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7)]) # panel port 1~8
+ self.fiber_mapping.extend([(0, 14), (0, 13), (0, 15), (0, 12), (0, 8), (0, 11), (0, 9), (0, 10)]) # panel port 9~16
+ self.fiber_mapping.extend([(0, 22), (0, 21), (0, 23), (0, 20), (0, 16), (0, 19), (0, 17), (0, 18)]) # panel port 17~24
+ self.fiber_mapping.extend([(1, 4), (1, 3), (1, 5), (1, 2), (1, 6), (1, 1), (1, 7), (1, 0)]) # panel port 25~32
+ self.fiber_mapping.extend([(1, 8), (1, 15), (1, 9), (1, 14), (1, 10), (1, 13), (1, 11), (1, 12)]) # panel port 33~40
+ self.fiber_mapping.extend([(1, 22), (1, 21), (1, 23), (1, 20), (1, 16), (1, 19), (1, 17), (1, 18)]) # panel port 41~48
+ self.fiber_mapping.extend([(1, 28), (1, 29), (1, 26), (1, 27), (1, 24), (1, 25)]) # panel port 49~54
+
+ self.udpClient = socket(AF_INET, SOCK_DGRAM)
+ self.sfp_present = [0]*(PORT_NUMBER+1)
+ self.sfp_enable = [0]*(PORT_NUMBER+1)
+ self.f_sfp_present = "/sys/class/sfp/sfp{}/sfp_presence"
+ self.f_sfp_enable = "/sys/class/sfp/sfp{}/sfp_enable"
+ self.sfp_scan_timer = 0
+
+ def is_qsfp(self, port):
+ if port <= 48:
+ return False
+ else:
+ return True
+
+ def get_sfp_present(self, port):
+ with open(self.f_sfp_present.format(port), 'r') as sfp_file:
+ return int(sfp_file.read())
+
+ def set_sfp_present(self, port, present):
+ self.sfp_present[port] = present
+
+ def set_sfp_enable(self, port, enable):
+ if self.is_qsfp(port):
+ if enable:
+ with open(self.f_sfp_enable.format(port), 'w') as sfp_file:
+ sfp_file.write("1")
+ self.sfp_enable[port] = 1
+ else:
+ with open(self.f_sfp_enable.format(port), 'w') as sfp_file:
+ sfp_file.write("0")
+ self.sfp_enable[port] = 0
+ else:
+ (ctlid, devid) = self.fiber_mapping[port]
+ req = struct.pack('=HHHBBHIBBBBI', 0, 9, 16, ctlid, devid, 0x50, 0, 0x56, 1, 0xf, 0, 1)
+ self.udpClient.sendto(req, ('localhost', 8101))
+ rsp, addr = self.udpClient.recvfrom(1024)
+ rsp_data = struct.unpack('=HHHBBHIBBBBIi512B', rsp)
+ enable_v = rsp_data[13]
+ if enable:
+ enable_v &= 0xf0
+ else:
+ enable_v |= 0x0f
+ data = struct.pack('=HHHBBHBBBB', 0, 11, 8, ctlid, 0x56, 0x50, devid, enable_v, 0xf, 0)
+ self.udpClient.sendto(data, ('localhost', 8101))
+ DBG_PRINT("set sfp{} to {}".format(port, ("enable" if enable else "disable")))
+
+ def initialize_configdb(self):
+ try:
+ f_mac = os.popen('ip link show eth0 | grep ether | awk \'{print $2}\'')
+ mac_addr = f_mac.read(17)
+ last_byte = mac_addr[-2:]
+ aligned_last_byte = format(int(int(str(last_byte), 16) + 1), '02x')
+ mac_addr = mac_addr[:-2] + aligned_last_byte
+ DBG_PRINT("start connect swss config-db to set device mac-address")
+ swss = swsssdk.SonicV2Connector()
+ swss.connect(swss.CONFIG_DB)
+ swss.set(swss.CONFIG_DB, "DEVICE_METADATA|localhost", 'mac', mac_addr)
+ mac_addr = swss.get(swss.CONFIG_DB, "DEVICE_METADATA|localhost", 'mac')
+ DBG_PRINT("set device mac-address: %s" % mac_addr)
+ except IOError as e:
+ DBG_PRINT(str(e))
+
+ def initialize_rpc(self):
+ while True:
+ try:
+ r_sel = [self.udpClient]
+ echo_req = struct.pack('=HHH', 0, 1, 0)
+ self.udpClient.sendto(echo_req, ('localhost', 8101))
+ result = select(r_sel, [], [], 1)
+ if self.udpClient in result[0]:
+ echo_rsp, srv_addr = self.udpClient.recvfrom(1024)
+ if echo_rsp:
+ break
+ DBG_PRINT("connect to sdk rpc server timeout, try again.")
+ except IOError as e:
+ DBG_PRINT(str(e))
+
+ DBG_PRINT("connect to sdk rpc server success.")
+
+ def initialize_gpio(self):
+ # set gpio 1,2,3,4,5,6,7,8 output mode
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 1, 1, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 1, 2, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 1, 3, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 1, 4, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 1, 5, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 1, 6, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 1, 7, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 1, 8, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ # set gpio 1,2,3,4,5,6,7,8 output 0 to reset i2c bridge
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 1, 0)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 2, 0)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 3, 0)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 4, 0)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 5, 0)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 6, 0)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 7, 0)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 8, 0)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ # set gpio 1,2,3,4,5,6,7,8 output 1 to release i2c bridge
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 1, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 2, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 3, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 4, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 5, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 6, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 7, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ gpio_init = struct.pack('=HHHBBB', 0, 13, 3, 2, 8, 1)
+ self.udpClient.sendto(gpio_init, ('localhost', 8101))
+ DBG_PRINT("config ctc chip gpio done.")
+
+ def initialize_sfp(self):
+ try:
+ for port in range(1, PORT_NUMBER+1):
+ if self.get_sfp_present(port):
+ self.set_sfp_present(port, 1)
+ self.set_sfp_enable(port, 1)
+ else:
+ self.set_sfp_present(port, 0)
+ self.set_sfp_enable(port, 0)
+ except IOError as e:
+ DBG_PRINT(str(e))
+
+ def initialize(self):
+ DBG_PRINT("start connect to sdk rpc server.")
+
+ self.initialize_configdb()
+ self.initialize_rpc()
+ self.initialize_gpio()
+ self.initialize_sfp()
+
+ def sfp_scan(self):
+ try:
+ for port in range(1, PORT_NUMBER+1):
+ cur_present = self.get_sfp_present(port)
+ if self.sfp_present[port] != cur_present:
+ self.set_sfp_present(port, cur_present)
+ self.set_sfp_enable(port, cur_present)
+ except IOError as e:
+ DBG_PRINT(str(e))
+
+ def start(self):
+ while True:
+ self.sfp_scan()
+ time.sleep(1)
+
+if __name__ == "__main__":
+ monitor = PlatformMonitor()
+ monitor.initialize()
+ monitor.start()
+
diff --git a/platform/centec/sonic-platform-modules-e582/LICENSE b/platform/centec/sonic-platform-modules-e582/LICENSE
new file mode 100644
index 0000000000..99228517ba
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/LICENSE
@@ -0,0 +1,15 @@
+Copyright (C) 2017 Centec, Inc
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
diff --git a/platform/centec/sonic-platform-modules-e582/README.md b/platform/centec/sonic-platform-modules-e582/README.md
new file mode 100644
index 0000000000..61b3ef6c87
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/README.md
@@ -0,0 +1 @@
+platform drivers for Centec E582 for the SONiC project
diff --git a/platform/centec/sonic-platform-modules-e582/debian/changelog b/platform/centec/sonic-platform-modules-e582/debian/changelog
new file mode 100644
index 0000000000..d6f8d9ed26
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/debian/changelog
@@ -0,0 +1,11 @@
+sonic-centec-platform-modules (1.1) unstable; urgency=low
+
+ * Add support for centec e582-48x2q4z
+
+ -- xuwj Thus, 25 Jan 2018 13:43:40 +0800
+
+sonic-centec-platform-modules (1.0) unstable; urgency=low
+
+ * Initial release
+
+ -- xuwj Mon, 22 Jan 2018 13:43:40 +0800
diff --git a/platform/centec/sonic-platform-modules-e582/debian/compat b/platform/centec/sonic-platform-modules-e582/debian/compat
new file mode 100644
index 0000000000..ec635144f6
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/platform/centec/sonic-platform-modules-e582/debian/control b/platform/centec/sonic-platform-modules-e582/debian/control
new file mode 100644
index 0000000000..103b6eca24
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/debian/control
@@ -0,0 +1,17 @@
+Source: sonic-centec-platform-modules
+Section: main
+Priority: extra
+Maintainer: yangbs
+Build-Depends: debhelper (>= 8.0.0), bzip2
+Standards-Version: 3.9.3
+
+Package: platform-modules-e582-48x2q4z
+Architecture: amd64
+Depends: linux-image-3.16.0-5-amd64
+Description: kernel modules for platform devices such as fan, led, sfp
+
+Package: platform-modules-e582-48x6q
+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/centec/sonic-platform-modules-e582/debian/platform-modules-e582-48x2q4z.init b/platform/centec/sonic-platform-modules-e582/debian/platform-modules-e582-48x2q4z.init
new file mode 100755
index 0000000000..3ef5e7e30b
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/debian/platform-modules-e582-48x2q4z.init
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+### BEGIN INIT INFO
+# Provides: setup-board
+# Required-Start:
+# Required-Stop:
+# Should-Start:
+# Should-Stop:
+# Default-Start: S
+# Default-Stop: 0 6
+# Short-Description: Setup e582-48x2q4z board.
+### END INIT INFO
+
+case "$1" in
+start)
+ echo -n "Setting up board... "
+ /usr/bin/48x2q4z_platform.sh init
+
+ echo "done."
+ ;;
+
+stop)
+ /usr/bin/48x2q4z_platform.sh deinit
+ echo "done."
+
+ ;;
+
+force-reload|restart)
+ echo "Not supported"
+ ;;
+
+*)
+ echo "Usage: service platform-modules-e582-48x2q4z {start|stop}"
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/platform/centec/sonic-platform-modules-e582/debian/platform-modules-e582-48x2q4z.install b/platform/centec/sonic-platform-modules-e582/debian/platform-modules-e582-48x2q4z.install
new file mode 100644
index 0000000000..86569b323b
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/debian/platform-modules-e582-48x2q4z.install
@@ -0,0 +1,2 @@
+48x2q4z/cfg/48x2q4z-modules.conf etc/modules-load.d
+48x2q4z/scripts/48x2q4z_platform.sh usr/bin
diff --git a/platform/centec/sonic-platform-modules-e582/debian/platform-modules-e582-48x6q.init b/platform/centec/sonic-platform-modules-e582/debian/platform-modules-e582-48x6q.init
new file mode 100755
index 0000000000..1c5b0c1c49
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/debian/platform-modules-e582-48x6q.init
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+### BEGIN INIT INFO
+# Provides: setup-board
+# Required-Start:
+# Required-Stop:
+# Should-Start:
+# Should-Stop:
+# Default-Start: S
+# Default-Stop: 0 6
+# Short-Description: Setup e582-48x6q board.
+### END INIT INFO
+
+case "$1" in
+start)
+ echo -n "Setting up board... "
+ /usr/bin/48x6q_platform.sh init
+
+ echo "done."
+ ;;
+
+stop)
+ /usr/bin/48x6q_platform.sh deinit
+ echo "done."
+
+ ;;
+
+force-reload|restart)
+ echo "Not supported"
+ ;;
+
+*)
+ echo "Usage: service platform-modules-e582-48x6q {start|stop}"
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/platform/centec/sonic-platform-modules-e582/debian/platform-modules-e582-48x6q.install b/platform/centec/sonic-platform-modules-e582/debian/platform-modules-e582-48x6q.install
new file mode 100644
index 0000000000..7ec21f3378
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/debian/platform-modules-e582-48x6q.install
@@ -0,0 +1,6 @@
+48x6q/cfg/48x6q-modules.conf etc/modules-load.d
+48x6q/cfg/minigraph.xml etc/sonic
+48x6q/cfg/config_db.json etc/sonic
+48x6q/cfg/config_db_l2l3.json etc/sonic
+48x6q/scripts/48x6q_platform.sh usr/bin
+48x6q/scripts/48x6q_platform_monitor.py usr/bin
diff --git a/platform/centec/sonic-platform-modules-e582/debian/rules b/platform/centec/sonic-platform-modules-e582/debian/rules
new file mode 100755
index 0000000000..9f5d67b1af
--- /dev/null
+++ b/platform/centec/sonic-platform-modules-e582/debian/rules
@@ -0,0 +1,35 @@
+#!/usr/bin/make -f
+
+export INSTALL_MOD_DIR:=extra
+
+KVERSION ?= $(shell uname -r)
+KERNEL_SRC := /lib/modules/$(KVERSION)
+MOD_SRC_DIR:= $(shell pwd)
+MODULE_DIRS:= 48x6q 48x2q4z
+
+%:
+ dh $@
+
+override_dh_auto_build:
+ (for mod in $(MODULE_DIRS); do \
+ make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \
+ done)
+
+override_dh_auto_install:
+ (for mod in $(MODULE_DIRS); do \
+ dh_installdirs -pplatform-modules-e582-$${mod} \
+ $(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
+ cp -f $(MOD_SRC_DIR)/$${mod}/modules/*.ko \
+ debian/platform-modules-e582-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
+ done)
+
+override_dh_usrlocal:
+
+override_dh_clean:
+ dh_clean
+ (for mod in $(MODULE_DIRS); do \
+ make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules clean; \
+ rm -rf $(MOD_SRC_DIR)/$${mod}/modules/*.ko; \
+ rm -rf debian/platform-modules-e582-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR)/*.ko; \
+ done)
+