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:
parent
6ea65056b9
commit
78c6ae112b
@ -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]"
|
||||
}
|
||||
}
|
||||
}
|
@ -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]"
|
||||
}
|
||||
}
|
||||
}
|
@ -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]"
|
||||
}
|
||||
}
|
||||
}
|
@ -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"
|
@ -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
|
@ -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
|
@ -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"
|
@ -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"
|
@ -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
|
@ -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
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
@ -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]"
|
||||
}
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/ivm.sai.config.yaml
|
1
device/celestica/x86_64-cel_midstone-100x-r0/default_sku
Normal file
1
device/celestica/x86_64-cel_midstone-100x-r0/default_sku
Normal file
@ -0,0 +1 @@
|
||||
Midstone-100x t1
|
@ -0,0 +1 @@
|
||||
CONSOLE_SPEED=115200
|
@ -0,0 +1,19 @@
|
||||
{
|
||||
"chassis": {
|
||||
"Midstone-100x": {
|
||||
"component": {
|
||||
"FPGA": {},
|
||||
"SYSCPLD": {},
|
||||
"SWCPLD1": {},
|
||||
"SWCPLD2": {},
|
||||
"SWCPLD3": {},
|
||||
"SWCPLD4": {},
|
||||
"Main_BIOS": {},
|
||||
"Backup_BIOS": {},
|
||||
"Main_BMC": {},
|
||||
"Backup_BMC": {},
|
||||
"COMeCPLD": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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
|
194
device/celestica/x86_64-cel_midstone-100x-r0/plugins/sfputil.py
Normal file
194
device/celestica/x86_64-cel_midstone-100x-r0/plugins/sfputil.py
Normal 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
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"skip_ledd": true
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
__all__ = ["platform", "chassis"]
|
||||
from sonic_platform import *
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.")
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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()
|
@ -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
|
1358
device/celestica/x86_64-cel_midstone-100x-r0/sonic_platform/sfp.py
Normal file
1358
device/celestica/x86_64-cel_midstone-100x-r0/sonic_platform/sfp.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -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)
|
@ -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
|
@ -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
|
@ -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))
|
@ -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
|
1
device/celestica/x86_64-cel_midstone-100x-r0/topo.conf
Normal file
1
device/celestica/x86_64-cel_midstone-100x-r0/topo.conf
Normal file
@ -0,0 +1 @@
|
||||
t1
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
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)
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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 */
|
@ -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");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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");
|
||||
|
@ -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 */
|
||||
|
@ -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");
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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
@ -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");
|
||||
|
@ -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 */
|
@ -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");
|
||||
|
@ -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()
|
@ -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 "$@"
|
@ -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',
|
||||
)
|
@ -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
|
@ -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
|
@ -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
|
Reference in New Issue
Block a user