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) +