201911 mx pull request (#10539)

Why I did it
Added Support for Celestica Midstone-100x platform

How I did it
Implemented the support for Celestica Midstone-100x platform

Platform: x86_64-cel_midstone-100x-r0
HwSKU: Midstone-100x
ASIC: innovium
ASIC Count: 1

How to verify it
Run platform test on testbed
This commit is contained in:
AntheaJiang 2022-07-01 01:03:49 +08:00 committed by GitHub
parent 6ea65056b9
commit 78c6ae112b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 13051 additions and 6 deletions

View File

@ -0,0 +1,137 @@
{# Default values which will be used if no actual configura available #}
{% set default_cable = '40m' %}
{# 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 is defined and 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 %}
{%- if switch_role.lower() == 'torrouter' %}
{%- for local_port in VLAN_MEMBER %}
{%- if local_port[1] == port_name %}
{%- set roles3 = switch_role + '_' + 'server' %}
{%- set roles3 = roles3 | lower %}
{%- if roles3 in ports2cable %}
{%- if cable_len.append(ports2cable[roles3]) %}{% endif %}
{%- endif %}
{%- endif %}
{%- endfor %}
{%- if cable_len -%}
{{ cable_len.0 }}
{%- else -%}
{{ default_cable }}
{%- endif %}
{%- else -%}
{{ default_cable }}
{%- endif %}
{%- endif %}
{%- endmacro %}
{%- if DEVICE_METADATA is defined %}
{%- set switch_role = DEVICE_METADATA['localhost']['type'] %}
{%- endif -%}
{% set port_names_list = [] %}
{% for port in PORT %}
{%- if port_names_list.append(port) %}{% endif %}
{% endfor %}
{% set port_names = port_names_list | join(',') -%}
{
"CABLE_LENGTH": {
"AZURE": {
{% for port in PORT %}
{% set cable = cable_length(port) -%}
"{{ port }}": "{{ cable }}"{%- if not loop.last -%},{% endif %}
{% endfor %}
}
},
"BUFFER_POOL": {
"ingress_lossless_pool": {
"size": "47218432",
"type": "ingress",
"mode": "dynamic",
"xoff": "17708800"
},
"lossy_pool": {
"size": "18874368",
"type": "egress",
"mode": "dynamic",
"xoff": "0"
}
},
"BUFFER_PROFILE": {
"ingress_lossless_profile": {
"pool":"[BUFFER_POOL|ingress_lossless_pool]",
"xoff":"38816",
"size":"1518",
"dynamic_th":"1",
"xon_offset":"13440"
},
"egress_lossless_profile": {
"pool":"[BUFFER_POOL|ingress_lossless_pool]",
"size":"0",
"static_th":"9497600"
},
"ingress_lossy_profile": {
"pool":"[BUFFER_POOL|lossy_pool]",
"size":"0",
"static_th":"9497600"
},
"egress_lossy_profile": {
"pool":"[BUFFER_POOL|lossy_pool]",
"size":"1518",
"dynamic_th":"2"
}
},
"BUFFER_PG": {
"{{ port_names }}|0-2": {
"profile" : "[BUFFER_PROFILE|ingress_lossy_profile]"
},
"{{ port_names }}|3-4": {
"profile" : "[BUFFER_PROFILE|ingress_lossless_profile]"
},
"{{ port_names }}|5-7": {
"profile" : "[BUFFER_PROFILE|ingress_lossy_profile]"
}
},
"BUFFER_QUEUE": {
"{{ port_names }}|3-4": {
"profile" : "[BUFFER_PROFILE|egress_lossless_profile]"
},
"{{ port_names }}|0-2": {
"profile" : "[BUFFER_PROFILE|egress_lossy_profile]"
},
"{{ port_names }}|5-7": {
"profile" : "[BUFFER_PROFILE|egress_lossy_profile]"
}
}
}

View File

@ -0,0 +1,38 @@
{% set port_names_list = [] %}
{% for port in PORT %}
{%- if port_names_list.append(port) %}{% endif %}
{% endfor %}
{% set port_names = port_names_list | join(',') -%}
{
"BUFFER_POOL": {
"lossy_pool": {
"size": "56985600",
"type": "egress",
"mode": "dynamic",
"xoff": "0"
}
},
"BUFFER_PROFILE": {
"ingress_lossy_profile": {
"pool":"[BUFFER_POOL|lossy_pool]",
"size":"0",
"static_th":"9497600"
},
"egress_lossy_profile": {
"pool":"[BUFFER_POOL|lossy_pool]",
"size":"1518",
"dynamic_th":"2"
}
},
"BUFFER_PG": {
"{{ port_names }}|0-7": {
"profile" : "[BUFFER_PROFILE|ingress_lossy_profile]"
}
},
"BUFFER_QUEUE": {
"{{ port_names }}|0-7": {
"profile" : "[BUFFER_PROFILE|egress_lossy_profile]"
}
}
}

View File

@ -0,0 +1,137 @@
{# Default values which will be used if no actual configura available #}
{% set default_cable = '40m' %}
{# 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 is defined and 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 %}
{%- if switch_role.lower() == 'torrouter' %}
{%- for local_port in VLAN_MEMBER %}
{%- if local_port[1] == port_name %}
{%- set roles3 = switch_role + '_' + 'server' %}
{%- set roles3 = roles3 | lower %}
{%- if roles3 in ports2cable %}
{%- if cable_len.append(ports2cable[roles3]) %}{% endif %}
{%- endif %}
{%- endif %}
{%- endfor %}
{%- if cable_len -%}
{{ cable_len.0 }}
{%- else -%}
{{ default_cable }}
{%- endif %}
{%- else -%}
{{ default_cable }}
{%- endif %}
{%- endif %}
{%- endmacro %}
{%- if DEVICE_METADATA is defined %}
{%- set switch_role = DEVICE_METADATA['localhost']['type'] %}
{%- endif -%}
{% set port_names_list = [] %}
{% for port in PORT %}
{%- if port_names_list.append(port) %}{% endif %}
{% endfor %}
{% set port_names = port_names_list | join(',') -%}
{
"CABLE_LENGTH": {
"AZURE": {
{% for port in PORT %}
{% set cable = cable_length(port) -%}
"{{ port }}": "{{ cable }}"{%- if not loop.last -%},{% endif %}
{% endfor %}
}
},
"BUFFER_POOL": {
"ingress_lossless_pool": {
"size": "47218432",
"type": "ingress",
"mode": "dynamic",
"xoff": "17708800"
},
"lossy_pool": {
"size": "18874368",
"type": "egress",
"mode": "dynamic",
"xoff": "0"
}
},
"BUFFER_PROFILE": {
"ingress_lossless_profile": {
"pool":"[BUFFER_POOL|ingress_lossless_pool]",
"xoff":"38816",
"size":"1518",
"dynamic_th":"1",
"xon_offset":"13440"
},
"egress_lossless_profile": {
"pool":"[BUFFER_POOL|ingress_lossless_pool]",
"size":"0",
"static_th":"9497600"
},
"ingress_lossy_profile": {
"pool":"[BUFFER_POOL|lossy_pool]",
"size":"0",
"static_th":"9497600"
},
"egress_lossy_profile": {
"pool":"[BUFFER_POOL|lossy_pool]",
"size":"1518",
"dynamic_th":"2"
}
},
"BUFFER_PG": {
"{{ port_names }}|0-2": {
"profile" : "[BUFFER_PROFILE|ingress_lossy_profile]"
},
"{{ port_names }}|3-4": {
"profile" : "[BUFFER_PROFILE|ingress_lossless_profile]"
},
"{{ port_names }}|5-7": {
"profile" : "[BUFFER_PROFILE|ingress_lossy_profile]"
}
},
"BUFFER_QUEUE": {
"{{ port_names }}|3-4": {
"profile" : "[BUFFER_PROFILE|egress_lossless_profile]"
},
"{{ port_names }}|0-2": {
"profile" : "[BUFFER_PROFILE|egress_lossy_profile]"
},
"{{ port_names }}|5-7": {
"profile" : "[BUFFER_PROFILE|egress_lossy_profile]"
}
}
}

View File

@ -0,0 +1,642 @@
ifcs:
options:
log_level: "info"
nodes:
- node_id: "0"
options:
sd_low_power_mode_global_default: "true"
sku: "configs/sku/innovium.77500"
netdev:
- auto_create: "no"
multi_interface: "yes"
buffer_management_mode: "api_driven"
max_lossless_tc: "2"
ilpm_enable: "1"
forward_profile: "IFCS_FORWARD_PROFILE_ID_PROFILE_E"
ecn_stats_enable: "1"
sys_clk: "1720"
ifc_clk: "1200"
mac_clk: "1340"
txring:
- txring_id: "0"
desc_count: "1024"
prio: "1"
netdev: "true"
- txring_id: "1"
desc_count: "1024"
prio: "1"
netdev: "true"
- txring_id: "2"
desc_count: "1024"
prio: "1"
netdev: "true"
- txring_id: "3"
desc_count: "1024"
prio: "1"
netdev: "true"
rxring:
- rxring_id: "0"
desc_count: "1024"
prio: "1"
netdev: "true"
queues: "0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39"
- rxring_id: "1"
desc_count: "1024"
prio: "1"
netdev: "true"
queues: "1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40"
- rxring_id: "2"
desc_count: "1024"
prio: "1"
netdev: "true"
queues: "2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 47"
- rxring_id: "3"
desc_count: "1024"
prio: "1"
queues: "42, 43, 44, 45, 46"
devports:
- id: "0"
sysport: "1000"
type: "cpu"
- fec: "KRFEC"
id: "221"
lanes: "4:4"
serdes_group: "27"
speed: "100G"
sysport: "221"
type: "eth"
- fec: "KRFEC"
id: "213"
lanes: "4:4"
serdes_group: "26"
speed: "100G"
sysport: "213"
type: "eth"
- fec: "KRFEC"
id: "205"
lanes: "4:4"
serdes_group: "25"
speed: "100G"
sysport: "205"
type: "eth"
- fec: "KRFEC"
id: "197"
lanes: "4:4"
serdes_group: "24"
speed: "100G"
sysport: "197"
type: "eth"
- fec: "KRFEC"
id: "189"
lanes: "4:4"
serdes_group: "23"
speed: "100G"
sysport: "189"
type: "eth"
- fec: "KRFEC"
id: "181"
lanes: "4:4"
serdes_group: "22"
speed: "100G"
sysport: "181"
type: "eth"
- fec: "KRFEC"
id: "173"
lanes: "4:4"
serdes_group: "21"
speed: "100G"
sysport: "173"
type: "eth"
- fec: "KRFEC"
id: "165"
lanes: "4:4"
serdes_group: "20"
speed: "100G"
sysport: "165"
type: "eth"
- fec: "KRFEC"
id: "253"
lanes: "4:4"
serdes_group: "31"
speed: "100G"
sysport: "253"
type: "eth"
- fec: "KRFEC"
id: "245"
lanes: "4:4"
serdes_group: "30"
speed: "100G"
sysport: "245"
type: "eth"
- fec: "KRFEC"
id: "237"
lanes: "4:4"
serdes_group: "29"
speed: "100G"
sysport: "237"
type: "eth"
- fec: "KRFEC"
id: "229"
lanes: "4:4"
serdes_group: "28"
speed: "100G"
sysport: "229"
type: "eth"
- fec: "KRFEC"
id: "157"
lanes: "4:4"
serdes_group: "19"
speed: "100G"
sysport: "157"
type: "eth"
- fec: "KRFEC"
id: "149"
lanes: "4:4"
serdes_group: "18"
speed: "100G"
sysport: "149"
type: "eth"
- fec: "KRFEC"
id: "141"
lanes: "4:4"
serdes_group: "17"
speed: "100G"
sysport: "141"
type: "eth"
- fec: "KRFEC"
id: "133"
lanes: "4:4"
serdes_group: "16"
speed: "100G"
sysport: "133"
type: "eth"
- fec: "KRFEC"
id: "117"
lanes: "4:4"
serdes_group: "14"
speed: "100G"
sysport: "117"
type: "eth"
- fec: "KRFEC"
id: "125"
lanes: "4:4"
serdes_group: "15"
speed: "100G"
sysport: "125"
type: "eth"
- fec: "KRFEC"
id: "101"
lanes: "4:4"
serdes_group: "12"
speed: "100G"
sysport: "101"
type: "eth"
- fec: "KRFEC"
id: "109"
lanes: "4:4"
serdes_group: "13"
speed: "100G"
sysport: "109"
type: "eth"
- fec: "KRFEC"
id: "21"
lanes: "4:4"
serdes_group: "2"
speed: "100G"
sysport: "21"
type: "eth"
- fec: "KRFEC"
id: "29"
lanes: "4:4"
serdes_group: "3"
speed: "100G"
sysport: "29"
type: "eth"
- fec: "KRFEC"
id: "5"
lanes: "4:4"
serdes_group: "0"
speed: "100G"
sysport: "5"
type: "eth"
- fec: "KRFEC"
id: "13"
lanes: "4:4"
serdes_group: "1"
speed: "100G"
sysport: "13"
type: "eth"
- fec: "KRFEC"
id: "85"
lanes: "4:4"
serdes_group: "10"
speed: "100G"
sysport: "85"
type: "eth"
- fec: "KRFEC"
id: "93"
lanes: "4:4"
serdes_group: "11"
speed: "100G"
sysport: "93"
type: "eth"
- fec: "KRFEC"
id: "69"
lanes: "4:4"
serdes_group: "8"
speed: "100G"
sysport: "69"
type: "eth"
- fec: "KRFEC"
id: "77"
lanes: "4:4"
serdes_group: "9"
speed: "100G"
sysport: "77"
type: "eth"
- fec: "KRFEC"
id: "53"
lanes: "4:4"
serdes_group: "6"
speed: "100G"
sysport: "53"
type: "eth"
- fec: "KRFEC"
id: "61"
lanes: "4:4"
serdes_group: "7"
speed: "100G"
sysport: "61"
type: "eth"
- fec: "KRFEC"
id: "37"
lanes: "4:4"
serdes_group: "4"
speed: "100G"
sysport: "37"
type: "eth"
- fec: "KRFEC"
id: "45"
lanes: "4:4"
serdes_group: "5"
speed: "100G"
sysport: "45"
type: "eth"
- fec: "KRFEC"
id: "209"
lanes: "0:4"
serdes_group: "26"
speed: "100G"
sysport: "209"
type: "eth"
- fec: "KRFEC"
id: "217"
lanes: "0:4"
serdes_group: "27"
speed: "100G"
sysport: "217"
type: "eth"
- fec: "KRFEC"
id: "193"
lanes: "0:4"
serdes_group: "24"
speed: "100G"
sysport: "193"
type: "eth"
- fec: "KRFEC"
id: "201"
lanes: "0:4"
serdes_group: "25"
speed: "100G"
sysport: "201"
type: "eth"
- fec: "KRFEC"
id: "177"
lanes: "0:4"
serdes_group: "22"
speed: "100G"
sysport: "177"
type: "eth"
- fec: "KRFEC"
id: "185"
lanes: "0:4"
serdes_group: "23"
speed: "100G"
sysport: "185"
type: "eth"
- fec: "KRFEC"
id: "161"
lanes: "0:4"
serdes_group: "20"
speed: "100G"
sysport: "161"
type: "eth"
- fec: "KRFEC"
id: "169"
lanes: "0:4"
serdes_group: "21"
speed: "100G"
sysport: "169"
type: "eth"
- fec: "KRFEC"
id: "241"
lanes: "0:4"
serdes_group: "30"
speed: "100G"
sysport: "241"
type: "eth"
- fec: "KRFEC"
id: "249"
lanes: "0:4"
serdes_group: "31"
speed: "100G"
sysport: "249"
type: "eth"
- fec: "KRFEC"
id: "225"
lanes: "0:4"
serdes_group: "28"
speed: "100G"
sysport: "225"
type: "eth"
- fec: "KRFEC"
id: "233"
lanes: "0:4"
serdes_group: "29"
speed: "100G"
sysport: "233"
type: "eth"
- fec: "KRFEC"
id: "145"
lanes: "0:4"
serdes_group: "18"
speed: "100G"
sysport: "145"
type: "eth"
- fec: "KRFEC"
id: "153"
lanes: "0:4"
serdes_group: "19"
speed: "100G"
sysport: "153"
type: "eth"
- fec: "KRFEC"
id: "129"
lanes: "0:4"
serdes_group: "16"
speed: "100G"
sysport: "129"
type: "eth"
- fec: "KRFEC"
id: "137"
lanes: "0:4"
serdes_group: "17"
speed: "100G"
sysport: "137"
type: "eth"
- fec: "KRFEC"
id: "121"
lanes: "0:4"
serdes_group: "15"
speed: "100G"
sysport: "121"
type: "eth"
- fec: "KRFEC"
id: "113"
lanes: "0:4"
serdes_group: "14"
speed: "100G"
sysport: "113"
type: "eth"
- fec: "KRFEC"
id: "105"
lanes: "0:4"
serdes_group: "13"
speed: "100G"
sysport: "105"
type: "eth"
- fec: "KRFEC"
id: "97"
lanes: "0:4"
serdes_group: "12"
speed: "100G"
sysport: "97"
type: "eth"
- fec: "KRFEC"
id: "25"
lanes: "0:4"
serdes_group: "3"
speed: "100G"
sysport: "25"
type: "eth"
- fec: "KRFEC"
id: "17"
lanes: "0:4"
serdes_group: "2"
speed: "100G"
sysport: "17"
type: "eth"
- fec: "KRFEC"
id: "9"
lanes: "0:4"
serdes_group: "1"
speed: "100G"
sysport: "9"
type: "eth"
- fec: "KRFEC"
id: "1"
lanes: "0:4"
serdes_group: "0"
speed: "100G"
sysport: "1"
type: "eth"
- fec: "KRFEC"
id: "89"
lanes: "0:4"
serdes_group: "11"
speed: "100G"
sysport: "89"
type: "eth"
- fec: "KRFEC"
id: "81"
lanes: "0:4"
serdes_group: "10"
speed: "100G"
sysport: "81"
type: "eth"
- fec: "KRFEC"
id: "73"
lanes: "0:4"
serdes_group: "9"
speed: "100G"
sysport: "73"
type: "eth"
- fec: "KRFEC"
id: "65"
lanes: "0:4"
serdes_group: "8"
speed: "100G"
sysport: "65"
type: "eth"
- fec: "KRFEC"
id: "57"
lanes: "0:4"
serdes_group: "7"
speed: "100G"
sysport: "57"
type: "eth"
- fec: "KRFEC"
id: "49"
lanes: "0:4"
serdes_group: "6"
speed: "100G"
sysport: "49"
type: "eth"
- fec: "KRFEC"
id: "41"
lanes: "0:4"
serdes_group: "5"
speed: "100G"
sysport: "41"
type: "eth"
- fec: "KRFEC"
id: "33"
lanes: "0:4"
serdes_group: "4"
speed: "100G"
sysport: "33"
type: "eth"
isg:
- id: "0"
lane_swap: "02317654"
tx_polarity: "11011000"
rx_polarity: "01101010"
- id: "1"
lane_swap: "20134567"
tx_polarity: "00001010"
rx_polarity: "00110100"
- id: "2"
lane_swap: "02137465"
tx_polarity: "00010010"
rx_polarity: "10110000"
- id: "3"
lane_swap: "12036475"
tx_polarity: "11100111"
rx_polarity: "10000001"
- id: "4"
lane_swap: "01237465"
tx_polarity: "00101101"
rx_polarity: "00111110"
- id: "5"
lane_swap: "12304675"
tx_polarity: "10001011"
rx_polarity: "01010110"
- id: "6"
lane_swap: "01237654"
tx_polarity: "00100110"
rx_polarity: "00011101"
- id: "7"
lane_swap: "12037456"
tx_polarity: "00101000"
rx_polarity: "00001111"
- id: "8"
lane_swap: "01237654"
tx_polarity: "10110110"
rx_polarity: "01011011"
- id: "9"
lane_swap: "12035467"
tx_polarity: "11101000"
rx_polarity: "00011001"
- id: "10"
lane_swap: "01235674"
tx_polarity: "01111111"
rx_polarity: "01011011"
- id: "11"
lane_swap: "01237564"
tx_polarity: "01101100"
rx_polarity: "11011000"
- id: "12"
lane_swap: "01237546"
tx_polarity: "00011101"
rx_polarity: "00000010"
- id: "13"
lane_swap: "03216475"
tx_polarity: "10000011"
rx_polarity: "11011111"
- id: "14"
lane_swap: "01237564"
tx_polarity: "00111011"
rx_polarity: "00000011"
- id: "15"
lane_swap: "03214567"
tx_polarity: "00000101"
rx_polarity: "01000111"
- id: "16"
lane_swap: "12034576"
tx_polarity: "00010100"
rx_polarity: "10000001"
- id: "17"
lane_swap: "02314567"
tx_polarity: "00100111"
rx_polarity: "00100000"
- id: "18"
lane_swap: "01234576"
tx_polarity: "00011101"
rx_polarity: "11100111"
- id: "19"
lane_swap: "13204567"
tx_polarity: "00011101"
rx_polarity: "00111001"
- id: "20"
lane_swap: "01237564"
tx_polarity: "00000111"
rx_polarity: "10010101"
- id: "21"
lane_swap: "01235647"
tx_polarity: "00111011"
rx_polarity: "00111101"
- id: "22"
lane_swap: "12307564"
tx_polarity: "11110100"
rx_polarity: "01010001"
- id: "23"
lane_swap: "03214657"
tx_polarity: "00111000"
rx_polarity: "10000111"
- id: "24"
lane_swap: "01236547"
tx_polarity: "00010111"
rx_polarity: "11001101"
- id: "25"
lane_swap: "01235647"
tx_polarity: "00101011"
rx_polarity: "01111110"
- id: "26"
lane_swap: "01234567"
tx_polarity: "00010101"
rx_polarity: "11000100"
- id: "27"
lane_swap: "01234567"
tx_polarity: "00100000"
rx_polarity: "00111110"
- id: "28"
lane_swap: "01236754"
tx_polarity: "10101001"
rx_polarity: "11011001"
- id: "29"
lane_swap: "01234567"
tx_polarity: "00101010"
rx_polarity: "10011111"
- id: "30"
lane_swap: "31204567"
tx_polarity: "00010101"
rx_polarity: "01101110"
- id: "31"
lane_swap: "01234567"
tx_polarity: "00100011"
rx_polarity: "11001110"
- id: "32"
lane_swap: "01234567"
rx_polarity: "00000000"
tx_polarity: "00000000"

View File

@ -0,0 +1,59 @@
sku: innovium.77500
device_id: 0x1b58
# Hardware constraint information
hardware:
num_ibs: 6
ports_per_ib: 32, 32, 32, 32, 20, 20
recirc_port_num: 32, 32, 32, 32, 32, 32
cpu_port_num: 33
cpu_port_ib: 0
mgmt_port_num: 33
mgmt_port_ibs: 1,2
pics_per_ib: 6, 7, 7, 6, 5, 5
pic_ports_per_pic: 8
max_serdes_speed: 25
num_shared_pics: 2
isg [0-4]:
ib: 0
pic_id: [0-4]
isg [5-9]:
ib: 5
pic_id: [0-4]
isg [10-14]:
ib: 1
pic_id: [0-4]
isg [16-20]:
ib: 3
pic_id: [0-4]
isg [21-25]:
ib: 4
pic_id: [0-4]
isg [26-30]:
ib: 2
pic_id: [0-4]
isg 15:
mode: 4:4
ib: 1, 3
pic_id: 5
isg 31:
mode: 4:4
ib: 0, 2
pic_id: 5
isg 32:
mode: 1:1
ib: 1, 2
pic_id: 6

View File

@ -0,0 +1,59 @@
sku: innovium.77700_B
device_id: 0x1b58
# Hardware constraint information
hardware:
num_ibs: 6
ports_per_ib: 32, 32, 32, 32, 20, 20
recirc_port_num: 32, 32, 32, 32, 32, 32
cpu_port_num: 33
cpu_port_ib: 0
mgmt_port_num: 33
mgmt_port_ibs: 1,2
pics_per_ib: 6, 7, 7, 6, 5, 5
pic_ports_per_pic: 8
max_serdes_speed: 50
num_shared_pics: 2
isg [0-4]:
ib: 0
pic_id: [0-4]
isg [5-9]:
ib: 5
pic_id: [0-4]
isg [10-14]:
ib: 1
pic_id: [0-4]
isg [16-20]:
ib: 3
pic_id: [0-4]
isg [21-25]:
ib: 4
pic_id: [0-4]
isg [26-30]:
ib: 2
pic_id: [0-4]
isg 15:
mode: 4:4
ib: 1, 3
pic_id: 5
isg 31:
mode: 4:4
ib: 0, 2
pic_id: 5
isg 32:
mode: 1:1
ib: 1, 2
pic_id: 6

View File

@ -0,0 +1,8 @@
IFCS_INIT_FILE : "/usr/share/sonic/hwsku/config_64x100G_midstone100x.yaml"
IFCS_SKU_FILE : "/usr/share/sonic/hwsku/innovium.77500"
IFCS_INNO_CLI_PORT : "9999"
IFCS_TARGET : "device"
INNOVIUM_DIR : "/innovium"
PYTHONPATH : "$INNOVIUM_DIR:$INNOVIUM_DIR/cmds:$INNOVIUM_DIR/scripts:$INNOVIUM_DIR/test/:$INNOVIUM_DIR/test/utils:$INNOVIUM_DIR/utils:$INNOVIUM_DIR/pyctypes"
IVM_SAI_DATAPATH_CONFIG_FILE: "/usr/share/sonic/hwsku/ivm.sai.datapath.config.yaml"
IVM_SAI_PARAM_A0008: "32"

View File

@ -0,0 +1,9 @@
ISAI_PARAM_P0_0_LS : "4608 4608 4608 4608 2880 2880"
ISAI_PARAM_P0_1_LS : "2226 1946 1946 1890 1218 1218"
ISAI_PARAM_P0_1_ALS : "434 154 154 98 98 98"
ISAI_PARAM_P1_0_LS : "1536 1536 1536 1536 960 960"
ISAI_PARAM_P1_0_LL : "3072 3072 3072 3072 1920 1920"
ISAI_PARAM_P1_1_LS : "1778 1498 1498 1442 938 938"
ISAI_PARAM_P1_1_LL : "2478 2478 2478 2478 2478 2478"
ISAI_PARAM_P1_1_ALS : "434 154 154 98 98 98"
ISAI_PARAM_P1_1_ALL : "126 126 126 126 126 126"

View File

@ -0,0 +1,18 @@
# PG lossless profiles.
# speed cable size xon xoff threshold xon_offset
25000 5m 1518 0 15680 1 13440
50000 5m 1518 0 21248 1 13440
100000 5m 1518 0 34624 1 13440
400000 5m 1518 0 117536 1 13440
25000 40m 1518 0 16928 1 13440
50000 40m 1518 0 23392 1 13440
100000 40m 1518 0 38816 1 13440
400000 40m 1518 0 135520 1 13440
25000 100m 1518 0 18848 1 13440
50000 100m 1518 0 27264 1 13440
100000 100m 1518 0 46496 1 13440
400000 100m 1518 0 166688 1 13440
25000 300m 1518 0 25184 1 13440
50000 300m 1518 0 40128 1 13440
100000 300m 1518 0 72384 1 13440
400000 300m 1518 0 268640 1 13440

View File

@ -0,0 +1,65 @@
# name lanes alias speed index mtu fec
Ethernet0 221,222,223,224 Eth1 100000 0 9126 rs
Ethernet4 213,214,215,216 Eth2 100000 1 9126 rs
Ethernet8 205,206,207,208 Eth3 100000 2 9126 rs
Ethernet12 197,198,199,200 Eth4 100000 3 9126 rs
Ethernet16 189,190,191,192 Eth5 100000 4 9126 rs
Ethernet20 181,182,183,184 Eth6 100000 5 9126 rs
Ethernet24 173,174,175,176 Eth7 100000 6 9126 rs
Ethernet28 165,166,167,168 Eth8 100000 7 9126 rs
Ethernet32 253,254,255,256 Eth9 100000 8 9126 rs
Ethernet36 245,246,247,248 Eth10 100000 9 9126 rs
Ethernet40 237,238,239,240 Eth11 100000 10 9126 rs
Ethernet44 229,230,231,232 Eth12 100000 11 9126 rs
Ethernet48 157,158,159,160 Eth13 100000 12 9126 rs
Ethernet52 149,150,151,152 Eth14 100000 13 9126 rs
Ethernet56 141,142,143,144 Eth15 100000 14 9126 rs
Ethernet60 133,134,135,136 Eth16 100000 15 9126 rs
Ethernet64 117,118,119,120 Eth17 100000 16 9126 rs
Ethernet68 125,126,127,128 Eth18 100000 17 9126 rs
Ethernet72 101,102,103,104 Eth19 100000 18 9126 rs
Ethernet76 109,110,111,112 Eth20 100000 19 9126 rs
Ethernet80 21,22,23,24 Eth21 100000 20 9126 rs
Ethernet84 29,30,31,32 Eth22 100000 21 9126 rs
Ethernet88 5,6,7,8 Eth23 100000 22 9126 rs
Ethernet92 13,14,15,16 Eth24 100000 23 9126 rs
Ethernet96 85,86,87,88 Eth25 100000 24 9126 rs
Ethernet100 93,94,95,96 Eth26 100000 25 9126 rs
Ethernet104 69,70,71,72 Eth27 100000 26 9126 rs
Ethernet108 77,78,79,80 Eth28 100000 27 9126 rs
Ethernet112 53,54,55,56 Eth29 100000 28 9126 rs
Ethernet116 61,62,63,64 Eth30 100000 29 9126 rs
Ethernet120 37,38,39,40 Eth31 100000 30 9126 rs
Ethernet124 45,46,47,48 Eth32 100000 31 9126 rs
Ethernet128 209,210,211,212 Eth33 100000 32 9126 rs
Ethernet132 217,218,219,220 Eth34 100000 33 9126 rs
Ethernet136 193,194,195,196 Eth35 100000 34 9126 rs
Ethernet140 201,202,203,204 Eth36 100000 35 9126 rs
Ethernet144 177,178,179,180 Eth37 100000 36 9126 rs
Ethernet148 185,186,187,188 Eth38 100000 37 9126 rs
Ethernet152 161,162,163,164 Eth39 100000 38 9126 rs
Ethernet156 169,170,171,172 Eth40 100000 39 9126 rs
Ethernet160 241,242,243,244 Eth41 100000 40 9126 rs
Ethernet164 249,250,251,252 Eth42 100000 41 9126 rs
Ethernet168 225,226,227,228 Eth43 100000 42 9126 rs
Ethernet172 233,234,235,236 Eth44 100000 43 9126 rs
Ethernet176 145,146,147,148 Eth45 100000 44 9126 rs
Ethernet180 153,154,155,156 Eth46 100000 45 9126 rs
Ethernet184 129,130,131,132 Eth47 100000 46 9126 rs
Ethernet188 137,138,139,140 Eth48 100000 47 9126 rs
Ethernet192 121,122,123,124 Eth49 100000 48 9126 rs
Ethernet196 113,114,115,116 Eth50 100000 49 9126 rs
Ethernet200 105,106,107,108 Eth51 100000 50 9126 rs
Ethernet204 97,98,99,100 Eth52 100000 51 9126 rs
Ethernet208 25,26,27,28 Eth53 100000 52 9126 rs
Ethernet212 17,18,19,20 Eth54 100000 53 9126 rs
Ethernet216 9,10,11,12 Eth55 100000 54 9126 rs
Ethernet220 1,2,3,4 Eth56 100000 55 9126 rs
Ethernet224 89,90,91,92 Eth57 100000 56 9126 rs
Ethernet228 81,82,83,84 Eth58 100000 57 9126 rs
Ethernet232 73,74,75,76 Eth59 100000 58 9126 rs
Ethernet236 65,66,67,68 Eth60 100000 59 9126 rs
Ethernet240 57,58,59,60 Eth61 100000 60 9126 rs
Ethernet244 49,50,51,52 Eth62 100000 61 9126 rs
Ethernet248 41,42,43,44 Eth63 100000 62 9126 rs
Ethernet252 33,34,35,36 Eth64 100000 63 9126 rs

View File

@ -0,0 +1,114 @@
{% set port_names_list = [] %}
{% for port in PORT %}
{%- if port_names_list.append(port) %}{% endif %}
{% endfor %}
{% set port_names = port_names_list | join(',') -%}
{
"TC_TO_QUEUE_MAP":{
"AZURE":{
"0":"0",
"1":"1",
"2":"2",
"3":"3",
"4":"4",
"5":"5",
"6":"6",
"7":"7"
}
},
"TC_TO_PRIORITY_GROUP_MAP": {
"AZURE": {
"0": "0",
"1": "0",
"2": "0",
"3": "3",
"4": "4",
"5": "0",
"6": "0",
"7": "0"
}
},
"DSCP_TO_TC_MAP": {
"AZURE": {
"0":"0",
"1":"0",
"2":"0",
"3":"3",
"4":"4",
"5":"0",
"6":"0",
"7":"0",
"8":"1",
"9":"0",
"10":"0",
"11":"0",
"12":"0",
"13":"0",
"14":"0",
"15":"0",
"16":"0",
"17":"0",
"18":"0",
"19":"0",
"20":"0",
"21":"0",
"22":"0",
"23":"0",
"24":"0",
"25":"0",
"26":"0",
"27":"0",
"28":"0",
"29":"0",
"30":"0",
"31":"0",
"32":"0",
"33":"0",
"34":"0",
"35":"0",
"36":"0",
"37":"0",
"38":"0",
"39":"0",
"40":"0",
"41":"0",
"42":"0",
"43":"0",
"44":"0",
"45":"0",
"46":"0",
"47":"0",
"48":"0",
"49":"0",
"50":"0",
"51":"0",
"52":"0",
"53":"0",
"54":"0",
"55":"0",
"56":"0",
"57":"0",
"58":"0",
"59":"0",
"60":"0",
"61":"0",
"62":"0",
"63":"0"
}
},
"PORT_QOS_MAP": {
"{{ port_names }}": {
"tc_to_pg_map": "[TC_TO_PRIORITY_GROUP_MAP|AZURE]",
"tc_to_queue_map": "[TC_TO_QUEUE_MAP|AZURE]",
"dscp_to_tc_map": "[DSCP_TO_TC_MAP|AZURE]",
"pfc_enable": "3,4"
}
},
"WRED_PROFILE": {
"AZURE_LOSSLESS" : {
"red_min_threshold":"50000"
}
}
}

View File

@ -0,0 +1,118 @@
{% set port_names_list = [] %}
{% for port in PORT %}
{%- if port_names_list.append(port) %}{% endif %}
{% endfor %}
{% set port_names = port_names_list | join(',') -%}
{
"TC_TO_QUEUE_MAP":{
"AZURE":{
"0":"0",
"1":"1",
"2":"2",
"3":"3",
"4":"4",
"5":"5",
"6":"6",
"7":"7"
}
},
"TC_TO_PRIORITY_GROUP_MAP": {
"AZURE": {
"0": "0",
"1": "0",
"2": "0",
"3": "3",
"4": "4",
"5": "0",
"6": "0",
"7": "0"
}
},
"DSCP_TO_TC_MAP": {
"AZURE": {
"0":"0",
"1":"0",
"2":"0",
"3":"0",
"4":"0",
"5":"0",
"6":"0",
"7":"0",
"8":"0",
"9":"0",
"10":"0",
"11":"0",
"12":"0",
"13":"0",
"14":"0",
"15":"0",
"16":"0",
"17":"0",
"18":"0",
"19":"0",
"20":"0",
"21":"0",
"22":"0",
"23":"0",
"24":"0",
"25":"0",
"26":"0",
"27":"0",
"28":"0",
"29":"0",
"30":"0",
"31":"0",
"32":"0",
"33":"0",
"34":"0",
"35":"0",
"36":"0",
"37":"0",
"38":"0",
"39":"0",
"40":"0",
"41":"0",
"42":"0",
"43":"0",
"44":"0",
"45":"0",
"46":"0",
"47":"0",
"48":"0",
"49":"0",
"50":"0",
"51":"0",
"52":"0",
"53":"0",
"54":"0",
"55":"0",
"56":"0",
"57":"0",
"58":"0",
"59":"0",
"60":"0",
"61":"0",
"62":"0",
"63":"0"
}
},
"PORT_QOS_MAP": {
"{{ port_names }}": {
"tc_to_pg_map": "[TC_TO_PRIORITY_GROUP_MAP|AZURE]",
"tc_to_queue_map": "[TC_TO_QUEUE_MAP|AZURE]",
"dscp_to_tc_map": "[DSCP_TO_TC_MAP|AZURE]"
}
},
"SCHEDULER": {
"scheduler.7": {
"type": "STRICT"
}
},
"QUEUE": {
"{{ port_names }}|7": {
"scheduler": "[SCHEDULER|scheduler.7]"
}
}
}

View File

@ -0,0 +1,114 @@
{% set port_names_list = [] %}
{% for port in PORT %}
{%- if port_names_list.append(port) %}{% endif %}
{% endfor %}
{% set port_names = port_names_list | join(',') -%}
{
"TC_TO_QUEUE_MAP":{
"AZURE":{
"0":"0",
"1":"1",
"2":"2",
"3":"3",
"4":"4",
"5":"5",
"6":"6",
"7":"7"
}
},
"TC_TO_PRIORITY_GROUP_MAP": {
"AZURE": {
"0": "0",
"1": "0",
"2": "0",
"3": "3",
"4": "4",
"5": "0",
"6": "0",
"7": "0"
}
},
"DSCP_TO_TC_MAP": {
"AZURE": {
"0":"0",
"1":"0",
"2":"0",
"3":"3",
"4":"4",
"5":"0",
"6":"0",
"7":"0",
"8":"1",
"9":"0",
"10":"0",
"11":"0",
"12":"0",
"13":"0",
"14":"0",
"15":"0",
"16":"0",
"17":"0",
"18":"0",
"19":"0",
"20":"0",
"21":"0",
"22":"0",
"23":"0",
"24":"0",
"25":"0",
"26":"0",
"27":"0",
"28":"0",
"29":"0",
"30":"0",
"31":"0",
"32":"0",
"33":"0",
"34":"0",
"35":"0",
"36":"0",
"37":"0",
"38":"0",
"39":"0",
"40":"0",
"41":"0",
"42":"0",
"43":"0",
"44":"0",
"45":"0",
"46":"0",
"47":"0",
"48":"0",
"49":"0",
"50":"0",
"51":"0",
"52":"0",
"53":"0",
"54":"0",
"55":"0",
"56":"0",
"57":"0",
"58":"0",
"59":"0",
"60":"0",
"61":"0",
"62":"0",
"63":"0"
}
},
"PORT_QOS_MAP": {
"{{ port_names }}": {
"tc_to_pg_map": "[TC_TO_PRIORITY_GROUP_MAP|AZURE]",
"tc_to_queue_map": "[TC_TO_QUEUE_MAP|AZURE]",
"dscp_to_tc_map": "[DSCP_TO_TC_MAP|AZURE]",
"pfc_enable": "3,4"
}
},
"WRED_PROFILE": {
"AZURE_LOSSLESS" : {
"red_min_threshold":"50000"
}
}
}

View File

@ -0,0 +1 @@
SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/ivm.sai.config.yaml

View File

@ -0,0 +1 @@
Midstone-100x t1

View File

@ -0,0 +1 @@
CONSOLE_SPEED=115200

View File

@ -0,0 +1,19 @@
{
"chassis": {
"Midstone-100x": {
"component": {
"FPGA": {},
"SYSCPLD": {},
"SWCPLD1": {},
"SWCPLD2": {},
"SWCPLD3": {},
"SWCPLD4": {},
"Main_BIOS": {},
"Backup_BIOS": {},
"Main_BMC": {},
"Backup_BMC": {},
"COMeCPLD": {}
}
}
}
}

View File

@ -0,0 +1,23 @@
#!/usr/bin/env python
#############################################################################
# Celestica Silverstone-x
#
# 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:
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-0056/eeprom"
super(board, self).__init__(self.eeprom_path, 0, '', True)

View File

@ -0,0 +1,90 @@
#!/usr/bin/env python
import subprocess
import sys
import re
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):
self.ipmi_raw = "docker exec -ti pmon ipmitool raw 0x4 0x2d"
self.psu1_id = "0x29"
self.psu2_id = "0x33"
PsuBase.__init__(self)
def run_command(self, command):
proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
(out, err) = proc.communicate()
if proc.returncode != 0:
sys.exit(proc.returncode)
return out
def find_value(self, in_string):
result = re.search("^.+ ([0-9a-f]{2}) .+$", in_string)
if result:
return result.group(1)
else:
return result
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 <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
psu_id = self.psu1_id if index == 1 else self.psu2_id
res_string = self.run_command(self.ipmi_raw + ' ' + psu_id)
status_byte = self.find_value(res_string)
if status_byte is None:
return False
failure_detected = (int(status_byte, 16) >> 1) & 1
input_lost = (int(status_byte, 16) >> 3) & 1
if failure_detected or input_lost:
return False
else:
return True
def get_psu_presence(self, index):
"""
Retrieves the presence status of power supply unit (PSU) defined
by 1-based index <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
psu_id = self.psu1_id if index == 1 else self.psu2_id
res_string = self.run_command(self.ipmi_raw + ' ' + psu_id)
status_byte = self.find_value(res_string)
if status_byte is None:
return False
presence = ( int(status_byte, 16) >> 0 ) & 1
if presence:
return True
else:
return False

View File

@ -0,0 +1,194 @@
#!/usr/bin/env python
#
# Platform-specific SFP transceiver interface for SONiC
# This plugin supports QSFP-DD, QSFP and SFP.
try:
import time
from sonic_sfp.sfputilbase import SfpUtilBase
except ImportError as e:
raise ImportError("%s - required module not found" % str(e))
class SfpUtil(SfpUtilBase):
"""Platform-specific SfpUtil class"""
PORT_START = 0
PORT_END = 65
QSFP_PORT_START = 0
QSFP_PORT_END = 63
SFP_PORT_START = 64
SFP_PORT_END = 65
EEPROM_OFFSET = 16
QSFP_PORT_INFO_PATH = '/sys/class/SFF'
SFP_PORT_INFO_PATH = '/sys/bus/platform/devices/cls-xcvr'
PORT_INFO_PATH = QSFP_PORT_INFO_PATH
_port_name = ""
_port_to_eeprom_mapping = {}
_port_to_i2cbus_mapping = {}
@property
def port_start(self):
return self.PORT_START
@property
def port_end(self):
return self.PORT_END
@property
def qsfp_ports(self):
return []
@property
def qsfp_ports(self):
return range(self.QSFP_PORT_START, self.QSFP_PORT_END + 1)
@property
def port_to_eeprom_mapping(self):
return self._port_to_eeprom_mapping
@property
def port_to_i2cbus_mapping(self):
return self._port_to_i2cbus_mapping
def get_port_name(self, port_num):
if port_num in self.qsfp_ports:
self._port_name = "QSFP" + str(port_num - self.QSFP_PORT_START + 1)
else:
self._port_name = "SFP" + str(port_num - self.SFP_PORT_START + 1)
return self._port_name
def get_eeprom_dom_raw(self, port_num):
if port_num in self.qsfp_ports:
# QSFP DOM EEPROM is also at addr 0x50 and thus also stored in eeprom_ifraw
return None
else:
# Read dom eeprom at addr 0x51
return self._read_eeprom_devid(port_num, self.DOM_EEPROM_ADDR, 256)
def __init__(self):
# Override port_to_eeprom_mapping for class initialization
eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom'
for x in range(self.QSFP_PORT_START, self.QSFP_PORT_END+1):
self.port_to_i2cbus_mapping[x] = (x + self.EEPROM_OFFSET)
self.port_to_eeprom_mapping[x] = eeprom_path.format(
x + self.EEPROM_OFFSET)
for x in range(self.SFP_PORT_START, self.SFP_PORT_END+1):
self.port_to_i2cbus_mapping[x] = (x - 52)
self.port_to_eeprom_mapping[x] = eeprom_path.format(
x - 52)
SfpUtilBase.__init__(self)
def get_presence(self, port_num):
# Check for invalid port_num
if port_num not in range(self.port_start, self.port_end + 1):
return False
# Get path for access port presence status
port_name = self.get_port_name(port_num)
sysfs_filename = "qsfp_modprs" if port_num in self.qsfp_ports else "sfp_modabs"
self.PORT_INFO_PATH = self.QSFP_PORT_INFO_PATH if port_num in self.qsfp_ports else self.SFP_PORT_INFO_PATH
reg_path = "/".join([self.PORT_INFO_PATH, port_name, sysfs_filename])
# Read status
try:
reg_file = open(reg_path)
content = reg_file.readline().rstrip()
reg_value = int(content)
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
# Module present is active low
if reg_value == 0:
return True
return False
def get_low_power_mode(self, port_num):
# Check for invalid QSFP port_num
if port_num not in self.qsfp_ports:
return False
try:
port_name = self.get_port_name(port_num)
reg_file = open("/".join([self.PORT_INFO_PATH,
port_name, "qsfp_lpmode"]))
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
# Read status
content = reg_file.readline().rstrip()
reg_value = int(content)
# low power mode is active high
if reg_value == 0:
return False
return True
def set_low_power_mode(self, port_num, lpmode):
# Check for invalid QSFP port_num
if port_num not in self.qsfp_ports:
return False
try:
port_name = self.get_port_name(port_num)
reg_file = open("/".join([self.PORT_INFO_PATH,
port_name, "qsfp_lpmode"]), "r+")
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
content = hex(lpmode)
reg_file.seek(0)
reg_file.write(content)
reg_file.close()
return True
def reset(self, port_num):
# Check for invalid QSFP port_num
if port_num not in self.qsfp_ports:
return False
try:
port_name = self.get_port_name(port_num)
reg_file = open("/".join([self.PORT_INFO_PATH,
port_name, "qsfp_reset"]), "w")
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
# Convert our register value back to a hex string and write back
reg_file.seek(0)
reg_file.write(hex(0))
reg_file.close()
# Sleep 1 second to allow it to settle
time.sleep(1)
# Flip the bit back high and write back to the register to take port out of reset
try:
reg_file = open(
"/".join([self.PORT_INFO_PATH, port_name, "qsfp_reset"]), "w")
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return False
reg_file.seek(0)
reg_file.write(hex(1))
reg_file.close()
return True
def get_transceiver_change_event(self, timeout=0):
"""
TBD
"""
raise NotImplementedError

View File

@ -0,0 +1,3 @@
{
"skip_ledd": true
}

View File

@ -0,0 +1,3 @@
__all__ = ["platform", "chassis"]
from sonic_platform import *

View File

@ -0,0 +1,412 @@
#!/usr/bin/env python
#############################################################################
# Celestica
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Chassis information which are available in the platform
#
#############################################################################
try:
import sys
import time
from sonic_platform_base.chassis_base import ChassisBase
from helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
NUM_FAN_TRAY = 5
NUM_FAN = 2
NUM_PSU = 2
NUM_THERMAL = 18
NUM_SFP = 64
NUM_COMPONENT = 11
RESET_REGISTER = "0xA106"
HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/"
REBOOT_CAUSE_FILE = "reboot-cause.txt"
PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt"
GETREG_PATH = "/sys/devices/platform/sys_cpld/getreg"
HOST_CHK_CMD = "docker > /dev/null 2>&1"
class Chassis(ChassisBase):
"""Platform-specific Chassis class"""
def __init__(self):
#self.config_data = {}
ChassisBase.__init__(self)
self._api_helper = APIHelper()
self.port_start = 0
self.port_end = NUM_SFP - 1
self.sfp_module_initialized = False
self.fan_module_initialized = False
self.__initialize_eeprom()
self.is_host = self._api_helper.is_host()
self.__initialize_fan()
self.__initialize_psu()
self.__initialize_thermals()
self.__initialize_sfp()
self.__initialize_components()
self.modprs_register = self.get_transceiver_status()
def __initialize_sfp(self):
from sonic_platform.sfp import Sfp
for index in range(0, NUM_SFP):
sfp = Sfp(index)
self._sfp_list.append(sfp)
self.sfp_module_initialized = True
def __initialize_psu(self):
from sonic_platform.psu import Psu
for index in range(0, NUM_PSU):
psu = Psu(index)
self._psu_list.append(psu)
def __initialize_fan(self):
from sonic_platform.fan import Fan
for fant_index in range(0, NUM_FAN_TRAY):
for fan_index in range(0, NUM_FAN):
if fant_index == 4 and fan_index == 0:
fan = Fan(fant_index, fan_index, True, 5) # PSU-1 FAN-1
elif fant_index == 4 and fan_index == 1:
fan = Fan(fant_index, fan_index, True, 6) # PSU-2 FAN-1
else:
fan = Fan(fant_index, fan_index)
self._fan_list.append(fan)
self.fan_module_initialized = True
def __initialize_thermals(self):
from sonic_platform.thermal import Thermal
airflow = self.__get_air_flow()
for index in range(0, NUM_THERMAL):
thermal = Thermal(index, airflow)
self._thermal_list.append(thermal)
def __initialize_eeprom(self):
from sonic_platform.eeprom import Tlv
self._eeprom = Tlv()
def __initialize_components(self):
from sonic_platform.component import Component
for index in range(0, NUM_COMPONENT):
component = Component(index)
self._component_list.append(component)
def __get_air_flow(self):
air_flow_path = '/usr/share/sonic/device/{}/fan_airflow'.format(self._api_helper.platform) if self.is_host else '/usr/share/sonic/platform/fan_airflow'
air_flow = self._api_helper.read_one_line_file(air_flow_path)
return air_flow or 'B2F'
def get_base_mac(self):
"""
Retrieves the base MAC address for the chassis
Returns:
A string containing the MAC address in the format
'XX:XX:XX:XX:XX:XX'
"""
return self._eeprom.get_mac()
def get_serial_number(self):
"""
Retrieves the hardware serial number for the chassis
Returns:
A string containing the hardware serial number for this chassis.
"""
return self._eeprom.get_serial()
def get_system_eeprom_info(self):
"""
Retrieves the full content of system EEPROM information for the chassis
Returns:
A dictionary where keys are the type code defined in
OCP ONIE TlvInfo EEPROM format and values are their corresponding
values.
"""
return self._eeprom.get_eeprom()
def get_reboot_cause(self):
"""
Retrieves the cause of the previous reboot
Returns:
A tuple (string, string) where the first element is a string
containing the cause of the previous reboot. This string must be
one of the predefined strings in this class. If the first string
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
to pass a description of the reboot cause.
REBOOT_CAUSE_POWER_LOSS = "Power Loss"
REBOOT_CAUSE_THERMAL_OVERLOAD_CPU = "Thermal Overload: CPU"
REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC = "Thermal Overload: ASIC"
REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER = "Thermal Overload: Other"
REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED = "Insufficient Fan Speed"
REBOOT_CAUSE_WATCHDOG = "Watchdog"
REBOOT_CAUSE_HARDWARE_OTHER = "Hardware - Other"
REBOOT_CAUSE_NON_HARDWARE = "Non-Hardware"
"""
reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE)
sw_reboot_cause = self._api_helper.read_txt_file(
reboot_cause_path) or "Unknown"
hw_reboot_cause = self._api_helper.get_cpld_reg_value(
GETREG_PATH, RESET_REGISTER)
prev_reboot_cause = {
'0x11': (self.REBOOT_CAUSE_POWER_LOSS, "The last reset is Power on reset"),
'0x22': (self.REBOOT_CAUSE_HARDWARE_OTHER, "The last reset is soft-set CPU warm reset"),
'0x33': (self.REBOOT_CAUSE_HARDWARE_OTHER, "The last reset is soft-set CPU cold reset"),
'0x44': (self.REBOOT_CAUSE_NON_HARDWARE, "The last reset is CPU warm reset"),
'0x55': (self.REBOOT_CAUSE_NON_HARDWARE, "The last reset is CPU cold reset"),
'0x66': (self.REBOOT_CAUSE_WATCHDOG, "The last reset is watchdog reset"),
'0x77': (self.REBOOT_CAUSE_HARDWARE_OTHER, "The last reset is power cycle reset")
}.get(hw_reboot_cause, (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Unknown reason'))
if sw_reboot_cause != 'Unknown':
prev_reboot_cause = (
self.REBOOT_CAUSE_NON_HARDWARE, sw_reboot_cause)
return prev_reboot_cause
##############################################################
####################### SFP methods ##########################
##############################################################
def get_num_sfps(self):
"""
Retrieves the number of sfps available on this chassis
Returns:
An integer, the number of sfps available on this chassis
"""
if not self.sfp_module_initialized:
self.__initialize_sfp()
return len(self._sfp_list)
def get_all_sfps(self):
"""
Retrieves all sfps available on this chassis
Returns:
A list of objects derived from SfpBase representing all sfps
available on this chassis
"""
if not self.sfp_module_initialized:
self.__initialize_sfp()
return self._sfp_list
def get_sfp(self, index):
"""
Retrieves sfp represented by (0-based) index <index>
Args:
index: An integer, the index (0-based) of the sfp to retrieve.
The index should be the sequence of a physical port in a chassis,
starting from 0.
For example, 0 for Ethernet0, 1 for Ethernet4 and so on.
Returns:
An object dervied from SfpBase representing the specified sfp
"""
sfp = None
if not self.sfp_module_initialized:
self.__initialize_sfp()
try:
sfp = self._sfp_list[index]
except IndexError:
sys.stderr.write("SFP index {} out of range (0-{})\n".format(
index, len(self._sfp_list)))
return sfp
##############################################################
####################### Other methods ########################
##############################################################
def get_watchdog(self):
"""
Retreives hardware watchdog device on this chassis
Returns:
An object derived from WatchdogBase representing the hardware
watchdog device
"""
if self._watchdog is None:
from sonic_platform.watchdog import Watchdog
self._watchdog = Watchdog()
return self._watchdog
##############################################################
###################### Device methods ########################
##############################################################
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return self._api_helper.hwsku
def get_presence(self):
"""
Retrieves the presence of the Chassis
Returns:
bool: True if Chassis is present, False if not
"""
return True
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return self._eeprom.get_pn()
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return self.get_serial_number()
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return True
def get_thermal_manager(self):
from .thermal_manager import ThermalManager
return ThermalManager
def get_fan_status(self):
if not self.fan_module_initialized:
self.__initialize_fan()
content = 0
for fan in self._fan_list:
if fan.get_presence():
content = content << 1 | 1
else:
content = content << 1
return content
def get_transceiver_status(self):
if not self.sfp_module_initialized:
self.__initialize_sfp()
content = 0
index = 0
for sfp in self.get_all_sfps():
if sfp.get_presence():
content = content | (1 << index)
index = index + 1
return content
def get_num_components(self):
return len(self._component_list)
def get_change_event(self, timeout=0):
"""
Returns a nested dictionary containing all devices which have
experienced a change at chassis level
Args:
timeout: Timeout in milliseconds (optional). If timeout == 0,
this method will block until a change is detected.
Returns:
(bool, dict):
- True if call successful, False if not;
- A nested dictionary where key is a device type,
value is a dictionary with key:value pairs in the format of
{'device_id':'device_event'},
where device_id is the device ID for this device and
device_event,
status='1' represents device inserted,
status='0' represents device removed.
Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}}
indicates that fan 0 has been removed, fan 2
has been inserted and sfp 11 has been removed.
Specifically for SFP event, besides SFP plug in and plug out,
there are some other error event could be raised from SFP, when
these error happened, SFP eeprom will not be avalaible, XCVRD shall
stop to read eeprom before SFP recovered from error status.
status='2' I2C bus stuck,
status='3' Bad eeprom,
status='4' Unsupported cable,
status='5' High Temperature,
status='6' Bad cable.
"""
start_time = time.time()
port_dict = {}
change_dict = {'fan':{}, 'sfp':{}}
port = self.port_start
forever = False
change_event = False
if timeout == 0:
forever = True
elif timeout > 0:
timeout = timeout / float(1000) # Convert to secs
else:
print "get_transceiver_change_event:Invalid timeout value", timeout
return False, {}
end_time = start_time + timeout
if start_time > end_time:
print 'get_transceiver_change_event:' \
'time wrap / invalid timeout value', timeout
return False, {} # Time wrap or possibly incorrect timeout
while timeout >= 0:
# Check for OIR events and return updated port_dict
reg_value = self.get_transceiver_status()
if reg_value != self.modprs_register:
changed_ports = self.modprs_register ^ reg_value
while port >= self.port_start and port <= self.port_end:
# Mask off the bit corresponding to our port
mask = (1 << port)
if changed_ports & mask:
# ModPrsL is active low
if reg_value & mask == 0:
port_dict[port] = '0'
else:
port_dict[port] = '1'
port += 1
# Update reg value
self.modprs_register = reg_value
change_dict['sfp'] = port_dict
change_event = True
if change_event:
return True, change_dict
if forever:
time.sleep(1)
else:
timeout = end_time - time.time()
if timeout >= 1:
time.sleep(1) # We poll at 1 second granularity
else:
if timeout > 0:
time.sleep(timeout)
return True, change_dict
print "get_transceiver_change_event: Should not reach here."
return False, change_dict

View File

@ -0,0 +1,380 @@
#!/usr/bin/env python
#############################################################################
# Celestica
#
# Component contains an implementation of SONiC Platform Base API and
# provides the components firmware management function
#
#############################################################################
import subprocess
try:
from sonic_platform_base.component_base import ComponentBase
from helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
FPGA_VERSION_PATH = "/sys/devices/platform/fpga-board/version"
SYSCPLD_VERSION_PATH = "/sys/devices/platform/sys_cpld/version"
SWCPLD1_VERSION_PATH = "/sys/bus/i2c/devices/i2c-10/10-0030/version"
SWCPLD2_VERSION_PATH = "/sys/bus/i2c/devices/i2c-10/10-0031/version"
SWCPLD3_VERSION_PATH = "/sys/bus/i2c/devices/i2c-10/10-0032/version"
SWCPLD4_VERSION_PATH = "/sys/bus/i2c/devices/i2c-10/10-0033/version"
COMeCPLD_VERSION_cmd= "ipmitool raw 0x3a 0x3e 1 0x1a 1 0xe0"
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
Main_BMC_cmd = "ipmitool raw 0x32 0x8f 0x08 0x01"
Backup_BMC_cmd = "ipmitool raw 0x32 0x8f 0x08 0x02"
#Fan_CPLD_cmd = "ipmitool raw 0x3a 0x64 02 01 00"
COMPONENT_NAME_LIST = ["FPGA", "SYSCPLD", "SWCPLD1", "SWCPLD2", "SWCPLD3","SWCPLD4", "COMeCPLD", "Main_BMC", "Backup_BMC", "Main_BIOS", "Backup_BIOS"]
COMPONENT_DES_LIST = ["Used for managering the CPU and expanding I2C channels", "Used for managing the CPU",
"Used for managing QSFP+ ports (1-16)", "Used for managing QSFP+ ports (17-32)", "Used for managing QSFP+ ports (33-48)", "Used for managing QSFP+ ports (49-64)","Used for managing the COMe","Main Baseboard Management Controller", "Backup Baseboard Management Controller", "Main basic Input/Output System", "Backup basic Input/Output System"]
class Component(ComponentBase):
"""Platform-specific Component class"""
DEVICE_TYPE = "component"
def __init__(self, component_index):
ComponentBase.__init__(self)
self.index = component_index
self._api_helper = APIHelper()
self.name = self.get_name()
def __get_bios_version(self):
# Retrieves the BIOS firmware version
status,result = self._api_helper.run_command("ipmitool raw 0x3a 0x64 00 01 0x70")
if result.strip() == "01":
if self.name == "Main_BIOS":
with open(BIOS_VERSION_PATH, 'r') as fd:
bios_version = fd.read()
return bios_version.strip()
elif self.name == "Backup_BIOS":
bios_version = "na"
return bios_version
elif result.strip() == "03":
if self.name == "Backup_BIOS":
with open(BIOS_VERSION_PATH, 'r') as fd:
bios_version = fd.read()
return bios_version.strip()
elif self.name == "Main_BIOS":
bios_version = "na"
return bios_version
def get_register_value(self, register):
# Retrieves the cpld register value
cmd = "echo {1} > {0}; cat {0}".format(GETREG_PATH, register)
p = subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err is not '':
return None
return raw_data.strip()
def __get_cpld_version(self):
if self.name == "SYSCPLD":
try:
with open(SYSCPLD_VERSION_PATH, 'r') as fd:
syscpld_version = fd.read()
return syscpld_version.strip()
except Exception as e:
return None
elif self.name == "SWCPLD1":
try:
with open(SWCPLD1_VERSION_PATH, 'r') as fd:
swcpld1_version = fd.read()
return swcpld1_version.strip()
except Exception as e:
return None
elif self.name == "SWCPLD2":
try:
with open(SWCPLD2_VERSION_PATH, 'r') as fd:
swcpld2_version = fd.read()
return swcpld2_version.strip()
except Exception as e:
return None
elif self.name == "SWCPLD3":
try:
with open(SWCPLD3_VERSION_PATH, 'r') as fd:
swcpld3_version = fd.read()
return swcpld3_version.strip()
except Exception as e:
return None
elif self.name == "SWCPLD4":
try:
with open(SWCPLD4_VERSION_PATH, 'r') as fd:
swcpld4_version = fd.read()
return swcpld4_version.strip()
except Exception as e:
return None
elif self.name == "COMeCPLD":
status, ver = self._api_helper.run_command(COMeCPLD_VERSION_cmd)
version1 = int(ver.strip()) / 10
version2 = int(ver.strip()) % 10
version = "%s.%s" % (version1, version2)
return str(version)
elif self.name == "FANCPLD":
status,ver = self._api_helper.run_command(Fan_CPLD_cmd)
version = int(ver.strip(), 16)
return str(version)
def __get_fpga_version(self):
# Retrieves the FPGA firmware version
try:
with open(FPGA_VERSION_PATH, 'r') as fd:
version = fd.read()
fpga_version = (version.strip().split("x")[1])
return fpga_version.strip()
except Exception as e:
return None
def __get_bmc_version(self):
# Retrieves the BMC firmware version
cmd = Main_BMC_cmd if self.name == "Main_BMC" else Backup_BMC_cmd
stasus, ver = self._api_helper.run_command(cmd)
return ver.strip()
def get_name(self):
"""
Retrieves the name of the component
Returns:
A string containing the name of the component
"""
return COMPONENT_NAME_LIST[self.index]
def get_description(self):
"""
Retrieves the description of the component
Returns:
A string containing the description of the component
"""
return COMPONENT_DES_LIST[self.index]
def get_firmware_version(self):
"""
Retrieves the firmware version of module
Returns:
string: The firmware versions of the module
"""
fw_version = None
if "BIOS" in self.name:
fw_version = self.__get_bios_version()
elif "CPLD" in self.name:
fw_version = self.__get_cpld_version()
elif self.name == "FPGA":
fw_version = self.__get_fpga_version()
elif "BMC" in self.name:
version = self.__get_bmc_version()
version_1 = int(version.strip().split(" ")[0], 16)
version_2 = int(version.strip().split(" ")[1], 16)
fw_version = "%s.%s" % (version_1, version_2)
return fw_version
def install_firmware(self, image_path):
"""
Install firmware to module
Args:
image_path: A string, path to firmware image
Returns:
A boolean, True if install successfully, False if not
"""
#if not os.path.isfile(image_path):
# return False
#op_cmd = "ipmitool raw 0x32 0xaa 0x00"
#cl_cmd = "ipmitool raw 0x32 0xaa 0x01"
#if "FPGA" in self.name:
# """img_name = os.path.basename(image_path)
# root, ext = os.path.splitext(img_name)
# ext = ".vme" if ext == "" else ext
# new_image_path = os.path.join("/tmp", (root.lower() + ext))
# shutil.copy(image_path, new_image_path)"""
# install_command = "/usr/local/lib/firmware/x86_64-cel_silverstone-x-r0/fpga_prog /sys/bus/pci/devices/0000:0b:00.0/resource0 %s" % image_path
# status, result = self._api_helper.run_command(install_command)
# if status == False:
# print("Running install command error")
# if 'Programing is complete' in result:
# print("Update success")
# else:
# print("Update failed")
#elif self.name == "Main_BIOS":
# self._api_helper.run_command(op_cmd)
# time.sleep(5)
# install_command = "echo y | /usr/local/lib/firmware/x86_64-cel_silverstone-x-r0/CFUFLASH -cd -d 2 -mse 1 %s " % image_path
# print("Updating now...Plz wait...")
# status, result = self._api_helper.run_command(install_command)
# if status == False:
# print("Running install command error")
# if 'Beginning to Deactive flashMode...end' in result:
# print("Update success")
# else:
# print("Update failed")
# time.sleep(10)
# self._api_helper.run_command(cl_cmd)
# elif self.name == "Backup_BIOS":
# self._api_helper.run_command(op_cmd)
# time.sleep(5)
# install_command = "echo y | /usr/local/lib/firmware/x86_64-cel_silverstone-x-r0/CFUFLASH -cd -d 2 -mse 2 %s " % image_path
# print("Updating now...Plz wait...")
# status, result = self._api_helper.run_command(install_command)
# if status == False:
# print("Running install command error")
# if 'Beginning to Deactive flashMode...end' in result:
# print("Update success")
# else:
# print("Update failed")
# time.sleep(10)
# self._api_helper.run_command(cl_cmd)
# elif self.name == "Main_BMC":
# self._api_helper.run_command(op_cmd)
# time.sleep(5)
# install_command = "/usr/local/lib/firmware/x86_64-cel_silverstone-x-r0/CFUFLASH -cd -fb -d 1 -mse 1 %s" % image_path
# print("Updating now...Plz wait...")
# status, result = self._api_helper.run_command(install_command)
# if status == False:
# print("Running install command error")
# if 'Beginning to Deactive flashMode...end' in result:
# print("Update success")
# print("BMC is rebooting now...Plz wait for about 180s")
# else:
# print("Update failed")
# elif self.name == "Backup_BMC":
# self._api_helper.run_command(op_cmd)
# time.sleep(5)
# install_command = "/usr/local/lib/firmware/x86_64-cel_silverstone-x-r0/CFUFLASH -cd -fb -d 1 -mse 2 %s" % image_path
# print("Updating now...Plz wait...")
# status, result = self._api_helper.run_command(install_command)
# if status == False:
# print("Running install command error")
# if 'Beginning to Deactive flashMode...end' in result:
# print("Update success")
# print("BMC is rebooting now...")
# else:
# print("Update failed")
# elif "CPLD" in self.name:
# self._api_helper.run_command(op_cmd)
# time.sleep(5)
# install_command = "echo y | /usr/local/lib/firmware/x86_64-cel_silverstone-x-r0/CFUFLASH -cd -d 4 %s " % image_path
# print("Updating now...Plz wait...")
# status, result = self._api_helper.run_command(install_command)
# if status == False:
# print("Running install command error")
# if 'Beginning to Deactive flashMode...end' in result:
# print("Update success")
# else:
# print("Update failed")
# time.sleep(10)
# self._api_helper.run_command(cl_cmd)
#not support because firmare update need 3rd tools that can't be submitted to community
return False
def update_firmware(self, image_path):
#if not os.path.isfile(image_path):
# return False
#op_cmd = "ipmitool raw 0x32 0xaa 0x00"
#cl_cmd = "ipmitool raw 0x32 0xaa 0x01"
#if "FPGA" in self.name:
# """img_name = os.path.basename(image_path)
# root, ext = os.path.splitext(img_name)
# ext = ".vme" if ext == "" else ext
# new_image_path = os.path.join("/tmp", (root.lower() + ext))
# shutil.copy(image_path, new_image_path)"""
# install_command = "/usr/local/lib/firmware/x86_64-cel_silverstone-x-r0/fpga_prog /sys/bus/pci/devices/0000:0b:00.0/resource0 %s" % image_path
# status, result = self._api_helper.run_command(install_command)
# if status == False:
# print("Running install command error")
# if 'Programing is complete' in result:
# print("Update success")
# else:
# print("Update failed")
#elif self.name == "Main_BIOS":
# self._api_helper.run_command(op_cmd)
# time.sleep(5)
# install_command = "echo y | /usr/local/lib/firmware/x86_64-cel_silverstone-x-r0/CFUFLASH -cd -d 2 -mse 1 %s " % image_path
# print("Updating now...Plz wait...")
# status, result = self._api_helper.run_command(install_command)
# if status == False:
# print("Running install command error")
# if 'Beginning to Deactive flashMode...end' in result:
# print("Update success")
# else:
# print("Update failed")
# time.sleep(10)
# self._api_helper.run_command(cl_cmd)
#elif self.name == "Backup_BIOS":
# self._api_helper.run_command(op_cmd)
# time.sleep(5)
# install_command = "echo y | /usr/local/lib/firmware/x86_64-cel_silverstone-x-r0/CFUFLASH -cd -d 2 -mse 2 %s " % image_path
# print("Updating now...Plz wait...")
# status, result = self._api_helper.run_command(install_command)
# if status == False:
# print("Running install command error")
# if 'Beginning to Deactive flashMode...end' in result:
# print("Update success")
# else:
# print("Update failed")
# time.sleep(10)
# self._api_helper.run_command(cl_cmd)
#elif self.name == "Main_BMC":
# self._api_helper.run_command(op_cmd)
# time.sleep(5)
# install_command = "/usr/local/lib/firmware/x86_64-cel_silverstone-x-r0/CFUFLASH -cd -fb -d 1 -mse 1 %s" % image_path
# print("Updating now...Please wait...")
# status, result = self._api_helper.run_command(install_command)
# if status == False:
# print("Running install command error")
# if 'Beginning to Deactive flashMode...end' in result:
# print("Update success")
# print("BMC is rebooting now...Please wait for about 180s")
# else:
# print("Update failed")
#elif self.name == "Backup_BMC":
# self._api_helper.run_command(op_cmd)
# time.sleep(5)
# install_command = "/usr/local/lib/firmware/x86_64-cel_silverstone-x-r0/CFUFLASH -cd -fb -d 1 -mse 2 %s" % image_path
# print("Updating now...Please wait...")
# status, result = self._api_helper.run_command(install_command)
# if status == False:
# print("Running install command error")
# if 'Beginning to Deactive flashMode...end' in result:
# print("Update success")
# print("BMC is rebooting now...")
# else:
# print("Update failed")
#elif "CPLD" in self.name:
# self._api_helper.run_command(op_cmd)
# time.sleep(5)
# install_command = "echo y | /usr/local/lib/firmware/x86_64-cel_silverstone-x-r0/CFUFLASH -cd -d 4 %s " % image_path
# print("Updating now...Please wait...")
# status, result = self._api_helper.run_command(install_command)
# if status == False:
# print("Running install command error")
# if 'Beginning to Deactive flashMode...end' in result:
# print("Update success")
# else:
# print("Update failed")
# time.sleep(10)
# self._api_helper.run_command(cl_cmd)
#not support firmware update because 3rd tools can't be uploaded to community
return False

View File

@ -0,0 +1,115 @@
#!/usr/bin/env python
#############################################################################
# Celestica Silverstone-x
#
# 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 os
import sys
import re
from cStringIO import StringIO
from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo
except ImportError, e:
raise ImportError(str(e) + "- required module not found")
CACHE_ROOT = '/var/cache/sonic/decode-syseeprom'
CACHE_FILE = 'syseeprom_cache'
TLV_EEPROM_I2C_BUS = 0
TLV_EEPROM_I2C_ADDR = 56
class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
EEPROM_DECODE_HEADLINES = 6
# TLV Value Display Switch
_TLV_DISPLAY_VENDOR_EXT = True
def __init__(self):
self._eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-00{1}/eeprom".format(TLV_EEPROM_I2C_BUS, TLV_EEPROM_I2C_ADDR)
super(Tlv, self).__init__(self._eeprom_path, 0, '', True)
self._eeprom = self._load_eeprom()
def __parse_output(self, decode_output):
decode_output.replace('\0', '')
lines = decode_output.split('\n')
lines = lines[self.EEPROM_DECODE_HEADLINES:]
_eeprom_info_dict = dict()
for line in lines:
try:
match = re.search(
'(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line)
if match is not None:
idx = match.group(1)
value = match.group(3).rstrip('\0')
_eeprom_info_dict[idx] = value
except Exception:
pass
return _eeprom_info_dict
def _load_eeprom(self):
original_stdout = sys.stdout
sys.stdout = StringIO()
try:
self.read_eeprom_db()
except Exception:
decode_output = sys.stdout.getvalue()
sys.stdout = original_stdout
return self.__parse_output(decode_output)
status = self.check_status()
if 'ok' not in status:
return False
if not os.path.exists(CACHE_ROOT):
try:
os.makedirs(CACHE_ROOT)
except Exception:
pass
#
# only the eeprom classes that inherit from eeprom_base
# support caching. Others will work normally
#
try:
self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE))
except Exception:
pass
e = self.read_eeprom()
if e is None:
return 0
try:
self.update_cache(e)
except Exception:
pass
self.decode_eeprom(e)
decode_output = sys.stdout.getvalue()
sys.stdout = original_stdout
(is_valid, valid_crc) = self.is_checksum_valid(e)
if not is_valid:
return False
return self.__parse_output(decode_output)
def get_eeprom(self):
return self._eeprom
def get_serial(self):
return self._eeprom.get('0x23', "Undefined.")
def get_mac(self):
return self._eeprom.get('0x24', "Undefined.")
def get_pn(self):
return self._eeprom.get('0x22', "Undefined.")

View File

@ -0,0 +1,312 @@
#!/usr/bin/env python
#############################################################################
# Celestica
#
# Module contains an implementation of SONiC Platform Base API and
# provides the fan status which are available in the platform
#
#############################################################################
import math
try:
from sonic_platform_base.fan_base import FanBase
from helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", "FAN-3F", "FAN-3R",
"FAN-4F", "FAN-4R"]
IPMI_OEM_NETFN = "0x3A"
IPMI_SENSOR_NETFN = "0x3A 0x63"
IPMI_FAN_SPEED_CMD = "0x04 {}" # fan speed
IPMI_GET_PSU1_FAN_SPEED_CMD = "0x3e 0x06 0xb0 2 0x90"
IPMI_GET_PSU2_FAN_SPEED_CMD = "0x3e 0x06 0xb2 2 0x90"
IPMI_GET_FAN_TARGET_SPEED_CMD = "0x3e 0 0x1a 1 {}"
IPMI_AIR_FLOW_CMD = "0x63 0x15 {}" # air flow
IPMI_AIR_PSU_FLOW_CMD = "0x62 {}" # psu air flow
IPMI_FAN_PRESENT_CMD = "0x63 0x03 {}"
IPMI_SET_FAN_LED_CMD = "0x39 0x02 {} {}"
IPMI_GET_FAN_LED_CMD = "0x39 0x01 {}"
IPMI_SET_PWM_CMD = "0x63 0x09 {} {}"
IPMI_SET_FAN_MANUAL_CMD = "0x63 0x01 0x00"
IPMI_SET_FAN_LED_MANUAL_CMD = "0x42 0x02 0x00"
IPMI_FRU_PRINT_ID = "ipmitool fru print {}"
IPMI_FRU_MODEL_KEY = "Board Part Number"
IPMI_FRU_SERIAL_KEY = "Board Serial"
MAX_OUTLET = 12600 # F2B xiqi
MAX_INLET = 10300 # B2F paiqi
SPEED_TOLERANCE = 10
FAN_LED_OFF_CMD = "0x00"
FAN_LED_GREEN_CMD = "0x01"
FAN_LED_AMBER_CMD = "0x02"
FAN1_FRU_ID = 6
class Fan(FanBase):
"""Platform-specific Fan class"""
def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
self.fan_index = fan_index
self.fan_tray_index = fan_tray_index
self.is_psu_fan = is_psu_fan
if self.is_psu_fan:
self.psu_index = psu_index
self._api_helper = APIHelper()
self.index = self.fan_tray_index * 2 + self.fan_index
def get_direction(self):
"""
Retrieves the direction of fan
Returns:
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
depending on fan direction
"""
direction = self.FAN_DIRECTION_EXHAUST
if self.fan_tray_index < 4:
fan_tray_index_ = self.fan_tray_index + 1
ipmi_cmd = IPMI_AIR_FLOW_CMD
else:
fan_tray_index_ = self.psu_index - 1
ipmi_cmd = IPMI_AIR_PSU_FLOW_CMD
status, raw_flow = self._api_helper.ipmi_raw(IPMI_OEM_NETFN, ipmi_cmd.format(hex(fan_tray_index_)))
if status and raw_flow == "01":
direction = self.FAN_DIRECTION_INTAKE
return direction
def get_speed(self):
"""
Retrieves the speed of fan as a percentage of full speed
Returns:
An integer, the percentage of full fan speed, in the range 0 (off)
to 100 (full speed)
Note:
M = 150
Max F2B = 12600 RPM
Max B2F = 10300 RPM
"""
# ipmitool raw 0x3a 0x03 0x01 0x01 {register}
# register = 22 32 42 52 62 72 82
max_rpm = MAX_INLET if self.fan_index % 2 == 0 else MAX_OUTLET
if self.fan_tray_index < 4:
fan_tray_index_ = self.fan_tray_index + 1
status, raw_ss_read = self._api_helper.ipmi_raw(IPMI_SENSOR_NETFN,IPMI_FAN_SPEED_CMD.format(fan_tray_index_))
if self.fan_index % 2 == 0: # self.fan_index = 0
ss_read = raw_ss_read.split()[0]
else:
ss_read = raw_ss_read.split()[1] # self.fan_index = 1
rpm_speed = int(ss_read, 16)*60
speed = int(float(rpm_speed) / max_rpm * 100)
else:
if self.psu_index == 5:
status, raw_ss_read = self._api_helper.ipmi_raw(IPMI_OEM_NETFN,IPMI_GET_PSU1_FAN_SPEED_CMD)
else:
status, raw_ss_read = self._api_helper.ipmi_raw(IPMI_OEM_NETFN,IPMI_GET_PSU2_FAN_SPEED_CMD)
raw_ss_read_reverse = raw_ss_read.split()[::-1]
data_high = ('{0:0{1}b}'.format(int(raw_ss_read_reverse[0], 16), len(raw_ss_read_reverse[0]) * 4))
n_bin = data_high[:5]
n = int(n_bin, 2)
data_low = ('{0:0{1}b}'.format(int(raw_ss_read_reverse[1], 16), len((raw_ss_read_reverse[0]) * 4)))
y_bin = data_high[-3:] + data_low
y = int(y_bin, 2)
rpm_speed = float(y * 2 ** n)
speed = int(rpm_speed / max_rpm * 100)
return speed if speed <= 100 else rpm_speed
def get_target_speed(self):
"""
Retrieves the target (expected) speed of the fan
Returns:
An integer, the percentage of full fan speed, in the range 0 (off)
to 100 (full speed)
Note:
speed_pc = pwm_target/255*100
0 : when PWM mode is use
pwm : when pwm mode is not use
"""
if self.fan_tray_index < 4:
ss_cmd = "0x4%s" % (hex(self.fan_tray_index * 4)[-1])
status,raw_ss_read = self._api_helper.ipmi_raw(IPMI_OEM_NETFN,IPMI_GET_FAN_TARGET_SPEED_CMD.format(ss_cmd))
pwm = int(raw_ss_read,16)
target = math.ceil(float(pwm)*100/255)
else:
target = "N/A"
return target
def get_speed_tolerance(self):
"""
Retrieves the speed tolerance of the fan
Returns:
An integer, the percentage of variance from target speed which is
considered tolerable
"""
return SPEED_TOLERANCE
def set_speed(self, speed):
"""
Sets the fan speed
Args:
speed: An integer, the percentage of full fan speed to set fan to,
in the range 0 (off) to 100 (full speed)
Returns:
A boolean, True if speed is set successfully, False if not
Notes:
pwm setting mode must set as Manual
manual: ipmitool raw 0x3a 0x63 0x01 0x00
auto: ipmitool raw 0x3a 0x63 0x01 0x1
"""
# ipmitool raw 0x3a 0x63 0x09 {fan_id} {pwm_speed}
speed_hex = hex(int(float(speed)/100 * 255))
if self.fan_tray_index < 4:
fan_tray_index_ = self.fan_tray_index + 1
else:
fan_tray_index_ = self.psu_index
status, set_manual_res = self._api_helper.ipmi_raw(IPMI_OEM_NETFN, IPMI_SET_FAN_MANUAL_CMD)
status, set_speed_res = self._api_helper.ipmi_raw(IPMI_OEM_NETFN, IPMI_SET_PWM_CMD.format(hex(fan_tray_index_),speed_hex))
set_speed = False if not status else True
return set_speed
def set_status_led(self, color):
"""
Sets the state of the fan module status LED
Args:
color: A string representing the color with which to set the
fan module status LED
Returns:
bool: True if status LED state is set successfully, False if not
Note:
LED setting mode must set as Manual
manual: ipmitool raw 0x3A 0x42 0x02 0x00
auto: ipmitool raw 0x3A 0x42 0x02 0x01
"""
led_cmd = {
self.STATUS_LED_COLOR_GREEN: FAN_LED_GREEN_CMD,
self.STATUS_LED_COLOR_AMBER: FAN_LED_AMBER_CMD,
self.STATUS_LED_COLOR_OFF: FAN_LED_OFF_CMD
}.get(color)
if self.fan_tray_index < 4:
fan_tray_index_ = self.fan_tray_index + 4
else:
fan_tray_index_ = 2
status, set_manual_res = self._api_helper.ipmi_raw(IPMI_OEM_NETFN, IPMI_SET_FAN_LED_MANUAL_CMD)
status, set_led = self._api_helper.ipmi_raw(IPMI_OEM_NETFN, IPMI_SET_FAN_LED_CMD.format(fan_tray_index_, led_cmd))
set_status_led = False if not status else True
return set_status_led
def get_status_led(self):
"""
Gets the state of the fan status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings above
Note:
STATUS_LED_COLOR_GREEN = "green"
STATUS_LED_COLOR_AMBER = "amber"
STATUS_LED_COLOR_RED = "red"
STATUS_LED_COLOR_OFF = "off"
"""
if self.fan_tray_index < 4:
fan_tray_index_ = self.fan_tray_index + 4
else:
fan_tray_index_ = 2
status, hx_color = self._api_helper.ipmi_raw(IPMI_OEM_NETFN, IPMI_GET_FAN_LED_CMD.format(fan_tray_index_))
status_led = {
"00": self.STATUS_LED_COLOR_OFF,
"01": self.STATUS_LED_COLOR_GREEN,
"02": self.STATUS_LED_COLOR_AMBER,
}.get(hx_color, self.STATUS_LED_COLOR_OFF)
return status_led
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
if not self.is_psu_fan:
fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index]
else:
fan_name = "PSU-{} FAN-1".format(self.psu_index-4)
return fan_name
def get_presence(self):
"""
Retrieves the presence of the FAN
Returns:
bool: True if FAN is present, False if not
"""
presence = False
if self.fan_tray_index < 4:
fan_tray_index_ = self.fan_tray_index + 1
else:
fan_tray_index_ = self.psu_index
status, raw_present = self._api_helper.ipmi_raw(IPMI_OEM_NETFN, IPMI_FAN_PRESENT_CMD.format(hex(fan_tray_index_)))
if status and raw_present == "01":
presence = True
return presence
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
model = "Unknown"
ipmi_fru_idx = self.fan_tray_index + FAN1_FRU_ID
status, raw_model = self._api_helper.ipmi_fru_id(ipmi_fru_idx, IPMI_FRU_MODEL_KEY)
fru_pn_list = raw_model.split()
if len(fru_pn_list) > 4:
model = fru_pn_list[4]
return model
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
serial = "Unknown"
ipmi_fru_idx = self.fan_tray_index + FAN1_FRU_ID
status, raw_model = self._api_helper.ipmi_fru_id(ipmi_fru_idx, IPMI_FRU_SERIAL_KEY)
fru_sr_list = raw_model.split()
if len(fru_sr_list) > 3:
serial = fru_sr_list[3]
return serial
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return self.get_presence() and self.get_speed() > 0

View File

@ -0,0 +1,135 @@
#!/usr/bin/env python
import os
import struct
import subprocess
from sonic_py_common import device_info
from mmap import *
HOST_CHK_CMD = "docker > /dev/null 2>&1"
EMPTY_STRING = ""
class APIHelper():
def __init__(self):
(self.platform, self.hwsku) = device_info.get_platform_and_hwsku()
def is_host(self):
return os.system(HOST_CHK_CMD) == 0
def pci_get_value(self, resource, offset):
status = True
result = ""
try:
fd = os.open(resource, os.O_RDWR)
mm = mmap(fd, 0)
mm.seek(int(offset))
read_data_stream = mm.read(4)
result = struct.unpack('I', read_data_stream)
except Exception:
status = False
return status, result
def run_command(self, cmd):
status = True
result = ""
try:
p = subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err == '':
result = raw_data.strip()
except Exception:
status = False
return status, result
def run_interactive_command(self, cmd):
try:
os.system(cmd)
except Exception:
return False
return True
def read_txt_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.read()
return data.strip()
except IOError:
pass
return None
def read_one_line_file(self, file_path):
try:
with open(file_path, 'r') as fd:
data = fd.readline()
return data.strip()
except IOError:
pass
return None
def write_txt_file(self, file_path, value):
try:
with open(file_path, 'w') as fd:
fd.write(str(value))
except Exception as E:
print(str(E))
return False
return True
def get_cpld_reg_value(self, getreg_path, register):
cmd = "echo {1} > {0}; cat {0}".format(getreg_path, register)
status, result = self.run_command(cmd)
return result if status else None
def ipmi_raw(self, netfn, cmd):
status = True
result = ""
try:
cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd))
p = subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err == '':
result = raw_data.strip()
else:
status = False
except Exception:
status = False
return status, result
def ipmi_fru_id(self, id, key=None):
status = True
result = ""
try:
cmd = "ipmitool fru print {}".format(str(
id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key))
p = subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err == '':
result = raw_data.strip()
else:
status = False
except Exception:
status = False
return status, result
def ipmi_set_ss_thres(self, id, threshold_key, value):
status = True
result = ""
try:
cmd = "ipmitool sensor thresh '{}' {} {}".format(
str(id), str(threshold_key), str(value))
p = subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
raw_data, err = p.communicate()
if err == '':
result = raw_data.strip()
else:
status = False
except Exception:
status = False
return status, result

View File

@ -0,0 +1,23 @@
#!/usr/bin/env python
#############################################################################
# Celestica
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
from sonic_platform_base.platform_base import PlatformBase
from sonic_platform.chassis import Chassis
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Platform(PlatformBase):
"""Platform-specific Platform class"""
def __init__(self):
PlatformBase.__init__(self)
self._chassis = Chassis()

View File

@ -0,0 +1,282 @@
#!/usr/bin/env python
#############################################################################
# Celestica
#
# Module contains an implementation of SONiC Platform Base API and
# provides the PSUs status which are available in the platform
#
#############################################################################
import subprocess
import re
import math
try:
from sonic_platform_base.psu_base import PsuBase
from helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
PSU_NAME_LIST = ["PSU-1", "PSU-2"]
PSU_I2C_MAPPING = {
0: {
"num": 10,
"addr": "5a"
},
1: {
"num": 11,
"addr": "5b"
},
}
IPMI_OEM_NETFN = "0x39"
IPMI_SENSOR_NETFN = "0x04"
IPMI_SS_READ_CMD = "0x2D {}"
IPMI_SET_PSU_LED_CMD = "0x02 0x02 {}"
IPMI_GET_PSU_LED_CMD = "0x01 0x02"
IPMI_FRU_PRINT_ID = "ipmitool fru print {}"
IPMI_FRU_MODEL_KEY = "Product Part Number"
IPMI_FRU_SERIAL_KEY = "Product Serial "
PSU_LED_OFF_CMD = "0x00"
PSU_LED_GREEN_CMD = "0x01"
PSU_LED_AMBER_CMD = "0x02"
PSU1_VOUT_SS_ID = "0x2f"
PSU1_COUT_SS_ID = "0x30"
PSU1_POUT_SS_ID = "0x31"
PSU1_STATUS_REG = "0x29"
PSU1_TMP1_REG = "0x2d"
PSU1_TMP2_REG = "0x2e"
PSU2_VOUT_SS_ID = "0x39"
PSU2_COUT_SS_ID = "0x3a"
PSU2_POUT_SS_ID = "0x3b"
PSU2_STATUS_REG = "0x33"
PSU2_TMP1_REG = "0x37"
PSU2_TMP2_REG = "0x38"
PSU1_FRU_ID = 4
SS_READ_OFFSET = 0
PSU_MAX_POWER = 1300
class Psu(PsuBase):
"""Platform-specific Psu class"""
def __init__(self, psu_index):
PsuBase.__init__(self)
self.index = psu_index
self._api_helper = APIHelper()
self.psu1_id = "0x29"
self.psu2_id = "0x33"
def get_voltage(self):
"""
Retrieves current PSU voltage output
Returns:
A float number, the output voltage in volts,
e.g. 12.1
"""
psu_vout_key = globals()['PSU{}_VOUT_SS_ID'.format(self.index + 1)]
status, raw_ss_read = self._api_helper.ipmi_raw(
IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_vout_key))
ss_read = raw_ss_read.split()[SS_READ_OFFSET]
# Formula: Rx1x10^-1
psu_voltage = int(ss_read, 16) * math.pow(10, -1)
return psu_voltage
def get_current(self):
"""
Retrieves present electric current supplied by PSU
Returns:
A float number, the electric current in amperes, e.g 15.4
"""
psu_cout_key = globals()['PSU{}_COUT_SS_ID'.format(self.index + 1)]
status, raw_ss_read = self._api_helper.ipmi_raw(
IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_cout_key))
ss_read = raw_ss_read.split()[SS_READ_OFFSET]
# Formula: Rx5x10^-1
psu_current = int(ss_read, 16) * 5 * math.pow(10, -1)
return psu_current
def get_power(self):
"""
Retrieves current energy supplied by PSU
Returns:
A float number, the power in watts, e.g. 302.6
"""
psu_pout_key = globals()['PSU{}_POUT_SS_ID'.format(self.index + 1)]
status, raw_ss_read = self._api_helper.ipmi_raw(
IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_pout_key))
ss_read = raw_ss_read.split()[SS_READ_OFFSET]
# Formula: Rx6x10^0
psu_power = int(ss_read, 16) * 6
return float(psu_power)
def get_powergood_status(self):
"""
Retrieves the powergood status of PSU
Returns:
A boolean, True if PSU has stablized its output voltages and passed all
its internal self-tests, False if not.
"""
return self.get_status()
def set_status_led(self, color):
"""
Sets the state of the PSU status LED
Args:
color: A string representing the color with which to set the PSU status LED
Note: Only support green and off
Returns:
bool: True if status LED state is set successfully, False if not
Note
Set manual
ipmitool raw 0x3a 0x42 0x2 0x00
"""
led_cmd = {
self.STATUS_LED_COLOR_GREEN: PSU_LED_GREEN_CMD,
self.STATUS_LED_COLOR_AMBER: PSU_LED_AMBER_CMD,
self.STATUS_LED_COLOR_OFF: PSU_LED_OFF_CMD
}.get(color)
self._api_helper.ipmi_raw("0x3a 0x42 0x02 0x00")
status, set_led = self._api_helper.ipmi_raw(
IPMI_OEM_NETFN, IPMI_SET_PSU_LED_CMD.format(led_cmd))
set_status_led = False if not status else True
return set_status_led
def get_status_led(self):
"""
Gets the state of the PSU status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings above
"""
status, hx_color = self._api_helper.ipmi_raw(
IPMI_OEM_NETFN, IPMI_GET_PSU_LED_CMD)
status_led = {
"00": self.STATUS_LED_COLOR_OFF,
"01": self.STATUS_LED_COLOR_GREEN,
"02": self.STATUS_LED_COLOR_AMBER,
}.get(hx_color, self.STATUS_LED_COLOR_OFF)
return status_led
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return PSU_NAME_LIST[self.index]
@staticmethod
def run_command(command):
proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
(out, err) = proc.communicate()
if proc.returncode != 0:
sys.exit(proc.returncode)
return out
@staticmethod
def find_value(in_string):
result = re.search("^.+ ([0-9a-f]{2}) .+$", in_string)
if result:
return result.group(1)
else:
return result
def get_presence(self):
"""
Retrieves the presence of the PSU
Returns:
bool: True if PSU is present, False if not
"""
if self.index is None:
return False
ipmi_raw = "ipmitool raw 0x4 0x2d"
psu_id = self.psu1_id if self.index == 1 else self.psu2_id
res_string = self.run_command(ipmi_raw + ' ' + psu_id)
status_byte = self.find_value(res_string)
if status_byte is None:
return False
presence = ( int(status_byte, 16) >> 0 ) & 1
if presence:
return True
else:
return False
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
eg.ipmitool fru print 4
Product Manufacturer : DELTA
Product Name : DPS-1300AB-6 J
Product Part Number : DPS-1300AB-6 J
Product Version : S1F
Product Serial : JDMD2111000125
Product Asset Tag : S1F
"""
model = "Unknown"
ipmi_fru_idx = self.index + PSU1_FRU_ID
status, raw_model = self._api_helper.ipmi_fru_id(
ipmi_fru_idx, IPMI_FRU_MODEL_KEY)
fru_pn_list = raw_model.split()
if len(fru_pn_list) > 4:
model = fru_pn_list[4]
return model
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
serial = "Unknown"
ipmi_fru_idx = self.index + PSU1_FRU_ID
status, raw_model = self._api_helper.ipmi_fru_id(
ipmi_fru_idx, IPMI_FRU_SERIAL_KEY)
fru_sr_list = raw_model.split()
if len(fru_sr_list) > 3:
serial = fru_sr_list[3]
return serial
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
if self.index is None:
return False
ipmi_raw = "ipmitool raw 0x4 0x2d"
psu_id = self.psu1_id if self.index == 1 else self.psu2_id
res_string = self.run_command(ipmi_raw + ' ' + psu_id)
status_byte = self.find_value(res_string)
if status_byte is None:
return False
failure_detected = (int(status_byte, 16) >> 1) & 1
input_lost = (int(status_byte, 16) >> 3) & 1
if failure_detected or input_lost:
return False
else:
return True

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,310 @@
#!/usr/bin/env python
#############################################################################
# Celestica
#
# Thermal contains an implementation of SONiC Platform Base API and
# provides the thermal device status which are available in the platform
#
#############################################################################
import os
import os.path
try:
from sonic_platform_base.thermal_base import ThermalBase
from helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
PLATFORM_CPLD_PATH = '/sys/devices/platform/sys_cpld'
GETREG_FILE = 'getreg'
FAN_DIRECTION_REG1 = '0xA141'
FAN_DIRECTION_REG2 = '0xA145'
FAN_DIRECTION_REG3 = '0xA149'
FAN_DIRECTION_REG4 = '0xA14D'
NULL_VAL = "N/A"
I2C_ADAPTER_PATH = "/sys/class/i2c-adapter"
IPMI_SENSOR_TEMP_CMD = "ipmitool sensor | grep degrees"
FANSHOW_CMD = "show platform fan"
THERMAL_INFO = [
{'name': 'CPU_TEMP', 'temp': 'na'}, # 0
{'name': 'TEMP_BB_U3', 'temp': 'na'}, # 1
{'name': 'TEMP_SW_U25', 'temp': 'na'}, # 2
{'name': 'TEMP_SW_U26', 'temp': 'na'}, # 3
{'name': 'TEMP_SW_U16', 'temp': 'na'}, # 4
{'name': 'TEMP_SW_U52', 'temp': 'na'}, # 5
{'name': 'TEMP_SW_CORE', 'temp': 'na'}, # 6
{'name': 'PSU1_Temp1', 'temp': 'na'}, # 7
{'name': 'PSU1_Temp2', 'temp': 'na'}, # 8
{'name': 'PSU1_Temp3', 'temp': 'na'}, # 9
{'name': 'PSU2_Temp1', 'temp': 'na'}, # 10
{'name': 'PSU2_Temp2', 'temp': 'na'}, # 11
{'name': 'PSU2_Temp3', 'temp': 'na'}, # 12
{'name': 'XP3R3V_LEFT_T', 'temp': 'na'}, # 13
{'name': 'XP3R3V_RIGHT_T', 'temp': 'na'}, # 14
{'name': 'U3P1_AVDD_T', 'temp': 'na'}, # 15
{'name': 'XP0R8V_VDD_T', 'temp': 'na'}, # 16
{'name': 'DIMMB0_TEMP', 'temp': 'na'}, # 17
]
thermal_temp_dict = {
"CPU_TEMP": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL, "max": 103, "high_critical_threshold": 105},
"TEMP_BB_U3": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": {"B2F": 55, "F2B": NULL_VAL}, "high_critical_threshold": {"B2F": 60, "F2B": NULL_VAL}},
"TEMP_SW_U25": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": NULL_VAL, "high_critical_threshold": NULL_VAL},
"TEMP_SW_U26": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": NULL_VAL, "high_critical_threshold": NULL_VAL},
"TEMP_SW_U16": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": {"B2F": NULL_VAL, "F2B": 55},
"high_critical_threshold": {"B2F": NULL_VAL, "F2B": 60}},
"TEMP_SW_U52": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": NULL_VAL, "high_critical_threshold": NULL_VAL},
"TEMP_SW_CORE": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": 105, "high_critical_threshold": 110},
"PSU1_Temp1": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": {"B2F": 61, "F2B": 61}, "high_critical_threshold": NULL_VAL},
"PSU1_Temp2": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": {"B2F": 107, "F2B": 108}, "high_critical_threshold": NULL_VAL},
"PSU1_Temp3": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": {"B2F": 106, "F2B": 91}, "high_critical_threshold": NULL_VAL},
"PSU2_Temp1": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": {"B2F": 61, "F2B": 61}, "high_critical_threshold": NULL_VAL},
"PSU2_Temp2": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": {"B2F": 107, "F2B": 108}, "high_critical_threshold": NULL_VAL},
"PSU2_Temp3": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": {"B2F": 106, "F2B": 91}, "high_critical_threshold": NULL_VAL},
"XP3R3V_LEFT_T": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": {"B2F": 125, "F2B": 125}, "high_critical_threshold": NULL_VAL},
"XP3R3V_RIGHT_T": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": {"B2F": 125, "F2B": 125}, "high_critical_threshold": NULL_VAL},
"U3P1_AVDD_T": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": {"B2F": 125, "F2B": 125}, "high_critical_threshold": NULL_VAL},
"XP0R8V_VDD_T": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": {"B2F": 125, "F2B": 125}, "high_critical_threshold": NULL_VAL},
"DIMMB0_TEMP": {"low_critical_threshold": NULL_VAL, "min": NULL_VAL,
"max": {"B2F": 85, "F2B": 85}, "high_critical_threshold": NULL_VAL},
}
temp_result = []
class Thermal(ThermalBase):
"""Platform-specific Thermal class"""
SS_CONFIG_PATH = "/usr/share/sonic/device/x86_64-cel_midstone-100x-r0/sonic_platform/sensors.conf"
def __init__(self, thermal_index, airflow):
self.index = thermal_index
self._api_helper = APIHelper()
self._airflow = self.__get_fan_direction()
self._thermal_info = THERMAL_INFO[self.index]
self.name = self.get_name()
def __get_fan_direction(self):
"""
Complete other path information according to the corresponding BUS path
"""
self.getreg_path = os.path.join(PLATFORM_CPLD_PATH, GETREG_FILE)
b2f = f2b = 0
for i in range(1,5):
value = self._api_helper.get_cpld_reg_value(
self.getreg_path, eval('FAN_DIRECTION_REG'+str(i)))
if int(value,16) & 0x8 :
b2f = b2f + 1
else:
f2b = f2b + 1
airflow = "B2F" if b2f > f2b else "F2B"
return airflow
def __get_thermal_info(self):
"""
Complete other path information according to the corresponding BUS path
"""
global temp_result
if self.index == 0:
status, temp_result_str = self._api_helper.run_command(IPMI_SENSOR_TEMP_CMD)
temp_result = temp_result_str.split('\n')
for i in temp_result:
if '|' not in i:
continue
sigle_list = i.split('|')
if self._thermal_info["name"] == sigle_list[0].strip():
self._thermal_info["temp"] = sigle_list[1].strip()
break
return True
def __set_threshold(self, temperature):
temp_file_path = self._thermal_info.get("max_temp", "N/A")
try:
with open(temp_file_path, 'w') as fd:
fd.write(str(temperature))
return True
except IOError:
return False
def get_temperature(self):
"""
Retrieves current temperature reading from thermal
Returns:
A float number of current temperature in Celsius up to nearest thousandth
of one degree Celsius, e.g. 30.125
"""
self.__get_thermal_info()
temperature = self._thermal_info.get("temp", "na")
if temperature != "na":
temperature = float(temperature)
else:
temperature = 0
return float("{:.3f}".format(temperature))
def get_high_threshold(self):
"""
Retrieves the high threshold temperature of thermal
Returns:
A float number, the high threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
high_threshold = thermal_temp_dict.get(self.name).get("max")
if isinstance(high_threshold, dict):
high_threshold = high_threshold.get(self._airflow)
if high_threshold != NULL_VAL:
high_threshold = float("{:.3f}".format(high_threshold))
return high_threshold
def get_low_threshold(self):
"""
Retrieves the low threshold temperature of thermal
Returns:
A float number, the low threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
low_threshold = thermal_temp_dict.get(self.name).get("min")
if low_threshold != NULL_VAL:
low_threshold = float("{:.3f}".format(low_threshold))
return low_threshold
def set_high_threshold(self, temperature):
"""
Sets the high threshold temperature of thermal
Args :
temperature: A float number up to nearest thousandth of one degree Celsius,
e.g. 30.125
Returns:
A boolean, True if threshold is set successfully, False if not
"""
#temp_file = "temp1_max"
#is_set = self.__set_threshold(int(temperature) * 1000)
#file_set = False
#if is_set:
# try:
# with open(self.SS_CONFIG_PATH, 'r+') as f:
# content = f.readlines()
# f.seek(0)
# ss_found = False
# for idx, val in enumerate(content):
# if self.name in val:
# ss_found = True
# elif ss_found and temp_file in val:
# content[idx] = " set {} {}\n".format(
# temp_file, temperature)
# f.writelines(content)
# file_set = True
# break
# except IOError:
# file_set = False
#return is_set & file_set
# Not Support
return False
@staticmethod
def set_low_threshold(temperature):
"""
Sets the low threshold temperature of thermal
Args :
temperature: A float number up to nearest thousandth of one degree Celsius,
e.g. 30.125
Returns:
A boolean, True if threshold is set successfully, False if not
"""
# Not Support
return False
def get_high_critical_threshold(self):
"""
Retrieves the high critical threshold temperature of thermal
Returns:
A float number, the high critical threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
high_critical_threshold = thermal_temp_dict.get(self.name).get("high_critical_threshold")
if isinstance(high_critical_threshold, dict):
high_critical_threshold = high_critical_threshold.get(str(self._airflow).upper())
if high_critical_threshold != NULL_VAL:
high_critical_threshold = float("{:.3f}".format(float(high_critical_threshold)))
return high_critical_threshold
def get_low_critical_threshold(self):
"""
Retrieves the low critical threshold temperature of thermal
Returns:
A float number, the low critical threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
low_critical_threshold = thermal_temp_dict.get(self.name).get("low_critical_threshold")
if low_critical_threshold != NULL_VAL:
low_critical_threshold = float("{:.3f}".format(float(low_critical_threshold)))
return low_critical_threshold
def get_name(self):
"""
Retrieves the name of the thermal device
Returns:
string: The name of the thermal device
"""
return self._thermal_info.get("name")
def get_presence(self):
"""
Retrieves the presence of the device
Returns:
bool: True if device is present, False if not
"""
return True if self.get_temperature() >= 0 else False
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
return self._thermal_info.get("model", NULL_VAL)
@staticmethod
def get_serial():
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
return NULL_VAL
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
if not self.get_presence():
return False
return True

View File

@ -0,0 +1,78 @@
from sonic_platform_base.sonic_thermal_control.thermal_action_base import ThermalPolicyActionBase
from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object
from .thermal_infos import ChassisInfo
from .helper import APIHelper
@thermal_json_object('thermal_control.control')
class ControlThermalAlgoAction(ThermalPolicyActionBase):
"""
Action to control the thermal control algorithm
"""
# JSON field definition
JSON_FIELD_STATUS = 'status'
def __init__(self):
self.status = True
def load_from_json(self, json_obj):
"""
Construct ControlThermalAlgoAction via JSON. JSON example:
{
"type": "thermal_control.control"
"status": "true"
}
:param json_obj: A JSON object representing a ControlThermalAlgoAction action.
:return:
"""
if ControlThermalAlgoAction.JSON_FIELD_STATUS in json_obj:
status_str = json_obj[ControlThermalAlgoAction.JSON_FIELD_STATUS].lower()
if status_str == 'true':
self.status = True
elif status_str == 'false':
self.status = False
else:
raise ValueError('Invalid {} field value, please specify true of false'.
format(ControlThermalAlgoAction.JSON_FIELD_STATUS))
else:
raise ValueError('ControlThermalAlgoAction '
'missing mandatory field {} in JSON policy file'.
format(ControlThermalAlgoAction.JSON_FIELD_STATUS))
def execute(self, thermal_info_dict):
"""
Disable thermal control algorithm
:param thermal_info_dict: A dictionary stores all thermal information.
:return:
"""
if ChassisInfo.INFO_NAME in thermal_info_dict:
chassis_info_obj = thermal_info_dict[ChassisInfo.INFO_NAME]
chassis = chassis_info_obj.get_chassis()
thermal_manager = chassis.get_thermal_manager()
if self.status:
thermal_manager.start_thermal_control_algorithm()
else:
thermal_manager.stop_thermal_control_algorithm()
@thermal_json_object('switch.power_cycling')
class SwitchPolicyAction(ThermalPolicyActionBase):
"""
Base class for thermal action. Once all thermal conditions in a thermal policy are matched,
all predefined thermal action will be executed.
"""
def execute(self, thermal_info_dict):
"""
Take action when thermal condition matches. For example, power cycle the switch.
:param thermal_info_dict: A dictionary stores all thermal information.
:return:
"""
thermal_overload_position_path = '/tmp/thermal_overload_position'
thermal_overload_position = APIHelper().read_one_line_file(
thermal_overload_position_path)
cmd = 'bash /usr/share/sonic/platform/thermal_overload_control.sh {}'.format(
thermal_overload_position)
APIHelper().run_command(cmd)

View File

@ -0,0 +1,77 @@
from sonic_platform_base.sonic_thermal_control.thermal_condition_base import ThermalPolicyConditionBase
from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object
class FanCondition(ThermalPolicyConditionBase):
def get_fan_info(self, thermal_info_dict):
from .thermal_infos import FanInfo
if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo):
return thermal_info_dict[FanInfo.INFO_NAME]
else:
return None
@thermal_json_object('fan.any.absence')
class AnyFanAbsenceCondition(FanCondition):
def is_match(self, thermal_info_dict):
fan_info_obj = self.get_fan_info(thermal_info_dict)
return len(fan_info_obj.get_absence_fans()) > 0 if fan_info_obj else False
@thermal_json_object('fan.any.fault')
class AnyFanFaultCondition(FanCondition):
def is_match(self, thermal_info_dict):
fan_info_obj = self.get_fan_info(thermal_info_dict)
return len(fan_info_obj.get_fault_fans()) > 0 if fan_info_obj else False
@thermal_json_object('fan.all.presence')
class AllFanPresenceCondition(FanCondition):
def is_match(self, thermal_info_dict):
fan_info_obj = self.get_fan_info(thermal_info_dict)
return len(fan_info_obj.get_absence_fans()) == 0 if fan_info_obj else False
@thermal_json_object('fan.all.good')
class AllFanGoodCondition(FanCondition):
def is_match(self, thermal_info_dict):
fan_info_obj = self.get_fan_info(thermal_info_dict)
return len(fan_info_obj.get_fault_fans()) == 0 if fan_info_obj else False
class ThermalCondition(ThermalPolicyConditionBase):
def get_thermal_info(self, thermal_info_dict):
from .thermal_infos import ThermalInfo
if ThermalInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo):
return thermal_info_dict[ThermalInfo.INFO_NAME]
else:
return None
@thermal_json_object('thermal.over.high_threshold')
class ThermalOverHighCriticalCondition(ThermalCondition):
def is_match(self, thermal_info_dict):
thermal_info_obj = self.get_thermal_info(thermal_info_dict)
if thermal_info_obj:
return thermal_info_obj.is_over_high_threshold()
else:
return False
@thermal_json_object('thermal.over.high_critical_threshold')
class ThermalOverHighCriticalCondition(ThermalCondition):
def is_match(self, thermal_info_dict):
thermal_info_obj = self.get_thermal_info(thermal_info_dict)
if thermal_info_obj:
return thermal_info_obj.is_over_high_critical_threshold()
else:
return False
@thermal_json_object('thermal.all.good')
class ThermalGoodCondition(ThermalCondition):
def is_match(self, thermal_info_dict):
thermal_info_obj = self.get_thermal_info(thermal_info_dict)
if thermal_info_obj:
return not thermal_info_obj.is_over_threshold()
else:
return False

View File

@ -0,0 +1,165 @@
from sonic_platform_base.sonic_thermal_control.thermal_info_base import ThermalPolicyInfoBase
from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object
from .helper import APIHelper
import time
@thermal_json_object('fan_info')
class FanInfo(ThermalPolicyInfoBase):
"""
Fan information needed by thermal policy
"""
# Fan information name
INFO_NAME = 'fan_info'
def __init__(self):
self._absence_fans = set()
self._presence_fans = set()
self._fault_fans = set()
self._status_changed = False
def collect(self, chassis):
"""
Collect absence and presence fans.
:param chassis: The chassis object
:return:
"""
self._status_changed = False
for fan in chassis.get_all_fans():
presence = fan.get_presence()
status = fan.get_status()
if presence and fan not in self._presence_fans:
self._presence_fans.add(fan)
self._status_changed = True
if fan in self._absence_fans:
self._absence_fans.remove(fan)
elif not presence and fan not in self._absence_fans:
self._absence_fans.add(fan)
self._status_changed = True
if fan in self._presence_fans:
self._presence_fans.remove(fan)
if not status and fan not in self._fault_fans:
self._fault_fans.add(fan)
self._status_changed = True
elif status and fan in self._fault_fans:
self._fault_fans.remove(fan)
self._status_changed = True
def get_absence_fans(self):
"""
Retrieves absence fans
:return: A set of absence fans
"""
return self._absence_fans
def get_presence_fans(self):
"""
Retrieves presence fans
:return: A set of presence fans
"""
return self._presence_fans
def get_fault_fans(self):
"""
Retrieves fault fans
:return: A set of fault fans
"""
return self._fault_fans
def is_status_changed(self):
"""
Retrieves if the status of fan information changed
:return: True if status changed else False
"""
return self._status_changed
@thermal_json_object('thermal_info')
class ThermalInfo(ThermalPolicyInfoBase):
"""
Thermal information needed by thermal policy
"""
# Fan information name
INFO_NAME = 'thermal_info'
def collect(self, chassis):
"""
Collect thermal sensor temperature change status
:param chassis: The chassis object
:return:
"""
self._over_high_threshold = False
self._over_high_critical_threshold = False
self._thermal_overload_position = 'cpu'
# Calculate average temp within the device
temp = 0
num_of_thermals = chassis.get_num_thermals()
for index in range(num_of_thermals):
thermal = chassis.get_thermal(index)
temp = thermal.get_temperature()
high_threshold = thermal.get_high_threshold()
high_critical_threshold = thermal.get_high_critical_threshold()
if high_threshold and temp > high_threshold:
self._over_high_threshold = True
if high_critical_threshold and temp > high_critical_threshold:
self._thermal_overload_position = thermal.postion
self._over_high_critical_threshold = True
def is_over_threshold(self):
"""
Retrieves if the temperature is over any threshold
:return: True if the temperature is over any threshold else False
"""
return self._over_high_threshold or self._over_high_critical_threshold
def is_over_high_critical_threshold(self):
"""
Retrieves if the temperature is over high critical threshold
:return: True if the temperature is over high critical threshold else False
"""
thermal_overload_position_path = '/tmp/thermal_overload_position'
if self._over_high_critical_threshold:
APIHelper().write_txt_file(thermal_overload_position_path,
self._thermal_overload_position)
time.sleep(1)
return self._over_high_critical_threshold
def is_over_high_threshold(self):
"""
Retrieves if the temperature is over high threshold
:return: True if the temperature is over high threshold else False
"""
return self._over_high_threshold
@thermal_json_object('chassis_info')
class ChassisInfo(ThermalPolicyInfoBase):
"""
Chassis information needed by thermal policy
"""
INFO_NAME = 'chassis_info'
def __init__(self):
self._chassis = None
def collect(self, chassis):
"""
Collect platform chassis.
:param chassis: The chassis object
:return:
"""
self._chassis = chassis
def get_chassis(self):
"""
Retrieves platform chassis object
:return: A platform chassis object.
"""
return self._chassis

View File

@ -0,0 +1,43 @@
from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase
from .helper import APIHelper
class ThermalManager(ThermalManagerBase):
FSC_ALGORITHM_CMD = 'service fancontrol {}'
@classmethod
def start_thermal_control_algorithm(cls):
"""
Start vendor specific thermal control algorithm. The default behavior of this function is a no-op.
:return:
"""
return cls._enable_fancontrol_service(True)
@classmethod
def stop_thermal_control_algorithm(cls):
"""
Stop thermal control algorithm
Returns:
bool: True if set success, False if fail.
"""
return cls._enable_fancontrol_service(False)
@classmethod
def deinitialize(cls):
"""
Destroy thermal manager, including any vendor specific cleanup. The default behavior of this function
is a no-op.
:return:
"""
return cls._enable_fancontrol_service(True)
@classmethod
def _enable_fancontrol_service(cls, enable):
"""
Control thermal by fcs algorithm
Args:
enable: Bool, indicate enable the algorithm or not
Returns:
bool: True if set success, False if fail.
"""
cmd = 'start' if enable else 'stop'
return APIHelper().run_command(cls.FSC_ALGORITHM_CMD.format(cmd))

View File

@ -0,0 +1,212 @@
#!/usr/bin/env python
#############################################################################
# Celestica
#
# Watchdog contains an implementation of SONiC Platform Base API
#
#############################################################################
import os
import time
try:
from sonic_platform_base.watchdog_base import WatchdogBase
from helper import APIHelper
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
PLATFORM_CPLD_PATH = '/sys/devices/platform/sys_cpld'
GETREG_FILE = 'getreg'
SETREG_FILE = 'setreg'
WDT_ENABLE_REG = '0xA187'
WDT_SET_TIMER_L_BIT_REG = '0xA183'
WDT_SET_TIMER_M_BIT_REG = '0xA182'
WDT_SET_TIMER_H_BIT_REG = '0xA181'
WDT_TIMER_L_BIT_REG = '0xA186'
WDT_TIMER_M_BIT_REG = '0xA185'
WDT_TIMER_H_BIT_REG = '0xA184'
WDT_KEEP_ALVIVE_REG = '0xA188'
ENABLE_CMD = '0x1'
DISABLE_CMD = '0x0'
WDT_COMMON_ERROR = -1
class Watchdog(WatchdogBase):
def __init__(self):
# Init helper
self._api_helper = APIHelper()
# Init cpld reg path
self.setreg_path = os.path.join(PLATFORM_CPLD_PATH, SETREG_FILE)
self.getreg_path = os.path.join(PLATFORM_CPLD_PATH, GETREG_FILE)
# Set default value
#self._disable()
#self.armed = False
value = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_ENABLE_REG)
hex_time = '{}'.format(value)
value = int(hex_time, 16)
self.armed = True if value else False
self.timeout = self._gettimeout()
self.arm_timestamp = 0
def _enable(self):
"""
Turn on the watchdog timer
"""
# echo 0xA187 0x1 > /sys/devices/platform/sys_cpld/setreg
enable_val = '{} {}'.format(WDT_ENABLE_REG, ENABLE_CMD)
return self._api_helper.write_txt_file(self.setreg_path, enable_val)
def _disable(self):
"""
Turn off the watchdog timer
"""
# echo 0xA187 0x0 > /sys/devices/platform/sys_cpld/setreg
disable_val = '{} {}'.format(WDT_ENABLE_REG, DISABLE_CMD)
return self._api_helper.write_txt_file(self.setreg_path, disable_val)
def _keepalive(self):
"""
Keep alive watchdog timer
"""
# echo 0xA188 > /sys/devices/platform/sys_cpld/getreg
# value = $(cat /sys/devices/platform/sys_cpld/getreg)
# echo 0xA188 (~ $value) & 0x01 > /sys/devices/platform/sys_cpld/setreg
value = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_KEEP_ALVIVE_REG)
value = int(value, 16)
enable_val = '{} 0x{}'.format(WDT_KEEP_ALVIVE_REG, (~value) & 0x01)
return self._api_helper.write_txt_file(self.setreg_path, enable_val)
def _get_level_hex(self, sub_hex):
sub_hex_str = sub_hex.replace("x", "0")
return hex(int(sub_hex_str, 16))
def _seconds_to_lmh_hex(self, seconds):
ms = seconds*1000 # calculate timeout in ms format
hex_str = hex(ms)
l = self._get_level_hex(hex_str[-2:])
m = self._get_level_hex(hex_str[-4:-2])
h = self._get_level_hex(hex_str[-6:-4])
return (l, m, h)
def _settimeout(self, seconds):
"""
Set watchdog timer timeout
@param seconds - timeout in seconds
@return is the actual set timeout
"""
# max = 0xffffff = 16777.215 seconds
(l, m, h) = self._seconds_to_lmh_hex(seconds)
set_h_val = '{} {}'.format(WDT_SET_TIMER_H_BIT_REG, h)
set_m_val = '{} {}'.format(WDT_SET_TIMER_M_BIT_REG, m)
set_l_val = '{} {}'.format(WDT_SET_TIMER_L_BIT_REG, l)
self._api_helper.write_txt_file(self.setreg_path, set_h_val)
self._api_helper.write_txt_file(self.setreg_path, set_m_val)
self._api_helper.write_txt_file(self.setreg_path, set_l_val)
return seconds
def _gettimeout(self):
"""
Get watchdog timeout
@return watchdog timeout
"""
h_bit = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_SET_TIMER_H_BIT_REG)
m_bit = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_SET_TIMER_M_BIT_REG)
l_bit = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_SET_TIMER_L_BIT_REG)
hex_time = '0x{}{}{}'.format(h_bit[2:], m_bit[2:], l_bit[2:])
ms = int(hex_time, 16)
return int(float(ms)/1000)
def arm(self, seconds):
"""
Arm the hardware watchdog with a timeout of <seconds> seconds.
If the watchdog is currently armed, calling this function will
simply reset the timer to the provided value. If the underlying
hardware does not support the value provided in <seconds>, this
method should arm the watchdog with the *next greater* available
value.
Returns:
An integer specifying the *actual* number of seconds the watchdog
was armed with. On failure returns -1.
"""
ret = WDT_COMMON_ERROR
if seconds < 0 or seconds > int(0xffffff/1000):
return ret
try:
if self.timeout != seconds:
self.timeout = self._settimeout(seconds)
if self.armed:
self._keepalive()
else:
self._enable()
self._keepalive()
self.armed = True
ret = self.timeout
self.arm_timestamp = time.time()
except IOError as e:
pass
return ret
def disarm(self):
"""
Disarm the hardware watchdog
Returns:
A boolean, True if watchdog is disarmed successfully, False if not
"""
disarmed = False
if self.is_armed():
try:
self._disable()
self.armed = False
disarmed = True
except IOError:
pass
return disarmed
def is_armed(self):
"""
Retrieves the armed state of the hardware watchdog.
Returns:
A boolean, True if watchdog is armed, False if not
"""
return self.armed
def get_remaining_time(self):
"""
If the watchdog is armed, retrieve the number of seconds remaining on
the watchdog timer
Returns:
An integer specifying the number of seconds remaining on thei
watchdog timer. If the watchdog is not armed, returns -1.
"""
h_bit = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_TIMER_H_BIT_REG)
m_bit = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_TIMER_M_BIT_REG)
l_bit = self._api_helper.get_cpld_reg_value(
self.getreg_path, WDT_TIMER_L_BIT_REG)
hex_time = '0x{}{}{}'.format(h_bit[2:], m_bit[2:], l_bit[2:])
ms = int(hex_time, 16)
return int(float(ms)/1000) if self.armed else WDT_COMMON_ERROR

View File

@ -0,0 +1 @@
t1

View File

@ -135,6 +135,8 @@ class Watchdog(WatchdogBase):
ret = WDT_COMMON_ERROR
if seconds < 0:
return ret
if seconds > 16778:
return ret
try:
if self.timeout != seconds:

View File

@ -5,6 +5,8 @@ $(SONIC_ONE_IMAGE)_MACHINE = innovium
$(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie
$(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(CEL_MIDSTONE_200I_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(CEL_MIDSTONE_100X_PLATFORM_MODULE)
#$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(CEL_SILVERSTONE_X_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELTA_ETC032IF_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELTA_EVSA32Q56_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(CAMEO_ESC601_32Q_PLATFORM_MODULE) $(CAMEO_ESC600_128Q_PLATFORM_MODULE) $(CAMEO_ESQC610_56SQ_PLATFORM_MODULE) $(CAMEO_ESC602_32Q_PLATFORM_MODULE) $(CAMEO_ESCC601_32Q_PLATFORM_MODULE)

View File

@ -1,12 +1,26 @@
# Celestica platform modules
CEL_PLATFORM_MODULE_VERSION = 0.2.2
CEL_MIDSTONE_200I_PLATFORM_MODULE_VERSION = 0.2.3
CEL_MIDSTONE_100X_PLATFORM_MODULE_VERSION = 0.2.3
CEL_SILVERSTONE_X_PLATFORM_MODULE_VERSION = 0.2.3
export CEL_PLATFORM_MODULE_VERSION
export CEL_MIDSTONE_200I_PLATFORM_MODULE_VERSION
export CEL_MIDSTONE_100X_PLATFORM_MODULE_VERSION
export CEL_SILVERSTONE_X_PLATFORM_MODULE_VERSION
CEL_MIDSTONE_200I_PLATFORM_MODULE = platform-modules-midstone-200i_$(CEL_PLATFORM_MODULE_VERSION)_$(CONFIGURED_ARCH).deb
CEL_MIDSTONE_200I_PLATFORM_MODULE = platform-modules-midstone-200i_$(CEL_MIDSTONE_200I_PLATFORM_MODULE_VERSION)_$(CONFIGURED_ARCH).deb
$(CEL_MIDSTONE_200I_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-cel
$(CEL_MIDSTONE_200I_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON)
$(CEL_MIDSTONE_200I_PLATFORM_MODULE)_PLATFORM = x86_64-cel_midstone-r0
SONIC_DPKG_DEBS += $(CEL_MIDSTONE_200I_PLATFORM_MODULE)
SONIC_STRETCH_DEBS+= $(CEL_MIDSTONE_200I_PLATFORM_MODULE)
CEL_MIDSTONE_100X_PLATFORM_MODULE = platform-modules-midstone-100x_$(CEL_MIDSTONE_100X_PLATFORM_MODULE_VERSION)_$(CONFIGURED_ARCH).deb
$(CEL_MIDSTONE_100X_PLATFORM_MODULE)_PLATFORM = x86_64-cel_midstone-100x-r0
$(eval $(call add_extra_package,$(CEL_MIDSTONE_200I_PLATFORM_MODULE),$(CEL_MIDSTONE_100X_PLATFORM_MODULE)))
#CEL_SILVERSTONE_X_PLATFORM_MODULE = platform-modules-silverstone-x_$(CEL_SILVERSTONE_X_PLATFORM_MODULE_VERSION)_$(CONFIGURED_ARCH).deb
#$(CEL_SILVERSTONE_X_PLATFORM_MODULE)_PLATFORM = x86_64-cel_silverstone-x-r0
#$(eval $(call add_extra_package,$(CEL_MIDSTONE_200I_PLATFORM_MODULE),$(CEL_SILVERSTONE_X_PLATFORM_MODULE)))
SONIC_STRETCH_DEBS += $(CEL_MIDSTONE_200I_PLATFORM_MODULE)

View File

@ -1,3 +1,9 @@
sonic-cel-platform-modules (0.2.3) unstable; urgency=low
* Add SilverstoneX and Midstone100x platform module.
-- Nicholas Wu <nicwu@celestica.com> Mon, 18 Apr 2021 10:10:10 +0700
sonic-cel-platform-modules (0.2.2) unstable; urgency=low
* Remove I2c mux ininitialization in init-script.

View File

@ -1,7 +1,7 @@
Source: sonic-cel-platform-modules
Section: main
Priority: extra
Maintainer: Wirut Getbamrung <wgetbumr@celestica.com>
Maintainer: Nicholas Wu <nicwu@celestica.com>
Build-Depends: debhelper (>= 8.0.0), bzip2
Standards-Version: 3.9.3
@ -9,3 +9,13 @@ Package: platform-modules-midstone-200i
Architecture: amd64
Depends: linux-image-4.9.0-14-2-amd64
Description: kernel modules for platform devices
Package: platform-modules-midstone-100x
Architecture: amd64
Depends: linux-image-4.9.0-14-2-amd64
Description: kernel modules for platform devices
#Package: platform-modules-silverstone-x
#Architecture: amd64
#Depends: linux-image-4.9.0-14-2-amd64
#Description: kernel modules for platform devices

View File

@ -0,0 +1,93 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: setup-board
# Required-Start: $portmap
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start: S
# Default-Stop: 0 6
# Short-Description: Setup SilverStone-x board.
### END INIT INFO
case "$1" in
start)
echo -n "Setting up board... "
depmod
modprobe i2c-dev
modprobe ipmi_devintf
modprobe fpga_device
modprobe fpga_i2c_ocores
modprobe fpga_system
modprobe i2c_switchcpld
modprobe lpc_basecpld
modprobe mc24lc64t
modprobe optoe
modprobe xcvr-cls
# Instantiate TLV EEPROM device on I801 bus
devname=`cat /sys/bus/i2c/devices/i2c-0/name`
if [[ $devname == 'SMBus'* ]]; then
echo 24lc64t 0x56 > /sys/bus/i2c/devices/i2c-0/new_device
fi
devname=`cat /sys/bus/i2c/devices/i2c-10/name`
if [[ $devname == 'ocores-i2c-cls' ]]; then
echo switchboard 0x30 > /sys/bus/i2c/devices/i2c-10/new_device
echo switchboard 0x31 > /sys/bus/i2c/devices/i2c-10/new_device
echo switchboard 0x32 > /sys/bus/i2c/devices/i2c-10/new_device
echo switchboard 0x33 > /sys/bus/i2c/devices/i2c-10/new_device
fi
for i in {16..79}; do
devname=`cat /sys/bus/i2c/devices/i2c-$i/name`
if [[ $devname == *'mux'* ]]; then
echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-"$i"/new_device
port='expr $i - 15'
echo QSFP$port > /sys/bus/i2c/devices/i2c-"$i"/"$i"-0050/port_name
fi
done
devname=`cat /sys/bus/i2c/devices/i2c-13/name`
if [[ $devname == *'ocores-i2c-cls'* ]]; then
echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-13/new_device
echo SFP1 > /sys/bus/i2c/devices/i2c-13/13-0050/port_name
fi
devname=`cat /sys/bus/i2c/devices/i2c-14/name`
if [[ $devname == *'ocores-i2c-cls'* ]]; then
echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-14/new_device
echo SFP2 > /sys/bus/i2c/devices/i2c-14/14-0050/port_name
fi
decode-syseeprom --init 2> /dev/null &
/bin/sh /usr/local/bin/platform_api_mgnt.sh init
echo "done."
;;
stop)
rmmod ipmi_devintf
rmmod xcvr-cls
rmmod optoe
rmmod mc24lc64t
rmmod lpc_basecpld
rmmod i2c_switchcpld
rmmod fpga_system
rmmod fpga_i2c_ocores
rmmod fpga_device
echo 0x56 > /sys/bus/i2c/devices/i2c-0/delete_device
echo "done."
;;
force-reload|restart)
echo "Not supported"
;;
*)
echo "Usage: /etc/init.d/platform-modules-midstone-100x.init {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,6 @@
midstone-100x/scripts/sensors usr/bin
midstone-100x/scripts/platform_sensors.py usr/local/bin
midstone-100x/cfg/midstone-100x-modules.conf etc/modules-load.d
midstone-100x/systemd/platform-modules-midstone-100x.service lib/systemd/system
midstone-100x/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_midstone-100x-r0
services/platform_api/platform_api_mgnt.sh usr/local/bin

View File

@ -0,0 +1,5 @@
depmod -a
systemctl enable platform-modules-midstone-100x.service
systemctl start platform-modules-midstone-100x.service
/usr/local/bin/platform_api_mgnt.sh install

View File

@ -5,7 +5,7 @@ export INSTALL_MOD_DIR:=extra
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
MODULE_DIRS:= midstone-200i
MODULE_DIRS:= midstone-200i midstone-100x
%:
dh $@
@ -13,6 +13,9 @@ MODULE_DIRS:= midstone-200i
override_dh_auto_build:
(for mod in $(MODULE_DIRS); do \
make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \
cd $(MOD_SRC_DIR)/$${mod}; \
python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
cd $(MOD_SRC_DIR); \
done)
override_dh_auto_install:

View File

@ -0,0 +1,16 @@
# /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-isch
i2c-ismt
i2c-dev
i2c-mux
i2c-smbus
i2c-mux-pca954x
ipmi_devintf
ipmi_si

View File

@ -0,0 +1 @@
obj-m := fpga_device.o fpga_i2c_ocores.o xcvr-cls.o mc24lc64t_device.o mc24lc64t.o fpga_system.o i2c_switchcpld.o lpc_basecpld.o optoe.o

View File

@ -0,0 +1,32 @@
#ifndef _LINUX_FPGA_H
#define _LINUX_FPGA_H
enum FPGA_TYPE {
FPGA_NONE = 0,
FPGA
};
/*
* port_info - optical port info
* @index: front panel port index starting from 1
* @typr: port type, see *PORT_TYPE*
*/
struct fpga_info {
const char *name;
unsigned int index;
enum FPGA_TYPE type;
};
/*
* fpga_platform_data - port xcvr private data
* @fpga_reg_size: register range of each port
* @num_ports: number of front panel ports
* @devices: list of front panel port info
*/
struct fpga_platform_data {
unsigned int fpga_reg_size;
int num_ports;
struct fpga_info *devices;
};
#endif /* _LINUX_I2C_CLS_H */

View File

@ -0,0 +1,961 @@
/*
* cls-switchboard.c - PCI device driver for Silverstone Switch board FPGA.
*
* Author: Pradchaya Phucharoen
*
* Copyright (C) 2019 Celestica Corp.
*
* 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 <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/acpi.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/i2c/pca954x.h>
#include "i2c-ocores.h"
#include "xcvr-cls.h"
#include "fpga.h"
#define MOD_VERSION "2.0.0"
#define DRV_NAME "fpga_device_board"
#define I2C_MUX_CHANNEL(_ch, _adap_id, _deselect) \
[_ch] = { .adap_id = _adap_id, .deselect_on_exit = _deselect }
#define FPGA_PCIE_DEVICE_ID 0x7021
#define FPGA_TYPE_ADDR 0x0C
#define FPGA_OTHER_CR_ADDR 0x14
#define BMC_PRESENT_BIT 0x08
#define BMC_PRESENT 0x00 /* FPGA_OTHER_CR_ADDR bit8 0-bmc present 1-bmc absent*/
#define FPGA_EXCLUDE_MIN_BUS 8 /* iic core 0-7 is share with BMC, 8 and 9 is for FPGA only, mask 0-7 when BMC is present*/
#define MMIO_BAR 0
#define I2C_BUS_LC_OFS 15
//#define I2C_BUS_LC2_OFS 55
/* I2C ocore configurations */
#define OCORE_REGSHIFT 2
#define OCORE_IP_CLK_khz 62500
#define OCORE_BUS_CLK_khz 100
#define OCORE_REG_IO_WIDTH 1
/* Optical port xcvr configuration */
#define XCVR_REG_SHIFT 2
#define XCVR_NUM_PORT 66
#define XCVR_PORT_REG_SIZE 0x10
/* i2c_bus_config - an i2c-core resource and platform data
* @id - I2C bus device ID, for identification.
* @res - resources for an i2c-core device.
* @num_res - size of the resources.
* @pdata - a platform data of an i2c-core device.
*/
struct i2c_bus_config {
int id;
struct resource *res;
ssize_t num_res;
struct ocores_i2c_platform_data pdata;
};
/* switchbrd_priv - switchboard private data */
struct switchbrd_priv {
void __iomem *iomem;
unsigned long base;
int num_i2c_bus;
const char *i2c_devname;
const char *xcvr_devname;
const char *fpga_devname;
struct platform_device **i2cbuses_pdev;
struct platform_device *regio_pdev;
struct platform_device *spiflash_pdev;
struct platform_device *xcvr_pdev;
struct platform_device *fpga_pdev;
};
/* I2C bus speed param */
static int bus_clock_master_1 = 100;
module_param(bus_clock_master_1, int, 0660);
MODULE_PARM_DESC(bus_clock_master_1,
"I2C master 1 bus speed in KHz 50/80/100/200/400");
static int bus_clock_master_2 = 100;
module_param(bus_clock_master_2, int, 0660);
MODULE_PARM_DESC(bus_clock_master_2,
"I2C master 2 bus speed in KHz 50/80/100/200/400");
static int bus_clock_master_3 = 100;
module_param(bus_clock_master_3, int, 0660);
MODULE_PARM_DESC(bus_clock_master_3,
"I2C master 3 bus speed in KHz 50/80/100/200/400");
static int bus_clock_master_4 = 100;
module_param(bus_clock_master_4, int, 0660);
MODULE_PARM_DESC(bus_clock_master_4,
"I2C master 4 bus speed in KHz 50/80/100/200/400");
static int bus_clock_master_5 = 100;
module_param(bus_clock_master_5, int, 0660);
MODULE_PARM_DESC(bus_clock_master_5,
"I2C master 5 bus speed in KHz 50/80/100/200/400");
static int bus_clock_master_6 = 100;
module_param(bus_clock_master_6, int, 0660);
MODULE_PARM_DESC(bus_clock_master_6,
"I2C master 6 bus speed in KHz 50/80/100/200/400");
static int bus_clock_master_7 = 100;
module_param(bus_clock_master_7, int, 0660);
MODULE_PARM_DESC(bus_clock_master_7,
"I2C master 7 bus speed in KHz 50/80/100/200/400");
static int bus_clock_master_8 = 100;
module_param(bus_clock_master_8, int, 0660);
MODULE_PARM_DESC(bus_clock_master_8,
"I2C master 8 bus speed in KHz 50/80/100/200/400");
static int bus_clock_master_9 = 100;
module_param(bus_clock_master_9, int, 0660);
MODULE_PARM_DESC(bus_clock_master_9,
"I2C master 9 bus speed in KHz 50/80/100/200/400");
static int bus_clock_master_10 = 100;
module_param(bus_clock_master_10, int, 0660);
MODULE_PARM_DESC(bus_clock_master_10,
"I2C master 10 bus speed in KHz 50/80/100/200/400");
static int bus_clock_master_11 = 100;
module_param(bus_clock_master_11, int, 0660);
MODULE_PARM_DESC(bus_clock_master_11,
"I2C master 11 bus speed in KHz 50/80/100/200/400");
static int bus_clock_master_12 = 100;
module_param(bus_clock_master_12, int, 0660);
MODULE_PARM_DESC(bus_clock_master_12,
"I2C master 12 bus speed in KHz 50/80/100/200/400");
static int bus_clock_master_13 = 100;
module_param(bus_clock_master_13, int, 0660);
MODULE_PARM_DESC(bus_clock_master_13,
"I2C master 13 bus speed in KHz 50/80/100/200/400");
static int bus_clock_master_14 = 100;
module_param(bus_clock_master_14, int, 0660);
MODULE_PARM_DESC(bus_clock_master_14,
"I2C master 14 bus speed in KHz 50/80/100/200/400");
// NOTE: Cloverstone i2c channel mapping is very wierd!!!
/* PCA9548 channel config on MASTER BUS */
static struct pca954x_platform_mode i2c_01_mux_70_LC[] = {
I2C_MUX_CHANNEL(0, I2C_BUS_LC_OFS + 1, true),
I2C_MUX_CHANNEL(1, I2C_BUS_LC_OFS + 2, true),
I2C_MUX_CHANNEL(2, I2C_BUS_LC_OFS + 34, true),
I2C_MUX_CHANNEL(3, I2C_BUS_LC_OFS + 33, true),
I2C_MUX_CHANNEL(4, I2C_BUS_LC_OFS + 3, true),
I2C_MUX_CHANNEL(5, I2C_BUS_LC_OFS + 4, true),
I2C_MUX_CHANNEL(6, I2C_BUS_LC_OFS + 36, true),
I2C_MUX_CHANNEL(7, I2C_BUS_LC_OFS + 35, true),
};
static struct pca954x_platform_mode i2c_01_mux_71_LC[] = {
I2C_MUX_CHANNEL(0, I2C_BUS_LC_OFS + 5, true),
I2C_MUX_CHANNEL(1, I2C_BUS_LC_OFS + 6, true),
I2C_MUX_CHANNEL(2, I2C_BUS_LC_OFS + 38, true),
I2C_MUX_CHANNEL(3, I2C_BUS_LC_OFS + 37, true),
I2C_MUX_CHANNEL(4, I2C_BUS_LC_OFS + 7, true),
I2C_MUX_CHANNEL(5, I2C_BUS_LC_OFS + 8, true),
I2C_MUX_CHANNEL(6, I2C_BUS_LC_OFS + 40, true),
I2C_MUX_CHANNEL(7, I2C_BUS_LC_OFS + 39, true),
};
static struct pca954x_platform_mode i2c_01_mux_72_LC[] = {
I2C_MUX_CHANNEL(0, I2C_BUS_LC_OFS + 9, true),
I2C_MUX_CHANNEL(1, I2C_BUS_LC_OFS + 10, true),
I2C_MUX_CHANNEL(2, I2C_BUS_LC_OFS + 42, true),
I2C_MUX_CHANNEL(3, I2C_BUS_LC_OFS + 41, true),
I2C_MUX_CHANNEL(4, I2C_BUS_LC_OFS + 11, true),
I2C_MUX_CHANNEL(5, I2C_BUS_LC_OFS + 12, true),
I2C_MUX_CHANNEL(6, I2C_BUS_LC_OFS + 44, true),
I2C_MUX_CHANNEL(7, I2C_BUS_LC_OFS + 43, true),
};
static struct pca954x_platform_mode i2c_01_mux_73_LC[] = {
I2C_MUX_CHANNEL(0, I2C_BUS_LC_OFS + 13, true),
I2C_MUX_CHANNEL(1, I2C_BUS_LC_OFS + 14, true),
I2C_MUX_CHANNEL(2, I2C_BUS_LC_OFS + 46, true),
I2C_MUX_CHANNEL(3, I2C_BUS_LC_OFS + 45, true),
I2C_MUX_CHANNEL(4, I2C_BUS_LC_OFS + 15, true),
I2C_MUX_CHANNEL(5, I2C_BUS_LC_OFS + 16, true),
I2C_MUX_CHANNEL(6, I2C_BUS_LC_OFS + 48, true),
I2C_MUX_CHANNEL(7, I2C_BUS_LC_OFS + 47, true),
};
static struct pca954x_platform_mode i2c_02_mux_70_LC[] = {
I2C_MUX_CHANNEL(0, I2C_BUS_LC_OFS + 17, true),
I2C_MUX_CHANNEL(1, I2C_BUS_LC_OFS + 18, true),
I2C_MUX_CHANNEL(2, I2C_BUS_LC_OFS + 50, true),
I2C_MUX_CHANNEL(3, I2C_BUS_LC_OFS + 49, true),
I2C_MUX_CHANNEL(4, I2C_BUS_LC_OFS + 19, true),
I2C_MUX_CHANNEL(5, I2C_BUS_LC_OFS + 20, true),
I2C_MUX_CHANNEL(6, I2C_BUS_LC_OFS + 52, true),
I2C_MUX_CHANNEL(7, I2C_BUS_LC_OFS + 51, true),
};
static struct pca954x_platform_mode i2c_02_mux_71_LC[] = {
I2C_MUX_CHANNEL(0, I2C_BUS_LC_OFS + 21, true),
I2C_MUX_CHANNEL(1, I2C_BUS_LC_OFS + 22, true),
I2C_MUX_CHANNEL(2, I2C_BUS_LC_OFS + 54, true),
I2C_MUX_CHANNEL(3, I2C_BUS_LC_OFS + 53, true),
I2C_MUX_CHANNEL(4, I2C_BUS_LC_OFS + 23, true),
I2C_MUX_CHANNEL(5, I2C_BUS_LC_OFS + 24, true),
I2C_MUX_CHANNEL(6, I2C_BUS_LC_OFS + 56, true),
I2C_MUX_CHANNEL(7, I2C_BUS_LC_OFS + 55, true),
};
static struct pca954x_platform_mode i2c_02_mux_72_LC[] = {
I2C_MUX_CHANNEL(0, I2C_BUS_LC_OFS + 25, true),
I2C_MUX_CHANNEL(1, I2C_BUS_LC_OFS + 26, true),
I2C_MUX_CHANNEL(2, I2C_BUS_LC_OFS + 58, true),
I2C_MUX_CHANNEL(3, I2C_BUS_LC_OFS + 57, true),
I2C_MUX_CHANNEL(4, I2C_BUS_LC_OFS + 27, true),
I2C_MUX_CHANNEL(5, I2C_BUS_LC_OFS + 28, true),
I2C_MUX_CHANNEL(6, I2C_BUS_LC_OFS + 60, true),
I2C_MUX_CHANNEL(7, I2C_BUS_LC_OFS + 59, true),
};
static struct pca954x_platform_mode i2c_02_mux_73_LC[] = {
I2C_MUX_CHANNEL(0, I2C_BUS_LC_OFS + 29, true),
I2C_MUX_CHANNEL(1, I2C_BUS_LC_OFS + 30, true),
I2C_MUX_CHANNEL(2, I2C_BUS_LC_OFS + 62, true),
I2C_MUX_CHANNEL(3, I2C_BUS_LC_OFS + 61, true),
I2C_MUX_CHANNEL(4, I2C_BUS_LC_OFS + 31, true),
I2C_MUX_CHANNEL(5, I2C_BUS_LC_OFS + 32, true),
I2C_MUX_CHANNEL(6, I2C_BUS_LC_OFS + 64, true),
I2C_MUX_CHANNEL(7, I2C_BUS_LC_OFS + 63, true),
};
static struct pca954x_platform_data om_muxes[] = {
{
.modes = i2c_01_mux_70_LC,
.num_modes = ARRAY_SIZE(i2c_01_mux_70_LC),
},
{
.modes = i2c_01_mux_71_LC,
.num_modes = ARRAY_SIZE(i2c_01_mux_71_LC),
},
{
.modes = i2c_01_mux_72_LC,
.num_modes = ARRAY_SIZE(i2c_01_mux_72_LC),
},
{
.modes = i2c_01_mux_73_LC,
.num_modes = ARRAY_SIZE(i2c_01_mux_73_LC),
},
{
.modes = i2c_02_mux_70_LC,
.num_modes = ARRAY_SIZE(i2c_02_mux_70_LC),
},
{
.modes = i2c_02_mux_71_LC,
.num_modes = ARRAY_SIZE(i2c_02_mux_71_LC),
},
{
.modes = i2c_02_mux_72_LC,
.num_modes = ARRAY_SIZE(i2c_02_mux_72_LC),
},
{
.modes = i2c_02_mux_73_LC,
.num_modes = ARRAY_SIZE(i2c_02_mux_73_LC),
},
};
/* Optical Module bus 0-7 i2c muxes info */
static struct i2c_board_info i2c_info1[] = {
{
I2C_BOARD_INFO("pca9548", 0x70),
.platform_data = &om_muxes[0],
},
{
I2C_BOARD_INFO("pca9548", 0x71),
.platform_data = &om_muxes[1],
},
{
I2C_BOARD_INFO("pca9548", 0x72),
.platform_data = &om_muxes[2],
},
{
I2C_BOARD_INFO("pca9548", 0x73),
.platform_data = &om_muxes[3],
},
};
static struct i2c_board_info i2c_info2[] = {
{
I2C_BOARD_INFO("pca9548", 0x70),
.platform_data = &om_muxes[4],
},
{
I2C_BOARD_INFO("pca9548", 0x71),
.platform_data = &om_muxes[5],
},
{
I2C_BOARD_INFO("pca9548", 0x72),
.platform_data = &om_muxes[6],
},
{
I2C_BOARD_INFO("pca9548", 0x73),
.platform_data = &om_muxes[7],
},
};
/* RESOURCE SEPERATES BY FUNCTION */
/* Resource IOMEM for FPGA extened i2c bus 0 */
static struct resource cls_i2c_res_0[] = {
{
.start = 0x00010000, .end = 0x00010FFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for FPGA extened i2c bus 1 */
static struct resource cls_i2c_res_1[] = {
{
.start = 0x00011000, .end = 0x00011FFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for FPGA extened i2c bus 2 */
static struct resource cls_i2c_res_2[] = {
{
.start = 0x00012000, .end = 0x00012FFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for FPGA extened i2c bus 3 */
static struct resource cls_i2c_res_3[] = {
{
.start = 0x00013000, .end = 0x00013FFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for FPGA extened i2c bus 4 */
static struct resource cls_i2c_res_4[] = {
{
.start = 0x00014000, .end = 0x00014FFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for FPGA extened i2c bus 5 */
static struct resource cls_i2c_res_5[] = {
{
.start = 0x00015000, .end = 0x00015FFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for FPGA extened i2c bus 6 */
static struct resource cls_i2c_res_6[] = {
{
.start = 0x00016000, .end = 0x00016FFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for FPGA extened i2c bus 7 */
static struct resource cls_i2c_res_7[] = {
{
.start = 0x00017000, .end = 0x00017FFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for FPGA extened i2c bus 8 */
static struct resource cls_i2c_res_8[] = {
{
.start = 0x00018000, .end = 0x00018FFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for FPGA extened i2c bus 9 */
static struct resource cls_i2c_res_9[] = {
{
.start = 0x00019000, .end = 0x00019FFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for i2c bus 10 */
static struct resource cls_i2c_res_10[] = {
{
.start = 0x0001A000, .end = 0x0001AFFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for i2c bus 11 */
static struct resource cls_i2c_res_11[] = {
{
.start = 0x0001B000, .end = 0x0001BFFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for i2c bus 12 */
static struct resource cls_i2c_res_12[] = {
{
.start = 0x0001C000, .end = 0x0001CFFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for i2c bus 13 */
static struct resource cls_i2c_res_13[] = {
{
.start = 0x0001D000, .end = 0x0001DFFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for front panel XCVR */
static struct resource xcvr_res[] = {
{
.start = 0x00001000, .end = 0x00001FFF,
.flags = IORESOURCE_MEM,},
};
/* Resource IOMEM for front panel XCVR */
static struct resource fpga_res[] = {
{
.start = 0x00000000, .end = 0x01FFFFFF,
.flags = IORESOURCE_MEM,},
};
static struct i2c_bus_config i2c_bus_configs[] = {
{
.id = 0,
.res = cls_i2c_res_0,
.num_res = ARRAY_SIZE(cls_i2c_res_0),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 0,
.devices = NULL,
},
},
{
.id = 1,
.res = cls_i2c_res_1,
.num_res = ARRAY_SIZE(cls_i2c_res_1),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 0,
.devices = NULL,
},
},
{
.id = 2,
.res = cls_i2c_res_2,
.num_res = ARRAY_SIZE(cls_i2c_res_2),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 0,
.devices = NULL,
},
},
{
.id = 3,
.res = cls_i2c_res_3,
.num_res = ARRAY_SIZE(cls_i2c_res_3),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 0,
.devices = NULL,
},
},
{
.id = 4,
.res = cls_i2c_res_4,
.num_res = ARRAY_SIZE(cls_i2c_res_4),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 0,
.devices = NULL,
},
},
{
.id = 5,
.res = cls_i2c_res_5,
.num_res = ARRAY_SIZE(cls_i2c_res_5),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 0,
.devices = NULL,
},
},
{
.id = 6,
.res = cls_i2c_res_6,
.num_res = ARRAY_SIZE(cls_i2c_res_6),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 0,
.devices = NULL,
},
},
{
.id = 7,
.res = cls_i2c_res_7,
.num_res = ARRAY_SIZE(cls_i2c_res_7),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 0,
.devices = NULL,
},
},
{
.id = 8,
.res = cls_i2c_res_8,
.num_res = ARRAY_SIZE(cls_i2c_res_8),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 0,
.devices = NULL,
},
},
{
.id = 9,
.res = cls_i2c_res_9,
.num_res = ARRAY_SIZE(cls_i2c_res_9),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 4,
.devices = i2c_info1,
},
},
{
.id = 10,
.res = cls_i2c_res_10,
.num_res = ARRAY_SIZE(cls_i2c_res_10),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 4,
.devices = i2c_info2,
},
},
{
.id = 11,
.res = cls_i2c_res_11,
.num_res = ARRAY_SIZE(cls_i2c_res_11),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 0,
.devices = NULL,
},
},
{
.id = 12,
.res = cls_i2c_res_12,
.num_res = ARRAY_SIZE(cls_i2c_res_12),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 0,
.devices = NULL,
},
},
{
.id = 13,
.res = cls_i2c_res_13,
.num_res = ARRAY_SIZE(cls_i2c_res_13),
.pdata = {
.reg_shift = OCORE_REGSHIFT,
.reg_io_width = OCORE_REG_IO_WIDTH,
.clock_khz = OCORE_IP_CLK_khz,
.bus_khz = OCORE_BUS_CLK_khz,
.big_endian = false,
.num_devices = 0,
.devices = NULL,
},
},
};
/* xcvr front panel mapping */
static struct port_info front_panel_ports[] = {
{"SFP1", 1, SFP},
{"SFP2", 2, SFP},
/* END OF LIST */
};
static struct cls_xcvr_platform_data xcvr_data[] = {
{
.port_reg_size = 0x0004,
.num_ports = ARRAY_SIZE(front_panel_ports),
.devices = front_panel_ports,
},
};
static struct fpga_info fpga_board_info[] = {
{"FPGA", 1, FPGA}
};
static struct fpga_platform_data fpga_data[] = {
{
.fpga_reg_size = 0x0004,
.num_ports = ARRAY_SIZE(fpga_board_info),
.devices = fpga_board_info,
},
};
//static int fpga_init_index = 0;
// TODO: Add a platform configuration struct, and use probe as a factory,
// so xcvr, fwupgrade device can configured as options.
static int cls_fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int err;
int num_i2c_bus, i = 0, ret, vector;
int bmc_present = 0; /* 0-present 1-absent */
unsigned long rstart;
void __iomem *base_addr;
struct switchbrd_priv *priv;
struct platform_device **i2cbuses_pdev;
//struct platform_device *regio_pdev;
struct platform_device *fpga_pdev;
struct platform_device *xcvr_pdev;
// uint32_t fpga_type;
printk("bus: %x \n",dev->bus->number);
err = pci_enable_device(dev);
if (err){
dev_err(&dev->dev, "Failed to enable PCI device\n");
goto err_exit;
}
pci_set_master(dev);
/* Check for valid MMIO address */
base_addr = pci_iomap(dev, MMIO_BAR, 0);
if (!base_addr) {
dev_err(&dev->dev, "Failed to map PCI device mem\n");
err = -ENODEV;
goto err_disable_device;
}
ret = pci_enable_msi(dev);
if (ret) {
dev_err(&dev->dev, "failed to allocate MSI entry\n");
goto err_unmap;
}
#if 0 /* only one FPGA, so not to judge FPGA TYTE*/
fpga_type = ioread32(base_addr + FPGA_TYPE_ADDR);
printk("fpga Type:0x%8.8x\n",fpga_type);
if (fpga_type == FPGA_CMM_TYPE) {
err = 0;
goto err_exit;
}
#endif
bmc_present = (ioread32(base_addr + FPGA_OTHER_CR_ADDR) >> BMC_PRESENT_BIT) & 0x01;
if (bmc_present == BMC_PRESENT) {
printk("BMC present\n");
} else {
printk("BMC absent\n");
}
rstart = pci_resource_start(dev, MMIO_BAR);
if (!rstart) {
dev_err(&dev->dev, "Switchboard base address uninitialized, "
"check FPGA\n");
err = -ENODEV;
goto err_diable_msi;
}
dev_dbg(&dev->dev, "BAR%d res: 0x%lx-0x%llx\n", MMIO_BAR,
rstart, pci_resource_end(dev, MMIO_BAR));
printk("BAR%d res: 0x%lx-0x%llx\n", MMIO_BAR,
rstart, pci_resource_end(dev, MMIO_BAR));
priv = devm_kzalloc(&dev->dev,
sizeof(struct switchbrd_priv), GFP_KERNEL);
if (!priv){
err = -ENOMEM;
goto err_diable_msi;
}
pci_set_drvdata(dev, priv);
num_i2c_bus = ARRAY_SIZE(i2c_bus_configs);
i2cbuses_pdev = devm_kzalloc(
&dev->dev,
num_i2c_bus * sizeof(struct platform_device*),
GFP_KERNEL);
fpga_res[0].start += rstart;
fpga_res[0].end += rstart;
xcvr_res[0].start += rstart;
xcvr_res[0].end += rstart;
printk("num_i2c_bus = %x,fpga_res start/end %x/%x,restart=%x\n",num_i2c_bus,fpga_res[0].start ,fpga_res[0].end,rstart );
printk("num_i2c_bus = %x,xcvr_res start/end %x/%x,restart=%x\n",num_i2c_bus,xcvr_res[0].start ,xcvr_res[0].end,rstart );
priv->i2c_devname = "ocores-i2c-cls";
priv->xcvr_devname = "cls-xcvr";
priv->fpga_devname = "fpga-board";
fpga_pdev = platform_device_register_resndata(
NULL,
priv->fpga_devname,
-1,
fpga_res,
ARRAY_SIZE(fpga_res),
&fpga_data,
sizeof(fpga_data));
if (IS_ERR(fpga_pdev)) {
dev_err(&dev->dev, "Failed to register fpga node\n");
err = PTR_ERR(fpga_pdev);
goto err_unmap;
}
printk("register fpga node\n");
xcvr_pdev = platform_device_register_resndata(
NULL,
priv->xcvr_devname,
-1,
xcvr_res,
ARRAY_SIZE(xcvr_res),
&xcvr_data,
sizeof(xcvr_data));
if (IS_ERR(xcvr_pdev)) {
dev_err(&dev->dev, "Failed to register xcvr node\n");
err = PTR_ERR(xcvr_pdev);
goto err_unregister_fpga_dev;
}
printk("register xcvr node\n");
if (bmc_present == BMC_PRESENT) {
i += FPGA_EXCLUDE_MIN_BUS; /* skip share bus so there's no dual i2c masters situation */
} else {
i = 0;
}
for(; i < num_i2c_bus; i++){
/* override resource with MEM/IO resource offset */
i2c_bus_configs[i].res[0].start += rstart;
i2c_bus_configs[i].res[0].end += rstart;
/* all fpga i2c bus share pci device msi irq */
i2c_bus_configs[i].pdata.irq = dev->irq;
dev_dbg(&dev->dev, "i2c-bus.%d: 0x%llx - 0x%llx\n",i2c_bus_configs[i].id, i2c_bus_configs[i].res[0].start, i2c_bus_configs[i].res[0].end);
printk("bus id:%d, i2c_bus_configs[%d].res[0].start/end=%x:%x\n", i2c_bus_configs[i].id, i, i2c_bus_configs[i].res[0].start,i2c_bus_configs[i].res[0].end);
switch (i + 1) {
case 1:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_1;
break;
case 2:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_2;
break;
case 3:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_3;
break;
case 4:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_4;
break;
case 5:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_5;
break;
case 6:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_6;
break;
case 7:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_7;
break;
case 8:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_8;
break;
case 9:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_9;
break;
case 10:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_10;
break;
case 11:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_11;
break;
case 12:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_12;
break;
case 13:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_13;
break;
case 14:
i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_14;
break;
default:
i2c_bus_configs[i].pdata.bus_khz = OCORE_BUS_CLK_khz;
}
i2cbuses_pdev[i] = platform_device_register_resndata(
&dev->dev,
priv->i2c_devname,
i2c_bus_configs[i].id,
i2c_bus_configs[i].res,
i2c_bus_configs[i].num_res,
&i2c_bus_configs[i].pdata,
sizeof(i2c_bus_configs[i].pdata));
if (IS_ERR(i2cbuses_pdev[i])) {
dev_err(&dev->dev, "Failed to register ocores-i2c-cls.%d\n",
i2c_bus_configs[i].id);
err = PTR_ERR(i2cbuses_pdev[i]);
goto err_unregister_ocore;
}
}
priv->iomem = base_addr;
priv->base = rstart;
priv->num_i2c_bus = num_i2c_bus;
priv->i2cbuses_pdev = i2cbuses_pdev;
priv->xcvr_pdev = xcvr_pdev;
priv->fpga_pdev = fpga_pdev;
printk("base_addr=%x\n",base_addr);
return 0;
err_unregister_ocore:
for(i = 0; i < num_i2c_bus; i++){
if(priv->i2cbuses_pdev[i]){
platform_device_unregister(priv->i2cbuses_pdev[i]);
}
}
platform_device_unregister(xcvr_pdev);
err_unregister_fpga_dev:
platform_device_unregister(fpga_pdev);
#if 0
err_free_vector:
pci_free_irq_vectors(dev);
#endif
err_diable_msi:
pci_disable_msi(dev);
err_unmap:
pci_iounmap(dev, base_addr);
err_disable_device:
pci_disable_device(dev);
err_exit:
return err;
}
static void cls_fpga_remove(struct pci_dev *dev)
{
int i;
struct switchbrd_priv *priv = pci_get_drvdata(dev);
for(i = 0; i < priv->num_i2c_bus; i++){
if(priv->i2cbuses_pdev[i])
platform_device_unregister(priv->i2cbuses_pdev[i]);
}
platform_device_unregister(priv->xcvr_pdev);
platform_device_unregister(priv->fpga_pdev);
#if 0
pci_free_irq_vectors(dev);
#endif
pci_disable_msi(dev);
pci_iounmap(dev, priv->iomem);
pci_disable_device(dev);
return;
};
static const struct pci_device_id pci_clsswbrd[] = {
{ PCI_VDEVICE(XILINX, FPGA_PCIE_DEVICE_ID) },
{0, }
};
MODULE_DEVICE_TABLE(pci, pci_clsswbrd);
static struct pci_driver cls_pci_driver = {
.name = DRV_NAME,
.id_table = pci_clsswbrd,
.probe = cls_fpga_probe,
.remove = cls_fpga_remove,
};
module_pci_driver(cls_pci_driver);
MODULE_AUTHOR("Nicholas Wu<nicwu@celestica.com>");
MODULE_DESCRIPTION("Celestica Midstone100X switchboard driver");
MODULE_VERSION(MOD_VERSION);
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,318 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* fpga-cls.c - front panel port control.
*
* Pradchaya Phucharoen <pphuchar@celestica.com>
* Copyright (C) 2019 Celestica Corp.
*/
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/hwmon.h>
#include <linux/acpi.h>
#define FPGA_VERSION 0x0000
#define FPGA_SCRATCH 0x0004
#define FPGA_REGISTER_SIZE 0x2000000
/*
* fpga_priv - port fpga private data
* @dev: device for reference
* @base: virtual base address
* @num_ports: number of front panel ports
* @fp_devs: list of front panel port devices
*/
struct fpga_priv {
void __iomem *base;
struct mutex fpga_lock; // For FPGA internal lock
void __iomem * fpga_read_addr;
};
/**
* Show the value of the register set by 'set_fpga_reg_address'
* If the address is not set by 'set_fpga_reg_address' first,
* The version register is selected by default.
* @param buf register value in hextring
* @return number of bytes read, or an error code
*/
static ssize_t get_fpga_reg_value(struct device *dev, struct device_attribute *devattr,
char *buf)
{
// read data from the address
uint32_t data;
struct fpga_priv *fpga = dev_get_drvdata(dev);
data = ioread32(fpga->fpga_read_addr);
return sprintf(buf, "0x%8.8x\n", data);
}
/**
* Store the register address
* @param buf address wanted to be read value of
* @return number of bytes stored, or an error code
*/
static ssize_t set_fpga_reg_address(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
uint32_t addr;
char *last;
struct fpga_priv *fpga = dev_get_drvdata(dev);
addr = (uint32_t)strtoul(buf, &last, 16);
if (addr == 0 && buf == last) {
return -EINVAL;
}
fpga->fpga_read_addr = fpga->base + addr;
return count;
}
/**
* Show value of fpga scratch register
* @param buf register value in hexstring
* @return number of bytes read, or an error code
*/
static ssize_t get_fpga_scratch(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct fpga_priv *fpga = dev_get_drvdata(dev);
return sprintf(buf, "0x%8.8x\n", ioread32(fpga->base + FPGA_SCRATCH) & 0xffffffff);
}
/**
* Store value of fpga scratch register
* @param buf scratch register value passing from user space
* @return number of bytes stored, or an error code
*/
static ssize_t set_fpga_scratch(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
uint32_t data;
char *last;
struct fpga_priv *fpga = dev_get_drvdata(dev);
data = (uint32_t)strtoul(buf, &last, 16);
if (data == 0 && buf == last) {
return -EINVAL;
}
iowrite32(data, fpga->base + FPGA_SCRATCH);
return count;
}
/**
* Show value of fpga version register
* @param buf register value in hexstring
* @return number of bytes read, or an error code
*/
static ssize_t get_fpga_version(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct fpga_priv *fpga = dev_get_drvdata(dev);
return sprintf(buf, "0x%8.8x\n", ioread32(fpga->base + FPGA_VERSION) & 0xffffffff);
}
/**
* Store a value in a specific register address
* @param buf the value and address in format '0xhhhh 0xhhhhhhhh'
* @return number of bytes sent by user space, or an error code
*/
static ssize_t set_fpga_reg_value(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
// register are 4 bytes
uint32_t addr;
uint32_t value;
uint32_t mode = 8;
char *tok;
char clone[count];
char *pclone = clone;
char *last;
struct fpga_priv *fpga = dev_get_drvdata(dev);
strcpy(clone, buf);
mutex_lock(&fpga->fpga_lock);
tok = strsep((char**)&pclone, " ");
if (tok == NULL) {
mutex_unlock(&fpga->fpga_lock);
return -EINVAL;
}
addr = (uint32_t)strtoul(tok, &last, 16);
if (addr == 0 && tok == last) {
mutex_unlock(&fpga->fpga_lock);
return -EINVAL;
}
tok = strsep((char**)&pclone, " ");
if (tok == NULL) {
mutex_unlock(&fpga->fpga_lock);
return -EINVAL;
}
value = (uint32_t)strtoul(tok, &last, 16);
if (value == 0 && tok == last) {
mutex_unlock(&fpga->fpga_lock);
return -EINVAL;
}
tok = strsep((char**)&pclone, " ");
if (tok == NULL) {
mode = 32;
} else {
mode = (uint32_t)strtoul(tok, &last, 10);
if (mode == 0 && tok == last) {
mutex_unlock(&fpga->fpga_lock);
return -EINVAL;
}
}
if (mode == 32) {
iowrite32(value, fpga->base + addr);
} else if (mode == 8) {
iowrite8(value, fpga->base + addr);
} else {
mutex_unlock(&fpga->fpga_lock);
return -EINVAL;
}
mutex_unlock(&fpga->fpga_lock);
return count;
}
/**
* Read all FPGA register in binary mode.
* @param buf Raw transceivers port startus and control register values
* @return number of bytes read, or an error code
*/
static ssize_t dump_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
unsigned long i = 0;
ssize_t status;
u8 read_reg;
struct device *dev = kobj_to_dev(kobj);
struct fpga_priv *fpga = dev_get_drvdata(dev);
if ( off + count > FPGA_REGISTER_SIZE ) {
return -EINVAL;
}
mutex_lock(&fpga->fpga_lock);
while (i < count) {
read_reg = ioread8(fpga->base + off + i);
buf[i++] = read_reg;
}
status = count;
mutex_unlock(&fpga->fpga_lock);
return status;
}
/* FPGA attributes */
static DEVICE_ATTR( getreg, 0600, get_fpga_reg_value, set_fpga_reg_address);
static DEVICE_ATTR( setreg, 0200, NULL , set_fpga_reg_value);
static DEVICE_ATTR( scratch, 0600, get_fpga_scratch, set_fpga_scratch);
static DEVICE_ATTR( version, 0400, get_fpga_version, NULL);
static BIN_ATTR_RO( dump, FPGA_REGISTER_SIZE);
static struct bin_attribute *fpga_bin_attrs[] = {
&bin_attr_dump,
NULL,
};
static struct attribute *fpga_attrs[] = {
&dev_attr_getreg.attr,
&dev_attr_scratch.attr,
&dev_attr_version.attr,
&dev_attr_setreg.attr,
NULL,
};
static struct attribute_group fpga_attr_grp = {
.attrs = fpga_attrs,
.bin_attrs = fpga_bin_attrs,
};
static int cls_fpga_probe(struct platform_device *pdev)
{
struct fpga_priv *fpga;
struct resource *res;
int ret;
fpga = devm_kzalloc(&pdev->dev, sizeof(struct fpga_priv), GFP_KERNEL);
if (!fpga){
ret = -ENOMEM;
goto err_exit;
}
mutex_init(&fpga->fpga_lock);
dev_set_drvdata(&pdev->dev, fpga);
/* mmap resource */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res) {
/* use devm_ioremap_resource to map whole fpga res again will be conflict*/
fpga->base = ioremap_nocache(res->start, res->end - res->start);
if (IS_ERR(fpga->base)){
ret = PTR_ERR(fpga->base);
goto mem_unmap;
}
}
printk("FPGA version: 0x%x\n", ioread32(fpga->base + FPGA_VERSION));
ret = sysfs_create_group(&pdev->dev.kobj, &fpga_attr_grp);
if (ret != 0) {
printk(KERN_ERR "Cannot create FPGA system sysfs attributes\n");
goto err_remove_fpga;
}
return 0;
err_remove_fpga:
sysfs_remove_group(&pdev->dev.kobj, &fpga_attr_grp);
mem_unmap:
iounmap(fpga->base);
err_exit:
return ret;
}
static int cls_fpga_remove(struct platform_device *pdev)
{
struct fpga_priv *fpga = dev_get_drvdata(&pdev->dev);
sysfs_remove_group(&pdev->dev.kobj, &fpga_attr_grp);
iounmap(fpga->base);
return 0;
}
static struct platform_driver cls_fpga_driver = {
.probe = cls_fpga_probe,
.remove = cls_fpga_remove,
.driver = {
.name = "fpga-board",
},
};
static int __init drv_init(void)
{
int rc = 0;
rc = platform_driver_register(&cls_fpga_driver);
return rc;
}
static void __exit drv_exit(void)
{
platform_driver_unregister(&cls_fpga_driver);
}
module_init(drv_init);
module_exit(drv_exit);
MODULE_AUTHOR("Nicholas Wu<nicwu@celestica.com>");
MODULE_DESCRIPTION("Celestica fpga control driver");
MODULE_VERSION("2.0.0");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:cls-fpga");

View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* i2c-ocores.h - definitions for the i2c-ocores interface
*
* Peter Korsgaard <peter@korsgaard.com>
*/
#ifndef _LINUX_I2C_OCORES_H
#define _LINUX_I2C_OCORES_H
struct ocores_i2c_platform_data {
u32 reg_shift; /* register offset shift value */
u32 reg_io_width; /* register io read/write width */
u32 clock_khz; /* input clock in kHz */
u32 bus_khz; /* bus clock in kHz */
bool big_endian; /* registers are big endian */
u8 num_devices; /* number of devices in the devices list */
int irq;
struct i2c_board_info const *devices; /* devices connected to the bus */
};
#endif /* _LINUX_I2C_OCORES_H */

View File

@ -0,0 +1,686 @@
/*
* switchboard.c - Celestica switchboard CPLD I2C driver.
* Copyright (C) 2019 Celestica Corp.
*
* 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.
*/
// TODO: User regmap for more descriptive register access. See MFD
// TODO: Add support of legacy i2c bus and smbus_emulated bus.
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/hwmon.h>
/**
* CPLD register address for read and write.
*/
#define VERSION_ADDR 0x00
#define SCRATCH_ADDR 0x01
#define PORT_LED_MOD_ADDR 0x09
#define PORT_LED_COLOR_ADDR 0x0A
#define PORT_SL_ADDR 0x10
#define PORT_CR_ADDR 0x11
#define PORT_SR_ADDR 0x12
#define PORT_INT_STAT 0x13
#define CTRL_RST 4
#define CTRL_LPMD 0
#define SR_MODPRS 4
#define SR_INTN 0
#define INT_STAT_LOS 0
/* One switchboard CPLD control 16 QSFP ports*/
#define QSFP_PORT_NUM 16
#define SWCPLD1_I2C_ADDR 0x30
#define SWCPLD2_I2C_ADDR 0x31
#define SWCPLD3_I2C_ADDR 0x32
#define SWCPLD4_I2C_ADDR 0x33
#define SWCPLD_NUM 4
/* Private data for switchboard CPLD */
struct switchboard_data {
struct device *sff_parent_dev;
struct device *sff_devices[QSFP_PORT_NUM];
struct regmap *regmap;
struct i2c_client *client;
struct class* class;
uint16_t read_addr;
struct mutex lock;
};
struct sff_device_data{
int portid;
struct i2c_client *client;
struct mutex *lock;
};
/* CPLD attributes */
static ssize_t version_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct switchboard_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
int value;
value = i2c_smbus_read_byte_data(client, VERSION_ADDR);
if(value < 0)
return value;
return sprintf(buf, "%d.%d\n", value >> 4, value & 0x0F);
}
static ssize_t scratch_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct switchboard_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
int value;
value = i2c_smbus_read_byte_data(client, SCRATCH_ADDR);
if(value < 0)
return value;
return sprintf(buf, "0x%.2x\n", value);
}
static ssize_t scratch_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
u8 value;
ssize_t status;
struct switchboard_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
status = kstrtou8(buf, 0, &value);
if(status != 0)
return status;
status = i2c_smbus_write_byte_data(client, SCRATCH_ADDR, value);
if(status == 0)
status = count;
return status;
}
static ssize_t getreg_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
uint16_t addr;
char *last;
struct switchboard_data *data = dev_get_drvdata(dev);
addr = (uint16_t)strtoul(buf,&last,16);
if(addr == 0 && buf == last){
return -EINVAL;
}
data->read_addr = addr;
return count;
}
static ssize_t getreg_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct switchboard_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
int value;
value = i2c_smbus_read_byte_data(client, data->read_addr);
if(value < 0)
return value;
return sprintf(buf, "0x%.2x\n", value);
}
static ssize_t setreg_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
// CPLD register is one byte
uint16_t addr;
uint8_t value;
char *tok;
char clone[count];
char *pclone = clone;
char *last;
struct switchboard_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
strcpy(clone, buf);
mutex_lock(&data->lock);
tok = strsep((char**)&pclone, " ");
if(tok == NULL){
mutex_unlock(&data->lock);
return -EINVAL;
}
addr = (uint16_t)strtoul(tok,&last,16);
if(addr == 0 && tok == last){
mutex_unlock(&data->lock);
return -EINVAL;
}
tok = strsep((char**)&pclone, " ");
if(tok == NULL){
mutex_unlock(&data->lock);
return -EINVAL;
}
value = (uint8_t)strtoul(tok,&last,16);
if(value == 0 && tok == last){
mutex_unlock(&data->lock);
return -EINVAL;
}
i2c_smbus_write_byte_data(client, addr, value);
mutex_unlock(&data->lock);
return count;
}
static ssize_t port_led_mode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct switchboard_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
int value;
value = i2c_smbus_read_byte_data(client, PORT_LED_MOD_ADDR);
if(value < 0)
return value;
value = value & 0x01;
return sprintf(buf, "%s\n",
value == 0x00 ? "normal" : "test");
}
static ssize_t port_led_mode_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned char led_mode;
ssize_t status;
struct switchboard_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
if(sysfs_streq(buf, "normal")){
led_mode = 0x00;
}else if(sysfs_streq(buf, "test")){
led_mode = 0x01;
}else{
count = -EINVAL;
return count;
}
mutex_lock(&data->lock);
status = i2c_smbus_write_byte_data(client, PORT_LED_MOD_ADDR, led_mode);
if(status == 0)
status = count;
mutex_unlock(&data->lock);
return status;
}
static ssize_t port_led_color_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct switchboard_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
int value;
value = i2c_smbus_read_byte_data(client, PORT_LED_COLOR_ADDR);
if(value < 0)
return value;
value = value & 0x07;
return sprintf(buf, "%s\n",
value == 0x00 ? "white" : value == 0x01 ? "yellow" : value == 0x05 ? "green" : value == 0x06 ? "blue" : "off");
}
static ssize_t port_led_color_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned char led_color;
ssize_t status;
struct switchboard_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
if(sysfs_streq(buf, "white")){
led_color = 0x00;
}else if(sysfs_streq(buf, "yellow")){
led_color = 0x01;
}else if(sysfs_streq(buf, "green")){
led_color = 0x05;
}else if(sysfs_streq(buf, "blue")){
led_color = 0x06;
}else if(sysfs_streq(buf, "off")){
led_color = 0x07;
}else{
count = -EINVAL;
return count;
}
mutex_lock(&data->lock);
status = i2c_smbus_write_byte_data(client, PORT_LED_COLOR_ADDR, led_color);
if(status == 0)
status = count;
mutex_unlock(&data->lock);
return status;
}
DEVICE_ATTR_RO(version);
DEVICE_ATTR_RW(scratch);
DEVICE_ATTR_RW(getreg);
DEVICE_ATTR_WO(setreg);
DEVICE_ATTR_RW(port_led_mode);
DEVICE_ATTR_RW(port_led_color);
/* QSPF attributes */
static ssize_t qsfp_reset_show(struct device *dev, struct device_attribute *attr, char *buf)
{
u8 data;
int len = 0;
struct sff_device_data *drvdata = dev_get_drvdata(dev);
struct i2c_client *client = drvdata->client;
u8 portid = drvdata->portid;
mutex_lock(drvdata->lock);
i2c_smbus_write_byte_data(client, PORT_SL_ADDR, portid);
data = i2c_smbus_read_byte_data(client, PORT_CR_ADDR);
len = sprintf(buf, "%x\n",(data >> CTRL_RST) & 0x01);
mutex_unlock(drvdata->lock);
return len;
}
static ssize_t qsfp_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
ssize_t status;
long value;
u8 data;
struct sff_device_data *drvdata = dev_get_drvdata(dev);
struct i2c_client *client = drvdata->client;
u8 portid = drvdata->portid;
mutex_lock(drvdata->lock);
status = kstrtol(buf, 0, &value);
if (status == 0) {
i2c_smbus_write_byte_data(client, PORT_SL_ADDR, portid);
// if value is 0, reset signal is low
data = i2c_smbus_read_byte_data(client, PORT_CR_ADDR);
if (!value)
data = data & ~( (u8)0x1 << CTRL_RST);
else
data = data | ((u8)0x1 << CTRL_RST);
i2c_smbus_write_byte_data(client, PORT_CR_ADDR, data);
status = size;
}
mutex_unlock(drvdata->lock);
return status;
}
static ssize_t qsfp_lpmode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int value;
struct sff_device_data *drvdata = dev_get_drvdata(dev);
struct i2c_client *client = drvdata->client;
u8 portid = drvdata->portid;
mutex_lock(drvdata->lock);
i2c_smbus_write_byte_data(client, PORT_SL_ADDR, portid);
value = i2c_smbus_read_byte_data(client, PORT_CR_ADDR);
if(value < 0)
return value;
mutex_unlock(drvdata->lock);
return sprintf(buf, "%d\n",(value >> CTRL_LPMD) & 0x01);
}
static ssize_t qsfp_lpmode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
ssize_t status;
long value;
u8 data;
struct sff_device_data *drvdata = dev_get_drvdata(dev);
struct i2c_client *client = drvdata->client;
u8 portid = drvdata->portid;
mutex_lock(drvdata->lock);
status = kstrtol(buf, 0, &value);
if (status == 0) {
i2c_smbus_write_byte_data(client, PORT_SL_ADDR, portid);
// if value is 0, reset signal is low
data = i2c_smbus_read_byte_data(client, PORT_CR_ADDR);
if (!value)
data = data & ~( (u8)0x1 << CTRL_LPMD);
else
data = data | ((u8)0x1 << CTRL_LPMD);
i2c_smbus_write_byte_data(client, PORT_CR_ADDR, data);
status = size;
}
mutex_unlock(drvdata->lock);
return status;
}
static ssize_t qsfp_modprs_show(struct device *dev, struct device_attribute *attr, char *buf)
{
u32 data;
int len = 0;
struct sff_device_data *drvdata = dev_get_drvdata(dev);
struct i2c_client *client = drvdata->client;
u8 portid = drvdata->portid;
mutex_lock(drvdata->lock);
i2c_smbus_write_byte_data(client, PORT_SL_ADDR, portid);
data = i2c_smbus_read_byte_data(client, PORT_SR_ADDR);
len = sprintf(buf, "%x\n",(data >> SR_MODPRS) & 0x01);
mutex_unlock(drvdata->lock);
return len;
}
static ssize_t qsfp_modirq_show(struct device *dev, struct device_attribute *attr, char *buf)
{
u32 data;
int len = 0;
struct sff_device_data *drvdata = dev_get_drvdata(dev);
struct i2c_client *client = drvdata->client;
u8 portid = drvdata->portid;
mutex_lock(drvdata->lock);
i2c_smbus_write_byte_data(client, PORT_SL_ADDR, portid);
data = i2c_smbus_read_byte_data(client, PORT_SR_ADDR);
len = sprintf(buf, "%x\n",(data >> SR_INTN) & 0x01);
mutex_unlock(drvdata->lock);
return len;
}
static ssize_t qsfp_modintl_show(struct device *dev, struct device_attribute *attr, char *buf){
u32 data;
int len = 0;
struct sff_device_data *drvdata = dev_get_drvdata(dev);
struct i2c_client *client = drvdata->client;
u8 portid = drvdata->portid;
mutex_lock(drvdata->lock);
i2c_smbus_write_byte_data(client, PORT_SL_ADDR, portid);
data = i2c_smbus_read_byte_data(client, PORT_INT_STAT);
len = sprintf(buf, "%x\n",(data >> INT_STAT_LOS) & 0x01);
mutex_unlock(drvdata->lock);
return len;
}
#if 0
static ssize_t qsfp_modintl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size){
ssize_t status;
long value;
u8 data;
struct sff_device_data *drvdata = dev_get_drvdata(dev);
struct i2c_client *client = drvdata->client;
u8 portid = drvdata->portid;
mutex_lock(&drvdata->lock);
status = kstrtol(buf, 0, &value);
if (status == 0) {
i2c_smbus_write_byte_data(client, PORT_SL_ADDR, portid);
// if value is 0, reset signal is low
data = i2c_smbus_read_byte_data(client, PORT_INT_MASk);
if (!value)
data = data & ~( (u8)0x1 << INT_MASk_LOS);
else
data = data | ((u8)0x1 << INT_MASk_LOS);
i2c_smbus_write_byte_data(client, PORT_INT_MASk, data);
status = size;
}
mutex_unlock(&drvdata->lock);
return status;
}
#endif
DEVICE_ATTR_RW(qsfp_reset);
DEVICE_ATTR_RW(qsfp_lpmode);
DEVICE_ATTR_RO(qsfp_modprs);
DEVICE_ATTR_RO(qsfp_modirq);
DEVICE_ATTR_RO(qsfp_modintl);
static struct attribute *switchboard_attrs[] = {
&dev_attr_version.attr,
&dev_attr_scratch.attr,
&dev_attr_getreg.attr,
&dev_attr_setreg.attr,
&dev_attr_port_led_mode.attr,
&dev_attr_port_led_color.attr,
NULL,
};
static struct attribute *sff_attrs[] = {
&dev_attr_qsfp_modirq.attr,
&dev_attr_qsfp_modprs.attr,
&dev_attr_qsfp_lpmode.attr,
&dev_attr_qsfp_reset.attr,
&dev_attr_qsfp_modintl.attr,
NULL,
};
static struct attribute_group switchboard_attrs_grp = {
.attrs = switchboard_attrs,
};
static struct attribute_group sff_attr_grp = {
.attrs = sff_attrs,
};
static const struct attribute_group *sff_attr_grps[] = {
&sff_attr_grp,
NULL
};
static struct device * cloverstone_dp_sff_init(struct device *dev, int portid) {
struct switchboard_data *data = dev_get_drvdata(dev);
struct sff_device_data *new_data;
struct device *new_device;
int device_id = 0;
char port_map[4][16] = {
{1, 2, 33, 34, 3, 4, 35, 36, 5, 6, 37, 38, 7, 8, 39, 40},
{9, 10, 41, 42, 11, 12, 43, 44, 13, 14, 45, 46, 15, 16, 47, 48},
{17, 18, 49, 50, 19, 20, 51, 52, 21, 22, 53, 54, 23, 24, 55, 56},
{25, 26, 57, 58, 27, 28, 59, 60, 29, 30, 61, 62, 31, 32, 63, 64}
};
new_data = kzalloc(sizeof(*new_data), GFP_KERNEL);
if (!new_data) {
printk(KERN_ALERT "Cannot alloc sff device data @port%d", portid);
return NULL;
}
/* The QSFP port ID start from 1 */
new_data->portid = portid + 1;
new_data->client = data->client;
new_data->lock = &(data->lock);
switch(data->client->addr){
case SWCPLD1_I2C_ADDR:{
device_id = 0;
}
break;
case SWCPLD2_I2C_ADDR:{
device_id = 1;
}
break;
case SWCPLD3_I2C_ADDR:{
device_id = 2;
}
break;
case SWCPLD4_I2C_ADDR:{
device_id = 3;
}
break;
}
/* CPLD1(0x30) control QSFP(1-16) and CPLD1(0x32) control QSFP(17-32) and SFP(1-2) */
new_device = device_create_with_groups(data->class,
NULL,
MKDEV(0, 0),
new_data,
sff_attr_grps,
"%s%d",
"QSFP", port_map[device_id][portid]);
if (IS_ERR(new_device)) {
printk(KERN_ALERT "Cannot create sff device @port%d", port_map[device_id][portid]);
kfree(new_data);
return NULL;
}
printk(KERN_INFO "Create sff device @port%d", port_map[device_id][portid]);
return new_device;
}
static int switchboard_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err, ret = 0;
struct device *dev;
struct switchboard_data *data;
static struct class* class;
u8 portid = 0;
struct sff_device_data *new_data;
dev = &client->dev;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
data = devm_kzalloc(dev, sizeof(struct switchboard_data),
GFP_KERNEL);
if (!data){
err = -ENOMEM;
goto fail_alloc_switchboard_data;
}
dev_set_drvdata(dev, data);
mutex_init(&data->lock);
data->client = client;
/*create CPLD sysfs*/
ret = sysfs_create_group(&dev->kobj, &switchboard_attrs_grp);
if (ret != 0) {
goto fail_alloc_switchboard_data;
}
if (class == NULL){
class = class_create(THIS_MODULE, "SFF");
data->class = class;
if (IS_ERR(data->class)) {
printk(KERN_ALERT "Failed to register device class\n");
err = PTR_ERR(data->class);
goto fail_sysfs_create_group;
}
}else{
data->class = class;
}
/* create 32 QSFP sysfs */
for (portid = 0; portid < QSFP_PORT_NUM; portid++) {
data->sff_devices[portid] = cloverstone_dp_sff_init(dev, portid);
if (IS_ERR(data->sff_devices[portid])){
printk(KERN_ALERT "Failed to register device\n");
err = PTR_ERR(data->sff_devices[portid]);
goto fail_register_sff_device;
}
}
return 0;
fail_register_sff_device:
for (portid = 0; portid < QSFP_PORT_NUM; portid++) {
if (data->sff_devices[portid] != NULL){
new_data = dev_get_drvdata(data->sff_devices[portid]);
device_unregister(data->sff_devices[portid]);
put_device(data->sff_devices[portid]);
kfree(new_data);
}
}
device_destroy(data->class, MKDEV(0, 0));
class_unregister(data->class);
class_destroy(data->class);
fail_sysfs_create_group:
sysfs_remove_group(&dev->kobj, &switchboard_attrs_grp);
fail_alloc_switchboard_data:
return err;
}
static int switchboard_remove(struct i2c_client *client)
{
u8 portid = 0;
struct sff_device_data *new_data;
struct device *dev = &client->dev;
struct switchboard_data *data = dev_get_drvdata(dev);
static u8 index = 1;
for (portid = 0; portid < QSFP_PORT_NUM; portid++) {
if (data->sff_devices[portid] != NULL){
new_data = dev_get_drvdata(data->sff_devices[portid]);
device_unregister(data->sff_devices[portid]);
put_device(data->sff_devices[portid]);
kfree(new_data);
}
}
if (index == SWCPLD_NUM){
device_destroy(data->class, MKDEV(0, 0));
class_unregister(data->class);
class_destroy(data->class);
}
sysfs_remove_group(&dev->kobj, &switchboard_attrs_grp);
index++;
return 0;
}
static const struct i2c_device_id switchboard_ids[] = {
{ "switchboard", 0 },
{ /* END OF List */ }
};
MODULE_DEVICE_TABLE(i2c, switchboard_ids);
struct i2c_driver switchboard_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "switchboard",
.owner = THIS_MODULE,
},
.probe = switchboard_probe,
.remove = switchboard_remove,
.id_table = switchboard_ids,
};
module_i2c_driver(switchboard_driver);
MODULE_AUTHOR("Celestica Inc.");
MODULE_DESCRIPTION("Celestica CPLD switchboard driver");
MODULE_VERSION("2.0.0");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,424 @@
/*
* cpld_b .c - The CPLD driver for the Base Board of cloverstone
* The driver implement sysfs to access CPLD register on the baseboard of cloverstone via LPC bus.
* Copyright (C) 2018 Celestica Corp.
*
* 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 <linux/interrupt.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/dmi.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <uapi/linux/stat.h>
#include <linux/string.h>
#define DRIVER_NAME "sys_cpld"
/**
* CPLD register address for read and write.
*/
#define VERSION_ADDR 0xA100
#define SCRATCH_ADDR 0xA101
#define SYS_LED_ADDR 0xA162
#define CPLD_REGISTER_SIZE 0xFF
struct cpld_b_data {
struct mutex cpld_lock;
uint16_t read_addr;
};
struct cpld_b_data *cpld_data;
/**
* Read the value from scratch register as hex string.
* @param dev kernel device
* @param devattr kernel device attribute
* @param buf buffer for get value
* @return Hex string read from scratch register.
*/
static ssize_t scratch_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
unsigned char data = 0;
mutex_lock(&cpld_data->cpld_lock);
data = inb(SCRATCH_ADDR);
mutex_unlock(&cpld_data->cpld_lock);
return sprintf(buf,"0x%2.2x\n", data);
}
/**
* Set scratch register with specific hex string.
* @param dev kernel device
* @param devattr kernel device attribute
* @param buf buffer of set value
* @param count number of bytes in buffer
* @return number of bytes written, or error code < 0.
*/
static ssize_t scratch_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
unsigned long data;
char *last;
mutex_lock(&cpld_data->cpld_lock);
data = (uint16_t)strtoul(buf,&last,16);
if(data == 0 && buf == last){
mutex_unlock(&cpld_data->cpld_lock);
return -EINVAL;
}
outb(data, SCRATCH_ADDR);
mutex_unlock(&cpld_data->cpld_lock);
return count;
}
static DEVICE_ATTR_RW(scratch);
/* CPLD version attributes */
static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int len = 0;
unsigned char value = 0;
// CPLD register is one byte
mutex_lock(&cpld_data->cpld_lock);
value = inb(VERSION_ADDR);
len = sprintf(buf, "%d.%d\n", value >> 4, value & 0x0F);
mutex_unlock(&cpld_data->cpld_lock);
return len;
}
static DEVICE_ATTR_RO(version);
static ssize_t getreg_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
// CPLD register is one byte
uint16_t addr;
char *last;
addr = (uint16_t)strtoul(buf,&last,16);
if(addr == 0 && buf == last){
return -EINVAL;
}
cpld_data->read_addr = addr;
return count;
}
static ssize_t getreg_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int len = 0;
// CPLD register is one byte
mutex_lock(&cpld_data->cpld_lock);
len = sprintf(buf, "0x%2.2x\n",inb(cpld_data->read_addr));
mutex_unlock(&cpld_data->cpld_lock);
return len;
}
static DEVICE_ATTR_RW(getreg);
static ssize_t setreg_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
// CPLD register is one byte
uint16_t addr;
uint8_t value;
char *tok;
char clone[count];
char *pclone = clone;
char *last;
strcpy(clone, buf);
mutex_lock(&cpld_data->cpld_lock);
tok = strsep((char**)&pclone, " ");
if(tok == NULL){
mutex_unlock(&cpld_data->cpld_lock);
return -EINVAL;
}
addr = (uint16_t)strtoul(tok,&last,16);
if(addr == 0 && tok == last){
mutex_unlock(&cpld_data->cpld_lock);
return -EINVAL;
}
tok = strsep((char**)&pclone, " ");
if(tok == NULL){
mutex_unlock(&cpld_data->cpld_lock);
return -EINVAL;
}
value = (uint8_t)strtoul(tok,&last,16);
if(value == 0 && tok == last){
mutex_unlock(&cpld_data->cpld_lock);
return -EINVAL;
}
outb(value,addr);
mutex_unlock(&cpld_data->cpld_lock);
return count;
}
static DEVICE_ATTR_WO(setreg);
/**
* Read all CPLD register in binary mode.
* @return number of byte read.
*/
static ssize_t dump_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
unsigned long i=0;
ssize_t status;
mutex_lock(&cpld_data->cpld_lock);
begin:
if(i < count){
buf[i++] = inb(VERSION_ADDR + off);
off++;
msleep(1);
goto begin;
}
status = count;
exit:
mutex_unlock(&cpld_data->cpld_lock);
return status;
}
static BIN_ATTR_RO(dump, CPLD_REGISTER_SIZE);
/**
* Show system led status - on/off/1k/4k
* @param dev kernel device
* @param devattr kernel device attribute
* @param buf buffer for get value
* @return Hex string read from scratch register.
*/
static ssize_t sys_led_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
unsigned char data = 0;
mutex_lock(&cpld_data->cpld_lock);
data = inb(SYS_LED_ADDR);
mutex_unlock(&cpld_data->cpld_lock);
data = data & 0x3;
return sprintf(buf, "%s\n",
data == 0x03 ? "off" : data == 0x02 ? "4k" : data ==0x01 ? "1k": "on");
}
/**
* Set the status of system led - on/off/1k/4k
* @param dev kernel device
* @param devattr kernel device attribute
* @param buf buffer of set value
* @param count number of bytes in buffer
* @return number of bytes written, or error code < 0.
*/
static ssize_t sys_led_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
unsigned char led_status,data;
if(sysfs_streq(buf, "off")){
led_status = 0x03;
}else if(sysfs_streq(buf, "4k")){
led_status = 0x02;
}else if(sysfs_streq(buf, "1k")){
led_status = 0x01;
}else if(sysfs_streq(buf, "on")){
led_status = 0x00;
}else{
count = -EINVAL;
return count;
}
mutex_lock(&cpld_data->cpld_lock);
data = inb(SYS_LED_ADDR);
data = data & ~(0x3);
data = data | led_status;
/* if bit[5:4] is not configured to 01(green) or 10(yellow),
led will be off after set this filed */
if(led_status == 0x00 && (0x0 == (data >> 4 & 0x3) || 0x3 == (data >> 4 & 0x3))){
data = data & ~(0x3 << 4);
data = data | (0x01 << 4); /* set bit[5:4] to 01(green) defaultly */
} else if(led_status == 0x01 || led_status == 0x02){
data = data & ~(0x3 << 4); /* set bit[5:4] to 00(blink) defaultly */
}
outb(data, SYS_LED_ADDR);
mutex_unlock(&cpld_data->cpld_lock);
return count;
}
static DEVICE_ATTR_RW(sys_led);
/**
* Show system led color - both/green/yellow/none
* @param dev kernel device
* @param devattr kernel device attribute
* @param buf buffer for get value
* @return Hex string read from scratch register.
*/
static ssize_t sys_led_color_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
unsigned char data = 0;
mutex_lock(&cpld_data->cpld_lock);
data = inb(SYS_LED_ADDR);
mutex_unlock(&cpld_data->cpld_lock);
data = (data >> 4) & 0x3;
return sprintf(buf, "%s\n",
data == 0x03 ? "off" : data == 0x02 ? "yellow" : data ==0x01 ? "green": "both");
}
/**
* Set the color of system led - both/green/yellow/none
* @param dev kernel device
* @param devattr kernel device attribute
* @param buf buffer of set value
* @param count number of bytes in buffer
* @return number of bytes written, or error code < 0.
*/
static ssize_t sys_led_color_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
unsigned char led_status,data;
if(sysfs_streq(buf, "off")){
led_status = 0x03;
}else if(sysfs_streq(buf, "yellow")){
led_status = 0x02;
}else if(sysfs_streq(buf, "green")){
led_status = 0x01;
}else if(sysfs_streq(buf, "both")){
led_status = 0x00;
}else{
count = -EINVAL;
return count;
}
mutex_lock(&cpld_data->cpld_lock);
data = inb(SYS_LED_ADDR);
data = data & ~( 0x3 << 4);
data = data | (led_status << 4);
outb(data, SYS_LED_ADDR);
mutex_unlock(&cpld_data->cpld_lock);
return count;
}
static DEVICE_ATTR_RW(sys_led_color);
static struct attribute *cpld_b_attrs[] = {
&dev_attr_version.attr,
&dev_attr_scratch.attr,
&dev_attr_getreg.attr,
&dev_attr_setreg.attr,
&dev_attr_sys_led.attr,
&dev_attr_sys_led_color.attr,
NULL,
};
static struct bin_attribute *cpld_b_bin_attrs[] = {
&bin_attr_dump,
NULL,
};
static struct attribute_group cpld_b_attrs_grp = {
.attrs = cpld_b_attrs,
.bin_attrs = cpld_b_bin_attrs,
};
static struct resource cpld_b_resources[] = {
{
.start = 0xA100,
.end = 0xA1FF,
.flags = IORESOURCE_IO,
},
};
static void cpld_b_dev_release( struct device * dev)
{
return;
}
static struct platform_device cpld_b_dev = {
.name = DRIVER_NAME,
.id = -1,
.num_resources = ARRAY_SIZE(cpld_b_resources),
.resource = cpld_b_resources,
.dev = {
.release = cpld_b_dev_release,
}
};
static int cpld_b_drv_probe(struct platform_device *pdev)
{
struct resource *res;
int err = 0;
cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct cpld_b_data),
GFP_KERNEL);
if (!cpld_data)
return -ENOMEM;
mutex_init(&cpld_data->cpld_lock);
cpld_data->read_addr = VERSION_ADDR;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (unlikely(!res)) {
printk(KERN_ERR "Specified Resource Not Available...\n");
return -ENODEV;
}
err = sysfs_create_group(&pdev->dev.kobj, &cpld_b_attrs_grp);
if (err) {
printk(KERN_ERR "Cannot create sysfs for baseboard CPLD\n");
return err;
}
return 0;
}
static int cpld_b_drv_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &cpld_b_attrs_grp);
return 0;
}
static struct platform_driver cpld_b_drv = {
.probe = cpld_b_drv_probe,
.remove = __exit_p(cpld_b_drv_remove),
.driver = {
.name = DRIVER_NAME,
},
};
int cpld_b_init(void)
{
// Register platform device and platform driver
platform_device_register(&cpld_b_dev);
platform_driver_register(&cpld_b_drv);
return 0;
}
void cpld_b_exit(void)
{
// Unregister platform device and platform driver
platform_driver_unregister(&cpld_b_drv);
platform_device_unregister(&cpld_b_dev);
}
module_init(cpld_b_init);
module_exit(cpld_b_exit);
MODULE_AUTHOR("Celestica Inc.");
MODULE_DESCRIPTION("LPC CPLD baseboard driver");
MODULE_VERSION("2.0.0");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,174 @@
/*
* mc24lc64t.c - driver for Microchip 24LC64T(TLV Eeprom)
*
* Copyright (C) 2017 Celestica Corp.
*
* 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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#define EEPROM_SIZE 8192 //mc24lt64t eeprom size in bytes.
struct mc24lc64t_data {
struct mutex update_lock;
};
static ssize_t mc24lc64t_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct i2c_client *client = kobj_to_i2c_client(kobj);
struct mc24lc64t_data *drvdata = i2c_get_clientdata(client);
unsigned long timeout, read_time, i = 0;
int status;
mutex_lock(&drvdata->update_lock);
if (i2c_smbus_write_byte_data(client, off>>8, off))
{
status = -EIO;
goto exit;
}
msleep(1);
begin:
if (i < count)
{
timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/
do {
read_time = jiffies;
status = i2c_smbus_read_byte(client);
if (status >= 0)
{
buf[i++] = status;
goto begin;
}
} while (time_before(read_time, timeout));
status = -ETIMEDOUT;
goto exit;
}
status = count;
exit:
mutex_unlock(&drvdata->update_lock);
return status;
}
static ssize_t mc24lc64t_write (struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count){
struct i2c_client *client = kobj_to_i2c_client(kobj);
struct mc24lc64t_data *drvdata = i2c_get_clientdata(client);
unsigned long timeout, write_time, i = 0;
int status;
u16 value;
mutex_lock(&drvdata->update_lock);
begin:
if (i < count){
timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/
value = (buf[i] << 8 | ( off &0xff));
do {
write_time = jiffies;
status = i2c_smbus_write_word_data(client, off>>8, value);
if (status >= 0)
{
// increase offset
off++;
// increase buffer index
i++;
goto begin;
}
} while (time_before(write_time, timeout));
status = -ETIMEDOUT;
goto exit;
}
status = count;
exit:
mutex_unlock(&drvdata->update_lock);
return status;
}
static struct bin_attribute mc24lc64t_bit_attr = {
.attr = {
.name = "eeprom",
.mode = S_IRUGO | S_IWUGO,
},
.size = EEPROM_SIZE,
.read = mc24lc64t_read,
.write = mc24lc64t_write,
};
static int mc24lc64t_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = client->adapter;
struct mc24lc64t_data *drvdata;
int err;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
| I2C_FUNC_SMBUS_READ_BYTE))
return -EPFNOSUPPORT;
if (!(drvdata = devm_kzalloc(&client->dev,
sizeof(struct mc24lc64t_data), GFP_KERNEL)))
return -ENOMEM;
i2c_set_clientdata(client, drvdata);
mutex_init(&drvdata->update_lock);
err = sysfs_create_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr);
return err;
}
static int mc24lc64t_remove(struct i2c_client *client)
{
struct mc24lc64t_data *drvdata = i2c_get_clientdata(client);
sysfs_remove_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr);
return 0;
}
static const struct i2c_device_id mc24lc64t_id[] = {
{ "24lc64t", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mc24lc64t_id);
static struct i2c_driver mc24lc64t_driver = {
.driver = {
.name = "mc24lc64t",
.owner = THIS_MODULE,
},
.probe = mc24lc64t_probe,
.remove = mc24lc64t_remove,
.id_table = mc24lc64t_id,
};
module_i2c_driver(mc24lc64t_driver);
MODULE_AUTHOR("Abhisit Sangjan <asang@celestica.com>");
MODULE_DESCRIPTION("Microchip 24LC64T Driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,85 @@
/*
* mct24lc64_device.c - A driver to read and write the EEPROM
*
* Copyright (C) 2020 Celestica Corp.
*
* 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 Freeoftware Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
**/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/types.h>
#define BUS_MIN 0 // according to the hw spec
#define BUS_MAX 0 // according to the hw spec
#define BUS_NUM (BUS_MAX - BUS_MIN + 1)
/* Optical Module device info */
static struct i2c_board_info i2c_info[] = {
{
I2C_BOARD_INFO("24lc64t", 0x56),
}
};
struct i2c_adapter *adapter[BUS_NUM];
struct i2c_client *client[BUS_NUM];
static int __init mc24lc64t_init(void)
{
int errno = 0;
int i = 0, j = 0;
int busnum = 0;
for( j = 0, i = BUS_MIN; i <= BUS_MAX; i++, j++ ){
adapter[j] = i2c_get_adapter(i);
if (IS_ERR(adapter[j])) {
errno = PTR_ERR(adapter[j]);
goto err_put_adapter_and_client;
}
client[j] = i2c_new_device(adapter[j], i2c_info);
if (IS_ERR(client[j])) {
errno = PTR_ERR(client[j]);
goto err_put_adapter_and_client;
}
}
return 0;
err_put_adapter_and_client:
for( j = 0, i = BUS_MIN; i <= BUS_MAX; i++, j++ ){
if (client[j])
i2c_unregister_device(client[j]);
if (adapter[j])
i2c_put_adapter(adapter[j]);
}
return errno;
}
module_init(mc24lc64t_init);
static void __exit mc24lc64t_exit(void)
{
int i = 0, j = 0;
for( j = 0, i = BUS_MIN; i <= BUS_MAX; i++, j++ ){
if (client[j])
i2c_unregister_device(client[j]);
if (adapter[j])
i2c_put_adapter(adapter[j]);
}
printk("mc24lc64t_exit\n");
}
module_exit(mc24lc64t_exit);
MODULE_DESCRIPTION("Device for mc24lc64t EEPROM");
MODULE_AUTHOR("Nicholas <nic@celestica.com>");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,347 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* xcvr-cls.c - front panel port control.
*
* Pradchaya Phucharoen <pphuchar@celestica.com>
* Copyright (C) 2019 Celestica Corp.
*/
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/hwmon.h>
#include "xcvr-cls.h"
/* FPGA front panel */
#define PORT_STATUS 0x0004
/*
* Port control degister
* LPMOD : active high, RW
* RST : active low, RW
* TXDIS : active high, RW
*/
#define CTRL_TXDISABLE BIT(3)
#define CTRL_TXFAULT BIT(2)
#define CTRL_ABSMOD BIT(1)
#define CTRL_RXLOS BIT(0)
/*
* port_data - optical port data
* @xcvr: xcvr memory accessor
* @name: port name
* @index: front panel port index starting from 1
*/
struct port_data {
struct xcvr_priv *xcvr;
const char *name;
unsigned int index;
};
/*
* xcvr_priv - port xcvr private data
* @dev: device for reference
* @base: virtual base address
* @num_ports: number of front panel ports
* @fp_devs: list of front panel port devices
*/
struct xcvr_priv {
struct device* dev;
void __iomem *base;
int port_reg_size;
int num_ports;
struct device **fp_devs;
};
static inline void port_setreg(struct xcvr_priv *xcvr, int reg, int index, u8 value)
{
return iowrite8(value, xcvr->base + reg + (index - 1) * xcvr->port_reg_size);
}
static inline u8 port_getreg(struct xcvr_priv *xcvr, int reg, int index)
{
return ioread8(xcvr->base + reg + (index - 1) * xcvr->port_reg_size);
}
static ssize_t sfp_txdisable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u8 data;
struct port_data *port_data = dev_get_drvdata(dev);
unsigned int index = port_data->index;
data = port_getreg(port_data->xcvr, PORT_STATUS, index);
return sprintf(buf, "%d\n", (data & CTRL_TXDISABLE)?1:0);
}
static ssize_t sfp_txfault_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u8 data;
struct port_data *port_data = dev_get_drvdata(dev);
unsigned int index = port_data->index;
data = port_getreg(port_data->xcvr, PORT_STATUS, index);
return sprintf(buf, "%d\n", (data & CTRL_TXFAULT)?1:0);
}
static ssize_t sfp_modabs_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u8 data;
struct port_data *port_data = dev_get_drvdata(dev);
unsigned int index = port_data->index;
data = port_getreg(port_data->xcvr, PORT_STATUS, index);
return sprintf(buf, "%d\n", (data & CTRL_ABSMOD)?1:0);
}
static ssize_t sfp_rxlos_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u8 data;
struct port_data *port_data = dev_get_drvdata(dev);
unsigned int index = port_data->index;
data = port_getreg(port_data->xcvr, PORT_STATUS, index);
return sprintf(buf, "%d\n", (data & CTRL_RXLOS)?1:0);
}
static ssize_t sfp_txdisable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
ssize_t status;
long value;
u8 data;
struct port_data *port_data = dev_get_drvdata(dev);
unsigned int index = port_data->index;
status = kstrtol(buf, 0, &value);
if (status == 0) {
data = port_getreg(port_data->xcvr, PORT_STATUS, index);
if (value == 0)
data &= ~CTRL_TXDISABLE;
else
data |= CTRL_TXDISABLE;
port_setreg(port_data->xcvr, PORT_STATUS, index, data);
status = size;
}
return status;
}
DEVICE_ATTR_RO(sfp_modabs);
DEVICE_ATTR_RO(sfp_txfault);
DEVICE_ATTR_RO(sfp_rxlos);
DEVICE_ATTR_RW(sfp_txdisable);
/* sfp_attrs */
static struct attribute *sfp_attrs[] = {
&dev_attr_sfp_modabs.attr,
&dev_attr_sfp_txfault.attr,
&dev_attr_sfp_rxlos.attr,
&dev_attr_sfp_txdisable.attr,
// &dev_attr_interrupt.attr,
// &dev_attr_interrupt_mask.attr,
NULL
};
//ATTRIBUTE_GROUPS(qsfp);
ATTRIBUTE_GROUPS(sfp);
/* A single port device init */
static struct device* init_port(struct device *dev,
struct xcvr_priv *xcvr,
struct port_info info,
const struct attribute_group **groups)
{
struct port_data *new_data;
new_data = devm_kzalloc(dev, sizeof(struct port_data), GFP_KERNEL);
if (!new_data)
return ERR_PTR(-ENOMEM);
new_data->index = info.index;
new_data->name = info.name;
new_data->xcvr = xcvr;
return devm_hwmon_device_register_with_groups(dev,
info.name,
new_data,
groups);
}
static void xcvr_cleanup(struct xcvr_priv *xcvr)
{
struct device *dev;
struct port_data *data;
int i;
for (i = 0; i < xcvr->num_ports; i++){
dev = xcvr->fp_devs[i];
if (dev == NULL)
continue;
data = dev_get_drvdata(dev);
sysfs_remove_link(&xcvr->dev->kobj, data->name);
}
}
static int cls_xcvr_probe(struct platform_device *pdev)
{
struct xcvr_priv *xcvr;
struct cls_xcvr_platform_data *pdata;
struct resource *res;
int ret;
int i;
struct device **port_devs;
xcvr = devm_kzalloc(&pdev->dev, sizeof(struct xcvr_priv), GFP_KERNEL);
if (!xcvr){
ret = -ENOMEM;
goto err_exit;
}
dev_set_drvdata(&pdev->dev, xcvr);
/* mmap resource */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res) {
xcvr->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(xcvr->base)){
ret = PTR_ERR(xcvr->base);
goto err_exit;
}
}
pdata = dev_get_platdata(&pdev->dev);
xcvr->dev = &pdev->dev;
if (pdata) {
/* assign pdata */
xcvr->num_ports = pdata->num_ports;
xcvr->port_reg_size = pdata->port_reg_size;
}
/* alloc front panel device list */
port_devs = devm_kzalloc(&pdev->dev,
xcvr->num_ports * sizeof(struct device*),
GFP_KERNEL);
if (!port_devs){
ret = -ENOMEM;
goto err_exit;
}
if (pdata) {
/* create each device attrs group determined by type */
for (i = 0; i < pdata->num_ports; i++) {
struct device *fp_dev;
// if (pdata->devices[i].type == SFP){
fp_dev = init_port(&pdev->dev,
xcvr,
pdata->devices[i],
sfp_groups);
// }else{
// fp_dev = init_port(&pdev->dev,
// xcvr,
// pdata->devices[i],
// qsfp_groups);
// }
if (IS_ERR(fp_dev)) {
dev_err(&pdev->dev,
"Failed to init port %s\n",
pdata->devices[i].name);
ret = PTR_ERR(fp_dev);
goto dev_clean_up;
}
dev_info(&pdev->dev,
"Register port %s\n",
pdata->devices[i].name);
WARN(sysfs_create_link(&pdev->dev.kobj,
&fp_dev->kobj,
pdata->devices[i].name),
"can't create symlink to %s\n", pdata->devices[i].name);
port_devs[i] = fp_dev;
fp_dev = NULL;
}
xcvr->fp_devs = port_devs;
}
return 0;
dev_clean_up:
xcvr_cleanup(xcvr);
err_exit:
return ret;
}
static int cls_xcvr_remove(struct platform_device *pdev)
{
struct xcvr_priv *xcvr = dev_get_drvdata(&pdev->dev);
xcvr_cleanup(xcvr);
return 0;
}
static struct platform_driver cls_xcvr_driver_lc = {
.probe = cls_xcvr_probe,
.remove = cls_xcvr_remove,
.driver = {
.name = "cls-xcvr",
},
};
#if 0
static struct platform_driver cls_xcvr_driver_lc2 = {
.probe = cls_xcvr_probe,
.remove = cls_xcvr_remove,
.driver = {
.name = "cls-xcvr1",
},
};
#endif
static int __init drv_init(void)
{
int rc = 0;
rc = platform_driver_register(&cls_xcvr_driver_lc);
// rc |= platform_driver_register(&cls_xcvr_driver_lc2);
return rc;
}
static void __exit drv_exit(void)
{
platform_driver_unregister(&cls_xcvr_driver_lc);
// platform_driver_unregister(&cls_xcvr_driver_lc2);
}
module_init(drv_init);
module_exit(drv_exit);
MODULE_AUTHOR("Pradchaya Phucharoen<pphuchar@celestica.com>");
MODULE_DESCRIPTION("Celestica xcvr control driver");
MODULE_VERSION("0.0.1-3");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:cls-xcvr");

View File

@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* xcvr-cls.h
*
* Pradchaya Phucharoen <pphuchar@celestica.com>
* Copyright (C) 2019 Celestica Corp.
*/
#ifndef _LINUX_I2C_CLS_H
#define _LINUX_I2C_CLS_H
enum PORT_TYPE {
NONE = 0,
SFP,
QSFP
};
/*
* port_info - optical port info
* @index: front panel port index starting from 1
* @typr: port type, see *PORT_TYPE*
*/
struct port_info {
const char *name;
unsigned int index;
enum PORT_TYPE type;
};
/*
* cls_xcvr_platform_data - port xcvr private data
* @port_reg_size: register range of each port
* @num_ports: number of front panel ports
* @devices: list of front panel port info
*/
struct cls_xcvr_platform_data {
unsigned int port_reg_size;
int num_ports;
struct port_info *devices;
};
#endif /* _LINUX_I2C_CLS_H */

View File

@ -0,0 +1,319 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* xcvr-cls.c - front panel port control.
*
* Nicholas Wu <nicwu@celestica.com>
* Copyright (C) 2019 Celestica Corp.
*/
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/hwmon.h>
#include "fpga_xcvr.h"
/* FPGA front panel */
#define PORT_TEST 0
#define PORT_CR_STATUS 0x4
/*
* Port control degister
* TXDIS : active high, RW
*/
#define CTRL_TXDIS BIT(3)
/*
* Port status register
* TXFAULT : active high, RO
* RXLOS : active high, RO
* MODABS : active high, RO, for SFP
*/
#define STAT_TXFAULT BIT(2)
#define STAT_MODABS BIT(1)
#define STAT_RXLOS BIT(0)
/*
* port_data - optical port data
* @xcvr: xcvr memory accessor
* @name: port name
* @index: front panel port index starting from 1
*/
struct port_data {
struct xcvr_priv *xcvr;
const char *name;
unsigned int index;
};
/*
* xcvr_priv - port xcvr private data
* @dev: device for reference
* @base: virtual base address
* @num_ports: number of front panel ports
* @fp_devs: list of front panel port devices
*/
struct xcvr_priv {
struct device* dev;
void __iomem *base;
int port_reg_size;
int num_ports;
struct device **fp_devs;
};
static inline void port_setreg(struct xcvr_priv *xcvr, int reg, int index, u8 value)
{
return iowrite8(value, xcvr->base + reg + (index - 1) * xcvr->port_reg_size);
}
static inline u8 port_getreg(struct xcvr_priv *xcvr, int reg, int index)
{
return ioread8(xcvr->base + reg + (index - 1) * xcvr->port_reg_size);
}
static ssize_t sfp_modabs_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u8 data;
struct port_data *port_data = dev_get_drvdata(dev);
unsigned int index = port_data->index;
data = port_getreg(port_data->xcvr, PORT_CR_STATUS, index);
return sprintf(buf, "%d\n", (data & STAT_MODABS)?1:0);
}
static ssize_t sfp_txfault_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u8 data;
struct port_data *port_data = dev_get_drvdata(dev);
unsigned int index = port_data->index;
data = port_getreg(port_data->xcvr, PORT_CR_STATUS, index);
return sprintf(buf, "%d\n", (data & STAT_TXFAULT)?1:0);
}
static ssize_t sfp_rxlos_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u8 data;
struct port_data *port_data = dev_get_drvdata(dev);
unsigned int index = port_data->index;
data = port_getreg(port_data->xcvr, PORT_CR_STATUS, index);
return sprintf(buf, "%d\n", (data & STAT_RXLOS)?1:0);
}
static ssize_t sfp_txdisable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u8 data;
struct port_data *port_data = dev_get_drvdata(dev);
unsigned int index = port_data->index;
data = port_getreg(port_data->xcvr, PORT_CR_STATUS, index);
return sprintf(buf, "%d\n", (data & CTRL_TXDIS)?1:0);
}
static ssize_t sfp_txdisable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
ssize_t status;
long value;
u8 data;
struct port_data *port_data = dev_get_drvdata(dev);
unsigned int index = port_data->index;
status = kstrtol(buf, 0, &value);
if (status == 0) {
data = port_getreg(port_data->xcvr, PORT_CR_STATUS, index);
if (value == 0)
data &= ~CTRL_TXDIS;
else
data |= CTRL_TXDIS;
port_setreg(port_data->xcvr, PORT_CR_STATUS, index, data);
status = size;
}
return status;
}
DEVICE_ATTR_RO(sfp_modabs);
DEVICE_ATTR_RO(sfp_txfault);
DEVICE_ATTR_RO(sfp_rxlos);
DEVICE_ATTR_RW(sfp_txdisable);
/* sfp_attrs */
static struct attribute *sfp_attrs[] = {
&dev_attr_sfp_modabs.attr,
&dev_attr_sfp_txfault.attr,
&dev_attr_sfp_rxlos.attr,
&dev_attr_sfp_txdisable.attr,
NULL
};
ATTRIBUTE_GROUPS(sfp);
/* A single port device init */
static struct device* init_port(struct device *dev,
struct xcvr_priv *xcvr,
struct port_info info,
const struct attribute_group **groups)
{
struct port_data *new_data;
new_data = devm_kzalloc(dev, sizeof(struct port_data), GFP_KERNEL);
if (!new_data)
return ERR_PTR(-ENOMEM);
new_data->index = info.index;
new_data->name = info.name;
new_data->xcvr = xcvr;
return devm_hwmon_device_register_with_groups(dev,
info.name,
new_data,
groups);
}
static void xcvr_cleanup(struct xcvr_priv *xcvr)
{
struct device *dev;
struct port_data *data;
int i;
for (i = 0; i < xcvr->num_ports; i++){
dev = xcvr->fp_devs[i];
if (dev == NULL)
continue;
data = dev_get_drvdata(dev);
sysfs_remove_link(&xcvr->dev->kobj, data->name);
}
}
static int cls_xcvr_probe(struct platform_device *pdev)
{
struct xcvr_priv *xcvr;
struct cls_xcvr_platform_data *pdata;
struct resource *res;
int ret;
int i;
struct device **port_devs;
xcvr = devm_kzalloc(&pdev->dev, sizeof(struct xcvr_priv), GFP_KERNEL);
if (!xcvr){
ret = -ENOMEM;
goto err_exit;
}
dev_set_drvdata(&pdev->dev, xcvr);
/* mmap resource */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res) {
xcvr->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(xcvr->base)){
ret = PTR_ERR(xcvr->base);
goto err_exit;
}
}
pdata = dev_get_platdata(&pdev->dev);
xcvr->dev = &pdev->dev;
if (pdata) {
/* assign pdata */
xcvr->num_ports = pdata->num_ports;
xcvr->port_reg_size = pdata->port_reg_size;
}
/* alloc front panel device list */
port_devs = devm_kzalloc(&pdev->dev,
xcvr->num_ports * sizeof(struct device*),
GFP_KERNEL);
if (!port_devs){
ret = -ENOMEM;
goto err_exit;
}
if (pdata) {
/* create each device attrs group determined by type */
for (i = 0; i < pdata->num_ports; i++) {
struct device *fp_dev;
fp_dev = init_port(&pdev->dev,
xcvr,
pdata->devices[i],
sfp_groups);
if (IS_ERR(fp_dev)) {
dev_err(&pdev->dev,
"Failed to init port %s\n",
pdata->devices[i].name);
ret = PTR_ERR(fp_dev);
goto dev_clean_up;
}
dev_info(&pdev->dev,
"Register port %s\n",
pdata->devices[i].name);
WARN(sysfs_create_link(&pdev->dev.kobj,
&fp_dev->kobj,
pdata->devices[i].name),
"can't create symlink to %s\n", pdata->devices[i].name);
port_devs[i] = fp_dev;
fp_dev = NULL;
}
xcvr->fp_devs = port_devs;
}
return 0;
dev_clean_up:
xcvr_cleanup(xcvr);
err_exit:
return ret;
}
static int cls_xcvr_remove(struct platform_device *pdev)
{
struct xcvr_priv *xcvr = dev_get_drvdata(&pdev->dev);
xcvr_cleanup(xcvr);
return 0;
}
static struct platform_driver cls_xcvr_driver = {
.probe = cls_xcvr_probe,
.remove = cls_xcvr_remove,
.driver = {
.name = "cls-xcvr",
},
};
static int __init drv_init(void)
{
int rc = 0;
rc = platform_driver_register(&cls_xcvr_driver);
return rc;
}
static void __exit drv_exit(void)
{
platform_driver_unregister(&cls_xcvr_driver);
}
module_init(drv_init);
module_exit(drv_exit);
MODULE_AUTHOR("Nicholas Wu<nicwu@celestica.com>");
MODULE_DESCRIPTION("Celestica xcvr control driver");
MODULE_VERSION("2.0.0");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:cls-xcvr");

View File

@ -0,0 +1,173 @@
#!/usr/bin/python
#
# Midstone-100x platform sensors. This script get the sensor data from BMC
# using ipmitool and display them in lm-sensor alike format.
#
# The following data is support:
# 1. Temperature sensors
# 2. PSUs
# 3. Fan trays
import sys
import logging
import subprocess
IPMI_SDR_CMD = "ipmitool sdr elist"
MAX_NUM_FANS = 7
MAX_NUM_PSUS = 2
def ipmi_sensor_dump(cmd):
''' Execute ipmitool command return dump output
exit if any error occur.
'''
sensor_dump = ''
try:
sensor_dump = subprocess.check_output(cmd, shell=True)
except subprocess.CalledProcessError as e:
logging.error('Error! Failed to execute: {}'.format(cmd))
sys.exit(1)
return sensor_dump
def get_reading_by_name(sensor_name, sdr_elist_dump):
'''
Search for the match sensor name, return sensor
reading value and unit, return object epmtry string
if search not match.
The output of sensor dump:
TEMP_FAN_U52 | 00h | ok | 7.1 | 31 degrees C
TEMP_FAN_U17 | 01h | ok | 7.1 | 27 degrees C
TEMP_SW_U52 | 02h | ok | 7.1 | 30 degrees C
Fan2_Status | 07h | ok | 29.2 | Present
Fan2_Front | 0Eh | ok | 29.2 | 12000 RPM
Fan2_Rear | 46h | ok | 29.2 | 14700 RPM
PSU2_Status | 39h | ok | 10.2 | Presence detected
PSU2_Fan | 3Dh | ok | 10.2 | 16000 RPM
PSU2_VIn | 3Ah | ok | 10.2 | 234.30 Volts
PSU2_CIn | 3Bh | ok | 10.2 | 0.80 Amps
'''
found = ''
for line in sdr_elist_dump.split("\n"):
if sensor_name in line:
found = line.strip()
break
if not found:
logging.error('Cannot find sensor name:' + sensor_name)
else:
try:
found = found.split('|')[4]
except IndexError:
logging.error('Cannot get sensor data of:' + sensor_name)
logging.basicConfig(level=logging.DEBUG)
return found
def read_temperature_sensors(ipmi_sdr_elist):
sensor_list = [
('TEMP_FAN_U52', 'Fan Tray Middle Temp'),
('TEMP_FAN_U17', 'Fan Tray Right Temp'),
('TEMP_SW_U52', 'Switchboard Left Inlet Temp'),
('TEMP_SW_U16', 'Switchboard Right Inlet Temp'),
('TEMP_BB_U3', 'Baseboard Temp'),
('TEMP_CPU', 'CPU Internal Temp'),
('TEMP_SW_Internal', 'ASIC Internal Temp'),
('SW_U04_Temp', 'IR3595 Chip Left Temp'),
('SW_U14_Temp', 'IR3595 Chip Right Temp'),
('SW_U4403_Temp', 'IR3584 Chip Temp'),
]
output = ''
sensor_format = '{0:{width}}{1}\n'
# Find max length of sensor calling name
max_name_width = max(len(sensor[1]) for sensor in sensor_list)
output += "Temperature Sensors\n"
output += "Adapter: IPMI adapter\n"
for sensor in sensor_list:
reading = get_reading_by_name(sensor[0],ipmi_sdr_elist)
output += sensor_format.format('{}:'.format(sensor[1]),
reading,
width=str(max_name_width+1))
output += '\n'
return output
def read_fan_sensors(num_fans, ipmi_sdr_elist):
sensor_list = [
('Fan{}_Status', 'Status'),
('Fan{}_Front', 'Fan {} front'),
('Fan{}_Rear', 'Fan {} rear'),
]
output = ''
sensor_format = '{0:{width}}{1}\n'
# Find max length of sensor calling name
max_name_width = max(len(sensor[1]) for sensor in sensor_list)
output += "Fan Trays\n"
output += "Adapter: IPMI adapter\n"
for fan_num in range(1, num_fans+1):
for sensor in sensor_list:
ipmi_sensor_name = sensor[0].format(fan_num)
display_sensor_name = sensor[1].format(fan_num)
reading = get_reading_by_name(ipmi_sensor_name, ipmi_sdr_elist)
output += sensor_format.format('{}:'.format(display_sensor_name),
reading,
width=str(max_name_width+1))
output += '\n'
return output
def read_psu_sensors(num_psus, ipmi_sdr_elist):
sensor_list = [
('PSU{}_Status', 'PSU {} Status'),
('PSU{}_Fan', 'PSU {} Fan'),
('PSU{}_VIn', 'PSU {} Input Voltag'),
('PSU{}_CIn', 'PSU {} Input Current'),
('PSU{}_PIn', 'PSU {} Input Power'),
('PSU{}_Temp1', 'PSU {} Temp1'),
('PSU{}_Temp2', 'PSU {} Temp2'),
('PSU{}_VOut', 'PSU {} Output Voltag'),
('PSU{}_COut', 'PSU {} Output Current'),
('PSU{}_POut', 'PSU {} Output Power'),
]
output = ''
sensor_format = '{0:{width}}{1}\n'
# Find max length of sensor calling name
max_name_width = max(len(sensor[1]) for sensor in sensor_list)
output += "PSU\n"
output += "Adapter: IPMI adapter\n"
for psu_num in range(1, num_psus+1):
for sensor in sensor_list:
ipmi_sensor_name = sensor[0].format(psu_num)
display_sensor_name = sensor[1].format(psu_num)
reading = get_reading_by_name(ipmi_sensor_name, ipmi_sdr_elist)
output += sensor_format.format('{}:'.format(display_sensor_name),
reading,
width=str(max_name_width+1))
output += '\n'
return output
def main():
output_string = ''
ipmi_sdr_elist = ipmi_sensor_dump(IPMI_SDR_CMD)
output_string += read_temperature_sensors(ipmi_sdr_elist)
output_string += read_psu_sensors(MAX_NUM_PSUS, ipmi_sdr_elist)
output_string += read_fan_sensors(MAX_NUM_FANS, ipmi_sdr_elist)
print(output_string)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,11 @@
#!/bin/bash
DOCKER_EXEC_FLAGS="i"
# Determine whether stdout is on a terminal
if [ -t 1 ] ; then
DOCKER_EXEC_FLAGS+="t"
fi
docker exec -$DOCKER_EXEC_FLAGS pmon sensors "$@"
docker exec -$DOCKER_EXEC_FLAGS pmon platform_sensors.py "$@"

View File

@ -0,0 +1,34 @@
from setuptools import setup
DEVICE_NAME = 'celestica'
HW_SKU = 'x86_64-cel_midstone-100x-r0'
setup(
name='sonic-platform',
version='1.0',
description='SONiC platform API implementation on Celestica Platforms',
license='Apache 2.0',
author='SONiC Team',
author_email='linuxnetdev@microsoft.com',
url='https://github.com/Azure/sonic-buildimage',
maintainer='Wirut Getbamrung',
maintainer_email='wgetbumr@celestica.com',
packages=[
'sonic_platform',
],
package_dir={
'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)},
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: Plugins',
'Intended Audience :: Developers',
'Intended Audience :: Information Technology',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: Apache Software License',
'Natural Language :: English',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python :: 2.7',
'Topic :: Utilities',
],
keywords='sonic SONiC platform PLATFORM',
)

View File

@ -0,0 +1,13 @@
[Unit]
Description=Celestica Midstone-100x platform modules
After=local-fs.target
Before=pmon.service
[Service]
Type=oneshot
ExecStart=-/etc/init.d/platform-modules-midstone-100x start
ExecStop=-/etc/init.d/platform-modules-midstone-100x stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,662 @@
#!/bin/bash
#
# Simple script implementing a temperature dependent fan speed control
# Supported Linux kernel versions: 2.6.5 and later
#
# Version 0.70
#
# Usage: fancontrol [CONFIGFILE]
#
# Dependencies:
# bash, egrep, sed, cut, sleep, readlink, lm_sensors :)
#
# Please send any questions, comments or success stories to
# marius.reiner@hdev.de
# Thanks!
#
# For configuration instructions and warnings please see fancontrol.txt, which
# can be found in the doc/ directory or at the website mentioned above.
#
#
# Copyright 2003 Marius Reiner <marius.reiner@hdev.de>
# Copyright (C) 2007-2009 Jean Delvare <khali@linux-fr.org>
#
# 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.
#
#
PIDFILE="/var/run/fancontrol.pid"
THERMAL_OVERLOAD_CONTROL_FILE="/usr/local/bin/thermal_overload_control.sh"
#DEBUG=1
MAX=255
function LoadConfig
{
local fcvcount fcv
echo "Loading configuration from $1 ..."
if [ ! -r "$1" ]
then
echo "Error: Can't read configuration file" >&2
exit 1
fi
# grep configuration from file
INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL=//g'`
DEVPATH=`egrep '^DEVPATH=.*$' $1 | sed -e 's/DEVPATH= *//g'`
DEVNAME=`egrep '^DEVNAME=.*$' $1 | sed -e 's/DEVNAME= *//g'`
FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS=//g'`
MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP=//g'`
MAXTEMP=`egrep '^MAXTEMP=.*$' $1 | sed -e 's/MAXTEMP=//g'`
MINSTART=`egrep '^MINSTART=.*$' $1 | sed -e 's/MINSTART=//g'`
MINSTOP=`egrep '^MINSTOP=.*$' $1 | sed -e 's/MINSTOP=//g'`
# optional settings:
FCFANS=`egrep '^FCFANS=.*$' $1 | sed -e 's/FCFANS=//g'`
MINPWM=`egrep '^MINPWM=.*$' $1 | sed -e 's/MINPWM=//g'`
MAXPWM=`egrep '^MAXPWM=.*$' $1 | sed -e 's/MAXPWM=//g'`
THYST=`egrep '^THYST=.*$' $1 | sed -e 's/THYST=//g'`
MAXTEMPCRIT=`egrep '^MAXTEMPCRIT=.*$' $1 | sed -e 's/MAXTEMPCRIT=//g'`
MAXTEMPTYPE=`egrep '^MAXTEMPTYPE=.*$' $1 | sed -e 's/MAXTEMPTYPE=//g'`
echo
# Check whether all mandatory settings are set
if [[ -z ${INTERVAL} || -z ${FCTEMPS} || -z ${MINTEMP} || -z ${MAXTEMP} || -z ${MINSTART} || -z ${MINSTOP} ]]
then
echo "Some mandatory settings missing, please check your config file!" >&2
exit 1
fi
if [ "$INTERVAL" -le 0 ]
then
echo "Error in configuration file:" >&2
echo "INTERVAL must be at least 1" >&2
exit 1
fi
# write settings to arrays for easier use and print them
echo
echo "Common settings:"
echo " INTERVAL=$INTERVAL"
let fcvcount=0
for fcv in $FCTEMPS
do
if ! echo $fcv | egrep -q '='
then
echo "Error in configuration file:" >&2
echo "FCTEMPS value is improperly formatted" >&2
exit 1
fi
AFCPWM[$fcvcount]=`echo $fcv |cut -d'=' -f1`
AFCTEMP[$fcvcount]=`echo $fcv |cut -d'=' -f2`
AFCFAN[$fcvcount]=`echo $FCFANS |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
AFCFANFAULT[$fcvcount]=`echo "${AFCFAN[$fcvcount]}" |sed -e 's/input/fault/g'`
AFCMINTEMP[$fcvcount]=`echo $MINTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
AFCMAXTEMP[$fcvcount]=`echo $MAXTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
AFCMINSTART[$fcvcount]=`echo $MINSTART |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
AFCMINSTOP[$fcvcount]=`echo $MINSTOP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
AFCMINPWM[$fcvcount]=`echo $MINPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
[ -z "${AFCMINPWM[$fcvcount]}" ] && AFCMINPWM[$fcvcount]=0
AFCMAXPWM[$fcvcount]=`echo $MAXPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
[ -z "${AFCMAXPWM[$fcvcount]}" ] && AFCMAXPWM[$fcvcount]=255
AFCTHYST[$fcvcount]=`echo $THYST |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
[ -z "${AFCTHYST[$fcvcount]}" ] && AFCTHYST[$fcvcount]=0
# verify the validity of the settings
if [ "${AFCMINTEMP[$fcvcount]}" -ge "${AFCMAXTEMP[$fcvcount]}" ]
then
echo "Error in configuration file (${AFCPWM[$fcvcount]}):" >&2
echo "MINTEMP must be less than MAXTEMP" >&2
exit 1
fi
if [ "${AFCMAXPWM[$fcvcount]}" -gt 255 ]
then
echo "Error in configuration file (${AFCPWM[$fcvcount]}):" >&2
echo "MAXPWM must be at most 255" >&2
exit 1
fi
if [ "${AFCMINSTOP[$fcvcount]}" -ge "${AFCMAXPWM[$fcvcount]}" ]
then
echo "Error in configuration file (${AFCPWM[$fcvcount]}):" >&2
echo "MINSTOP must be less than MAXPWM" >&2
exit 1
fi
if [ "${AFCMINSTOP[$fcvcount]}" -lt "${AFCMINPWM[$fcvcount]}" ]
then
echo "Error in configuration file (${AFCPWM[$fcvcount]}):" >&2
echo "MINSTOP must be greater than or equal to MINPWM" >&2
exit 1
fi
if [ "${AFCMINPWM[$fcvcount]}" -lt 0 ]
then
echo "Error in configuration file (${AFCPWM[$fcvcount]}):" >&2
echo "MINPWM must be at least 0" >&2
exit 1
fi
echo
echo "Settings for ${AFCPWM[$fcvcount]}:"
echo " Depends on ${AFCTEMP[$fcvcount]}"
echo " Controls ${AFCFAN[$fcvcount]}"
echo " MINTEMP=${AFCMINTEMP[$fcvcount]}"
echo " MAXTEMP=${AFCMAXTEMP[$fcvcount]}"
echo " MINSTART=${AFCMINSTART[$fcvcount]}"
echo " MINSTOP=${AFCMINSTOP[$fcvcount]}"
echo " MINPWM=${AFCMINPWM[$fcvcount]}"
echo " MAXPWM=${AFCMAXPWM[$fcvcount]}"
echo " THYST=${AFCTHYST[$fcvcount]}"
let fcvcount=fcvcount+1
done
echo
let tscount=0
for ts in $MAXTEMPCRIT
do
CSTEMP[$tscount]=`echo $ts | cut -d '=' -f1`
CSMAXTEMPCRIT[$tscount]=`echo $ts | cut -d '=' -f2`
CSMAXTEMPTYPE=($(echo $MAXTEMPTYPE |sed -e 's/ /\n/g'| cut -d'=' -f2))
echo
echo "Settings for ${CSMAXTEMPTYPE[$tscount]} temperature sensor:"
echo " Depends on ${CSTEMP[$tscount]}"
echo " MAXTEMPCRIT=${CSMAXTEMPCRIT[$tscount]}"
let tscount=tscount+1
done
echo
}
function CheckFanFault()
{
let fancount=0
while (( $fancount < ${#AFCFANFAULT[@]} )) # go through all fan fault.
do
fault=`cat ${AFCFANFAULT[$fancount]}`
if [[ "$fault" == "1" ]]
then
return 1 # fan fault detected
fi
let fancount=$fancount+1
done
return 0
}
function CheckTempOver()
{
let tempcount=0
while (( $tempcount < ${#CSTEMP[@]} )) # go through all temp.
do
ctemp=`cat ${CSTEMP[$tempcount]}`
let maxcrit="${CSMAXTEMPCRIT[$tempcount]}*1000"
if [ $ctemp -ge $maxcrit ]
then
logger "Thermal overload : ${CSMAXTEMPTYPE[$tempcount]} temperature ${ctemp} > ${maxcrit}"
if [ -f "$THERMAL_OVERLOAD_CONTROL_FILE" ]
then
toc_cmd="${THERMAL_OVERLOAD_CONTROL_FILE} ${CSMAXTEMPTYPE[$tempcount],,}"
bash $toc_cmd
exit 1
fi
fi
let tempcount=$tempcount+1
done
return 0
}
function DevicePath()
{
if [ -h "$1/device" ]
then
readlink -f "$1/device" | sed -e 's/^\/sys\///'
fi
}
function DeviceName()
{
if [ -r "$1/name" ]
then
cat "$1/name" | sed -e 's/[[:space:]=]/_/g'
elif [ -r "$1/device/name" ]
then
cat "$1/device/name" | sed -e 's/[[:space:]=]/_/g'
fi
}
function ValidateDevices()
{
local OLD_DEVPATH="$1" OLD_DEVNAME="$2" outdated=0
local entry device name path
for entry in $OLD_DEVPATH
do
device=`echo "$entry" | sed -e 's/=[^=]*$//'`
path=`echo "$entry" | sed -e 's/^[^=]*=//'`
if [ "`DevicePath "$device"`" != "$path" ]
then
echo "Device path of $device has changed" >&2
outdated=1
fi
done
for entry in $OLD_DEVNAME
do
device=`echo "$entry" | sed -e 's/=[^=]*$//'`
name=`echo "$entry" | sed -e 's/^[^=]*=//'`
if [ "`DeviceName "$device"`" != "$name" ]
then
echo "Device name of $device has changed" >&2
outdated=1
fi
done
return $outdated
}
# Check that all referenced sysfs files exist
function CheckFiles
{
local outdated=0 fcvcount pwmo tsen fan
let fcvcount=0
while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
do
pwmo=${AFCPWM[$fcvcount]}
if [ ! -w $pwmo ]
then
echo "Error: file $pwmo doesn't exist" >&2
outdated=1
fi
let fcvcount=$fcvcount+1
done
let fcvcount=0
while (( $fcvcount < ${#AFCTEMP[@]} )) # go through all temp inputs
do
tsen=${AFCTEMP[$fcvcount]}
if [ ! -r $tsen ]
then
echo "Error: file $tsen doesn't exist" >&2
outdated=1
fi
let fcvcount=$fcvcount+1
done
let fcvcount=0
while (( $fcvcount < ${#AFCFAN[@]} )) # go through all fan inputs
do
# A given PWM output can control several fans
for fan in $(echo ${AFCFAN[$fcvcount]} | sed -e 's/+/ /')
do
if [ ! -r $fan ]
then
echo "Error: file $fan doesn't exist" >&2
outdated=1
fi
done
let fcvcount=$fcvcount+1
done
if [ $outdated -eq 1 ]
then
echo >&2
echo "At least one referenced file is missing. Either some required kernel" >&2
echo "modules haven't been loaded, or your configuration file is outdated." >&2
echo "In the latter case, you should run pwmconfig again." >&2
fi
return $outdated
}
if [ "$1" == "--check" ]
then
if [ -f "$2" ]
then
LoadConfig $2
else
LoadConfig /etc/fancontrol
fi
exit 0
fi
if [ -f "$1" ]
then
LoadConfig $1
else
LoadConfig /etc/fancontrol
fi
# Detect path to sensors
if echo "${AFCPWM[0]}" | egrep -q '^/'
then
DIR=/
elif echo "${AFCPWM[0]}" | egrep -q '^hwmon[0-9]'
then
DIR=/sys/class/hwmon
elif echo "${AFCPWM[0]}" | egrep -q '^[1-9]*[0-9]-[0-9abcdef]{4}'
then
DIR=/sys/bus/i2c/devices
else
echo "$0: Invalid path to sensors" >&2
exit 1
fi
if [ ! -d $DIR ]
then
echo $0: 'No sensors found! (did you load the necessary modules?)' >&2
exit 1
fi
cd $DIR
# Check for configuration change
# if [ "$DIR" != "/" ] && [ -z "$DEVPATH" -o -z "$DEVNAME" ]
# then
# echo "Configuration is too old, please run pwmconfig again" >&2
# exit 1
# fi
if [ "$DIR" = "/" -a -n "$DEVPATH" ]
then
echo "Unneeded DEVPATH with absolute device paths" >&2
exit 1
fi
if ! ValidateDevices "$DEVPATH" "$DEVNAME"
then
echo "Configuration appears to be outdated, please run pwmconfig again" >&2
exit 1
fi
CheckFiles || exit 1
if [ -f "$PIDFILE" ]
then
echo "File $PIDFILE exists, is fancontrol already running?" >&2
exit 1
fi
echo $$ > "$PIDFILE"
# $1 = pwm file name
function pwmdisable()
{
local ENABLE=${1}_enable
# No enable file? Just set to max
if [ ! -f $ENABLE ]
then
echo $MAX > $1
return 0
fi
# Try pwmN_enable=0
echo 0 > $ENABLE 2> /dev/null
if [ `cat $ENABLE` -eq 0 ]
then
# Success
echo $MAX > $1
return 0
fi
# It didn't work, try pwmN_enable=1 pwmN=255
echo 1 > $ENABLE 2> /dev/null
echo $MAX > $1
if [ `cat $ENABLE` -eq 1 -a `cat $1` -ge 190 ]
then
# Success
return 0
fi
# Nothing worked
echo "$ENABLE stuck to" `cat $ENABLE` >&2
return 1
}
# $1 = pwm file name
function pwmenable()
{
local ENABLE=${1}_enable
if [ -f $ENABLE ]
then
echo 1 > $ENABLE 2> /dev/null
if [ $? -ne 0 ]
then
return 1
fi
fi
echo $MAX > $1
}
function restorefans()
{
local status=$1 fcvcount pwmo
echo 'Aborting, restoring fans...'
let fcvcount=0
while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
do
pwmo=${AFCPWM[$fcvcount]}
pwmdisable $pwmo
let fcvcount=$fcvcount+1
done
echo 'Verify fans have returned to full speed'
rm -f "$PIDFILE"
exit $status
}
trap 'restorefans 0' SIGQUIT SIGTERM
trap 'restorefans 1' SIGHUP SIGINT
function upperBound
{
# $1: temperature
# $2: Tmin
# $3: Tmax
# $4: MinPWM
# $5: MaxPWM
# $6 Thyst
# upper_bound = (temperature-Tmin+2) * (MaxPWM-MinPWM)/(Tmax-Tmin)+MinPWM
let a="($1-$2+$6)*($5-$4)/($3-$2)+$4"
up_b=$a
}
function lowerBound
{
# $1: temperature
# $2: Tmin
# $3: Tmax
# $4: MinPWM
# $5: MaxPWM
# $6 Thyst
# lower_bound = (temperature-Tmin) *(MaxPWM-MinPWM)/(Tmax-Tmin)+MinPWM
let a="($1-$2)*($5-$4)/($3-$2)+$4"
lw_b=$a
}
# main function
function UpdateFanSpeeds
{
local fcvcount
local pwmo tsens fan mint maxt minsa minso minpwm maxpwm tHyst
local tval pwmpval fanval min_fanval one_fan one_fanval
local -i pwmval
let fcvcount=0
while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
do
#hopefully shorter vars will improve readability:
pwmo=${AFCPWM[$fcvcount]}
tsens=${AFCTEMP[$fcvcount]}
fan=${AFCFAN[$fcvcount]}
let mint="${AFCMINTEMP[$fcvcount]}*1000"
let maxt="${AFCMAXTEMP[$fcvcount]}*1000"
minsa=${AFCMINSTART[$fcvcount]}
minso=${AFCMINSTOP[$fcvcount]}
minpwm=${AFCMINPWM[$fcvcount]}
maxpwm=${AFCMAXPWM[$fcvcount]}
let tHyst="${AFCTHYST[$fcvcount]}*1000"
#if some fan fault detected all pwm=100%
CheckFanFault
if [ $? -ne 0 ]
then
echo $MAX > $pwmo
let fcvcount=$fcvcount+1
continue
fi
#check thermal overload
CheckTempOver
read tval < ${tsens}
if [ $? -ne 0 ]
then
echo "Error reading temperature from $DIR/$tsens"
restorefans 1
fi
read pwmpval < ${pwmo}
if [ $? -ne 0 ]
then
echo "Error reading PWM value from $DIR/$pwmo"
restorefans 1
fi
# If fanspeed-sensor output shall be used, do it
if [[ -n ${fan} ]]
then
min_fanval=100000
fanval=
# A given PWM output can control several fans
for one_fan in $(echo $fan | sed -e 's/+/ /')
do
read one_fanval < ${one_fan}
if [ $? -ne 0 ]
then
echo "Error reading Fan value from $DIR/$one_fan" >&2
restorefans 1
fi
# Remember the minimum, it only matters if it is 0
if [ $one_fanval -lt $min_fanval ]
then
min_fanval=$one_fanval
fi
if [ -z "$fanval" ]
then
fanval=$one_fanval
else
fanval="$fanval/$one_fanval"
fi
done
else
fanval=1 # set it to a non zero value, so the rest of the script still works
fi
# debug info
if [ "$DEBUG" != "" ]
then
echo "pwmo=$pwmo"
echo "tsens=$tsens"
echo "fan=$fan"
echo "mint=$mint"
echo "maxt=$maxt"
echo "minsa=$minsa"
echo "minso=$minso"
echo "minpwm=$minpwm"
echo "maxpwm=$maxpwm"
echo "tval=$tval"
echo "pwmpval=$pwmpval"
echo "fanval=$fanval"
echo "min_fanval=$min_fanval"
echo "tHyst=$tHyst"
fi
pwmval=$pwmpval
if (( $tval+$tHyst <= $mint ))
then pwmval=$minpwm # below min temp, use defined min pwm
elif (( $tval >= $maxt ))
then pwmval=$maxpwm # over max temp, use defined max pwm
elif (( $tval+$tHyst >= $maxt )) && (( $pwmpval == $maxpwm ))
then pwmval=$maxpwm
else
# calculate the new value from temperature and settings
# pwmval="(${tval}-${mint})*(${maxpwm}-${minso})/(${maxt}-${mint})+${minso}
lowerBound ${tval} ${mint} ${maxt} ${minpwm} ${maxpwm} ${tHyst}
lb=$lw_b
upperBound ${tval} ${mint} ${maxt} ${minpwm} ${maxpwm} ${tHyst}
ub=$up_b
if [ "$DEBUG" != "" ]
then
echo "old pwm=$pwmval lw_b=$lw_b up_b=$up_b"
fi
if [[ "$pwmval" -gt "$ub" ]]
then
pwmval=$ub
else
if [[ "$pwmval" -lt "$lb" ]]
then
pwmval=$lb
fi
fi
if [ $pwmpval -eq 0 -o $min_fanval -eq 0 ]
then # if fan was stopped start it using a safe value
echo $minsa > $pwmo
# Sleep while still handling signals
sleep 1 &
wait $!
fi
fi
echo $pwmval > $pwmo # write new value to pwm output
if [ $? -ne 0 ]
then
echo "Error writing PWM value to $DIR/$pwmo" >&2
restorefans 1
fi
if [ "$DEBUG" != "" ]
then
echo "new pwmval=$pwmval"
fi
let fcvcount=$fcvcount+1
done
}
echo 'Enabling PWM on fans...'
let fcvcount=0
while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
do
pwmo=${AFCPWM[$fcvcount]}
pwmenable $pwmo
if [ $? -ne 0 ]
then
echo "Error enabling PWM on $DIR/$pwmo" >&2
restorefans 1
fi
let fcvcount=$fcvcount+1
done
echo 'Starting automatic fan control...'
# main loop calling the main function at specified intervals
while true
do
UpdateFanSpeeds
# Sleep while still handling signals
sleep $INTERVAL &
wait $!
done

View File

@ -0,0 +1,41 @@
#!/bin/bash
PREV_REBOOT_CAUSE="/host/reboot-cause/"
DEVICE="/usr/share/sonic/device"
PLATFORM=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
FILES=$DEVICE/$PLATFORM/api_files
install() {
# Install sonic-platform package
if [ -e $DEVICE/$PLATFORM/sonic_platform-1.0-py2-none-any.whl ]; then
pip install $DEVICE/$PLATFORM/sonic_platform-1.0-py2-none-any.whl
fi
}
init() {
# mount needed files for sonic-platform package
mkdir -p $FILES
mkdir -p $FILES/reboot-cause
mount -B $PREV_REBOOT_CAUSE $FILES/reboot-cause
}
deinit() {
# deinit sonic-platform package
umount -f $PREV_REBOOT_CAUSE $FILES/reboot-cause >/dev/null 2>/dev/null
}
uninstall() {
# Uninstall sonic-platform package
pip uninstall -y sonic-platform >/dev/null 2>/dev/null
}
case "$1" in
install | uninstall | init | deinit)
$1
;;
*)
echo "Usage: $0 {install|uninstall|init|deinit}"
exit 1
;;
esac