Merge 3458f59b2c
into 610685d27b
This commit is contained in:
commit
105b464c56
@ -0,0 +1,4 @@
|
||||
CONSOLE_PORT=0x3f8
|
||||
CONSOLE_DEV=0
|
||||
CONSOLE_SPEED=115200
|
||||
ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="pcie_aspm=off intel_iommu=off modprobe.blacklist=i2c-ismt,i2c_ismt,i2c-i801,i2c_i801"
|
167
device/accton/x86_64-accton_as4630_54npe-r0/pcie.yaml
Normal file
167
device/accton/x86_64-accton_as4630_54npe-r0/pcie.yaml
Normal file
@ -0,0 +1,167 @@
|
||||
- bus: '00'
|
||||
dev: '00'
|
||||
fn: '0'
|
||||
id: '1980'
|
||||
name: 'Host bridge: Intel Corporation Atom Processor C3000 Series System Agent (rev
|
||||
11)'
|
||||
- bus: '00'
|
||||
dev: '04'
|
||||
fn: '0'
|
||||
id: 19a1
|
||||
name: 'Host bridge: Intel Corporation Atom Processor C3000 Series Error Registers
|
||||
(rev 11)'
|
||||
- bus: '00'
|
||||
dev: '05'
|
||||
fn: '0'
|
||||
id: 19a2
|
||||
name: 'Generic system peripheral [0807]: Intel Corporation Atom Processor C3000
|
||||
Series Root Complex Event Collector (rev 11)'
|
||||
- bus: '00'
|
||||
dev: '06'
|
||||
fn: '0'
|
||||
id: 19a3
|
||||
name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series Integrated QAT
|
||||
Root Port (rev 11)'
|
||||
- bus: '00'
|
||||
dev: 09
|
||||
fn: '0'
|
||||
id: 19a4
|
||||
name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series PCI Express Root
|
||||
Port #0 (rev 11)'
|
||||
- bus: '00'
|
||||
dev: 0b
|
||||
fn: '0'
|
||||
id: 19a6
|
||||
name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series PCI Express Root
|
||||
Port #2 (rev 11)'
|
||||
- bus: '00'
|
||||
dev: 0e
|
||||
fn: '0'
|
||||
id: 19a8
|
||||
name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series PCI Express Root
|
||||
Port #4 (rev 11)'
|
||||
- bus: '00'
|
||||
dev: '10'
|
||||
fn: '0'
|
||||
id: 19aa
|
||||
name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series PCI Express Root
|
||||
Port #6 (rev 11)'
|
||||
- bus: '00'
|
||||
dev: '12'
|
||||
fn: '0'
|
||||
id: 19ac
|
||||
name: 'System peripheral: Intel Corporation Atom Processor C3000 Series SMBus Contoller
|
||||
- Host (rev 11)'
|
||||
- bus: '00'
|
||||
dev: '13'
|
||||
fn: '0'
|
||||
id: 19b2
|
||||
name: 'SATA controller: Intel Corporation Atom Processor C3000 Series SATA Controller
|
||||
0 (rev 11)'
|
||||
- bus: '00'
|
||||
dev: '15'
|
||||
fn: '0'
|
||||
id: 19d0
|
||||
name: 'USB controller: Intel Corporation Atom Processor C3000 Series USB 3.0 xHCI
|
||||
Controller (rev 11)'
|
||||
- bus: '00'
|
||||
dev: '16'
|
||||
fn: '0'
|
||||
id: 19d1
|
||||
name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series Integrated LAN
|
||||
Root Port #0 (rev 11)'
|
||||
- bus: '00'
|
||||
dev: '17'
|
||||
fn: '0'
|
||||
id: 19d2
|
||||
name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series Integrated LAN
|
||||
Root Port #1 (rev 11)'
|
||||
- bus: '00'
|
||||
dev: '18'
|
||||
fn: '0'
|
||||
id: 19d3
|
||||
name: 'Communication controller: Intel Corporation Atom Processor C3000 Series ME
|
||||
HECI 1 (rev 11)'
|
||||
- bus: '00'
|
||||
dev: 1a
|
||||
fn: '0'
|
||||
id: 19d8
|
||||
name: 'Serial controller: Intel Corporation Atom Processor C3000 Series HSUART Controller
|
||||
(rev 11)'
|
||||
- bus: '00'
|
||||
dev: 1a
|
||||
fn: '1'
|
||||
id: 19d8
|
||||
name: 'Serial controller: Intel Corporation Atom Processor C3000 Series HSUART Controller
|
||||
(rev 11)'
|
||||
- bus: '00'
|
||||
dev: 1a
|
||||
fn: '2'
|
||||
id: 19d8
|
||||
name: 'Serial controller: Intel Corporation Atom Processor C3000 Series HSUART Controller
|
||||
(rev 11)'
|
||||
- bus: '00'
|
||||
dev: 1c
|
||||
fn: '0'
|
||||
id: 19db
|
||||
name: 'SD Host controller: Intel Corporation Device 19db (rev 11)'
|
||||
- bus: '00'
|
||||
dev: 1f
|
||||
fn: '0'
|
||||
id: 19dc
|
||||
name: 'ISA bridge: Intel Corporation Atom Processor C3000 Series LPC or eSPI (rev
|
||||
11)'
|
||||
- bus: '00'
|
||||
dev: 1f
|
||||
fn: '1'
|
||||
id: 19dd
|
||||
name: 'Memory controller: Intel Corporation Atom Processor C3000 Series Primary
|
||||
to Side Band (P2SB) Bridge (rev 11)'
|
||||
- bus: '00'
|
||||
dev: 1f
|
||||
fn: '2'
|
||||
id: 19de
|
||||
name: 'Memory controller: Intel Corporation Atom Processor C3000 Series Power Management
|
||||
Controller (rev 11)'
|
||||
- bus: '00'
|
||||
dev: 1f
|
||||
fn: '4'
|
||||
id: 19df
|
||||
name: 'SMBus: Intel Corporation Atom Processor C3000 Series SMBus controller (rev
|
||||
11)'
|
||||
- bus: '00'
|
||||
dev: 1f
|
||||
fn: '5'
|
||||
id: 19e0
|
||||
name: 'Serial bus controller [0c80]: Intel Corporation Atom Processor C3000 Series
|
||||
SPI Controller (rev 11)'
|
||||
- bus: '01'
|
||||
dev: '00'
|
||||
fn: '0'
|
||||
id: 19e2
|
||||
name: 'Co-processor: Intel Corporation Atom Processor C3000 Series QuickAssist Technology
|
||||
(rev 11)'
|
||||
- bus: '05'
|
||||
dev: '00'
|
||||
fn: '0'
|
||||
id: b370
|
||||
name: 'Ethernet controller: Broadcom Inc. and subsidiaries BCM56370 Switch ASIC
|
||||
(rev 03)'
|
||||
- bus: '06'
|
||||
dev: '00'
|
||||
fn: '0'
|
||||
id: 15c2
|
||||
name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 Backplane
|
||||
(rev 11)'
|
||||
- bus: '06'
|
||||
dev: '00'
|
||||
fn: '1'
|
||||
id: 15c2
|
||||
name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 Backplane
|
||||
(rev 11)'
|
||||
- bus: 08
|
||||
dev: '00'
|
||||
fn: '0'
|
||||
id: 15e5
|
||||
name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 1GbE (rev
|
||||
11)'
|
788
device/accton/x86_64-accton_as4630_54npe-r0/platform.json
Normal file
788
device/accton/x86_64-accton_as4630_54npe-r0/platform.json
Normal file
@ -0,0 +1,788 @@
|
||||
{
|
||||
"chassis": {
|
||||
"name": "4630-54NPE",
|
||||
"thermal_manager":false,
|
||||
"status_led": {
|
||||
"controllable": true,
|
||||
"colors": ["STATUS_LED_COLOR_GREEN", "STATUS_LED_COLOR_GREEN_BLINK", "STATUS_LED_COLOR_AMBER", "STATUS_LED_COLOR_OFF"]
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"name": "CPLD1"
|
||||
},
|
||||
{
|
||||
"name": "CPLD2"
|
||||
},
|
||||
{
|
||||
"name": "BIOS"
|
||||
}
|
||||
],
|
||||
"fans": [
|
||||
{
|
||||
"name": "FAN-1",
|
||||
"speed": {
|
||||
"controllable": true,
|
||||
"minimum": 7
|
||||
},
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FAN-2",
|
||||
"speed": {
|
||||
"controllable": true,
|
||||
"minimum": 7
|
||||
},
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FAN-3",
|
||||
"speed": {
|
||||
"controllable": true,
|
||||
"minimum": 7
|
||||
},
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"fan_drawers":[
|
||||
{
|
||||
"name": "FanTray1",
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
},
|
||||
"num_fans" : 1,
|
||||
"fans": [
|
||||
{
|
||||
"name": "FAN-1",
|
||||
"speed": {
|
||||
"controllable": true,
|
||||
"minimum": 7
|
||||
},
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "FanTray2",
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
},
|
||||
"num_fans" : 1,
|
||||
"fans": [
|
||||
{
|
||||
"name": "FAN-2",
|
||||
"speed": {
|
||||
"controllable": true,
|
||||
"minimum": 7
|
||||
},
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
}
|
||||
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "FanTray3",
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
},
|
||||
"num_fans" : 1,
|
||||
"fans": [
|
||||
{
|
||||
"name": "FAN-3",
|
||||
"speed": {
|
||||
"controllable": true,
|
||||
"minimum": 7
|
||||
},
|
||||
"status_led": {
|
||||
"controllable": false
|
||||
}
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"psus": [
|
||||
{
|
||||
"name": "PSU-1",
|
||||
"status_led": {
|
||||
"controllable": true,
|
||||
"colors": ["STATUS_LED_COLOR_GREEN", "STATUS_LED_COLOR_AMBER", "STATUS_LED_COLOR_OFF"]
|
||||
},
|
||||
"fans": [
|
||||
{
|
||||
"name": "PSU-1 FAN-1"
|
||||
}
|
||||
],
|
||||
"thermals": [
|
||||
{
|
||||
"name": "PSU-1 temp sensor 1",
|
||||
"controllable": false,
|
||||
"low-crit-threshold": false,
|
||||
"high-crit-threshold": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PSU-2",
|
||||
"status_led": {
|
||||
"controllable": true,
|
||||
"colors": ["STATUS_LED_COLOR_GREEN", "STATUS_LED_COLOR_AMBER", "STATUS_LED_COLOR_OFF"]
|
||||
},
|
||||
"fans": [
|
||||
{
|
||||
"name": "PSU-2 FAN-1"
|
||||
}
|
||||
],
|
||||
"thermals": [
|
||||
{
|
||||
"name": "PSU-2 temp sensor 1",
|
||||
"controllable": false,
|
||||
"low-crit-threshold": false,
|
||||
"high-crit-threshold": false
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"thermals": [
|
||||
{
|
||||
"name": "Temp sensor 1",
|
||||
"controllable": true,
|
||||
"low-threshold": false,
|
||||
"high-threshold": true,
|
||||
"low-crit-threshold": false,
|
||||
"high-crit-threshold": false
|
||||
},
|
||||
{
|
||||
"name": "Temp sensor 2",
|
||||
"controllable": true,
|
||||
"low-threshold": false,
|
||||
"high-threshold": true,
|
||||
"low-crit-threshold": false,
|
||||
"high-crit-threshold": false
|
||||
},
|
||||
{
|
||||
"name": "Temp sensor 3",
|
||||
"controllable": true,
|
||||
"low-threshold": false,
|
||||
"high-threshold": true,
|
||||
"low-crit-threshold": false,
|
||||
"high-crit-threshold": false
|
||||
},
|
||||
{
|
||||
"name": "Temp sensor 4",
|
||||
"controllable": false,
|
||||
"low-threshold": false,
|
||||
"high-threshold": true,
|
||||
"low-crit-threshold": false,
|
||||
"high-crit-threshold": true
|
||||
}
|
||||
],
|
||||
"sfps": [
|
||||
{
|
||||
"name": "Ethernet0"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet1"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet2"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet3"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet4"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet5"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet6"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet7"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet8"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet9"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet10"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet11"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet12"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet13"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet14"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet15"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet16"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet17"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet18"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet19"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet20"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet21"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet22"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet23"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet24"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet25"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet26"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet27"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet28"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet29"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet30"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet31"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet32"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet33"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet34"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet35"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet36"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet37"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet38"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet39"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet40"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet41"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet42"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet43"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet44"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet45"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet46"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet47"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet48"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet49"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet50"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet51"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet52"
|
||||
},
|
||||
{
|
||||
"name": "Ethernet56"
|
||||
}
|
||||
]
|
||||
},
|
||||
"interfaces": {
|
||||
"Ethernet0": {
|
||||
"index": "1",
|
||||
"lanes": "2",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth1(Port1)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet1": {
|
||||
"index": "2",
|
||||
"lanes": "1",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth2(Port2)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet2": {
|
||||
"index": "3",
|
||||
"lanes": "4",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth3(Port3)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet3": {
|
||||
"index": "4",
|
||||
"lanes": "3",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth4(Port4)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet4": {
|
||||
"index": "5",
|
||||
"lanes": "6",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth5(Port5)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet5": {
|
||||
"index": "6",
|
||||
"lanes": "5",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth6(Port6)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet6": {
|
||||
"index": "7",
|
||||
"lanes": "8",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth7(Port7)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet7": {
|
||||
"index": "8",
|
||||
"lanes": "7",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth8(Port8)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet8": {
|
||||
"index": "9",
|
||||
"lanes": "10",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth9(Port9)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet9": {
|
||||
"index": "10",
|
||||
"lanes": "9",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth10(Port10)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet10": {
|
||||
"index": "11",
|
||||
"lanes": "12",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth11(Port11)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet11": {
|
||||
"index": "12",
|
||||
"lanes": "11",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth12(Port12)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet12": {
|
||||
"index": "13",
|
||||
"lanes": "14",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth13(Port13)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet13": {
|
||||
"index": "14",
|
||||
"lanes": "13",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth14(Port14)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet14": {
|
||||
"index": "15",
|
||||
"lanes": "16",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth15(Port15)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet15": {
|
||||
"index": "16",
|
||||
"lanes": "15",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth16(Port16)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet16": {
|
||||
"index": "17",
|
||||
"lanes": "18",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth17(Port17)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet17": {
|
||||
"index": "18",
|
||||
"lanes": "17",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth18(Port18)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet18": {
|
||||
"index": "19",
|
||||
"lanes": "20",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth19(Port19)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet19": {
|
||||
"index": "20",
|
||||
"lanes": "19",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth20(Port20)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet20": {
|
||||
"index": "21",
|
||||
"lanes": "22",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth21(Port21)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet21": {
|
||||
"index": "22",
|
||||
"lanes": "21",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth22(Port22)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet22": {
|
||||
"index": "23",
|
||||
"lanes": "24",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth23(Port23)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet23": {
|
||||
"index": "24",
|
||||
"lanes": "23",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth24(Port24)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet24": {
|
||||
"index": "25",
|
||||
"lanes": "26",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth25(Port25)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet25": {
|
||||
"index": "26",
|
||||
"lanes": "25",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth26(Port26)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet26": {
|
||||
"index": "27",
|
||||
"lanes": "28",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth27(Port27)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet27": {
|
||||
"index": "28",
|
||||
"lanes": "27",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth28(Port28)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet28": {
|
||||
"index": "29",
|
||||
"lanes": "30",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth29(Port29)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet29": {
|
||||
"index": "30",
|
||||
"lanes": "29",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth30(Port30)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet30": {
|
||||
"index": "31",
|
||||
"lanes": "32",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth31(Port31)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet31": {
|
||||
"index": "32",
|
||||
"lanes": "31",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth32(Port32)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet32": {
|
||||
"index": "33",
|
||||
"lanes": "34",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth33(Port33)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet33": {
|
||||
"index": "34",
|
||||
"lanes": "33",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth34(Port34)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet34": {
|
||||
"index": "35",
|
||||
"lanes": "36",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth35(Port35)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet35": {
|
||||
"index": "36",
|
||||
"lanes": "35",
|
||||
"breakout_modes": {
|
||||
"1x2.5G": ["Eth36(Port36)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet36": {
|
||||
"index": "37",
|
||||
"lanes": "51",
|
||||
"breakout_modes": {
|
||||
"1x10G": ["Eth37(Port37)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet37": {
|
||||
"index": "38",
|
||||
"lanes": "52",
|
||||
"breakout_modes": {
|
||||
"1x10G": ["Eth38(Port38)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet38": {
|
||||
"index": "39",
|
||||
"lanes": "49",
|
||||
"breakout_modes": {
|
||||
"1x10G": ["Eth39(Port39)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet39": {
|
||||
"index": "40",
|
||||
"lanes": "50",
|
||||
"breakout_modes": {
|
||||
"1x10G": ["Eth40(Port40)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet40": {
|
||||
"index": "41",
|
||||
"lanes": "55",
|
||||
"breakout_modes": {
|
||||
"1x10G": ["Eth41(Port41)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet41": {
|
||||
"index": "42",
|
||||
"lanes": "56",
|
||||
"breakout_modes": {
|
||||
"1x10G": ["Eth42(Port42)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet42": {
|
||||
"index": "43",
|
||||
"lanes": "53",
|
||||
"breakout_modes": {
|
||||
"1x10G": ["Eth43(Port43)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet43": {
|
||||
"index": "44",
|
||||
"lanes": "54",
|
||||
"breakout_modes": {
|
||||
"1x10G": ["Eth44(Port44)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet44": {
|
||||
"index": "45",
|
||||
"lanes": "59",
|
||||
"breakout_modes": {
|
||||
"1x10G": ["Eth45(Port45)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet45": {
|
||||
"index": "46",
|
||||
"lanes": "60",
|
||||
"breakout_modes": {
|
||||
"1x10G": ["Eth46(Port46)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet46": {
|
||||
"index": "47",
|
||||
"lanes": "57",
|
||||
"breakout_modes": {
|
||||
"1x10G": ["Eth47(Port47)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet47": {
|
||||
"index": "48",
|
||||
"lanes": "58",
|
||||
"breakout_modes": {
|
||||
"1x10G": ["Eth48(Port48)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet48": {
|
||||
"index": "49",
|
||||
"lanes": "67",
|
||||
"breakout_modes": {
|
||||
"1x25G[10G]": ["Eth49(Port49)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet49": {
|
||||
"index": "50",
|
||||
"lanes": "66",
|
||||
"breakout_modes": {
|
||||
"1x25G[10G]": ["Eth50(Port50)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet50": {
|
||||
"index": "51",
|
||||
"lanes": "65",
|
||||
"breakout_modes": {
|
||||
"1x25G[10G]": ["Eth51(Port51)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet51": {
|
||||
"index": "52",
|
||||
"lanes": "68",
|
||||
"breakout_modes": {
|
||||
"1x25G[10G]": ["Eth52(Port52)"]
|
||||
}
|
||||
},
|
||||
"Ethernet52": {
|
||||
"index": "53,53,53,53",
|
||||
"lanes": "73,74,75,76",
|
||||
"breakout_modes": {
|
||||
"1x100G[40G]": ["Eth53(Port53)"],
|
||||
"4x25G[10G]": ["Eth53/1(Port53)", "Eth53/2(Port53)", "Eth53/3(Port53)", "Eth53/4(Port53)"]
|
||||
}
|
||||
},
|
||||
|
||||
"Ethernet56": {
|
||||
"index": "54,54,54,54",
|
||||
"lanes": "69,70,71,72",
|
||||
"breakout_modes": {
|
||||
"1x100G[40G]": ["Eth54(Port54)"],
|
||||
"4x25G[10G]": ["Eth54/1(Port54)", "Eth54/2(Port54)", "Eth54/3(Port54)", "Eth54/4(Port54)"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
broadcom
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"chassis": {
|
||||
"4630-54NPE-O-AC-F": {
|
||||
"component": {
|
||||
"CPLD1": { },
|
||||
"CPLD2": { },
|
||||
"BIOS": { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
try:
|
||||
from sonic_eeprom import eeprom_tlvinfo
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class board(eeprom_tlvinfo.TlvInfoDecoder):
|
||||
_TLV_INFO_MAX_LEN = 256
|
||||
|
||||
def __init__(self, name, path, cpld_root, ro):
|
||||
self.eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom"
|
||||
super(board, self).__init__(self.eeprom_path, 0, '', True)
|
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
# Accton
|
||||
#
|
||||
# Module contains an implementation of SONiC PSU Base API and
|
||||
# provides the PSUs status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
from sonic_psu.psu_base import PsuBase
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class PsuUtil(PsuBase):
|
||||
"""Platform-specific PSUutil class"""
|
||||
|
||||
def __init__(self):
|
||||
PsuBase.__init__(self)
|
||||
|
||||
self.psu_path = "/sys/bus/i2c/devices/"
|
||||
self.psu_presence = "/psu_present"
|
||||
self.psu_oper_status = "/psu_power_good"
|
||||
self.psu_mapping = {
|
||||
1: "10-0050",
|
||||
2: "11-0051",
|
||||
}
|
||||
|
||||
def get_num_psus(self):
|
||||
return len(self.psu_mapping)
|
||||
|
||||
def get_psu_status(self, index):
|
||||
if index is None:
|
||||
return False
|
||||
|
||||
status = 0
|
||||
node = self.psu_path + self.psu_mapping[index] + self.psu_oper_status
|
||||
try:
|
||||
with open(node, 'r') as power_status:
|
||||
status = int(power_status.read())
|
||||
except IOError:
|
||||
return False
|
||||
|
||||
return status == 1
|
||||
|
||||
def get_psu_presence(self, index):
|
||||
if index is None:
|
||||
return False
|
||||
|
||||
status = 0
|
||||
node = self.psu_path + self.psu_mapping[index] + self.psu_presence
|
||||
try:
|
||||
with open(node, 'r') as presence_status:
|
||||
status = int(presence_status.read())
|
||||
except IOError:
|
||||
return False
|
||||
|
||||
return status == 1
|
211
device/accton/x86_64-accton_as4630_54npe-r0/plugins/sfputil.py
Normal file
211
device/accton/x86_64-accton_as4630_54npe-r0/plugins/sfputil.py
Normal file
@ -0,0 +1,211 @@
|
||||
# sfputil.py
|
||||
#
|
||||
# Platform-specific SFP transceiver interface for SONiC
|
||||
#
|
||||
|
||||
try:
|
||||
import sys
|
||||
import time
|
||||
from ctypes import create_string_buffer
|
||||
from sonic_sfp.sfputilbase import SfpUtilBase
|
||||
except ImportError as e:
|
||||
raise ImportError("%s - required module not found" % str(e))
|
||||
|
||||
SFP_STATUS_INSERTED = '1'
|
||||
SFP_STATUS_REMOVED = '0'
|
||||
|
||||
|
||||
class SfpUtil(SfpUtilBase):
|
||||
"""Platform-specific SfpUtil class"""
|
||||
|
||||
PORT_START = 49
|
||||
PORT_END = 54
|
||||
PORTS_IN_BLOCK = 54
|
||||
QSFP_START = 53
|
||||
|
||||
BASE_OOM_PATH = "/sys/bus/i2c/devices/{0}-0050/"
|
||||
BASE_CPLD_PATH = "/sys/bus/i2c/devices/3-0060/"
|
||||
|
||||
_port_to_is_present = {}
|
||||
_port_to_lp_mode = {}
|
||||
|
||||
_port_to_eeprom_mapping = {}
|
||||
_port_to_i2c_mapping = {
|
||||
49: [18],
|
||||
50: [19],
|
||||
51: [20],
|
||||
52: [21],
|
||||
53: [22],
|
||||
54: [23],
|
||||
}
|
||||
|
||||
@property
|
||||
def port_start(self):
|
||||
return self.PORT_START
|
||||
|
||||
@property
|
||||
def port_end(self):
|
||||
return self.PORT_END
|
||||
|
||||
@property
|
||||
def qsfp_ports(self):
|
||||
return range(self.QSFP_START, self.PORTS_IN_BLOCK + 1)
|
||||
|
||||
@property
|
||||
def port_to_eeprom_mapping(self):
|
||||
return self._port_to_eeprom_mapping
|
||||
|
||||
def __init__(self):
|
||||
eeprom_path = self.BASE_OOM_PATH + "eeprom"
|
||||
for x in range(self.port_start, self.port_end + 1):
|
||||
self.port_to_eeprom_mapping[x] = eeprom_path.format(
|
||||
self._port_to_i2c_mapping[x][0])
|
||||
SfpUtilBase.__init__(self)
|
||||
|
||||
def get_presence(self, port_num):
|
||||
# Check for invalid port_num
|
||||
if port_num < self.port_start or port_num > self.port_end:
|
||||
return False
|
||||
|
||||
present_path = self.BASE_CPLD_PATH + "module_present_" + str(port_num)
|
||||
self.__port_to_is_present = present_path
|
||||
|
||||
try:
|
||||
val_file = open(self.__port_to_is_present)
|
||||
content = val_file.readline().rstrip()
|
||||
val_file.close()
|
||||
except IOError as e:
|
||||
print("Error: unable to access file: %s" % str(e))
|
||||
return False
|
||||
|
||||
if content == "1":
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_low_power_mode(self, port_num):
|
||||
# Check for invalid port_num
|
||||
if port_num < self.QSFP_START or port_num > self.port_end:
|
||||
return False
|
||||
|
||||
try:
|
||||
eeprom = None
|
||||
if not self.get_presence(port_num):
|
||||
return False
|
||||
eeprom = open(self.port_to_eeprom_mapping[port_num], "rb")
|
||||
eeprom.seek(93)
|
||||
lpmode = ord(eeprom.read(1))
|
||||
|
||||
# if "Power override" bit is 1 and "Power set" bit is 1
|
||||
if ((lpmode & 0x3) == 0x3):
|
||||
return True
|
||||
|
||||
# High Power Mode if one of the following conditions is matched:
|
||||
# 1. "Power override" bit is 0
|
||||
# 2. "Power override" bit is 1 and "Power set" bit is 0
|
||||
else:
|
||||
return False
|
||||
|
||||
except IOError as e:
|
||||
print("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
finally:
|
||||
if eeprom is not None:
|
||||
eeprom.close()
|
||||
time.sleep(0.01)
|
||||
|
||||
def set_low_power_mode(self, port_num, lpmode):
|
||||
# Check for invalid port_num
|
||||
if port_num < self.QSFP_START or port_num > self.port_end:
|
||||
return False
|
||||
|
||||
try:
|
||||
eeprom = None
|
||||
if not self.get_presence(port_num):
|
||||
return False # Port is not present, unable to set the eeprom
|
||||
|
||||
# Fill in write buffer
|
||||
# 0x3:Low Power Mode, 0x1:High Power Mode
|
||||
regval = 0x3 if lpmode else 0x1
|
||||
|
||||
buffer = create_string_buffer(1)
|
||||
buffer[0] = regval
|
||||
|
||||
# Write to eeprom
|
||||
eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b")
|
||||
eeprom.seek(93)
|
||||
eeprom.write(buffer[0])
|
||||
return True
|
||||
except IOError as e:
|
||||
print("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
finally:
|
||||
if eeprom is not None:
|
||||
eeprom.close()
|
||||
time.sleep(0.01)
|
||||
|
||||
def reset(self, port_num):
|
||||
if not port_num in self.qsfp_ports:
|
||||
return False
|
||||
|
||||
path = self.BASE_CPLD_PATH + "module_reset_" + str(port_num)
|
||||
self.__port_to_mod_rst = path
|
||||
try:
|
||||
reg_file = open(self.__port_to_mod_rst, 'r+')
|
||||
except IOError as e:
|
||||
print("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
|
||||
#toggle reset
|
||||
reg_file.seek(0)
|
||||
reg_file.write('1')
|
||||
time.sleep(1)
|
||||
reg_file.seek(0)
|
||||
reg_file.write('0')
|
||||
reg_file.close()
|
||||
return True
|
||||
|
||||
@property
|
||||
def _get_presence_bitmap(self):
|
||||
|
||||
bits = []
|
||||
for x in range(self.port_start, self.port_end + 1):
|
||||
bits.append(str(int(self.get_presence(x))))
|
||||
|
||||
rev = "".join(bits[::-1])
|
||||
return int(rev, 2)
|
||||
|
||||
data = {'present': 0}
|
||||
|
||||
def get_transceiver_change_event(self, timeout=0):
|
||||
port_dict = {}
|
||||
|
||||
if timeout == 0:
|
||||
cd_ms = sys.maxsize
|
||||
else:
|
||||
cd_ms = timeout
|
||||
|
||||
# poll per second
|
||||
while cd_ms > 0:
|
||||
reg_value = self._get_presence_bitmap
|
||||
changed_ports = self.data['present'] ^ reg_value
|
||||
if changed_ports != 0:
|
||||
break
|
||||
time.sleep(1)
|
||||
cd_ms = cd_ms - 1000
|
||||
|
||||
if changed_ports != 0:
|
||||
for port in range(self.port_start, self.port_end + 1):
|
||||
# Mask off the bit corresponding to our port
|
||||
mask = (1 << (port - self.port_start))
|
||||
if changed_ports & mask:
|
||||
if (reg_value & mask) == 0:
|
||||
port_dict[port] = SFP_STATUS_REMOVED
|
||||
else:
|
||||
port_dict[port] = SFP_STATUS_INSERTED
|
||||
|
||||
# Update cache
|
||||
self.data['present'] = reg_value
|
||||
return True, port_dict
|
||||
else:
|
||||
return True, {}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"skip_ledd": true
|
||||
}
|
40
device/accton/x86_64-accton_as4630_54npe-r0/sensors.conf
Normal file
40
device/accton/x86_64-accton_as4630_54npe-r0/sensors.conf
Normal file
@ -0,0 +1,40 @@
|
||||
# libsensors configuration file for as4630-54npe
|
||||
# ------------------------------------------------
|
||||
#
|
||||
|
||||
bus "i2c-3" "i2c-1-mux (chan_id 1)"
|
||||
bus "i2c-10" "i2c-2-mux (chan_id 0)"
|
||||
bus "i2c-11" "i2c-2-mux (chan_id 1)"
|
||||
bus "i2c-14" "i2c-2-mux (chan_id 4)"
|
||||
bus "i2c-24" "i2c-3-mux (chan_id 6)"
|
||||
bus "i2c-25" "i2c-3-mux (chan_id 7)"
|
||||
|
||||
|
||||
chip "ype1200am-i2c-*-58"
|
||||
label in3 "PSU 1 Voltage"
|
||||
label fan1 "PSU 1 Fan"
|
||||
label temp1 "PSU 1 Temperature"
|
||||
label power2 "PSU 1 Power"
|
||||
label curr2 "PSU 1 Current"
|
||||
|
||||
chip "ype1200am-i2c-*-59"
|
||||
label in3 "PSU 2 Voltage"
|
||||
label fan1 "PSU 2 Fan"
|
||||
label temp1 "PSU 2 Temperature"
|
||||
label power2 "PSU 2 Power"
|
||||
label curr2 "PSU 2 Current"
|
||||
|
||||
chip "as4630_54npe_cpld-*"
|
||||
label fan1 "Fan 1"
|
||||
label fan2 "Fan 2"
|
||||
label fan3 "Fan 3"
|
||||
|
||||
|
||||
chip "lm77-i2c-*-48"
|
||||
label temp1 "Main Board Temperature"
|
||||
|
||||
chip "lm75-i2c-*-4a"
|
||||
label temp1 "Fan Board Temperature"
|
||||
|
||||
chip "lm75-i2c-*-4b"
|
||||
label temp1 "CPU Board Temperature"
|
@ -0,0 +1,2 @@
|
||||
__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ]
|
||||
from . import platform
|
@ -0,0 +1,251 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the Chassis information which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import sys
|
||||
|
||||
try:
|
||||
from sonic_platform_base.chassis_base import ChassisBase
|
||||
from .helper import APIHelper
|
||||
from .event import SfpEvent
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
NUM_FAN_TRAY = 3
|
||||
NUM_FAN = 2
|
||||
NUM_PSU = 2
|
||||
NUM_THERMAL = 4
|
||||
PORT_START = 49
|
||||
PORT_END = 54
|
||||
NUM_COMPONENT = 3
|
||||
HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/"
|
||||
PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/"
|
||||
REBOOT_CAUSE_FILE = "reboot-cause.txt"
|
||||
PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt"
|
||||
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
|
||||
SYSLED_FNODE = "/sys/class/leds/diag/brightness"
|
||||
SYSLED_MODES = {
|
||||
"0": "STATUS_LED_COLOR_OFF",
|
||||
"1": "STATUS_LED_COLOR_GREEN",
|
||||
"2": "STATUS_LED_COLOR_AMBER",
|
||||
"5": "STATUS_LED_COLOR_GREEN_BLINK"
|
||||
}
|
||||
|
||||
|
||||
class Chassis(ChassisBase):
|
||||
"""Platform-specific Chassis class"""
|
||||
|
||||
def __init__(self):
|
||||
ChassisBase.__init__(self)
|
||||
self._api_helper = APIHelper()
|
||||
self.is_host = self._api_helper.is_host()
|
||||
|
||||
self.config_data = {}
|
||||
|
||||
self.__initialize_fan()
|
||||
self.__initialize_psu()
|
||||
self.__initialize_thermals()
|
||||
self.__initialize_components()
|
||||
self.__initialize_sfp()
|
||||
self.__initialize_eeprom()
|
||||
|
||||
def __initialize_sfp(self):
|
||||
from sonic_platform.sfp import Sfp
|
||||
for index in range(0, PORT_END):
|
||||
sfp = Sfp(index)
|
||||
self._sfp_list.append(sfp)
|
||||
self._sfpevent = SfpEvent(self._sfp_list)
|
||||
self.sfp_module_initialized = True
|
||||
|
||||
def __initialize_fan(self):
|
||||
from sonic_platform.fan_drawer import FanDrawer
|
||||
for fant_index in range(NUM_FAN_TRAY):
|
||||
fandrawer = FanDrawer(fant_index)
|
||||
self._fan_drawer_list.append(fandrawer)
|
||||
self._fan_list.extend(fandrawer._fan_list)
|
||||
|
||||
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_thermals(self):
|
||||
from sonic_platform.thermal import Thermal
|
||||
for index in range(0, NUM_THERMAL):
|
||||
thermal = Thermal(index)
|
||||
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_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
|
||||
return self._eeprom.get_modelstr()
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the Chassis
|
||||
Returns:
|
||||
bool: True if Chassis is present, False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
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_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_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 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_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE)
|
||||
sw_reboot_cause = self._api_helper.read_txt_file(
|
||||
reboot_cause_path) or "Unknown"
|
||||
|
||||
return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause)
|
||||
|
||||
def get_change_event(self, timeout=0):
|
||||
# SFP event
|
||||
if not self.sfp_module_initialized:
|
||||
self.__initialize_sfp()
|
||||
return self._sfpevent.get_sfp_event(timeout)
|
||||
|
||||
def get_sfp(self, index):
|
||||
"""
|
||||
Retrieves sfp represented by (1-based) index <index>
|
||||
Args:
|
||||
index: An integer, the index (1-based) of the sfp to retrieve.
|
||||
The index should be the sequence of a physical port in a chassis,
|
||||
starting from 1.
|
||||
For example, 1 for Ethernet0, 2 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:
|
||||
# The index will start from 1
|
||||
sfp = self._sfp_list[index - 1]
|
||||
except IndexError:
|
||||
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
|
||||
index, len(self._sfp_list)))
|
||||
return sfp
|
||||
|
||||
def get_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
|
||||
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
|
||||
"""
|
||||
return -1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return False
|
||||
|
||||
def initizalize_system_led(self):
|
||||
return True
|
||||
|
||||
def get_status_led(self):
|
||||
val = self._api_helper.read_txt_file(SYSLED_FNODE)
|
||||
return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN"
|
||||
|
||||
def set_status_led(self, color):
|
||||
mode = None
|
||||
for key, val in SYSLED_MODES.items():
|
||||
if val == color:
|
||||
mode = key
|
||||
break
|
||||
if mode is None:
|
||||
return False
|
||||
else:
|
||||
return self._api_helper.write_txt_file(SYSLED_FNODE, mode)
|
||||
|
||||
def get_port_or_cage_type(self, port):
|
||||
from sonic_platform_base.sfp_base import SfpBase
|
||||
if port in range(1, 49):
|
||||
return SfpBase.SFP_PORT_TYPE_BIT_RJ45
|
||||
elif port in range(49, 53):
|
||||
return SfpBase.SFP_PORT_TYPE_BIT_SFP | SfpBase.SFP_PORT_TYPE_BIT_SFP_PLUS | SfpBase.SFP_PORT_TYPE_BIT_SFP28
|
||||
else:
|
||||
return SfpBase.SFP_PORT_TYPE_BIT_QSFP | SfpBase.SFP_PORT_TYPE_BIT_QSFP_PLUS | SfpBase.SFP_PORT_TYPE_BIT_QSFP28
|
||||
|
||||
def get_revision(self):
|
||||
"""
|
||||
Retrieves the hardware revision of the device
|
||||
|
||||
Returns:
|
||||
string: Revision value of device
|
||||
"""
|
||||
return self._eeprom.get_revisionstr()
|
@ -0,0 +1,194 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Component contains an implementation of SONiC Platform Base API and
|
||||
# provides the components firmware management function
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import os
|
||||
import json
|
||||
|
||||
try:
|
||||
from sonic_platform_base.component_base import ComponentBase
|
||||
from .helper import APIHelper
|
||||
from sonic_py_common.general import getstatusoutput_noshell
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
CPLD_ADDR_MAPPING = {
|
||||
"CPLD1": "3-0060",
|
||||
}
|
||||
SYSFS_PATH = "/sys/bus/i2c/devices/"
|
||||
BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version"
|
||||
COMPONENT_LIST = [
|
||||
("CPLD1", "CPLD MAIN"),
|
||||
("CPLD2", "CPLD CPU"),
|
||||
("BIOS", "Basic Input/Output System")
|
||||
]
|
||||
|
||||
class Component(ComponentBase):
|
||||
"""Platform-specific Component class"""
|
||||
|
||||
DEVICE_TYPE = "component"
|
||||
|
||||
def __init__(self, component_index=0):
|
||||
self._api_helper = APIHelper()
|
||||
ComponentBase.__init__(self)
|
||||
self.index = component_index
|
||||
self.name = self.get_name()
|
||||
|
||||
def __get_bios_version(self):
|
||||
# Retrieves the BIOS firmware version
|
||||
try:
|
||||
with open(BIOS_VERSION_PATH, 'r') as fd:
|
||||
bios_version = fd.read()
|
||||
return bios_version.strip()
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
def __get_cpld_version(self):
|
||||
# Retrieves the CPLD firmware version
|
||||
cpld_version = dict()
|
||||
try:
|
||||
cpld_path = "{}{}{}".format(SYSFS_PATH, CPLD_ADDR_MAPPING[self.name], '/version')
|
||||
cpld_version_raw = self._api_helper.read_txt_file(cpld_path)
|
||||
cpld_version[self.name] = "{}".format(int(cpld_version_raw, 10))
|
||||
except Exception as e:
|
||||
print('Get exception when read cpld')
|
||||
cpld_version[self.name] = 'None'
|
||||
return cpld_version
|
||||
|
||||
def __get_cpldcpu_version(self):
|
||||
cpld_version = dict()
|
||||
cmd = ["i2cget", "-y", "1", "0x65", "0x01"]
|
||||
status, output1 = getstatusoutput_noshell(cmd)
|
||||
cmd = ["i2cget", "-y", "1", "0x65", "0x02"]
|
||||
status, output2 = getstatusoutput_noshell(cmd)
|
||||
cpld_version[self.name] = "{}{}{}".format(int(output1, 16), ".", int(output2, 16))
|
||||
return cpld_version
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the component
|
||||
Returns:
|
||||
A string containing the name of the component
|
||||
"""
|
||||
return COMPONENT_LIST[self.index][0]
|
||||
|
||||
def get_description(self):
|
||||
"""
|
||||
Retrieves the description of the component
|
||||
Returns:
|
||||
A string containing the description of the component
|
||||
"""
|
||||
return COMPONENT_LIST[self.index][1]
|
||||
|
||||
def get_firmware_version(self):
|
||||
"""
|
||||
Retrieves the firmware version of module
|
||||
Returns:
|
||||
string: The firmware versions of the module
|
||||
"""
|
||||
fw_version = None
|
||||
if self.name == "BIOS":
|
||||
fw_version = self.__get_bios_version()
|
||||
elif self.name == "CPLD1":
|
||||
cpld_version = self.__get_cpld_version()
|
||||
fw_version = cpld_version.get(self.name)
|
||||
elif self.name == "CPLD2":
|
||||
cpld_version = self.__get_cpldcpu_version()
|
||||
fw_version = cpld_version.get(self.name)
|
||||
|
||||
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
|
||||
"""
|
||||
ret, output = getstatusoutput_noshell(["tar", "-C", "/tmp", "-xzf", image_path])
|
||||
if ret != 0:
|
||||
print("Installation failed because of wrong image package")
|
||||
return False
|
||||
|
||||
if os.path.exists("/tmp/install.json") is False:
|
||||
print("Installation failed without jsonfile")
|
||||
return False
|
||||
|
||||
input_file = open('/tmp/install.json')
|
||||
json_array = json.load(input_file)
|
||||
ret = 1
|
||||
for item in json_array:
|
||||
if item.get('id') is None or item.get('path') is None:
|
||||
continue
|
||||
if self.name == item['id'] and item['path'] and item.get('cpu'):
|
||||
print("Find", item['id'], item['path'], item['cpu'])
|
||||
ret, output = getstatusoutput_noshell(["/tmp/run_install.sh", item['id'], item['path'], item['cpu']])
|
||||
if ret == 0:
|
||||
break
|
||||
elif self.name == item['id'] and item['path']:
|
||||
print("Find", item['id'], item['path'])
|
||||
ret, output = getstatusoutput_noshell(["/tmp/run_install.sh", item['id'], item['path']])
|
||||
if ret == 0:
|
||||
break
|
||||
|
||||
if ret == 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the device
|
||||
Returns:
|
||||
bool: True if device 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 'N/A'
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the device
|
||||
Returns:
|
||||
string: Serial number of device
|
||||
"""
|
||||
return 'N/A'
|
||||
|
||||
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_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device.
|
||||
If the agent cannot determine the parent-relative position
|
||||
for some reason, or if the associated value of
|
||||
entPhysicalContainedIn is'0', then the value '-1' is returned
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent device
|
||||
or -1 if cannot determine the position
|
||||
"""
|
||||
return -1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return False
|
@ -0,0 +1,136 @@
|
||||
try:
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
if sys.version_info[0] >= 3:
|
||||
from io import StringIO
|
||||
else:
|
||||
from cStringIO import StringIO
|
||||
|
||||
from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
CACHE_ROOT = '/var/cache/sonic/decode-syseeprom'
|
||||
CACHE_FILE = 'syseeprom_cache'
|
||||
NULL = 'N/A'
|
||||
|
||||
class Tlv(eeprom_tlvinfo.TlvInfoDecoder):
|
||||
|
||||
EEPROM_DECODE_HEADLINES = 6
|
||||
|
||||
def __init__(self):
|
||||
self._eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom"
|
||||
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]+)(.+)', 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 _valid_tlv(self, eeprom_data):
|
||||
tlvinfo_type_codes_list = [
|
||||
self._TLV_CODE_PRODUCT_NAME,
|
||||
self._TLV_CODE_PART_NUMBER,
|
||||
self._TLV_CODE_SERIAL_NUMBER,
|
||||
self._TLV_CODE_MAC_BASE,
|
||||
self._TLV_CODE_MANUF_DATE,
|
||||
self._TLV_CODE_DEVICE_VERSION,
|
||||
self._TLV_CODE_LABEL_REVISION,
|
||||
self._TLV_CODE_PLATFORM_NAME,
|
||||
self._TLV_CODE_ONIE_VERSION,
|
||||
self._TLV_CODE_MAC_SIZE,
|
||||
self._TLV_CODE_MANUF_NAME,
|
||||
self._TLV_CODE_MANUF_COUNTRY,
|
||||
self._TLV_CODE_VENDOR_NAME,
|
||||
self._TLV_CODE_DIAG_VERSION,
|
||||
self._TLV_CODE_SERVICE_TAG,
|
||||
self._TLV_CODE_VENDOR_EXT,
|
||||
self._TLV_CODE_CRC_32
|
||||
]
|
||||
|
||||
for code in tlvinfo_type_codes_list:
|
||||
code_str = "0x{:X}".format(code)
|
||||
eeprom_data[code_str] = eeprom_data.get(code_str, NULL)
|
||||
return eeprom_data
|
||||
|
||||
def get_eeprom(self):
|
||||
return self._valid_tlv(self._eeprom)
|
||||
|
||||
def get_pn(self):
|
||||
return self._eeprom.get('0x22', NULL)
|
||||
|
||||
def get_serial(self):
|
||||
return self._eeprom.get('0x23', NULL)
|
||||
|
||||
def get_mac(self):
|
||||
return self._eeprom.get('0x24', NULL)
|
||||
|
||||
def get_modelstr(self):
|
||||
return self._eeprom.get('0x21', NULL)
|
||||
|
||||
def get_revisionstr(self):
|
||||
return self._eeprom.get('0x27', NULL)
|
@ -0,0 +1,109 @@
|
||||
try:
|
||||
import time
|
||||
from sonic_py_common.logger import Logger
|
||||
from .sfp import Sfp
|
||||
except ImportError as e:
|
||||
raise ImportError(repr(e) + " - required module not found")
|
||||
|
||||
POLL_INTERVAL_IN_SEC = 1
|
||||
|
||||
# SFP errors that will block eeprom accessing
|
||||
SFP_BLOCKING_ERRORS = [
|
||||
Sfp.SFP_ERROR_BIT_I2C_STUCK,
|
||||
Sfp.SFP_ERROR_BIT_BAD_EEPROM,
|
||||
Sfp.SFP_ERROR_BIT_UNSUPPORTED_CABLE,
|
||||
Sfp.SFP_ERROR_BIT_HIGH_TEMP,
|
||||
Sfp.SFP_ERROR_BIT_BAD_CABLE
|
||||
]
|
||||
|
||||
class SfpEvent:
|
||||
''' Listen to insert/remove sfp events '''
|
||||
|
||||
def __init__(self, sfp_list):
|
||||
self._sfp_list = sfp_list
|
||||
self._logger = Logger()
|
||||
self._sfp_change_event_data = {'present': 0}
|
||||
|
||||
def get_presence_bitmap(self):
|
||||
bitmap = 0
|
||||
for sfp in self._sfp_list:
|
||||
modpres = sfp.get_presence()
|
||||
i = sfp.get_position_in_parent() - 1
|
||||
if modpres:
|
||||
bitmap = bitmap | (1 << i)
|
||||
return bitmap
|
||||
|
||||
def get_sfp_event(self, timeout=2000):
|
||||
port_dict = {}
|
||||
change_dict = {}
|
||||
change_dict['sfp'] = port_dict
|
||||
|
||||
if timeout < 1000:
|
||||
cd_ms = 1000
|
||||
else:
|
||||
cd_ms = timeout
|
||||
|
||||
while cd_ms > 0:
|
||||
bitmap = self.get_presence_bitmap()
|
||||
changed_ports = self._sfp_change_event_data['present'] ^ bitmap
|
||||
if changed_ports != 0:
|
||||
break
|
||||
time.sleep(POLL_INTERVAL_IN_SEC)
|
||||
# timeout=0 means wait for event forever
|
||||
if timeout != 0:
|
||||
cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000
|
||||
|
||||
if changed_ports != 0:
|
||||
for sfp in self._sfp_list:
|
||||
i = sfp.get_position_in_parent() - 1
|
||||
if (changed_ports & (1 << i)) == 0:
|
||||
continue
|
||||
|
||||
if (bitmap & (1 << i)) == 0:
|
||||
port_dict[i + 1] = '0'
|
||||
else:
|
||||
# sfp.refresh_optoe_dev_class()
|
||||
sfp_state_bits = self.get_sfp_state_bits(sfp, True)
|
||||
sfp_state_bits = self.check_sfp_blocking_errors(sfp_state_bits)
|
||||
|
||||
port_dict[i + 1] = str(sfp_state_bits)
|
||||
|
||||
# Update the cache dict
|
||||
self._sfp_change_event_data['present'] = bitmap
|
||||
return True, change_dict
|
||||
else:
|
||||
return True, change_dict
|
||||
|
||||
def get_sfp_state_bits(self, sfp, present):
|
||||
sfp_state_bits = 0
|
||||
|
||||
if present is True:
|
||||
sfp_state_bits |= Sfp.SFP_STATUS_BIT_INSERTED
|
||||
else:
|
||||
return sfp_state_bits
|
||||
|
||||
status = sfp.validate_eeprom()
|
||||
if status is None:
|
||||
sfp_state_bits |= Sfp.SFP_ERROR_BIT_I2C_STUCK
|
||||
return sfp_state_bits
|
||||
elif status is not True:
|
||||
sfp_state_bits |= Sfp.SFP_ERROR_BIT_BAD_EEPROM
|
||||
return sfp_state_bits
|
||||
|
||||
status = sfp.validate_temperature()
|
||||
if status is None:
|
||||
sfp_state_bits |= Sfp.SFP_ERROR_BIT_I2C_STUCK
|
||||
return sfp_state_bits
|
||||
elif status is not True:
|
||||
sfp_state_bits |= Sfp.SFP_ERROR_BIT_HIGH_TEMP
|
||||
return sfp_state_bits
|
||||
|
||||
return sfp_state_bits
|
||||
|
||||
def check_sfp_blocking_errors(self, sfp_state_bits):
|
||||
for i in SFP_BLOCKING_ERRORS:
|
||||
if (i & sfp_state_bits) == 0:
|
||||
continue
|
||||
sfp_state_bits |= Sfp.SFP_ERROR_BIT_BLOCKING
|
||||
|
||||
return sfp_state_bits
|
@ -0,0 +1,282 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the fan status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
|
||||
|
||||
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")
|
||||
|
||||
PSU_FAN_MAX_RPM = 26688
|
||||
SPEED_TOLERANCE = 15
|
||||
CPLD_FAN_I2C_PATH = "/sys/bus/i2c/devices/3-0060/fan_"
|
||||
I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
|
||||
PSU_HWMON_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "58"
|
||||
},
|
||||
1: {
|
||||
"num": 11,
|
||||
"addr": "59"
|
||||
},
|
||||
}
|
||||
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "50"
|
||||
},
|
||||
1: {
|
||||
"num": 11,
|
||||
"addr": "51"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3"]
|
||||
|
||||
class Fan(FanBase):
|
||||
"""Platform-specific Fan class"""
|
||||
|
||||
def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0):
|
||||
self._api_helper = APIHelper()
|
||||
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.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num']
|
||||
self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr']
|
||||
self.psu_hwmon_path = I2C_PATH.format(
|
||||
self.psu_i2c_num, self.psu_i2c_addr)
|
||||
|
||||
self.psu_i2c_num = PSU_CPLD_I2C_MAPPING[self.psu_index]['num']
|
||||
self.psu_i2c_addr = PSU_CPLD_I2C_MAPPING[self.psu_index]['addr']
|
||||
self.psu_cpld_path = I2C_PATH.format(
|
||||
self.psu_i2c_num, self.psu_i2c_addr)
|
||||
|
||||
FanBase.__init__(self)
|
||||
|
||||
|
||||
def get_direction(self):
|
||||
"""
|
||||
Retrieves the direction of fan
|
||||
Returns:
|
||||
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
|
||||
depending on fan direction
|
||||
"""
|
||||
if not self.is_psu_fan:
|
||||
dir_str = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'direction_', self.fan_tray_index + 1)
|
||||
val = self._api_helper.read_txt_file(dir_str)
|
||||
if val is not None:
|
||||
if int(val, 10) == 0:#F2B
|
||||
direction = self.FAN_DIRECTION_EXHAUST
|
||||
else:
|
||||
direction = self.FAN_DIRECTION_INTAKE
|
||||
else:
|
||||
direction = self.FAN_DIRECTION_EXHAUST
|
||||
|
||||
else: #For PSU
|
||||
dir_str = "{}{}".format(self.psu_hwmon_path, 'psu_fan_dir')
|
||||
val = self._api_helper.read_txt_file(dir_str)
|
||||
if val is not None:
|
||||
if val == 'F2B':
|
||||
direction = self.FAN_DIRECTION_EXHAUST
|
||||
else:
|
||||
direction = self.FAN_DIRECTION_INTAKE
|
||||
else:
|
||||
direction = self.FAN_DIRECTION_EXHAUST
|
||||
|
||||
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)
|
||||
|
||||
"""
|
||||
speed = 0
|
||||
if self.is_psu_fan:
|
||||
psu_fan_path = "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm')
|
||||
fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path)
|
||||
if fan_speed_rpm is not None:
|
||||
speed = (int(fan_speed_rpm, 10)) * 100 / 26688
|
||||
if speed > 100:
|
||||
speed = 100
|
||||
else:
|
||||
return 0
|
||||
elif self.get_presence():
|
||||
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, 'duty_cycle_percentage')
|
||||
speed = self._api_helper.read_txt_file(speed_path)
|
||||
if speed is None:
|
||||
return 0
|
||||
return int(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
|
||||
"""
|
||||
return self.get_speed()
|
||||
|
||||
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
|
||||
|
||||
"""
|
||||
|
||||
if not self.is_psu_fan and self.get_presence():
|
||||
speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, 'duty_cycle_percentage')
|
||||
return self._api_helper.write_txt_file(speed_path, int(speed))
|
||||
|
||||
return False
|
||||
|
||||
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
|
||||
"""
|
||||
return False #Not supported
|
||||
|
||||
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
|
||||
"""
|
||||
status = self.get_presence()
|
||||
if status is None:
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
|
||||
return {
|
||||
1: self.STATUS_LED_COLOR_GREEN,
|
||||
0: self.STATUS_LED_COLOR_RED
|
||||
}.get(status, self.STATUS_LED_COLOR_OFF)
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
fan_name = FAN_NAME_LIST[self.fan_tray_index] \
|
||||
if not self.is_psu_fan \
|
||||
else "PSU-{} FAN-{}".format(self.psu_index + 1, self.fan_index + 1)
|
||||
|
||||
return fan_name
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the FAN
|
||||
Returns:
|
||||
bool: True if FAN is present, False if not
|
||||
"""
|
||||
|
||||
|
||||
if self.is_psu_fan:
|
||||
present_path="{}{}".format(self.psu_cpld_path, 'psu_present')
|
||||
else:
|
||||
present_path = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'present_', self.fan_tray_index + 1)
|
||||
|
||||
val = self._api_helper.read_txt_file(present_path)
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return False
|
||||
|
||||
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.is_psu_fan:
|
||||
psu_fan_path = "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault')
|
||||
val = self._api_helper.read_txt_file(psu_fan_path)
|
||||
if val is not None:
|
||||
return int(val, 10) == 0
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
path = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'fault_', self.fan_tray_index + 1)
|
||||
val = self._api_helper.read_txt_file(path)
|
||||
if val is not None:
|
||||
return int(val, 10) == 0
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
|
||||
return "N/A"
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the device
|
||||
Returns:
|
||||
string: Serial number of device
|
||||
"""
|
||||
return "N/A"
|
||||
|
||||
def get_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device.
|
||||
If the agent cannot determine the parent-relative position
|
||||
for some reason, or if the associated value of
|
||||
entPhysicalContainedIn is'0', then the value '-1' is returned
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent device
|
||||
or -1 if cannot determine the position
|
||||
"""
|
||||
return (self.fan_tray_index + 1) \
|
||||
if not self.is_psu_fan else (self.psu_index + 1)
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True if not self.is_psu_fan else False
|
@ -0,0 +1,116 @@
|
||||
########################################################################
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the Fan-Drawers' information available in the platform.
|
||||
#
|
||||
########################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_base.fan_drawer_base import FanDrawerBase
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
FANS_PER_FANTRAY = 1
|
||||
|
||||
|
||||
class FanDrawer(FanDrawerBase):
|
||||
"""Platform-specific Fan class"""
|
||||
|
||||
def __init__(self, fantray_index):
|
||||
|
||||
FanDrawerBase.__init__(self)
|
||||
# FanTray is 0-based in platforms
|
||||
self.fantrayindex = fantray_index
|
||||
self.__initialize_fan_drawer()
|
||||
|
||||
|
||||
def __initialize_fan_drawer(self):
|
||||
from sonic_platform.fan import Fan
|
||||
for i in range(FANS_PER_FANTRAY):
|
||||
self._fan_list.append(Fan(self.fantrayindex, i))
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the fan drawer name
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return "FanTray{}".format(self.fantrayindex + 1)
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the device
|
||||
Returns:
|
||||
bool: True if device is present, False if not
|
||||
"""
|
||||
return self._fan_list[0].get_presence()
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
return self._fan_list[0].get_model()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the device
|
||||
Returns:
|
||||
string: Serial number of device
|
||||
"""
|
||||
return self._fan_list[0].get_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._fan_list[0].get_status()
|
||||
|
||||
def get_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device.
|
||||
If the agent cannot determine the parent-relative position
|
||||
for some reason, or if the associated value of
|
||||
entPhysicalContainedIn is'0', then the value '-1' is returned
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent device
|
||||
or -1 if cannot determine the position
|
||||
"""
|
||||
return (self.fantrayindex + 1)
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
||||
|
||||
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
|
||||
"""
|
||||
return False #Not supported
|
||||
|
||||
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
|
||||
"""
|
||||
status = self.get_presence()
|
||||
if status is None:
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
|
||||
return {
|
||||
1: self.STATUS_LED_COLOR_GREEN,
|
||||
0: self.STATUS_LED_COLOR_RED
|
||||
}.get(status, self.STATUS_LED_COLOR_OFF)
|
@ -0,0 +1,370 @@
|
||||
import os
|
||||
import struct
|
||||
import json
|
||||
import fcntl
|
||||
from mmap import *
|
||||
from sonic_py_common import device_info
|
||||
from sonic_py_common import logger
|
||||
from threading import Lock
|
||||
from typing import cast
|
||||
from sonic_py_common.general import getstatusoutput_noshell_pipe
|
||||
from sonic_py_common.general import getstatusoutput_noshell
|
||||
|
||||
HOST_CHK_CMD = ["docker"]
|
||||
EMPTY_STRING = ""
|
||||
|
||||
|
||||
class APIHelper():
|
||||
|
||||
def __init__(self):
|
||||
(self.platform, self.hwsku) = device_info.get_platform_and_hwsku()
|
||||
|
||||
def is_host(self):
|
||||
try:
|
||||
status, output = getstatusoutput_noshell(HOST_CHK_CMD)
|
||||
return status == 0
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
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_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', errors='replace') as fd:
|
||||
data = fd.read()
|
||||
ret = data.strip()
|
||||
if len(ret) > 0:
|
||||
return ret
|
||||
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 IOError:
|
||||
return False
|
||||
return True
|
||||
|
||||
def ipmi_raw(self, netfn, cmd):
|
||||
status = True
|
||||
result = ""
|
||||
try:
|
||||
err, raw_data = getstatusoutput_noshell_pipe(['ipmitool', 'raw', str(netfn), str(cmd)])
|
||||
if err == [0]:
|
||||
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:
|
||||
if (key is None):
|
||||
err, raw_data = getstatusoutput_noshell_pipe(['ipmitool', 'fru', 'print', str(id)])
|
||||
else:
|
||||
err, raw_data = getstatusoutput_noshell_pipe(['ipmitool', 'fru', 'print', str(id)], ['grep', str(key)])
|
||||
if err == [0] or err == [0, 0]:
|
||||
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:
|
||||
err, raw_data = getstatusoutput_noshell_pipe(['ipmitool', 'sensor', 'thresh', str(id), str(threshold_key), str(value)])
|
||||
if err == [0]:
|
||||
result = raw_data.strip()
|
||||
else:
|
||||
status = False
|
||||
except Exception:
|
||||
status = False
|
||||
return status, result
|
||||
|
||||
|
||||
class FileLock:
|
||||
"""
|
||||
Due to pmon docker not installing the py-filelock, this class
|
||||
implements a simple file lock feature.
|
||||
Ref: https://github.com/tox-dev/py-filelock/blob/main/src/filelock/
|
||||
"""
|
||||
|
||||
def __init__(self, lock_file):
|
||||
self._lock_file = lock_file
|
||||
self._thread_lock = Lock()
|
||||
self.is_locked = False
|
||||
self._lock_file_fd = None
|
||||
|
||||
def acquire(self):
|
||||
with self._thread_lock:
|
||||
if self.is_locked:
|
||||
return
|
||||
|
||||
fd = os.open(self._lock_file, flags=(os.O_RDWR | os.O_CREAT | os.O_TRUNC))
|
||||
fcntl.flock(fd, fcntl.LOCK_EX)
|
||||
self._lock_file_fd = fd
|
||||
self.is_locked = True
|
||||
|
||||
def release(self):
|
||||
with self._thread_lock:
|
||||
if self.is_locked:
|
||||
fd = cast(int, self._lock_file_fd)
|
||||
self._lock_file_fd = None
|
||||
fcntl.flock(fd, fcntl.LOCK_UN)
|
||||
os.close(fd)
|
||||
self.is_locked = False
|
||||
|
||||
def __enter__(self):
|
||||
self.acquire()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, traceback):
|
||||
self.release()
|
||||
|
||||
def __del__(self):
|
||||
self.release()
|
||||
|
||||
|
||||
DEVICE_THRESHOLD_JSON_PATH = "/tmp/device_threshold.json"
|
||||
|
||||
|
||||
class DeviceThreshold:
|
||||
HIGH_THRESHOLD = 'high_threshold'
|
||||
LOW_THRESHOLD = 'low_threshold'
|
||||
HIGH_CRIT_THRESHOLD = 'high_critical_threshold'
|
||||
LOW_CRIT_THRESHOLD = 'low_critical_threshold'
|
||||
NOT_AVAILABLE = 'N/A'
|
||||
|
||||
def __init__(self, th_name=NOT_AVAILABLE):
|
||||
self.flock = FileLock("{}.lock".format(DEVICE_THRESHOLD_JSON_PATH))
|
||||
self.name = th_name
|
||||
self.__log = logger.Logger(log_identifier="DeviceThreshold")
|
||||
|
||||
self.__db_data = {}
|
||||
self.__db_mtime = 0
|
||||
|
||||
def __reload_db(self):
|
||||
try:
|
||||
db_data = {}
|
||||
with self.flock:
|
||||
with open(DEVICE_THRESHOLD_JSON_PATH, "r") as db_file:
|
||||
db_data = json.load(db_file)
|
||||
except Exception as e:
|
||||
self.__log.log_warning('{}'.format(str(e)))
|
||||
return None
|
||||
|
||||
return db_data
|
||||
|
||||
def __get_data(self, field):
|
||||
"""
|
||||
Retrieves data frome JSON file by field
|
||||
|
||||
Args :
|
||||
field: String
|
||||
|
||||
Returns:
|
||||
A string if getting is successfully, 'N/A' if not
|
||||
"""
|
||||
if os.path.exists(DEVICE_THRESHOLD_JSON_PATH):
|
||||
new_mtime = os.path.getmtime(DEVICE_THRESHOLD_JSON_PATH)
|
||||
if new_mtime != self.__db_mtime:
|
||||
new_data = self.__reload_db()
|
||||
if new_data is not None:
|
||||
self.__db_data = new_data
|
||||
self.__db_mtime = new_mtime
|
||||
|
||||
if self.name not in self.__db_data.keys():
|
||||
return self.NOT_AVAILABLE
|
||||
|
||||
if field not in self.__db_data[self.name].keys():
|
||||
return self.NOT_AVAILABLE
|
||||
|
||||
return self.__db_data[self.name][field]
|
||||
|
||||
def __set_data(self, field, new_val):
|
||||
"""
|
||||
Set data to JSON file by field
|
||||
|
||||
Args :
|
||||
field: String
|
||||
new_val: String
|
||||
|
||||
Returns:
|
||||
A boolean, True if setting is set successfully, False if not
|
||||
"""
|
||||
if self.name not in self.__db_data.keys():
|
||||
self.__db_data[self.name] = {}
|
||||
|
||||
old_val = self.__db_data[self.name].get(field, None)
|
||||
if old_val is not None and old_val == new_val:
|
||||
return True
|
||||
|
||||
self.__db_data[self.name][field] = new_val
|
||||
|
||||
try:
|
||||
with self.flock:
|
||||
db_data = {}
|
||||
mode = "r+" if os.path.exists(DEVICE_THRESHOLD_JSON_PATH) else "w+"
|
||||
with open(DEVICE_THRESHOLD_JSON_PATH, mode) as db_file:
|
||||
if mode == "r+":
|
||||
db_data = json.load(db_file)
|
||||
|
||||
if self.name not in db_data.keys():
|
||||
db_data[self.name] = {}
|
||||
|
||||
db_data[self.name][field] = new_val
|
||||
|
||||
if mode == "r+":
|
||||
db_file.seek(0)
|
||||
# erase old data
|
||||
db_file.truncate(0)
|
||||
# write all data
|
||||
json.dump(db_data, db_file, indent=4)
|
||||
self.__db_mtime = os.path.getmtime(DEVICE_THRESHOLD_JSON_PATH)
|
||||
except Exception as e:
|
||||
self.__log.log_error('{}'.format(str(e)))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_high_threshold(self):
|
||||
"""
|
||||
Retrieves the high threshold temperature from JSON file.
|
||||
|
||||
Returns:
|
||||
string : the high threshold temperature of thermal,
|
||||
e.g. "30.125"
|
||||
"""
|
||||
return self.__get_data(self.HIGH_THRESHOLD)
|
||||
|
||||
def set_high_threshold(self, temperature):
|
||||
"""
|
||||
Sets the high threshold temperature of thermal
|
||||
Args :
|
||||
temperature: A string of temperature, e.g. "30.125"
|
||||
Returns:
|
||||
A boolean, True if threshold is set successfully, False if not
|
||||
"""
|
||||
if isinstance(temperature, str) is not True:
|
||||
raise TypeError('The parameter requires string type.')
|
||||
|
||||
try:
|
||||
if temperature != self.NOT_AVAILABLE:
|
||||
float(temperature)
|
||||
except ValueError:
|
||||
raise ValueError('The parameter requires a float string. ex:\"30.1\"')
|
||||
|
||||
return self.__set_data(self.HIGH_THRESHOLD, temperature)
|
||||
|
||||
def get_low_threshold(self):
|
||||
"""
|
||||
Retrieves the low threshold temperature from JSON file.
|
||||
|
||||
Returns:
|
||||
string : the low threshold temperature of thermal,
|
||||
e.g. "30.125"
|
||||
"""
|
||||
return self.__get_data(self.LOW_THRESHOLD)
|
||||
|
||||
def set_low_threshold(self, temperature):
|
||||
"""
|
||||
Sets the low threshold temperature of thermal
|
||||
Args :
|
||||
temperature: A string of temperature, e.g. "30.125"
|
||||
Returns:
|
||||
A boolean, True if threshold is set successfully, False if not
|
||||
"""
|
||||
if isinstance(temperature, str) is not True:
|
||||
raise TypeError('The parameter requires string type.')
|
||||
|
||||
try:
|
||||
if temperature != self.NOT_AVAILABLE:
|
||||
float(temperature)
|
||||
except ValueError:
|
||||
raise ValueError('The parameter requires a float string. ex:\"30.1\"')
|
||||
|
||||
return self.__set_data(self.LOW_THRESHOLD, temperature)
|
||||
|
||||
def get_high_critical_threshold(self):
|
||||
"""
|
||||
Retrieves the high critical threshold temperature from JSON file.
|
||||
|
||||
Returns:
|
||||
string : the high critical threshold temperature of thermal,
|
||||
e.g. "30.125"
|
||||
"""
|
||||
return self.__get_data(self.HIGH_CRIT_THRESHOLD)
|
||||
|
||||
def set_high_critical_threshold(self, temperature):
|
||||
"""
|
||||
Sets the high critical threshold temperature of thermal
|
||||
Args :
|
||||
temperature: A string of temperature, e.g. "30.125"
|
||||
Returns:
|
||||
A boolean, True if threshold is set successfully, False if not
|
||||
"""
|
||||
if isinstance(temperature, str) is not True:
|
||||
raise TypeError('The parameter requires string type.')
|
||||
|
||||
try:
|
||||
if temperature != self.NOT_AVAILABLE:
|
||||
float(temperature)
|
||||
except ValueError:
|
||||
raise ValueError('The parameter requires a float string. ex:\"30.1\"')
|
||||
|
||||
return self.__set_data(self.HIGH_CRIT_THRESHOLD, temperature)
|
||||
|
||||
def get_low_critical_threshold(self):
|
||||
"""
|
||||
Retrieves the low critical threshold temperature from JSON file.
|
||||
|
||||
Returns:
|
||||
string : the low critical threshold temperature of thermal,
|
||||
e.g. "30.125"
|
||||
"""
|
||||
return self.__get_data(self.LOW_CRIT_THRESHOLD)
|
||||
|
||||
def set_low_critical_threshold(self, temperature):
|
||||
"""
|
||||
Sets the low critical threshold temperature of thermal
|
||||
Args :
|
||||
temperature: A string of temperature, e.g. "30.125"
|
||||
Returns:
|
||||
A boolean, True if threshold is set successfully, False if not
|
||||
"""
|
||||
if isinstance(temperature, str) is not True:
|
||||
raise TypeError('The parameter requires string type.')
|
||||
|
||||
try:
|
||||
if temperature != self.NOT_AVAILABLE:
|
||||
float(temperature)
|
||||
except ValueError:
|
||||
raise ValueError('The parameter requires a float string. ex:\"30.1\"')
|
||||
|
||||
return self.__set_data(self.LOW_CRIT_THRESHOLD, temperature)
|
@ -0,0 +1,19 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the fan status which are available in the platform
|
||||
# Base PCIe class
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Pcie(PcieUtil):
|
||||
"""Edgecore Platform-specific PCIe class"""
|
||||
|
||||
def __init__(self, platform_path):
|
||||
PcieUtil.__init__(self, platform_path)
|
@ -0,0 +1,21 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# 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,307 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the PSUs status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
from sonic_platform_base.psu_base import PsuBase
|
||||
from sonic_platform.thermal import Thermal
|
||||
from .helper import APIHelper
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
I2C_PATH = "/sys/bus/i2c/devices/{0}-00{1}/"
|
||||
|
||||
PSU_NAME_LIST = ["PSU-1", "PSU-2"]
|
||||
PSU_NUM_FAN = [1, 1]
|
||||
PSU_HWMON_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "58"
|
||||
},
|
||||
1: {
|
||||
"num": 11,
|
||||
"addr": "59"
|
||||
},
|
||||
}
|
||||
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "50"
|
||||
},
|
||||
1: {
|
||||
"num": 11,
|
||||
"addr": "51"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class Psu(PsuBase):
|
||||
"""Platform-specific Psu class"""
|
||||
|
||||
def __init__(self, psu_index=0):
|
||||
PsuBase.__init__(self)
|
||||
self.index = psu_index
|
||||
self._api_helper = APIHelper()
|
||||
|
||||
self.i2c_num = PSU_HWMON_I2C_MAPPING[self.index]["num"]
|
||||
self.i2c_addr = PSU_HWMON_I2C_MAPPING[self.index]["addr"]
|
||||
self.hwmon_path = I2C_PATH.format(self.i2c_num, self.i2c_addr)
|
||||
|
||||
self.i2c_num = PSU_CPLD_I2C_MAPPING[self.index]["num"]
|
||||
self.i2c_addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"]
|
||||
self.cpld_path = I2C_PATH.format(self.i2c_num, self.i2c_addr)
|
||||
self.__initialize_fan()
|
||||
|
||||
def __initialize_fan(self):
|
||||
from sonic_platform.fan import Fan
|
||||
for fan_index in range(0, PSU_NUM_FAN[self.index]):
|
||||
fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index)
|
||||
self._fan_list.append(fan)
|
||||
|
||||
self._thermal_list.append(Thermal(is_psu=True, psu_index=self.index))
|
||||
|
||||
def get_voltage(self):
|
||||
"""
|
||||
Retrieves current PSU voltage output
|
||||
Returns:
|
||||
A float number, the output voltage in volts,
|
||||
e.g. 12.1
|
||||
"""
|
||||
if self.get_status() is not True:
|
||||
return 0
|
||||
|
||||
vout_path = "{}{}".format(self.hwmon_path, 'psu_v_out')
|
||||
vout_val = self._api_helper.read_txt_file(vout_path)
|
||||
if vout_val is not None:
|
||||
return float(vout_val) / 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_current(self):
|
||||
"""
|
||||
Retrieves present electric current supplied by PSU
|
||||
Returns:
|
||||
A float number, the electric current in amperes, e.g 15.4
|
||||
"""
|
||||
if self.get_status() is not True:
|
||||
return 0
|
||||
|
||||
iout_path = "{}{}".format(self.hwmon_path, 'psu_i_out')
|
||||
val = self._api_helper.read_txt_file(iout_path)
|
||||
if val is not None:
|
||||
return float(val) / 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_power(self):
|
||||
"""
|
||||
Retrieves current energy supplied by PSU
|
||||
Returns:
|
||||
A float number, the power in watts, e.g. 302.6
|
||||
"""
|
||||
if self.get_status() is not True:
|
||||
return 0
|
||||
|
||||
pout_path = "{}{}".format(self.hwmon_path, 'psu_p_out')
|
||||
val = self._api_helper.read_txt_file(pout_path)
|
||||
if val is not None:
|
||||
return float(val) / 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
return False #Controlled by HW
|
||||
|
||||
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 = self.get_status()
|
||||
if status is None:
|
||||
return self.STATUS_LED_COLOR_OFF
|
||||
|
||||
return {
|
||||
1: self.STATUS_LED_COLOR_GREEN,
|
||||
0: self.STATUS_LED_COLOR_RED
|
||||
}.get(status, self.STATUS_LED_COLOR_OFF)
|
||||
|
||||
def get_temperature(self):
|
||||
"""
|
||||
Retrieves current temperature reading from PSU
|
||||
Returns:
|
||||
A float number of current temperature in Celsius up to nearest thousandth
|
||||
of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
temp_path = "{}{}".format(self.hwmon_path, 'psu_temp1_input')
|
||||
val = self._api_helper.read_txt_file(temp_path)
|
||||
if val is not None:
|
||||
return float(val) / 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_temperature_high_threshold(self):
|
||||
"""
|
||||
Retrieves the high threshold temperature of PSU
|
||||
Returns:
|
||||
A float number, the high threshold temperature of PSU in Celsius
|
||||
up to nearest thousandth of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
return self._thermal_list[0].get_high_threshold()
|
||||
|
||||
def get_voltage_high_threshold(self):
|
||||
"""
|
||||
Retrieves the high threshold PSU voltage output
|
||||
Returns:
|
||||
A float number, the high threshold output voltage in volts,
|
||||
e.g. 12.1
|
||||
"""
|
||||
vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_max')
|
||||
vout_val = self._api_helper.read_txt_file(vout_path)
|
||||
if vout_val is not None:
|
||||
return float(vout_val) / 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_voltage_low_threshold(self):
|
||||
"""
|
||||
Retrieves the low threshold PSU voltage output
|
||||
Returns:
|
||||
A float number, the low threshold output voltage in volts,
|
||||
e.g. 12.1
|
||||
"""
|
||||
vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_min')
|
||||
vout_val = self._api_helper.read_txt_file(vout_path)
|
||||
if vout_val is not None:
|
||||
return float(vout_val) / 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return PSU_NAME_LIST[self.index]
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the PSU
|
||||
Returns:
|
||||
bool: True if PSU is present, False if not
|
||||
"""
|
||||
presence_path = "{}{}".format(self.cpld_path, 'psu_present')
|
||||
val = self._api_helper.read_txt_file(presence_path)
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the device
|
||||
Returns:
|
||||
A boolean value, True if device is operating properly, False if not
|
||||
"""
|
||||
power_path = "{}{}".format(self.cpld_path, 'psu_power_good')
|
||||
val = self._api_helper.read_txt_file(power_path)
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
model_path = "{}{}".format(self.cpld_path, 'psu_model_name')
|
||||
model = self._api_helper.read_txt_file(model_path)
|
||||
if model is None:
|
||||
return "N/A"
|
||||
|
||||
return model
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the device
|
||||
Returns:
|
||||
string: Serial number of device
|
||||
"""
|
||||
serial_path = "{}{}".format(self.cpld_path, 'psu_serial_number')
|
||||
serial = self._api_helper.read_txt_file(serial_path)
|
||||
if serial is None:
|
||||
return "N/A"
|
||||
return serial
|
||||
|
||||
def get_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
|
||||
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
|
||||
"""
|
||||
return self.index + 1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
||||
|
||||
def get_revision(self):
|
||||
"""
|
||||
Retrieves the hardware revision of the device
|
||||
|
||||
Returns:
|
||||
string: Revision value of device
|
||||
"""
|
||||
revision_path = "{}{}".format(self.hwmon_path, 'psu_mfr_revision')
|
||||
revision = self._api_helper.read_txt_file(revision_path)
|
||||
if revision is None:
|
||||
return 'N/A'
|
||||
|
||||
return revision
|
||||
|
||||
def get_maximum_supplied_power(self):
|
||||
"""
|
||||
Retrieves the maximum supplied power by PSU
|
||||
Returns:
|
||||
A float number, the maximum power output in Watts.
|
||||
e.g. 1200.1
|
||||
"""
|
||||
pout_max_path = "{}{}".format(self.hwmon_path, 'psu_mfr_pout_max')
|
||||
val = self._api_helper.read_txt_file(pout_max_path)
|
||||
if val is not None:
|
||||
return float(val) / 1000
|
||||
else:
|
||||
return 0.0
|
@ -0,0 +1,526 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# Sfp contains an implementation of SONiC Platform Base API and
|
||||
# provides the sfp device status which are available in the platform
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
import time
|
||||
|
||||
try:
|
||||
from sonic_py_common.logger import Logger
|
||||
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
|
||||
from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper
|
||||
from .helper import APIHelper
|
||||
from sonic_py_common import device_info
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
NONE_SFP_TYPE = "NONE-SFP"
|
||||
SFP_TYPE = "SFP"
|
||||
QSFP_TYPE = "QSFP"
|
||||
|
||||
CPLD_I2C_PATH = "/sys/bus/i2c/devices/3-0060/"
|
||||
|
||||
logger = Logger()
|
||||
class Sfp(SfpOptoeBase):
|
||||
"""Platform-specific Sfp class"""
|
||||
|
||||
# Port number
|
||||
PORT_START = 49
|
||||
PORT_END = 54
|
||||
|
||||
# Path to sysfs
|
||||
PLATFORM_ROOT_PATH = "/usr/share/sonic/device"
|
||||
PMON_HWSKU_PATH = "/usr/share/sonic/hwsku"
|
||||
HOST_CHK_CMD = "which systemctl > /dev/null 2>&1"
|
||||
|
||||
_port_to_i2c_mapping = {
|
||||
49: 18,
|
||||
50: 19,
|
||||
51: 20,
|
||||
52: 21,
|
||||
53: 22,
|
||||
54: 23,
|
||||
}
|
||||
|
||||
SFP_TYPE_CODE_LIST = [
|
||||
0x03, # SFP/SFP+/SFP28
|
||||
0x0b # DWDM-SFP/SFP+
|
||||
]
|
||||
QSFP_TYPE_CODE_LIST = [
|
||||
0x0c, # QSFP
|
||||
0x0d, # QSFP+ or later
|
||||
0x11, # QSFP28 or later
|
||||
0xe1 # QSFP28 EDFA
|
||||
]
|
||||
|
||||
def __init__(self, sfp_index=0):
|
||||
SfpOptoeBase.__init__(self)
|
||||
self._api_helper = APIHelper()
|
||||
# Init index
|
||||
self.port_num = sfp_index + 1
|
||||
self.index = self.port_num
|
||||
if self.port_num < self.PORT_START:
|
||||
self.sfp_type = NONE_SFP_TYPE
|
||||
elif self.port_num < 53:
|
||||
self.sfp_type = SFP_TYPE
|
||||
else:
|
||||
self.sfp_type = QSFP_TYPE
|
||||
|
||||
# Init eeprom path
|
||||
eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom'
|
||||
self.port_to_eeprom_mapping = {}
|
||||
for x in range(self.PORT_START, self.PORT_END + 1):
|
||||
self.port_to_eeprom_mapping[x] = eeprom_path.format(self._port_to_i2c_mapping[x])
|
||||
|
||||
def get_eeprom_path(self):
|
||||
return self.port_to_eeprom_mapping[self.port_num]
|
||||
|
||||
def get_reset_status(self):
|
||||
"""
|
||||
Retrieves the reset status of SFP
|
||||
Returns:
|
||||
A Boolean, True if reset enabled, False if disabled
|
||||
"""
|
||||
if self.port_num < 53: #Copper port and sfp ports aren't supported.
|
||||
return False
|
||||
|
||||
reset_path = "{}{}{}".format(CPLD_I2C_PATH, "module_reset_", str(self.port_num))
|
||||
val = self._api_helper.read_txt_file(reset_path)
|
||||
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return False # CPLD port doesn't support this feature
|
||||
|
||||
def get_rx_los(self):
|
||||
"""
|
||||
Retrieves the RX LOS (lost-of-signal) status of SFP
|
||||
Returns:
|
||||
A Boolean, True if SFP has RX LOS, False if not.
|
||||
Note : RX LOS status is latched until a call to get_rx_los or a reset.
|
||||
"""
|
||||
rx_los = [False]
|
||||
|
||||
if self.port_num < 49: #Copper port, no sysfs
|
||||
return [False]
|
||||
|
||||
if self.port_num < 53:
|
||||
rx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_rx_los_', self.port_num)
|
||||
rx_los = self._api_helper.read_txt_file(rx_path)
|
||||
if rx_los is not None:
|
||||
if rx_los == '1':
|
||||
return [True]
|
||||
else:
|
||||
return [False]
|
||||
else:
|
||||
return [False]
|
||||
else:
|
||||
api = self.get_xcvr_api()
|
||||
if api is not None:
|
||||
rx_los = api.get_rx_los()
|
||||
if isinstance(rx_los, list) and "N/A" in rx_los:
|
||||
return [False for _ in rx_los]
|
||||
return rx_los
|
||||
return None
|
||||
|
||||
def get_tx_fault(self):
|
||||
"""
|
||||
Retrieves the TX fault status of SFP
|
||||
Returns:
|
||||
A Boolean, True if SFP has TX fault, False if not
|
||||
Note : TX fault status is lached until a call to get_tx_fault or a reset.
|
||||
"""
|
||||
tx_fault = [False]
|
||||
if self.port_num < 49: #Copper port, no sysfs
|
||||
return [False]
|
||||
|
||||
if self.port_num < 53:
|
||||
tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_fault_', self.port_num)
|
||||
tx_fault = self._api_helper.read_txt_file(tx_path)
|
||||
if tx_fault is not None:
|
||||
if tx_fault == '1':
|
||||
return [True]
|
||||
else:
|
||||
return [False]
|
||||
else:
|
||||
return [False]
|
||||
else:
|
||||
api = self.get_xcvr_api()
|
||||
if api is not None:
|
||||
tx_fault = api.get_tx_fault()
|
||||
if isinstance(tx_fault, list) and "N/A" in tx_fault:
|
||||
return [False for _ in tx_fault]
|
||||
return tx_fault
|
||||
return None
|
||||
|
||||
def get_tx_disable(self):
|
||||
"""
|
||||
Retrieves the tx_disable status of this SFP
|
||||
Returns:
|
||||
A Boolean, True if tx_disable is enabled, False if disabled
|
||||
"""
|
||||
if self.port_num < 49: #Copper port, no sysfs
|
||||
return False
|
||||
|
||||
if self.port_num < 53:
|
||||
tx_disable = False
|
||||
|
||||
tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num)
|
||||
tx_disable = self._api_helper.read_txt_file(tx_path)
|
||||
if tx_disable is not None:
|
||||
return tx_disable
|
||||
else:
|
||||
return False
|
||||
|
||||
else:
|
||||
api = self.get_xcvr_api()
|
||||
return api.get_tx_disable() if api is not None else None
|
||||
|
||||
def get_lpmode(self):
|
||||
"""
|
||||
Retrieves the lpmode (low power mode) status of this SFP
|
||||
Returns:
|
||||
A Boolean, True if lpmode is enabled, False if disabled
|
||||
"""
|
||||
if self.port_num < 53:
|
||||
# SFP doesn't support this feature
|
||||
return False
|
||||
else:
|
||||
power_set = self.get_power_set()
|
||||
power_override = self.get_power_override()
|
||||
return power_set and power_override
|
||||
|
||||
def get_power_set(self):
|
||||
if self.port_num < 53:
|
||||
# SFP doesn't support this feature
|
||||
return False
|
||||
else:
|
||||
api = self.get_xcvr_api()
|
||||
return api.get_power_set() if api is not None else None
|
||||
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset SFP and return all user module settings to their default srate.
|
||||
Returns:
|
||||
A boolean, True if successful, False if not
|
||||
"""
|
||||
# Check for invalid port_num
|
||||
if self.port_num < 53:
|
||||
return False
|
||||
|
||||
reset_path = "{}{}{}".format(CPLD_I2C_PATH, 'module_reset_', self.port_num)
|
||||
ret = self._api_helper.write_txt_file(reset_path, 1)
|
||||
if ret is not True:
|
||||
return ret
|
||||
|
||||
time.sleep(0.01)
|
||||
ret = self._api_helper.write_txt_file(reset_path, 0)
|
||||
time.sleep(0.2)
|
||||
|
||||
return ret
|
||||
|
||||
def tx_disable(self, tx_disable):
|
||||
"""
|
||||
Disable SFP TX for all channels
|
||||
Args:
|
||||
tx_disable : A Boolean, True to enable tx_disable mode, False to disable
|
||||
tx_disable mode.
|
||||
Returns:
|
||||
A boolean, True if tx_disable is set successfully, False if not
|
||||
"""
|
||||
if self.port_num < 49: #Copper port, no sysfs
|
||||
return [False]
|
||||
|
||||
if self.port_num < 53:
|
||||
tx_disable = False
|
||||
|
||||
tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num)
|
||||
tx_disable = self._api_helper.read_txt_file(tx_path)
|
||||
if tx_disable is not None:
|
||||
if tx_disable == '1':
|
||||
return [True]
|
||||
else:
|
||||
return [False]
|
||||
else:
|
||||
return [False]
|
||||
|
||||
else:
|
||||
if not self.get_presence():
|
||||
return False
|
||||
api = self.get_xcvr_api()
|
||||
return api.tx_disable(tx_disable) if api is not None else None
|
||||
|
||||
def set_lpmode(self, lpmode):
|
||||
"""
|
||||
Sets the lpmode (low power mode) of SFP
|
||||
Args:
|
||||
lpmode: A Boolean, True to enable lpmode, False to disable it
|
||||
Note : lpmode can be overridden by set_power_override
|
||||
Returns:
|
||||
A boolean, True if lpmode is set successfully, False if not
|
||||
"""
|
||||
if self.port_num < 53:
|
||||
return False # SFP doesn't support this feature
|
||||
else:
|
||||
# use power override to control lpmode
|
||||
if not self.get_presence():
|
||||
return False
|
||||
api = self.get_xcvr_api()
|
||||
if api is None:
|
||||
return False
|
||||
if api.get_lpmode_support() is False:
|
||||
logger.log_notice("The transceiver of port {} doesn't support to set low power mode.". format(self.port_num))
|
||||
return True
|
||||
if lpmode is True:
|
||||
ret = api.set_power_override(True, True)
|
||||
else:
|
||||
ret = api.set_power_override(True, False)
|
||||
|
||||
return ret
|
||||
|
||||
def set_power_override(self, power_override, power_set):
|
||||
"""
|
||||
Sets SFP power level using power_override and power_set
|
||||
Args:
|
||||
power_override :
|
||||
A Boolean, True to override set_lpmode and use power_set
|
||||
to control SFP power, False to disable SFP power control
|
||||
through power_override/power_set and use set_lpmode
|
||||
to control SFP power.
|
||||
power_set :
|
||||
Only valid when power_override is True.
|
||||
A Boolean, True to set SFP to low power mode, False to set
|
||||
SFP to high power mode.
|
||||
Returns:
|
||||
A boolean, True if power-override and power_set are set successfully,
|
||||
False if not
|
||||
"""
|
||||
if self.port_num < 53:
|
||||
return False # SFP doesn't support this feature
|
||||
else:
|
||||
if not self.get_presence():
|
||||
return False
|
||||
api = self.get_xcvr_api()
|
||||
return api.set_power_override(power_override, power_set) if api is not None else None
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
sfputil_helper = SfpUtilHelper()
|
||||
port_config_file_path = device_info.get_path_to_port_config_file()
|
||||
sfputil_helper.read_porttab_mappings(port_config_file_path)
|
||||
name = sfputil_helper.logical[self.port_num - 1] or "Unknown"
|
||||
return name
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the device
|
||||
Returns:
|
||||
bool: True if device is present, False if not
|
||||
"""
|
||||
if self.port_num < 49: #Copper port, no sysfs
|
||||
return False
|
||||
|
||||
present_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_present_', self.port_num)
|
||||
val = self._api_helper.read_txt_file(present_path)
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
transceiver_dom_info_dict = self.get_transceiver_info()
|
||||
return transceiver_dom_info_dict.get("model", "N/A")
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the device
|
||||
Returns:
|
||||
string: Serial number of device
|
||||
"""
|
||||
transceiver_dom_info_dict = self.get_transceiver_info()
|
||||
return transceiver_dom_info_dict.get("serial", "N/A")
|
||||
|
||||
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 not self.get_reset_status()
|
||||
|
||||
def get_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
|
||||
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
|
||||
"""
|
||||
return self.port_num
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Indicate whether this device is replaceable.
|
||||
Returns:
|
||||
bool: True if it is replaceable.
|
||||
"""
|
||||
return True
|
||||
|
||||
def __validate_eeprom_sfp(self):
|
||||
checksum_test = 0
|
||||
eeprom_raw = self.read_eeprom(0, 96)
|
||||
if eeprom_raw is None:
|
||||
return None
|
||||
|
||||
for i in range(0, 63):
|
||||
checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF
|
||||
else:
|
||||
if checksum_test != eeprom_raw[63]:
|
||||
return False
|
||||
|
||||
checksum_test = 0
|
||||
for i in range(64, 95):
|
||||
checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF
|
||||
else:
|
||||
if checksum_test != eeprom_raw[95]:
|
||||
return False
|
||||
|
||||
api = self.get_xcvr_api()
|
||||
if api is None:
|
||||
return False
|
||||
|
||||
if api.is_flat_memory():
|
||||
return True
|
||||
|
||||
checksum_test = 0
|
||||
eeprom_raw = self.read_eeprom(384, 96)
|
||||
if eeprom_raw is None:
|
||||
return None
|
||||
|
||||
for i in range(0, 95):
|
||||
checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF
|
||||
else:
|
||||
if checksum_test != eeprom_raw[95]:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def __validate_eeprom_qsfp(self):
|
||||
checksum_test = 0
|
||||
eeprom_raw = self.read_eeprom(128, 96)
|
||||
if eeprom_raw is None:
|
||||
return None
|
||||
|
||||
for i in range(0, 63):
|
||||
checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF
|
||||
else:
|
||||
if checksum_test != eeprom_raw[63]:
|
||||
return False
|
||||
|
||||
checksum_test = 0
|
||||
for i in range(64, 95):
|
||||
checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF
|
||||
else:
|
||||
if checksum_test != eeprom_raw[95]:
|
||||
return False
|
||||
|
||||
api = self.get_xcvr_api()
|
||||
if api is None:
|
||||
return False
|
||||
|
||||
if api.is_flat_memory():
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
def validate_eeprom(self):
|
||||
id_byte_raw = self.read_eeprom(0, 1)
|
||||
if id_byte_raw is None:
|
||||
return None
|
||||
|
||||
type_id = id_byte_raw[0]
|
||||
if type_id in self.QSFP_TYPE_CODE_LIST:
|
||||
return self.__validate_eeprom_qsfp()
|
||||
elif type_id in self.SFP_TYPE_CODE_LIST:
|
||||
return self.__validate_eeprom_sfp()
|
||||
|
||||
return False
|
||||
|
||||
def validate_temperature(self):
|
||||
temperature = self.get_temperature()
|
||||
if temperature is None:
|
||||
return None
|
||||
|
||||
threshold_dict = self.get_transceiver_threshold_info()
|
||||
if threshold_dict is None:
|
||||
return None
|
||||
|
||||
if isinstance(temperature, float) is not True:
|
||||
return True
|
||||
|
||||
if isinstance(threshold_dict['temphighalarm'], float) is not True:
|
||||
return True
|
||||
|
||||
return threshold_dict['temphighalarm'] > temperature
|
||||
|
||||
def __get_error_description(self):
|
||||
if not self.get_presence():
|
||||
return self.SFP_STATUS_UNPLUGGED
|
||||
|
||||
err_stat = self.SFP_STATUS_BIT_INSERTED
|
||||
|
||||
status = self.validate_eeprom()
|
||||
if status is not True:
|
||||
err_stat = (err_stat | self.SFP_ERROR_BIT_BAD_EEPROM)
|
||||
|
||||
status = self.validate_temperature()
|
||||
if status is not True:
|
||||
err_stat = (err_stat | self.SFP_ERROR_BIT_HIGH_TEMP)
|
||||
|
||||
if err_stat is self.SFP_STATUS_BIT_INSERTED:
|
||||
return self.SFP_STATUS_OK
|
||||
else:
|
||||
err_desc = ''
|
||||
cnt = 0
|
||||
for key in self.SFP_ERROR_BIT_TO_DESCRIPTION_DICT:
|
||||
if (err_stat & key) != 0:
|
||||
if cnt > 0:
|
||||
err_desc = err_desc + "|"
|
||||
cnt = cnt + 1
|
||||
err_desc = err_desc + self.SFP_ERROR_BIT_TO_DESCRIPTION_DICT[key]
|
||||
|
||||
return err_desc
|
||||
|
||||
def get_error_description(self):
|
||||
"""
|
||||
Retrives the error descriptions of the SFP module
|
||||
|
||||
Returns:
|
||||
String that represents the current error descriptions of vendor specific errors
|
||||
In case there are multiple errors, they should be joined by '|',
|
||||
like: "Bad EEPROM|Unsupported cable"
|
||||
"""
|
||||
if self.port_num < 49:
|
||||
# RJ45 doesn't support this feature
|
||||
return None
|
||||
else:
|
||||
api = self.get_xcvr_api()
|
||||
if api is not None:
|
||||
try:
|
||||
return api.get_error_description()
|
||||
except NotImplementedError:
|
||||
return self.__get_error_description()
|
||||
else:
|
||||
return self.__get_error_description()
|
@ -0,0 +1,422 @@
|
||||
#############################################################################
|
||||
# Edgecore
|
||||
#
|
||||
# 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
|
||||
import glob
|
||||
|
||||
try:
|
||||
from sonic_platform_base.thermal_base import ThermalBase
|
||||
from .helper import DeviceThreshold
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/"
|
||||
PSU_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "58"
|
||||
},
|
||||
1: {
|
||||
"num": 11,
|
||||
"addr": "59"
|
||||
},
|
||||
}
|
||||
|
||||
PSU_CPLD_I2C_MAPPING = {
|
||||
0: {
|
||||
"num": 10,
|
||||
"addr": "50"
|
||||
},
|
||||
1: {
|
||||
"num": 11,
|
||||
"addr": "51"
|
||||
},
|
||||
}
|
||||
|
||||
NOT_AVAILABLE = DeviceThreshold.NOT_AVAILABLE
|
||||
HIGH_THRESHOLD = DeviceThreshold.HIGH_THRESHOLD
|
||||
LOW_THRESHOLD = DeviceThreshold.LOW_THRESHOLD
|
||||
HIGH_CRIT_THRESHOLD = DeviceThreshold.HIGH_CRIT_THRESHOLD
|
||||
LOW_CRIT_THRESHOLD = DeviceThreshold.LOW_CRIT_THRESHOLD
|
||||
|
||||
DEFAULT_THRESHOLD = {
|
||||
'Temp sensor 1': {
|
||||
HIGH_THRESHOLD: '80.0',
|
||||
LOW_THRESHOLD: NOT_AVAILABLE,
|
||||
HIGH_CRIT_THRESHOLD: NOT_AVAILABLE,
|
||||
LOW_CRIT_THRESHOLD: NOT_AVAILABLE
|
||||
},
|
||||
'Temp sensor 2': {
|
||||
HIGH_THRESHOLD: '80.0',
|
||||
LOW_THRESHOLD: NOT_AVAILABLE,
|
||||
HIGH_CRIT_THRESHOLD: NOT_AVAILABLE,
|
||||
LOW_CRIT_THRESHOLD: NOT_AVAILABLE
|
||||
},
|
||||
'Temp sensor 3': {
|
||||
HIGH_THRESHOLD: '80.0',
|
||||
LOW_THRESHOLD: NOT_AVAILABLE,
|
||||
HIGH_CRIT_THRESHOLD: NOT_AVAILABLE,
|
||||
LOW_CRIT_THRESHOLD: NOT_AVAILABLE
|
||||
},
|
||||
'Temp sensor 4': {
|
||||
HIGH_THRESHOLD: '71.0',
|
||||
LOW_THRESHOLD: NOT_AVAILABLE,
|
||||
HIGH_CRIT_THRESHOLD: '91.0',
|
||||
LOW_CRIT_THRESHOLD: NOT_AVAILABLE
|
||||
},
|
||||
'PSU-1 temp sensor 1': {
|
||||
HIGH_THRESHOLD: '80.0',
|
||||
LOW_THRESHOLD: NOT_AVAILABLE,
|
||||
HIGH_CRIT_THRESHOLD: NOT_AVAILABLE,
|
||||
LOW_CRIT_THRESHOLD: NOT_AVAILABLE
|
||||
},
|
||||
'PSU-2 temp sensor 1': {
|
||||
HIGH_THRESHOLD: '80.0',
|
||||
LOW_THRESHOLD: NOT_AVAILABLE,
|
||||
HIGH_CRIT_THRESHOLD: NOT_AVAILABLE,
|
||||
LOW_CRIT_THRESHOLD: NOT_AVAILABLE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Thermal(ThermalBase):
|
||||
"""Platform-specific Thermal class"""
|
||||
|
||||
THERMAL_NAME_LIST = []
|
||||
PSU_THERMAL_NAME_LIST = []
|
||||
SYSFS_PATH = "/sys/bus/i2c/devices"
|
||||
CPU_SYSFS_PATH = "/sys/devices/platform"
|
||||
|
||||
def __init__(self, thermal_index=0, is_psu=False, psu_index=0):
|
||||
self.index = thermal_index
|
||||
self.is_psu = is_psu
|
||||
self.psu_index = psu_index
|
||||
self.min_temperature = None
|
||||
self.max_temperature = None
|
||||
|
||||
if self.is_psu:
|
||||
psu_i2c_bus = PSU_I2C_MAPPING[psu_index]["num"]
|
||||
psu_i2c_addr = PSU_I2C_MAPPING[psu_index]["addr"]
|
||||
self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus,
|
||||
psu_i2c_addr)
|
||||
psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["num"]
|
||||
psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"]
|
||||
self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr)
|
||||
# Add thermal name
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 1")
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 2")
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 3")
|
||||
self.THERMAL_NAME_LIST.append("Temp sensor 4")
|
||||
self.PSU_THERMAL_NAME_LIST.append("PSU-1 temp sensor 1")
|
||||
self.PSU_THERMAL_NAME_LIST.append("PSU-2 temp sensor 1")
|
||||
|
||||
# Threshold Configuration
|
||||
self.__conf = DeviceThreshold(self.get_name())
|
||||
# Default threshold.
|
||||
self.__default_threshold = DEFAULT_THRESHOLD[self.get_name()]
|
||||
|
||||
# Set hwmon path
|
||||
i2c_path = {
|
||||
0: "14-0048/hwmon/hwmon*/",
|
||||
1: "24-004b/hwmon/hwmon*/",
|
||||
2: "25-004a/hwmon/hwmon*/",
|
||||
3: "coretemp.0/hwmon/hwmon*/"
|
||||
}.get(self.index, None)
|
||||
|
||||
self.is_cpu = False
|
||||
if self.index == 3:
|
||||
self.is_cpu = True
|
||||
self.hwmon_path = "{}/{}".format(self.CPU_SYSFS_PATH, i2c_path)
|
||||
else:
|
||||
self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path)
|
||||
self.ss_key = self.THERMAL_NAME_LIST[self.index]
|
||||
self.ss_index = 1
|
||||
|
||||
def __read_txt_file(self, file_path):
|
||||
for filename in glob.glob(file_path):
|
||||
try:
|
||||
with open(filename, 'r') as fd:
|
||||
data = fd.readline().strip()
|
||||
if len(data) > 0:
|
||||
return data
|
||||
except IOError as e:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def __get_temp(self, temp_file):
|
||||
if not self.is_psu:
|
||||
temp_file_path = os.path.join(self.hwmon_path, temp_file)
|
||||
else:
|
||||
temp_file_path = temp_file
|
||||
raw_temp = self.__read_txt_file(temp_file_path)
|
||||
if raw_temp is not None:
|
||||
return float(raw_temp) / 1000
|
||||
else:
|
||||
return 0
|
||||
|
||||
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
|
||||
"""
|
||||
if not self.is_psu:
|
||||
temp_file = "temp{}_input".format(self.ss_index)
|
||||
else:
|
||||
temp_file = self.psu_hwmon_path + "psu_temp1_input"
|
||||
|
||||
current = self.__get_temp(temp_file)
|
||||
|
||||
if self.min_temperature is None or \
|
||||
current < self.min_temperature:
|
||||
self.min_temperature = current
|
||||
|
||||
if self.max_temperature is None or \
|
||||
current > self.max_temperature:
|
||||
self.max_temperature = current
|
||||
|
||||
return current
|
||||
|
||||
def set_high_threshold(self, temperature):
|
||||
try:
|
||||
value = float(temperature)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
# The new value can not be more than the default value.
|
||||
default_value = self.__default_threshold[HIGH_THRESHOLD]
|
||||
if default_value != NOT_AVAILABLE:
|
||||
if value > float(default_value):
|
||||
return False
|
||||
|
||||
try:
|
||||
self.__conf.set_high_threshold(str(value))
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_high_threshold(self):
|
||||
value = self.__conf.get_high_threshold()
|
||||
if value != NOT_AVAILABLE:
|
||||
return float(value)
|
||||
|
||||
default_value = self.__default_threshold[HIGH_THRESHOLD]
|
||||
if default_value != NOT_AVAILABLE:
|
||||
return float(default_value)
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
def set_low_threshold(self, temperature):
|
||||
try:
|
||||
value = float(temperature)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
# The new value can not be less than the default value.
|
||||
default_value = self.__default_threshold[LOW_THRESHOLD]
|
||||
if default_value != NOT_AVAILABLE:
|
||||
if value < float(default_value):
|
||||
return False
|
||||
|
||||
try:
|
||||
self.__conf.set_low_threshold(str(value))
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_low_threshold(self):
|
||||
value = self.__conf.get_low_threshold()
|
||||
if value != NOT_AVAILABLE:
|
||||
return float(value)
|
||||
|
||||
default_value = self.__default_threshold[LOW_THRESHOLD]
|
||||
if default_value != NOT_AVAILABLE:
|
||||
return float(default_value)
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
def set_high_critical_threshold(self, temperature):
|
||||
try:
|
||||
value = float(temperature)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
# The new value can not be more than the default value.
|
||||
default_value = self.__default_threshold[HIGH_CRIT_THRESHOLD]
|
||||
if default_value != NOT_AVAILABLE:
|
||||
if value > float(default_value):
|
||||
return False
|
||||
|
||||
try:
|
||||
self.__conf.set_high_critical_threshold(str(value))
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_high_critical_threshold(self):
|
||||
value = self.__conf.get_high_critical_threshold()
|
||||
if value != NOT_AVAILABLE:
|
||||
return float(value)
|
||||
|
||||
default_value = self.__default_threshold[HIGH_CRIT_THRESHOLD]
|
||||
if default_value != NOT_AVAILABLE:
|
||||
return float(default_value)
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
def set_low_critical_threshold(self, temperature):
|
||||
try:
|
||||
value = float(temperature)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
# The new value can not be less than the default value.
|
||||
default_value = self.__default_threshold[LOW_CRIT_THRESHOLD]
|
||||
if default_value != NOT_AVAILABLE:
|
||||
if value < float(default_value):
|
||||
return False
|
||||
|
||||
try:
|
||||
self.__conf.set_low_critical_threshold(str(value))
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_low_critical_threshold(self):
|
||||
value = self.__conf.get_low_critical_threshold()
|
||||
if value != NOT_AVAILABLE:
|
||||
return float(value)
|
||||
|
||||
default_value = self.__default_threshold[LOW_CRIT_THRESHOLD]
|
||||
if default_value != NOT_AVAILABLE:
|
||||
return float(default_value)
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the thermal device
|
||||
Returns:
|
||||
string: The name of the thermal device
|
||||
"""
|
||||
if self.is_psu:
|
||||
return self.PSU_THERMAL_NAME_LIST[self.psu_index]
|
||||
else:
|
||||
return self.THERMAL_NAME_LIST[self.index]
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the Thermal
|
||||
Returns:
|
||||
bool: True if Thermal is present, False if not
|
||||
"""
|
||||
if self.is_cpu:
|
||||
return True
|
||||
|
||||
if self.is_psu:
|
||||
val = self.__read_txt_file(self.cpld_path + "psu_present")
|
||||
if val is not None:
|
||||
return int(val, 10) == 1
|
||||
else:
|
||||
return False
|
||||
temp_file = "temp{}_input".format(self.ss_index)
|
||||
temp_file_path = os.path.join(self.hwmon_path, temp_file)
|
||||
raw_txt = self.__read_txt_file(temp_file_path)
|
||||
if raw_txt is not None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
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.is_cpu:
|
||||
return True
|
||||
|
||||
if self.is_psu:
|
||||
temp_file = self.psu_hwmon_path + "psu_temp_fault"
|
||||
psu_temp_fault = self.__read_txt_file(temp_file)
|
||||
if psu_temp_fault is None:
|
||||
psu_temp_fault = '1'
|
||||
return self.get_presence() and (not int(psu_temp_fault))
|
||||
|
||||
file_str = "temp{}_input".format(self.ss_index)
|
||||
file_path = os.path.join(self.hwmon_path, file_str)
|
||||
raw_txt = self.__read_txt_file(file_path)
|
||||
if raw_txt is None:
|
||||
return False
|
||||
else:
|
||||
return int(raw_txt) != 0
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the device
|
||||
Returns:
|
||||
string: Model/part number of device
|
||||
"""
|
||||
|
||||
return "N/A"
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the device
|
||||
Returns:
|
||||
string: Serial number of device
|
||||
"""
|
||||
return "N/A"
|
||||
|
||||
def get_position_in_parent(self):
|
||||
"""
|
||||
Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position
|
||||
for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned
|
||||
Returns:
|
||||
integer: The 1-based relative physical position in parent device or -1 if cannot determine the position
|
||||
"""
|
||||
return self.index + 1
|
||||
|
||||
def is_replaceable(self):
|
||||
"""
|
||||
Retrieves whether thermal module is replaceable
|
||||
Returns:
|
||||
A boolean value, True if replaceable, False if not
|
||||
"""
|
||||
return False
|
||||
|
||||
def get_minimum_recorded(self):
|
||||
"""
|
||||
Retrieves the minimum recorded temperature of thermal
|
||||
Returns:
|
||||
A float number, the minimum recorded temperature of thermal in Celsius
|
||||
up to nearest thousandth of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
if self.min_temperature is None:
|
||||
self.get_temperature()
|
||||
|
||||
return self.min_temperature
|
||||
|
||||
def get_maximum_recorded(self):
|
||||
"""
|
||||
Retrieves the maximum recorded temperature of thermal
|
||||
Returns:
|
||||
A float number, the maximum recorded temperature of thermal in Celsius
|
||||
up to nearest thousandth of one degree Celsius, e.g. 30.125
|
||||
"""
|
||||
if self.max_temperature is None:
|
||||
self.get_temperature()
|
||||
|
||||
return self.max_temperature
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"services_to_ignore": [],
|
||||
"devices_to_ignore": [
|
||||
"asic"
|
||||
],
|
||||
"user_defined_checkers": [],
|
||||
"polling_interval": 60,
|
||||
"led_color": {
|
||||
"fault": "STATUS_LED_COLOR_AMBER",
|
||||
"normal": "STATUS_LED_COLOR_GREEN",
|
||||
"booting": "STATUS_LED_COLOR_GREEN_BLINK"
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
|
||||
$(ACCTON_AS7726_32X_PLATFORM_MODULE) \
|
||||
$(ACCTON_AS4630_54PE_PLATFORM_MODULE) \
|
||||
$(ACCTON_AS4630_54TE_PLATFORM_MODULE) \
|
||||
$(ACCTON_AS4630_54NPE_PLATFORM_MODULE) \
|
||||
$(ACCTON_MINIPACK_PLATFORM_MODULE) \
|
||||
$(ACCTON_AS5812_54X_PLATFORM_MODULE) \
|
||||
$(ACCTON_AS5812_54T_PLATFORM_MODULE) \
|
||||
|
@ -11,6 +11,7 @@ ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION = 1.1
|
||||
ACCTON_AS7726_32X_PLATFORM_MODULE_VERSION = 1.1
|
||||
ACCTON_AS4630_54PE_PLATFORM_MODULE_VERSION = 1.1
|
||||
ACCTON_AS4630_54TE_PLATFORM_MODULE_VERSION = 1.1
|
||||
ACCTON_AS4630_54NPE_PLATFORM_MODULE_VERSION = 1.1
|
||||
ACCTON_MINIPACK_PLATFORM_MODULE_VERSION = 1.1
|
||||
ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION = 1.1
|
||||
ACCTON_AS5812_54T_PLATFORM_MODULE_VERSION = 1.1
|
||||
@ -32,6 +33,7 @@ export ACCTON_AS6712_32X_PLATFORM_MODULE_VERSION
|
||||
export ACCTON_AS7726_32X_PLATFORM_MODULE_VERSION
|
||||
export ACCTON_AS4630_54PE_PLATFORM_MODULE_VERSION
|
||||
export ACCTON_AS4630_54TE_PLATFORM_MODULE_VERSION
|
||||
export ACCTON_AS4630_54NPE_PLATFORM_MODULE_VERSION
|
||||
export ACCTON_MINIPACK_PLATFORM_MODULE_VERSION
|
||||
export ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION
|
||||
export ACCTON_AS5812_54T_PLATFORM_MODULE_VERSION
|
||||
@ -92,6 +94,10 @@ ACCTON_AS4630_54TE_PLATFORM_MODULE = sonic-platform-accton-as4630-54te_$(ACCTON_
|
||||
$(ACCTON_AS4630_54TE_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as4630_54te-r0
|
||||
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS4630_54TE_PLATFORM_MODULE)))
|
||||
|
||||
ACCTON_AS4630_54NPE_PLATFORM_MODULE = sonic-platform-accton-as4630-54npe_$(ACCTON_AS4630_54NPE_PLATFORM_MODULE_VERSION)_amd64.deb
|
||||
$(ACCTON_AS4630_54NPE_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as4630_54npe-r0
|
||||
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS4630_54NPE_PLATFORM_MODULE)))
|
||||
|
||||
ACCTON_MINIPACK_PLATFORM_MODULE = sonic-platform-accton-minipack_$(ACCTON_MINIPACK_PLATFORM_MODULE_VERSION)_amd64.deb
|
||||
$(ACCTON_MINIPACK_PLATFORM_MODULE)_PLATFORM = x86_64-accton_minipack-r0
|
||||
$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_MINIPACK_PLATFORM_MODULE)))
|
||||
|
@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2019 Edgecore Networks Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
|
||||
# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
#
|
||||
# See the Apache Version 2.0 License for specific language governing
|
||||
# permissions and limitations under the License.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# HISTORY:
|
||||
# mm/dd/yyyy (A.D.)
|
||||
# 10/24/2019:Jostar craete for as4630_54npe
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
try:
|
||||
import logging
|
||||
except ImportError as e:
|
||||
raise ImportError('%s - required module not found' % str(e))
|
||||
|
||||
|
||||
class FanUtil(object):
|
||||
"""Platform-specific FanUtil class"""
|
||||
|
||||
FAN_NUM_ON_MAIN_BROAD = 3
|
||||
FAN_NUM_1_IDX = 1
|
||||
FAN_NUM_2_IDX = 2
|
||||
FAN_NUM_3_IDX = 3
|
||||
|
||||
FAN_NODE_NUM_OF_MAP = 4
|
||||
FAN_NODE_FAULT_IDX_OF_MAP = 1
|
||||
FAN_NODE_DIR_IDX_OF_MAP = 2
|
||||
FAN_NODE_PRESENT_IDX_OF_MAP = 3
|
||||
FAN_NODE_SPEED_IDX_OF_MAP = 4
|
||||
|
||||
BASE_VAL_PATH = '/sys/bus/i2c/devices/3-0060/{0}'
|
||||
FAN_DUTY_PATH = '/sys/bus/i2c/devices/3-0060/fan_duty_cycle_percentage'
|
||||
|
||||
""" Dictionary where
|
||||
key1 = fan id index (integer) starting from 1
|
||||
key2 = fan node index (interger) starting from 1
|
||||
value = path to fan device file (string) """
|
||||
_fan_device_path_mapping = {}
|
||||
|
||||
_fan_device_node_mapping = {
|
||||
(FAN_NUM_1_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan_fault_1',
|
||||
(FAN_NUM_1_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan_direction_1',
|
||||
(FAN_NUM_1_IDX, FAN_NODE_PRESENT_IDX_OF_MAP): 'fan_present_1',
|
||||
(FAN_NUM_1_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan1_input',
|
||||
|
||||
|
||||
(FAN_NUM_2_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan_fault_2',
|
||||
(FAN_NUM_2_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan_direction_2',
|
||||
(FAN_NUM_2_IDX, FAN_NODE_PRESENT_IDX_OF_MAP): 'fan_present_2',
|
||||
(FAN_NUM_2_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan2_input',
|
||||
|
||||
(FAN_NUM_3_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan_fault_3',
|
||||
(FAN_NUM_3_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan_direction_3',
|
||||
(FAN_NUM_3_IDX, FAN_NODE_PRESENT_IDX_OF_MAP): 'fan_present_3',
|
||||
(FAN_NUM_3_IDX, FAN_NODE_SPEED_IDX_OF_MAP): 'fan3_input',
|
||||
}
|
||||
|
||||
def _get_fan_device_node(self, fan_num, node_num):
|
||||
return self._fan_device_node_mapping[(fan_num, node_num)]
|
||||
|
||||
def _get_fan_node_val(self, fan_num, node_num):
|
||||
if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
|
||||
logging.debug('GET. Parameter error. fan_num:%d', fan_num)
|
||||
return None
|
||||
|
||||
if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP:
|
||||
logging.debug('GET. Parameter error. node_num:%d', node_num)
|
||||
return None
|
||||
|
||||
device_path = self.get_fan_device_path(fan_num, node_num)
|
||||
|
||||
try:
|
||||
val_file = open(device_path, 'r')
|
||||
except IOError as e:
|
||||
logging.error('GET. unable to open file: %s', str(e))
|
||||
return None
|
||||
|
||||
content = val_file.readline().rstrip()
|
||||
if content == '':
|
||||
logging.debug('GET. content is NULL. device_path:%s', device_path)
|
||||
return None
|
||||
|
||||
try:
|
||||
val_file.close()
|
||||
except Exception:
|
||||
logging.debug(
|
||||
'GET. unable to close file. device_path:%s',
|
||||
device_path)
|
||||
return None
|
||||
|
||||
return int(content)
|
||||
|
||||
def _set_fan_node_val(self, fan_num, node_num, val):
|
||||
if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
|
||||
logging.debug('GET. Parameter error. fan_num:%d', fan_num)
|
||||
return None
|
||||
|
||||
if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP:
|
||||
logging.debug('GET. Parameter error. node_num:%d', node_num)
|
||||
return None
|
||||
|
||||
content = str(val)
|
||||
if content == '':
|
||||
logging.debug('GET. content is NULL. device_path:%s', device_path)
|
||||
return None
|
||||
|
||||
device_path = self.get_fan_device_path(fan_num, node_num)
|
||||
try:
|
||||
val_file = open(device_path, 'w')
|
||||
except IOError as e:
|
||||
logging.error('GET. unable to open file: %s', str(e))
|
||||
return None
|
||||
|
||||
val_file.write(content)
|
||||
|
||||
try:
|
||||
val_file.close()
|
||||
except Exception:
|
||||
logging.debug(
|
||||
'GET. unable to close file. device_path:%s',
|
||||
device_path)
|
||||
return None
|
||||
|
||||
return True
|
||||
|
||||
def __init__(self):
|
||||
fan_path = self.BASE_VAL_PATH
|
||||
for fan_num in range(
|
||||
self.FAN_NUM_1_IDX,
|
||||
self.FAN_NUM_ON_MAIN_BROAD + 1):
|
||||
for node_num in range(
|
||||
self.FAN_NODE_FAULT_IDX_OF_MAP,
|
||||
self.FAN_NODE_NUM_OF_MAP + 1):
|
||||
self._fan_device_path_mapping[(fan_num, node_num)] = fan_path.format(
|
||||
self._fan_device_node_mapping[(fan_num, node_num)])
|
||||
|
||||
def get_size_node_map(self):
|
||||
return len(self._fan_device_node_mapping)
|
||||
|
||||
def get_fan_device_path(self, fan_num, node_num):
|
||||
return self._fan_device_path_mapping[(fan_num, node_num)]
|
||||
|
||||
def get_fan_fault(self, fan_num):
|
||||
return self._get_fan_node_val(fan_num, self.FAN_NODE_FAULT_IDX_OF_MAP)
|
||||
|
||||
def get_fan_present(self, fan_num):
|
||||
return self._get_fan_node_val(
|
||||
fan_num, self.FAN_NODE_PRESENT_IDX_OF_MAP)
|
||||
|
||||
def get_fan_dir(self, fan_num):
|
||||
return self._get_fan_node_val(fan_num, self.FAN_NODE_DIR_IDX_OF_MAP)
|
||||
|
||||
def get_fan_duty_cycle(self):
|
||||
try:
|
||||
val_file = open(self.FAN_DUTY_PATH)
|
||||
except IOError as e:
|
||||
print("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
|
||||
content = val_file.readline().rstrip()
|
||||
val_file.close()
|
||||
|
||||
return int(content)
|
||||
|
||||
def set_fan_duty_cycle(self, val):
|
||||
try:
|
||||
fan_file = open(self.FAN_DUTY_PATH, 'r+')
|
||||
except IOError as e:
|
||||
print("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
|
||||
fan_file.write(str(val))
|
||||
fan_file.close()
|
||||
return True
|
||||
|
||||
def get_fan_speed(self, fan_num):
|
||||
return self._get_fan_node_val(fan_num, self.FAN_NODE_SPEED_IDX_OF_MAP)
|
||||
|
||||
def get_fan_status(self, fan_num):
|
||||
if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD:
|
||||
logging.debug('GET. Parameter error. fan_num, %d', fan_num)
|
||||
return None
|
||||
if self.get_fan_fault(
|
||||
fan_num) == 0 and self.get_fan_present(fan_num) > 0:
|
||||
return 1
|
||||
else:
|
||||
logging.debug('GET. FAN fault. fan_num, %d', fan_num)
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
fan = FanUtil()
|
||||
logging.debug('fan_duty_cycle=%d', fan.get_fan_duty_cycle())
|
||||
for i in range(1, 4):
|
||||
logging.debug('fan-%d speed=%d', i, fan.get_fan_speed(i))
|
||||
logging.debug('fan-%d present=%d', i, fan.get_fan_present(i))
|
||||
logging.debug('fan-%d fault=%d', i, fan.get_fan_fault(i))
|
||||
logging.debug('fan-%d status=%d', i, fan.get_fan_status(i))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2019 Edgecore Networks Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
|
||||
# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
#
|
||||
# See the Apache Version 2.0 License for specific language governing
|
||||
# permissions and limitations under the License.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# HISTORY:
|
||||
# mm/dd/yyyy (A.D.)
|
||||
# 10/24/2019:Jostar craete for as4630_54npe
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
try:
|
||||
import logging
|
||||
import glob
|
||||
except ImportError as e:
|
||||
raise ImportError('%s - required module not found' % str(e))
|
||||
|
||||
|
||||
class ThermalUtil(object):
|
||||
"""Platform-specific ThermalUtil class"""
|
||||
THERMAL_NUM_MAX = 4
|
||||
THERMAL_NUM_1_IDX = 1
|
||||
THERMAL_NUM_2_IDX = 2
|
||||
THERMAL_NUM_3_IDX = 3
|
||||
THERMAL_NUM_4_IDX = 4
|
||||
|
||||
""" Dictionary where
|
||||
key1 = thermal id index (integer) starting from 1
|
||||
value = path to fan device file (string) """
|
||||
|
||||
thermal_sysfspath = {
|
||||
THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/14-0048/hwmon/hwmon*/temp1_input"],
|
||||
THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/24-004b/hwmon/hwmon*/temp1_input"],
|
||||
THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/25-004a/hwmon/hwmon*/temp1_input"],
|
||||
THERMAL_NUM_4_IDX: ["/sys/class/hwmon/hwmon1/temp1_input"],
|
||||
}
|
||||
|
||||
def _get_thermal_val(self, thermal_num):
|
||||
if thermal_num < self.THERMAL_NUM_1_IDX or thermal_num > self.THERMAL_NUM_MAX:
|
||||
logging.debug('GET. Parameter error. thermal_num, %d', thermal_num)
|
||||
return None
|
||||
|
||||
device_path = self.get_thermal_path(thermal_num)
|
||||
for filename in glob.glob(device_path):
|
||||
try:
|
||||
val_file = open(filename, 'r')
|
||||
except IOError as e:
|
||||
logging.error('GET. unable to open file: %s', str(e))
|
||||
return None
|
||||
content = val_file.readline().rstrip()
|
||||
if content == '':
|
||||
logging.debug(
|
||||
'GET. content is NULL. device_path:%s',
|
||||
device_path)
|
||||
return None
|
||||
try:
|
||||
val_file.close()
|
||||
except BaseException:
|
||||
logging.debug(
|
||||
'GET. unable to close file. device_path:%s',
|
||||
device_path)
|
||||
return None
|
||||
|
||||
return int(content)
|
||||
|
||||
return 0
|
||||
|
||||
def get_num_thermals(self):
|
||||
return self.THERMAL_NUM_MAX
|
||||
|
||||
def get_size_path_map(self):
|
||||
return len(self.thermal_sysfspath)
|
||||
|
||||
def get_thermal_path(self, thermal_num):
|
||||
return self.thermal_sysfspath[thermal_num][0]
|
@ -0,0 +1,19 @@
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m:= x86-64-accton-as4630-54npe-cpld.o x86-64-accton-as4630-54npe-psu.o \
|
||||
x86-64-accton-as4630-54npe-leds.o ym2651y.o
|
||||
|
||||
else
|
||||
ifeq (,$(KERNEL_SRC))
|
||||
#$(error KERNEL_SRC is not defined)
|
||||
KVERSION=3.16.0-8-amd64
|
||||
KERNEL_DIR = /usr/src/linux-headers-$(KVERSION)/
|
||||
KERNELDIR:=$(KERNEL_DIR)
|
||||
else
|
||||
KERNELDIR:=$(KERNEL_SRC)
|
||||
endif
|
||||
PWD:=$(shell pwd)
|
||||
default:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
clean:
|
||||
rm -rf *.o *.mod.o *.mod.o *.mod.c *.ko .*cmd .tmp_versions Module.markers Module.symvers modules.order
|
||||
endif
|
@ -0,0 +1,911 @@
|
||||
/*
|
||||
* Copyright (C) Jostar yang <jostar_yang@accton.com.tw>
|
||||
*
|
||||
* This module supports the accton cpld that hold the channel select
|
||||
* mechanism for other i2c slave devices, such as SFP.
|
||||
* This includes the:
|
||||
* Accton as4630_54npe CPLD
|
||||
*
|
||||
* Based on:
|
||||
* pca954x.c from Kumar Gala <galak@kernel.crashing.org>
|
||||
* Copyright (C) 2006
|
||||
*
|
||||
* Based on:
|
||||
* pca954x.c from Ken Harrenstien
|
||||
* Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
|
||||
*
|
||||
* Based on:
|
||||
* i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
|
||||
* and
|
||||
* pca9540.c from Jean Delvare <khali@linux-fr.org>.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
||||
#define I2C_RW_RETRY_COUNT 10
|
||||
#define I2C_RW_RETRY_INTERVAL 60 /* ms */
|
||||
#define FAN_DUTY_CYCLE_REG_MASK 0x1F
|
||||
#define FAN_MAX_DUTY_CYCLE 100
|
||||
#define FAN_REG_VAL_TO_SPEED_RPM_STEP 114 // R.P.M value = read value x3.79*60/2
|
||||
|
||||
#define NUM_THERMAL_SENSORS (3) /* Get sum of this number of sensors.*/
|
||||
#define THERMAL_SENSORS_ADDRS {0x48, 0x4a, 0x4b}
|
||||
|
||||
static LIST_HEAD(cpld_client_list);
|
||||
static struct mutex list_lock;
|
||||
|
||||
struct cpld_client_node {
|
||||
struct i2c_client *client;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
enum cpld_type {
|
||||
as4630_54npe_cpld,
|
||||
};
|
||||
enum fan_id {
|
||||
FAN1_ID,
|
||||
FAN2_ID,
|
||||
FAN3_ID,
|
||||
};
|
||||
|
||||
static const u8 fan_reg[] = {
|
||||
0x87, /* fan status, fan direction */
|
||||
0x1A, /* fan PWM(for fan1 ,fan2) */
|
||||
0x1B, /* fan PWM(for fan1 ,fan2) */
|
||||
0x88, /* front fan1 speed(rpm) */
|
||||
0x89, /* front fan2 speed(rpm) */
|
||||
0x8A, /* front fan3 speed(rpm) */
|
||||
0x20, /*fan fault*/
|
||||
};
|
||||
|
||||
struct as4630_54npe_cpld_data {
|
||||
enum cpld_type type;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* != 0 if registers are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
u8 reg_fan_val[ARRAY_SIZE(fan_reg)]; /* Register value */
|
||||
int system_temp; /*In unit of mini-Celsius*/
|
||||
int sensors_found;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static const struct i2c_device_id as4630_54npe_cpld_id[] = {
|
||||
{ "as4630_54npe_cpld", as4630_54npe_cpld},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, as4630_54npe_cpld_id);
|
||||
|
||||
#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index
|
||||
#define TRANSCEIVER_LPMODE_ATTR_ID(index) MODULE_LPMODE_##index
|
||||
#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index
|
||||
#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index
|
||||
#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index
|
||||
#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index
|
||||
#define FAN_SPEED_RPM_ATTR_ID(index) FAN_SPEED_RPM_##index
|
||||
#define FAN_DIRECTION_ID(index) FAN_DIRECTION_##index
|
||||
#define FAN_PRESENT_ATTR_ID(index) FAN_PRESENT_##index
|
||||
#define FAN_FAULT_ATTR_ID(index) FAN_FAULT_##index
|
||||
|
||||
enum as4630_54npe_cpld_sysfs_attributes {
|
||||
CPLD_VERSION,
|
||||
ACCESS,
|
||||
/* transceiver attributes */
|
||||
TRANSCEIVER_RXLOS_ATTR_ID(49),
|
||||
TRANSCEIVER_RXLOS_ATTR_ID(50),
|
||||
TRANSCEIVER_RXLOS_ATTR_ID(51),
|
||||
TRANSCEIVER_RXLOS_ATTR_ID(52),
|
||||
TRANSCEIVER_TXFAULT_ATTR_ID(49),
|
||||
TRANSCEIVER_TXFAULT_ATTR_ID(50),
|
||||
TRANSCEIVER_TXFAULT_ATTR_ID(51),
|
||||
TRANSCEIVER_TXFAULT_ATTR_ID(52),
|
||||
TRANSCEIVER_PRESENT_ATTR_ID(49),
|
||||
TRANSCEIVER_PRESENT_ATTR_ID(50),
|
||||
TRANSCEIVER_PRESENT_ATTR_ID(51),
|
||||
TRANSCEIVER_PRESENT_ATTR_ID(52),
|
||||
TRANSCEIVER_PRESENT_ATTR_ID(53),
|
||||
TRANSCEIVER_PRESENT_ATTR_ID(54),
|
||||
TRANSCEIVER_RESET_ATTR_ID(53),
|
||||
TRANSCEIVER_RESET_ATTR_ID(54),
|
||||
TRANSCEIVER_LPMODE_ATTR_ID(53),
|
||||
TRANSCEIVER_LPMODE_ATTR_ID(54),
|
||||
TRANSCEIVER_TXDISABLE_ATTR_ID(49),
|
||||
TRANSCEIVER_TXDISABLE_ATTR_ID(50),
|
||||
TRANSCEIVER_TXDISABLE_ATTR_ID(51),
|
||||
TRANSCEIVER_TXDISABLE_ATTR_ID(52),
|
||||
FAN_PRESENT_ATTR_ID(1),
|
||||
FAN_PRESENT_ATTR_ID(2),
|
||||
FAN_PRESENT_ATTR_ID(3),
|
||||
FAN_SPEED_RPM_ATTR_ID(1),
|
||||
FAN_SPEED_RPM_ATTR_ID(2),
|
||||
FAN_SPEED_RPM_ATTR_ID(3),
|
||||
FAN_DIRECTION_ID(1),
|
||||
FAN_DIRECTION_ID(2),
|
||||
FAN_DIRECTION_ID(3),
|
||||
FAN_FAULT_ATTR_ID(1),
|
||||
FAN_FAULT_ATTR_ID(2),
|
||||
FAN_FAULT_ATTR_ID(3),
|
||||
FAN_DUTY_CYCLE_PERCENTAGE,
|
||||
};
|
||||
|
||||
/* sysfs attributes for hwmon
|
||||
*/
|
||||
static ssize_t show_status(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count);
|
||||
static ssize_t set_qsfp(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count);
|
||||
static ssize_t access(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count);
|
||||
static ssize_t show_version(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
static int as4630_54npe_cpld_read_internal(struct i2c_client *client, u8 reg);
|
||||
static int as4630_54npe_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value);
|
||||
|
||||
/*fan sysfs*/
|
||||
static struct as4630_54npe_cpld_data *as4630_54npe_fan_update_device(struct device *dev);
|
||||
static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf);
|
||||
static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count);
|
||||
|
||||
/* transceiver attributes */
|
||||
#define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \
|
||||
static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index); \
|
||||
static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_tx_disable, MODULE_TXDISABLE_##index); \
|
||||
static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \
|
||||
static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_TXFAULT_##index);
|
||||
|
||||
#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \
|
||||
&sensor_dev_attr_module_present_##index.dev_attr.attr, \
|
||||
&sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \
|
||||
&sensor_dev_attr_module_rx_los_##index.dev_attr.attr, \
|
||||
&sensor_dev_attr_module_tx_fault_##index.dev_attr.attr
|
||||
|
||||
#define DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \
|
||||
static SENSOR_DEVICE_ATTR(module_lpmode_##index, S_IRUGO | S_IWUSR, show_status, set_qsfp, MODULE_LPMODE_##index); \
|
||||
static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, show_status, set_qsfp, MODULE_RESET_##index); \
|
||||
static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index);
|
||||
|
||||
#define DECLARE_QSFP_TRANSCEIVER_ATTR(index) \
|
||||
&sensor_dev_attr_module_lpmode_##index.dev_attr.attr, \
|
||||
&sensor_dev_attr_module_reset_##index.dev_attr.attr, \
|
||||
&sensor_dev_attr_module_present_##index.dev_attr.attr
|
||||
|
||||
|
||||
#define DECLARE_FAN_SENSOR_DEV_ATTR(index) \
|
||||
static SENSOR_DEVICE_ATTR(fan_present_##index, S_IRUGO, fan_show_value, NULL, FAN_PRESENT_##index); \
|
||||
static SENSOR_DEVICE_ATTR(fan_fault_##index, S_IRUGO, fan_show_value, NULL, FAN_FAULT_##index); \
|
||||
static SENSOR_DEVICE_ATTR(fan_speed_rpm_##index, S_IRUGO, fan_show_value, NULL, FAN_SPEED_RPM_##index); \
|
||||
static SENSOR_DEVICE_ATTR(fan##index##_input, S_IRUGO, fan_show_value, NULL, FAN_SPEED_RPM_##index);\
|
||||
static SENSOR_DEVICE_ATTR(fan_direction_##index, S_IRUGO, fan_show_value, NULL, FAN_DIRECTION_##index);
|
||||
|
||||
#define DECLARE_FAN_ATTR(index) \
|
||||
&sensor_dev_attr_fan_present_##index.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan_fault_##index.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan_speed_rpm_##index.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan##index##_input.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan_direction_##index.dev_attr.attr
|
||||
|
||||
#define DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(index) \
|
||||
static SENSOR_DEVICE_ATTR(fan_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN_DUTY_CYCLE_PERCENTAGE);
|
||||
#define DECLARE_FAN_DUTY_CYCLE_ATTR(index) &sensor_dev_attr_fan_duty_cycle_percentage.dev_attr.attr
|
||||
|
||||
|
||||
static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION);
|
||||
static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS);
|
||||
|
||||
|
||||
|
||||
/* transceiver attributes */
|
||||
DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(49);
|
||||
DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(50);
|
||||
DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(51);
|
||||
DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(52);
|
||||
DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(53);
|
||||
DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(54);
|
||||
/* fan attributes */
|
||||
DECLARE_FAN_SENSOR_DEV_ATTR(1);
|
||||
DECLARE_FAN_SENSOR_DEV_ATTR(2);
|
||||
DECLARE_FAN_SENSOR_DEV_ATTR(3);
|
||||
DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(1);
|
||||
|
||||
static struct attribute *as4630_54npe_cpld_attributes[] = {
|
||||
&sensor_dev_attr_version.dev_attr.attr,
|
||||
&sensor_dev_attr_access.dev_attr.attr,
|
||||
DECLARE_SFP_TRANSCEIVER_ATTR(49),
|
||||
DECLARE_SFP_TRANSCEIVER_ATTR(50),
|
||||
DECLARE_SFP_TRANSCEIVER_ATTR(51),
|
||||
DECLARE_SFP_TRANSCEIVER_ATTR(52),
|
||||
DECLARE_QSFP_TRANSCEIVER_ATTR(53),
|
||||
DECLARE_QSFP_TRANSCEIVER_ATTR(54),
|
||||
DECLARE_FAN_ATTR(1),
|
||||
DECLARE_FAN_ATTR(2),
|
||||
DECLARE_FAN_ATTR(3),
|
||||
DECLARE_FAN_DUTY_CYCLE_ATTR(1),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group as4630_54npe_cpld_group = {
|
||||
.attrs = as4630_54npe_cpld_attributes,
|
||||
};
|
||||
|
||||
|
||||
static ssize_t show_status(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as4630_54npe_cpld_data *data = i2c_get_clientdata(client);
|
||||
int status = 0;
|
||||
u8 reg = 0, mask = 0, revert = 0;
|
||||
|
||||
switch (attr->index)
|
||||
{
|
||||
case MODULE_RXLOS_49 ... MODULE_RXLOS_50:
|
||||
reg=0x5;
|
||||
mask = 0x1<< (attr->index==MODULE_RXLOS_49?4:0);
|
||||
break;
|
||||
case MODULE_TXFAULT_49 ... MODULE_TXFAULT_50:
|
||||
reg=0x5;
|
||||
mask=0x1 << (attr->index==MODULE_TXFAULT_49?5:1);
|
||||
break;
|
||||
case MODULE_PRESENT_49 ... MODULE_PRESENT_50:
|
||||
reg=0x5;
|
||||
mask=0x1 << (attr->index==MODULE_PRESENT_49?6:2);
|
||||
break;
|
||||
case MODULE_TXDISABLE_49 ... MODULE_TXDISABLE_50:
|
||||
reg=0x5;
|
||||
mask=0x1 << (attr->index==MODULE_TXDISABLE_49?7:3);
|
||||
break;
|
||||
|
||||
case MODULE_RXLOS_51 ... MODULE_RXLOS_52:
|
||||
reg=0x6;
|
||||
mask = 0x1<< (attr->index==MODULE_RXLOS_51?4:0);
|
||||
break;
|
||||
case MODULE_TXFAULT_51 ... MODULE_TXFAULT_52:
|
||||
reg=0x6;
|
||||
mask=0x1 << (attr->index==MODULE_TXFAULT_51?5:1);
|
||||
break;
|
||||
case MODULE_PRESENT_51 ... MODULE_PRESENT_52:
|
||||
reg=0x6;
|
||||
mask=0x1 << (attr->index==MODULE_PRESENT_51?6:2);
|
||||
break;
|
||||
case MODULE_TXDISABLE_51 ... MODULE_TXDISABLE_52:
|
||||
reg=0x6;
|
||||
mask=0x1 << (attr->index==MODULE_TXDISABLE_51?7:3);
|
||||
break;
|
||||
case MODULE_PRESENT_53 ... MODULE_PRESENT_54:
|
||||
reg=0x21;
|
||||
mask=0x1 << (attr->index==MODULE_PRESENT_53?0:4);
|
||||
break;
|
||||
case MODULE_RESET_53 ... MODULE_RESET_54:
|
||||
reg=0x21;
|
||||
mask=0x1 << (attr->index==MODULE_RESET_53?3:7);
|
||||
revert = 1;
|
||||
break;
|
||||
case MODULE_LPMODE_53 ... MODULE_LPMODE_54:
|
||||
reg = 0x21;
|
||||
mask = 0x1 << (attr->index==MODULE_LPMODE_53?2:6);
|
||||
revert = 0;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( attr->index >= MODULE_PRESENT_49 && attr->index <= MODULE_PRESENT_54 )
|
||||
{
|
||||
revert = 1;
|
||||
}
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
status = as4630_54npe_cpld_read_internal(client, reg);
|
||||
if (unlikely(status < 0)) {
|
||||
goto exit;
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return sprintf(buf, "%d\n", revert ? !(status & mask) : !!(status & mask));
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t set_qsfp(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as4630_54npe_cpld_data *data = i2c_get_clientdata(client);
|
||||
long disable;
|
||||
int status;
|
||||
u8 reg = 0, mask = 0, revert = 0;
|
||||
|
||||
status = kstrtol(buf, 10, &disable);
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
reg = 0x21;
|
||||
switch (attr->index)
|
||||
{
|
||||
case MODULE_RESET_53 ... MODULE_RESET_54:
|
||||
mask=0x1 << (attr->index==MODULE_RESET_53?3:7);
|
||||
revert = 1;
|
||||
break;
|
||||
case MODULE_LPMODE_53 ... MODULE_LPMODE_54:
|
||||
mask=0x1 << (attr->index==MODULE_LPMODE_53?2:6);
|
||||
revert = 0;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
disable = revert ? disable : !disable;
|
||||
/* Read current status */
|
||||
mutex_lock(&data->update_lock);
|
||||
status = as4630_54npe_cpld_read_internal(client, reg);
|
||||
if (unlikely(status < 0)) {
|
||||
goto exit;
|
||||
}
|
||||
if (disable) {
|
||||
status &= ~mask;
|
||||
}
|
||||
else {
|
||||
status |= mask;
|
||||
}
|
||||
status = as4630_54npe_cpld_write_internal(client, reg, status);
|
||||
if (unlikely(status < 0)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as4630_54npe_cpld_data *data = i2c_get_clientdata(client);
|
||||
long disable;
|
||||
int status;
|
||||
u8 reg = 0, mask = 0;
|
||||
|
||||
status = kstrtol(buf, 10, &disable);
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
reg = 0x9;
|
||||
switch (attr->index)
|
||||
{
|
||||
case MODULE_TXDISABLE_49 ... MODULE_TXDISABLE_50:
|
||||
reg=0x5;
|
||||
mask=0x1 << (attr->index==MODULE_TXDISABLE_49?7:3);
|
||||
break;
|
||||
case MODULE_TXDISABLE_51 ... MODULE_TXDISABLE_52:
|
||||
reg=0x6;
|
||||
mask=0x1 << (attr->index==MODULE_TXDISABLE_51?7:3);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read current status */
|
||||
mutex_lock(&data->update_lock);
|
||||
status = as4630_54npe_cpld_read_internal(client, reg);
|
||||
if (unlikely(status < 0)) {
|
||||
goto exit;
|
||||
}
|
||||
/* Update tx_disable status */
|
||||
if (!disable) {
|
||||
status &= ~mask;
|
||||
}
|
||||
else {
|
||||
status |= mask;
|
||||
}
|
||||
status = as4630_54npe_cpld_write_internal(client, reg, status);
|
||||
if (unlikely(status < 0)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t access(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int status;
|
||||
u32 addr, val;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as4630_54npe_cpld_data *data = i2c_get_clientdata(client);
|
||||
|
||||
if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (addr > 0xFF || val > 0xFF) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
status = as4630_54npe_cpld_write_internal(client, addr, val);
|
||||
if (unlikely(status < 0)) {
|
||||
goto exit;
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void as4630_54npe_cpld_add_client(struct i2c_client *client)
|
||||
{
|
||||
struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL);
|
||||
|
||||
if (!node) {
|
||||
dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr);
|
||||
return;
|
||||
}
|
||||
|
||||
node->client = client;
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
list_add(&node->list, &cpld_client_list);
|
||||
mutex_unlock(&list_lock);
|
||||
}
|
||||
|
||||
static void as4630_54npe_cpld_remove_client(struct i2c_client *client)
|
||||
{
|
||||
struct list_head *list_node = NULL;
|
||||
struct cpld_client_node *cpld_node = NULL;
|
||||
int found = 0;
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
|
||||
list_for_each(list_node, &cpld_client_list)
|
||||
{
|
||||
cpld_node = list_entry(list_node, struct cpld_client_node, list);
|
||||
|
||||
if (cpld_node->client == client) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
list_del(list_node);
|
||||
kfree(cpld_node);
|
||||
}
|
||||
|
||||
mutex_unlock(&list_lock);
|
||||
}
|
||||
|
||||
static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int val = 0;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
val = i2c_smbus_read_byte_data(client, 0x1);
|
||||
|
||||
if (val < 0) {
|
||||
dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val);
|
||||
}
|
||||
|
||||
return sprintf(buf, "%d\n", val);
|
||||
}
|
||||
|
||||
/* fan utility functions
|
||||
*/
|
||||
static u32 reg_val_to_duty_cycle(u8 reg_val)
|
||||
{
|
||||
reg_val &= FAN_DUTY_CYCLE_REG_MASK;
|
||||
return ((u32)(reg_val) * 625)/ 100;
|
||||
}
|
||||
|
||||
static u8 duty_cycle_to_reg_val(u8 duty_cycle)
|
||||
{
|
||||
return ((u32)duty_cycle * 100 / 625);
|
||||
}
|
||||
|
||||
static u32 reg_val_to_speed_rpm(u8 reg_val)
|
||||
{
|
||||
return (u32)reg_val * FAN_REG_VAL_TO_SPEED_RPM_STEP;
|
||||
}
|
||||
|
||||
static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int error, value;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
error = kstrtoint(buf, 10, &value);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (value < 0 || value > FAN_MAX_DUTY_CYCLE)
|
||||
return -EINVAL;
|
||||
|
||||
as4630_54npe_cpld_write_internal(client, fan_reg[1], duty_cycle_to_reg_val(value));
|
||||
as4630_54npe_cpld_write_internal(client, fan_reg[2], duty_cycle_to_reg_val(value));
|
||||
return count;
|
||||
}
|
||||
|
||||
static u8 reg_val_to_direction(u8 reg_val, enum fan_id id)
|
||||
{
|
||||
u8 mask = (1 << (4 + id));
|
||||
|
||||
reg_val &= mask;
|
||||
|
||||
return reg_val ? 0 : 1;
|
||||
}
|
||||
|
||||
static u8 reg_val_to_is_present(u8 reg_val, enum fan_id id)
|
||||
{
|
||||
u8 mask = (1 << id);
|
||||
|
||||
reg_val &= mask;
|
||||
|
||||
return reg_val ? 0 : 1;
|
||||
}
|
||||
|
||||
static u8 is_fan_fault(struct as4630_54npe_cpld_data *data, enum fan_id id)
|
||||
{
|
||||
u8 ret = 1;
|
||||
|
||||
if(id > FAN3_ID)
|
||||
return 1;
|
||||
/* Check if the speed of front or rear fan is ZERO,
|
||||
*/
|
||||
if (reg_val_to_speed_rpm(data->reg_fan_val[id+3]))
|
||||
{
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t fan_show_value(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
u32 duty_cycle;
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct as4630_54npe_cpld_data *data = as4630_54npe_fan_update_device(dev);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (data->valid) {
|
||||
switch (attr->index)
|
||||
{
|
||||
case FAN_PRESENT_1:
|
||||
case FAN_PRESENT_2:
|
||||
case FAN_PRESENT_3:
|
||||
ret = sprintf(buf, "%d\n",
|
||||
reg_val_to_is_present(data->reg_fan_val[0],
|
||||
attr->index - FAN_PRESENT_1));
|
||||
break;
|
||||
case FAN_DUTY_CYCLE_PERCENTAGE:
|
||||
duty_cycle = reg_val_to_duty_cycle(data->reg_fan_val[1]);
|
||||
ret = sprintf(buf, "%u\n", duty_cycle);
|
||||
break;
|
||||
case FAN_SPEED_RPM_1:
|
||||
case FAN_SPEED_RPM_2:
|
||||
case FAN_SPEED_RPM_3:
|
||||
ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_fan_val[attr->index-FAN_SPEED_RPM_1+3]));
|
||||
break;
|
||||
case FAN_FAULT_1:
|
||||
case FAN_FAULT_2:
|
||||
case FAN_FAULT_3:
|
||||
ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN_FAULT_1));
|
||||
break;
|
||||
case FAN_DIRECTION_1:
|
||||
case FAN_DIRECTION_2:
|
||||
case FAN_DIRECTION_3:
|
||||
ret = sprintf(buf, "%d\n",
|
||||
reg_val_to_direction(data->reg_fan_val[0],
|
||||
attr->index - FAN_DIRECTION_1));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct as4630_54npe_cpld_data *as4630_54npe_fan_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as4630_54npe_cpld_data *data = i2c_get_clientdata(client);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2) ||
|
||||
!data->valid) {
|
||||
int i;
|
||||
|
||||
dev_dbg(&client->dev, "Starting as4630_54npe_fan update\n");
|
||||
data->valid = 0;
|
||||
|
||||
/* Update fan data
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(data->reg_fan_val); i++) {
|
||||
int status = as4630_54npe_cpld_read_internal(client, fan_reg[i]);
|
||||
if (status < 0) {
|
||||
data->valid = 0;
|
||||
mutex_unlock(&data->update_lock);
|
||||
dev_dbg(&client->dev, "reg 0x%x, err %d\n", fan_reg[i], status);
|
||||
return data;
|
||||
}
|
||||
else {
|
||||
data->reg_fan_val[i] = status & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
static ssize_t show_power(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as4630_54npe_cpld_data *data = i2c_get_clientdata(client);
|
||||
int status = 0;
|
||||
u8 reg = 0, mask = 0;
|
||||
|
||||
reg=0xc;
|
||||
mask=0x2;
|
||||
mutex_lock(&data->update_lock);
|
||||
status = as4630_54npe_cpld_read_internal(client, reg);
|
||||
if (unlikely(status < 0)) {
|
||||
goto exit;
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return sprintf(buf, "%d\n", !(status & mask));
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return status;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
* I2C init/probing/exit functions
|
||||
*/
|
||||
static int as4630_54npe_cpld_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
struct as4630_54npe_cpld_data *data;
|
||||
int ret = -ENODEV;
|
||||
// int status;
|
||||
const struct attribute_group *group = NULL;
|
||||
|
||||
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
|
||||
goto exit;
|
||||
|
||||
data = kzalloc(sizeof(struct as4630_54npe_cpld_data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
data->type = id->driver_data;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
switch (data->type)
|
||||
{
|
||||
case as4630_54npe_cpld:
|
||||
group = &as4630_54npe_cpld_group;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (group)
|
||||
{
|
||||
ret = sysfs_create_group(&client->dev.kobj, group);
|
||||
if (ret) {
|
||||
goto exit_free;
|
||||
}
|
||||
}
|
||||
|
||||
as4630_54npe_cpld_add_client(client);
|
||||
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
ret = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int as4630_54npe_cpld_remove(struct i2c_client *client)
|
||||
{
|
||||
struct as4630_54npe_cpld_data *data = i2c_get_clientdata(client);
|
||||
const struct attribute_group *group = NULL;
|
||||
|
||||
as4630_54npe_cpld_remove_client(client);
|
||||
|
||||
/* Remove sysfs hooks */
|
||||
switch (data->type)
|
||||
{
|
||||
case as4630_54npe_cpld:
|
||||
group = &as4630_54npe_cpld_group;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (group) {
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, group);
|
||||
}
|
||||
|
||||
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int as4630_54npe_cpld_read_internal(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
int status = 0, retry = I2C_RW_RETRY_COUNT;
|
||||
|
||||
while (retry) {
|
||||
status = i2c_smbus_read_byte_data(client, reg);
|
||||
if (unlikely(status < 0)) {
|
||||
msleep(I2C_RW_RETRY_INTERVAL);
|
||||
retry--;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int as4630_54npe_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
int status = 0, retry = I2C_RW_RETRY_COUNT;
|
||||
|
||||
while (retry) {
|
||||
status = i2c_smbus_write_byte_data(client, reg, value);
|
||||
if (unlikely(status < 0)) {
|
||||
msleep(I2C_RW_RETRY_INTERVAL);
|
||||
retry--;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int as4630_54npe_cpld_read(unsigned short cpld_addr, u8 reg)
|
||||
{
|
||||
struct list_head *list_node = NULL;
|
||||
struct cpld_client_node *cpld_node = NULL;
|
||||
int ret = -EPERM;
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
|
||||
list_for_each(list_node, &cpld_client_list)
|
||||
{
|
||||
cpld_node = list_entry(list_node, struct cpld_client_node, list);
|
||||
|
||||
if (cpld_node->client->addr == cpld_addr) {
|
||||
ret = as4630_54npe_cpld_read_internal(cpld_node->client, reg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&list_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(as4630_54npe_cpld_read);
|
||||
|
||||
int as4630_54npe_cpld_write(unsigned short cpld_addr, u8 reg, u8 value)
|
||||
{
|
||||
struct list_head *list_node = NULL;
|
||||
struct cpld_client_node *cpld_node = NULL;
|
||||
int ret = -EIO;
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
|
||||
list_for_each(list_node, &cpld_client_list)
|
||||
{
|
||||
cpld_node = list_entry(list_node, struct cpld_client_node, list);
|
||||
|
||||
if (cpld_node->client->addr == cpld_addr) {
|
||||
ret = as4630_54npe_cpld_write_internal(cpld_node->client, reg, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&list_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(as4630_54npe_cpld_write);
|
||||
|
||||
static struct i2c_driver as4630_54npe_cpld_driver = {
|
||||
.driver = {
|
||||
.name = "as4630_54npe_cpld",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = as4630_54npe_cpld_probe,
|
||||
.remove = as4630_54npe_cpld_remove,
|
||||
.id_table = as4630_54npe_cpld_id,
|
||||
};
|
||||
|
||||
static int __init as4630_54npe_cpld_init(void)
|
||||
{
|
||||
mutex_init(&list_lock);
|
||||
return i2c_add_driver(&as4630_54npe_cpld_driver);
|
||||
}
|
||||
|
||||
static void __exit as4630_54npe_cpld_exit(void)
|
||||
{
|
||||
i2c_del_driver(&as4630_54npe_cpld_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Jostar Yang <jostar_yang@accton.com.tw>");
|
||||
MODULE_DESCRIPTION("Accton I2C CPLD driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(as4630_54npe_cpld_init);
|
||||
module_exit(as4630_54npe_cpld_exit);
|
@ -0,0 +1,579 @@
|
||||
/*
|
||||
* A LED driver for the accton_as4630_54npe_led
|
||||
*
|
||||
* Copyright (C) 2014 Accton Technology Corporation.
|
||||
* Brandon Chuang <brandon_chuang@accton.com.tw>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
extern int as4630_54npe_cpld_read (unsigned short cpld_addr, u8 reg);
|
||||
extern int as4630_54npe_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
|
||||
|
||||
#define DRVNAME "accton_as4630_54npe_led"
|
||||
|
||||
struct accton_as4630_54npe_led_data {
|
||||
struct platform_device *pdev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* != 0 if registers are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
u8 reg_val[2]; /* only 1 register*/
|
||||
};
|
||||
|
||||
static struct accton_as4630_54npe_led_data *ledctl = NULL;
|
||||
|
||||
/* LED related data
|
||||
*/
|
||||
|
||||
#define LED_CNTRLER_I2C_ADDRESS (0x60)
|
||||
|
||||
#define LED_TYPE_DIAG_REG_MASK (0x20|0x40|0x80)
|
||||
#define LED_MODE_DIAG_GREEN_VALUE (0x20)
|
||||
#define LED_MODE_DIAG_GREEN_BLINK_VALUE (0x60)
|
||||
#define LED_MODE_DIAG_AMBER_VALUE (0x80) /*It's yellow actually. Green+Red=Yellow*/
|
||||
#define LED_MODE_DIAG_OFF_VALUE (0x0)
|
||||
|
||||
#define LED_TYPE_PRI_REG_MASK (0x8|0x4)
|
||||
#define LED_MODE_PRI_GREEN_VALUE 0x4
|
||||
#define LED_MODE_PRI_AMBER_VALUE 0x8
|
||||
#define LED_MODE_PRI_OFF_VALUE 0x0
|
||||
|
||||
#define LED_TYPE_POE_REG_MASK (0x2|0x1)
|
||||
#define LED_MODE_POE_GREEN_VALUE 0x1
|
||||
#define LED_MODE_POE_AMBER_VALUE 0x2
|
||||
#define LED_MODE_POE_OFF_VALUE 0x3
|
||||
|
||||
#define LED_TYPE_STK1_REG_MASK 0x20
|
||||
#define LED_MODE_STK1_GREEN_VALUE 0x0
|
||||
#define LED_MODE_STK1_OFF_VALUE 0x20
|
||||
|
||||
#define LED_TYPE_STK2_REG_MASK 0x10
|
||||
#define LED_MODE_STK2_GREEN_VALUE 0x0
|
||||
#define LED_MODE_STK2_OFF_VALUE 0x10
|
||||
|
||||
#define LED_TYPE_FAN_REG_MASK (0x8|0x4)
|
||||
#define LED_MODE_FAN_AMBER_VALUE 0x8
|
||||
#define LED_MODE_FAN_GREEN_VALUE 0x4
|
||||
#define LED_MODE_FAN_OFF_VALUE (0xC)
|
||||
|
||||
#define LED_TYPE_PSU2_REG_MASK (0x80|0x40)
|
||||
#define LED_MODE_PSU2_AMBER_VALUE 0x80
|
||||
#define LED_MODE_PSU2_GREEN_VALUE 0x40
|
||||
#define LED_MODE_PSU2_OFF_VALUE (0xC0)
|
||||
|
||||
#define LED_TYPE_PSU1_REG_MASK (0x2|0x1)
|
||||
#define LED_MODE_PSU1_AMBER_VALUE 0x2
|
||||
#define LED_MODE_PSU1_GREEN_VALUE 0x1
|
||||
#define LED_MODE_PSU1_OFF_VALUE (0x3)
|
||||
|
||||
enum led_type {
|
||||
LED_TYPE_DIAG,
|
||||
LED_TYPE_PRI,
|
||||
LED_TYPE_POE,
|
||||
LED_TYPE_STK1,
|
||||
LED_TYPE_STK2,
|
||||
LED_TYPE_FAN,
|
||||
LED_TYPE_PSU1,
|
||||
LED_TYPE_PSU2
|
||||
};
|
||||
|
||||
struct led_reg {
|
||||
u32 types;
|
||||
u8 reg_addr;
|
||||
};
|
||||
|
||||
static const struct led_reg led_reg_map[] = {
|
||||
{(1<<LED_TYPE_DIAG)| (1<<LED_TYPE_PRI) | (1<<LED_TYPE_PSU1) , 0x30},
|
||||
{(1<<LED_TYPE_PSU2) | (1<<LED_TYPE_FAN) | (1<<LED_TYPE_POE) |(1<<LED_TYPE_STK1) | (1<<LED_TYPE_STK2) , 0x31},
|
||||
};
|
||||
|
||||
|
||||
enum led_light_mode {
|
||||
LED_MODE_OFF = 0,
|
||||
LED_MODE_GREEN,
|
||||
LED_MODE_AMBER,
|
||||
LED_MODE_RED,
|
||||
LED_MODE_BLUE,
|
||||
LED_MODE_GREEN_BLINK,
|
||||
LED_MODE_AMBER_BLINK,
|
||||
LED_MODE_RED_BLINK,
|
||||
LED_MODE_BLUE_BLINK,
|
||||
LED_MODE_AUTO,
|
||||
LED_MODE_UNKNOWN
|
||||
};
|
||||
|
||||
struct led_type_mode {
|
||||
enum led_type type;
|
||||
enum led_light_mode mode;
|
||||
int reg_bit_mask;
|
||||
int mode_value;
|
||||
};
|
||||
|
||||
static struct led_type_mode led_type_mode_data[] = {
|
||||
{LED_TYPE_PRI, LED_MODE_OFF, LED_TYPE_PRI_REG_MASK, LED_MODE_PRI_OFF_VALUE},
|
||||
{LED_TYPE_PRI, LED_MODE_GREEN, LED_TYPE_PRI_REG_MASK, LED_MODE_PRI_GREEN_VALUE},
|
||||
{LED_TYPE_PRI, LED_MODE_AMBER, LED_TYPE_PRI_REG_MASK, LED_MODE_PRI_AMBER_VALUE},
|
||||
|
||||
{LED_TYPE_DIAG,LED_MODE_OFF, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_OFF_VALUE},
|
||||
{LED_TYPE_DIAG,LED_MODE_GREEN, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_GREEN_VALUE},
|
||||
{LED_TYPE_DIAG,LED_MODE_GREEN_BLINK, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_GREEN_BLINK_VALUE},
|
||||
{LED_TYPE_DIAG,LED_MODE_AMBER, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_AMBER_VALUE},
|
||||
|
||||
{LED_TYPE_POE,LED_MODE_OFF, LED_TYPE_POE_REG_MASK, LED_MODE_POE_OFF_VALUE},
|
||||
{LED_TYPE_POE,LED_MODE_GREEN, LED_TYPE_POE_REG_MASK, LED_MODE_POE_GREEN_VALUE},
|
||||
{LED_TYPE_POE,LED_MODE_AMBER, LED_TYPE_POE_REG_MASK, LED_MODE_POE_AMBER_VALUE},
|
||||
|
||||
{LED_TYPE_STK1,LED_MODE_OFF, LED_TYPE_STK1_REG_MASK, LED_MODE_STK1_OFF_VALUE},
|
||||
{LED_TYPE_STK1,LED_MODE_GREEN, LED_TYPE_STK1_REG_MASK, LED_MODE_STK1_GREEN_VALUE},
|
||||
|
||||
{LED_TYPE_STK2,LED_MODE_OFF, LED_TYPE_STK2_REG_MASK, LED_MODE_STK2_OFF_VALUE},
|
||||
{LED_TYPE_STK2,LED_MODE_GREEN, LED_TYPE_STK2_REG_MASK, LED_MODE_STK2_GREEN_VALUE},
|
||||
|
||||
{LED_TYPE_FAN,LED_MODE_OFF, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_OFF_VALUE},
|
||||
{LED_TYPE_FAN,LED_MODE_GREEN, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_GREEN_VALUE},
|
||||
{LED_TYPE_FAN,LED_MODE_AMBER, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_AMBER_VALUE},
|
||||
|
||||
{LED_TYPE_PSU1,LED_MODE_OFF, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_OFF_VALUE},
|
||||
{LED_TYPE_PSU1,LED_MODE_GREEN, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_GREEN_VALUE},
|
||||
{LED_TYPE_PSU1,LED_MODE_AMBER, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_AMBER_VALUE},
|
||||
|
||||
{LED_TYPE_PSU2,LED_MODE_OFF, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_OFF_VALUE},
|
||||
{LED_TYPE_PSU2,LED_MODE_GREEN, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_GREEN_VALUE},
|
||||
{LED_TYPE_PSU2,LED_MODE_AMBER, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_AMBER_VALUE},
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void accton_as4630_54npe_led_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode, enum led_type type);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static int accton_getLedReg(enum led_type type, u8 *reg)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(led_reg_map); i++) {
|
||||
if(led_reg_map[i].types & (1<<type)) {
|
||||
*reg = led_reg_map[i].reg_addr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int led_reg_val_to_light_mode(enum led_type type, u8 reg_val) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) {
|
||||
|
||||
if (type != led_type_mode_data[i].type)
|
||||
continue;
|
||||
|
||||
if ((led_type_mode_data[i].reg_bit_mask & reg_val) ==
|
||||
led_type_mode_data[i].mode_value)
|
||||
{
|
||||
return led_type_mode_data[i].mode;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 led_light_mode_to_reg_val(enum led_type type,
|
||||
enum led_light_mode mode, u8 reg_val) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) {
|
||||
if (type != led_type_mode_data[i].type)
|
||||
continue;
|
||||
|
||||
if (mode != led_type_mode_data[i].mode)
|
||||
continue;
|
||||
reg_val = led_type_mode_data[i].mode_value |
|
||||
(reg_val & (~led_type_mode_data[i].reg_bit_mask));
|
||||
break;
|
||||
}
|
||||
|
||||
return reg_val;
|
||||
}
|
||||
|
||||
static int accton_as4630_54npe_led_read_value(u8 reg)
|
||||
{
|
||||
return as4630_54npe_cpld_read(LED_CNTRLER_I2C_ADDRESS, reg);
|
||||
}
|
||||
|
||||
static int accton_as4630_54npe_led_write_value(u8 reg, u8 value)
|
||||
{
|
||||
return as4630_54npe_cpld_write(LED_CNTRLER_I2C_ADDRESS, reg, value);
|
||||
}
|
||||
|
||||
static void accton_as4630_54npe_led_update(void)
|
||||
{
|
||||
mutex_lock(&ledctl->update_lock);
|
||||
|
||||
if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2)
|
||||
|| !ledctl->valid) {
|
||||
int i;
|
||||
|
||||
dev_dbg(&ledctl->pdev->dev, "Starting accton_as4630_54npe_led update\n");
|
||||
|
||||
/* Update LED data
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) {
|
||||
int status = accton_as4630_54npe_led_read_value(led_reg_map[i].reg_addr);
|
||||
|
||||
if (status < 0) {
|
||||
ledctl->valid = 0;
|
||||
dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", led_reg_map[i].reg_addr, status);
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
ledctl->reg_val[i] = status;
|
||||
}
|
||||
}
|
||||
|
||||
ledctl->last_updated = jiffies;
|
||||
ledctl->valid = 1;
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ledctl->update_lock);
|
||||
}
|
||||
|
||||
static void accton_as4630_54npe_led_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode,
|
||||
enum led_type type)
|
||||
{
|
||||
int reg_val;
|
||||
u8 reg ;
|
||||
mutex_lock(&ledctl->update_lock);
|
||||
|
||||
if( !accton_getLedReg(type, ®))
|
||||
{
|
||||
dev_dbg(&ledctl->pdev->dev, "Not match item for %d.\n", type);
|
||||
}
|
||||
|
||||
|
||||
reg_val = accton_as4630_54npe_led_read_value(reg);
|
||||
if (reg_val < 0) {
|
||||
dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", reg, reg_val);
|
||||
goto exit;
|
||||
}
|
||||
reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val);
|
||||
|
||||
accton_as4630_54npe_led_write_value(reg, reg_val);
|
||||
|
||||
/* to prevent the slow-update issue */
|
||||
ledctl->valid = 0;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ledctl->update_lock);
|
||||
}
|
||||
|
||||
|
||||
static void accton_as4630_54npe_led_diag_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode)
|
||||
{
|
||||
accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_DIAG);
|
||||
}
|
||||
|
||||
static enum led_brightness accton_as4630_54npe_led_diag_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as4630_54npe_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_DIAG, ledctl->reg_val[0]);
|
||||
}
|
||||
|
||||
static void accton_as4630_54npe_led_pri_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode)
|
||||
{
|
||||
accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_PRI);
|
||||
}
|
||||
|
||||
static enum led_brightness accton_as4630_54npe_led_pri_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as4630_54npe_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_PRI, ledctl->reg_val[0]);
|
||||
}
|
||||
|
||||
static void accton_as4630_54npe_led_poe_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode)
|
||||
{
|
||||
accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_POE);
|
||||
}
|
||||
|
||||
static enum led_brightness accton_as4630_54npe_led_poe_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as4630_54npe_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_POE, ledctl->reg_val[1]);
|
||||
}
|
||||
|
||||
|
||||
static void accton_as4630_54npe_led_stk1_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode)
|
||||
{
|
||||
accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_STK1);
|
||||
}
|
||||
|
||||
static enum led_brightness accton_as4630_54npe_led_stk1_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as4630_54npe_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_STK1, ledctl->reg_val[1]);
|
||||
}
|
||||
|
||||
static void accton_as4630_54npe_led_stk2_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode)
|
||||
{
|
||||
accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_STK2);
|
||||
}
|
||||
|
||||
static enum led_brightness accton_as4630_54npe_led_stk2_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as4630_54npe_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_STK2, ledctl->reg_val[1]);
|
||||
}
|
||||
|
||||
static void accton_as4630_54npe_led_fan_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode)
|
||||
{
|
||||
accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_FAN);
|
||||
}
|
||||
|
||||
static enum led_brightness accton_as4630_54npe_led_fan_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as4630_54npe_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[1]);
|
||||
}
|
||||
|
||||
static void accton_as4630_54npe_led_psu1_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode)
|
||||
{
|
||||
accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_PSU1);
|
||||
}
|
||||
|
||||
static enum led_brightness accton_as4630_54npe_led_psu1_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as4630_54npe_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_PSU1, ledctl->reg_val[0]);
|
||||
}
|
||||
|
||||
static void accton_as4630_54npe_led_psu2_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness led_light_mode)
|
||||
{
|
||||
accton_as4630_54npe_led_set(led_cdev, led_light_mode, LED_TYPE_PSU2);
|
||||
}
|
||||
|
||||
static enum led_brightness accton_as4630_54npe_led_psu2_get(struct led_classdev *cdev)
|
||||
{
|
||||
accton_as4630_54npe_led_update();
|
||||
return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[1]);
|
||||
}
|
||||
|
||||
static struct led_classdev accton_as4630_54npe_leds[] = {
|
||||
[LED_TYPE_DIAG] = {
|
||||
.name = "diag",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = accton_as4630_54npe_led_diag_set,
|
||||
.brightness_get = accton_as4630_54npe_led_diag_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_GREEN_BLINK,
|
||||
},
|
||||
[LED_TYPE_PRI] = {
|
||||
.name = "pri",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = accton_as4630_54npe_led_pri_set,
|
||||
.brightness_get = accton_as4630_54npe_led_pri_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_AMBER,
|
||||
},
|
||||
[LED_TYPE_POE] = {
|
||||
.name = "poe",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = accton_as4630_54npe_led_poe_set,
|
||||
.brightness_get = accton_as4630_54npe_led_poe_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_AMBER,
|
||||
},
|
||||
[LED_TYPE_STK1] = {
|
||||
.name = "stk1",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = accton_as4630_54npe_led_stk1_set,
|
||||
.brightness_get = accton_as4630_54npe_led_stk1_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_GREEN,
|
||||
},
|
||||
[LED_TYPE_STK2] = {
|
||||
.name = "stk2",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = accton_as4630_54npe_led_stk2_set,
|
||||
.brightness_get = accton_as4630_54npe_led_stk2_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_GREEN,
|
||||
},
|
||||
[LED_TYPE_FAN] = {
|
||||
.name = "fan",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = accton_as4630_54npe_led_fan_set,
|
||||
.brightness_get = accton_as4630_54npe_led_fan_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_AUTO,
|
||||
},
|
||||
[LED_TYPE_PSU1] = {
|
||||
.name = "psu1",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = accton_as4630_54npe_led_psu1_set,
|
||||
.brightness_get = accton_as4630_54npe_led_psu1_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_AUTO,
|
||||
},
|
||||
[LED_TYPE_PSU2] = {
|
||||
.name = "psu2",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = accton_as4630_54npe_led_psu2_set,
|
||||
.brightness_get = accton_as4630_54npe_led_psu2_get,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
.max_brightness = LED_MODE_AUTO,
|
||||
},
|
||||
};
|
||||
|
||||
static int accton_as4630_54npe_led_suspend(struct platform_device *dev,
|
||||
pm_message_t state)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(accton_as4630_54npe_leds); i++) {
|
||||
led_classdev_suspend(&accton_as4630_54npe_leds[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int accton_as4630_54npe_led_resume(struct platform_device *dev)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(accton_as4630_54npe_leds); i++) {
|
||||
led_classdev_resume(&accton_as4630_54npe_leds[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int accton_as4630_54npe_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(accton_as4630_54npe_leds); i++) {
|
||||
ret = led_classdev_register(&pdev->dev, &accton_as4630_54npe_leds[i]);
|
||||
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if all LEDs were successfully registered */
|
||||
if (i != ARRAY_SIZE(accton_as4630_54npe_leds)) {
|
||||
int j;
|
||||
|
||||
/* only unregister the LEDs that were successfully registered */
|
||||
for (j = 0; j < i; j++) {
|
||||
led_classdev_unregister(&accton_as4630_54npe_leds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int accton_as4630_54npe_led_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(accton_as4630_54npe_leds); i++) {
|
||||
led_classdev_unregister(&accton_as4630_54npe_leds[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver accton_as4630_54npe_led_driver = {
|
||||
.probe = accton_as4630_54npe_led_probe,
|
||||
.remove = accton_as4630_54npe_led_remove,
|
||||
.suspend = accton_as4630_54npe_led_suspend,
|
||||
.resume = accton_as4630_54npe_led_resume,
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init accton_as4630_54npe_led_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&accton_as4630_54npe_led_driver);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ledctl = kzalloc(sizeof(struct accton_as4630_54npe_led_data), GFP_KERNEL);
|
||||
if (!ledctl) {
|
||||
ret = -ENOMEM;
|
||||
platform_driver_unregister(&accton_as4630_54npe_led_driver);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mutex_init(&ledctl->update_lock);
|
||||
|
||||
ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
|
||||
if (IS_ERR(ledctl->pdev)) {
|
||||
ret = PTR_ERR(ledctl->pdev);
|
||||
platform_driver_unregister(&accton_as4630_54npe_led_driver);
|
||||
kfree(ledctl);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit accton_as4630_54npe_led_exit(void)
|
||||
{
|
||||
platform_device_unregister(ledctl->pdev);
|
||||
platform_driver_unregister(&accton_as4630_54npe_led_driver);
|
||||
kfree(ledctl);
|
||||
}
|
||||
|
||||
module_init(accton_as4630_54npe_led_init);
|
||||
module_exit(accton_as4630_54npe_led_exit);
|
||||
|
||||
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
|
||||
MODULE_DESCRIPTION("accton_as4630_54npe_led driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -0,0 +1,342 @@
|
||||
/*
|
||||
* An hwmon driver for accton as4630_54npe Power Module
|
||||
*
|
||||
* Copyright (C) 2014 Accton Technology Corporation.
|
||||
* Brandon Chuang <brandon_chuang@accton.com.tw>
|
||||
*
|
||||
* Based on ad7414.c
|
||||
* Copyright 2006 Stefan Roese <sr at denx.de>, DENX Software Engineering
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmi.h>
|
||||
#define __STDC_WANT_LIB_EXT1__ 1
|
||||
#include <linux/string.h>
|
||||
|
||||
#define MAX_MODEL_NAME 20
|
||||
#define MAX_SERIAL_NUMBER 19
|
||||
|
||||
static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf);
|
||||
static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf);
|
||||
static int as4630_54npe_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len);
|
||||
extern int as4630_54npe_cpld_read(unsigned short cpld_addr, u8 reg);
|
||||
|
||||
/* Addresses scanned
|
||||
*/
|
||||
static const unsigned short normal_i2c[] = { 0x50, 0x51, I2C_CLIENT_END };
|
||||
|
||||
/* Each client has this additional data
|
||||
*/
|
||||
struct as4630_54npe_psu_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if registers are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
u8 index; /* PSU index */
|
||||
u8 status; /* Status(present/power_good) register read from CPLD */
|
||||
char model_name[MAX_MODEL_NAME]; /* Model name, read from eeprom */
|
||||
char serial_number[MAX_SERIAL_NUMBER];
|
||||
};
|
||||
|
||||
static struct as4630_54npe_psu_data *as4630_54npe_psu_update_device(struct device *dev);
|
||||
|
||||
enum as4630_54npe_psu_sysfs_attributes {
|
||||
PSU_PRESENT,
|
||||
PSU_MODEL_NAME,
|
||||
PSU_POWER_GOOD,
|
||||
PSU_SERIAL_NUMBER
|
||||
};
|
||||
|
||||
/* sysfs attributes for hwmon
|
||||
*/
|
||||
static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT);
|
||||
static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME);
|
||||
static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD);
|
||||
static SENSOR_DEVICE_ATTR(psu_serial_number, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER);
|
||||
|
||||
|
||||
static struct attribute *as4630_54npe_psu_attributes[] = {
|
||||
&sensor_dev_attr_psu_present.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_model_name.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_power_good.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_serial_number.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static ssize_t show_status(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct as4630_54npe_psu_data *data = as4630_54npe_psu_update_device(dev);
|
||||
u8 status = 0;
|
||||
|
||||
if (attr->index == PSU_PRESENT) {
|
||||
if(data->index==0)
|
||||
status = !( (data->status >> 5) & 0x1);
|
||||
else
|
||||
status = !( (data->status >> 1) & 0x1);
|
||||
}
|
||||
else { /* PSU_POWER_GOOD */
|
||||
if(data->index==0)
|
||||
status = ( (data->status >> 6) & 0x1);
|
||||
else
|
||||
status = ( (data->status >> 2) & 0x1);
|
||||
}
|
||||
|
||||
return sprintf(buf, "%d\n", status);
|
||||
}
|
||||
|
||||
static ssize_t show_string(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct as4630_54npe_psu_data *data = as4630_54npe_psu_update_device(dev);
|
||||
char *ptr = NULL;
|
||||
|
||||
if (!data->valid) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
switch (attr->index) {
|
||||
case PSU_MODEL_NAME:
|
||||
ptr = data->model_name;
|
||||
break;
|
||||
case PSU_SERIAL_NUMBER:
|
||||
ptr = data->serial_number;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return sprintf(buf, "%s\n", ptr);
|
||||
}
|
||||
|
||||
static const struct attribute_group as4630_54npe_psu_group = {
|
||||
.attrs = as4630_54npe_psu_attributes,
|
||||
};
|
||||
|
||||
static int as4630_54npe_psu_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *dev_id)
|
||||
{
|
||||
struct as4630_54npe_psu_data *data;
|
||||
int status;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
||||
status = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
data = kzalloc(sizeof(struct as4630_54npe_psu_data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
status = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->valid = 0;
|
||||
data->index = dev_id->driver_data;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
dev_info(&client->dev, "chip found\n");
|
||||
|
||||
/* Register sysfs hooks */
|
||||
status = sysfs_create_group(&client->dev.kobj, &as4630_54npe_psu_group);
|
||||
if (status) {
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
status = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "%s: psu '%s'\n",
|
||||
dev_name(data->hwmon_dev), client->name);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &as4630_54npe_psu_group);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int as4630_54npe_psu_remove(struct i2c_client *client)
|
||||
{
|
||||
struct as4630_54npe_psu_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &as4630_54npe_psu_group);
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum psu_index
|
||||
{
|
||||
as4630_54npe_psu1,
|
||||
as4630_54npe_psu2
|
||||
};
|
||||
|
||||
static const struct i2c_device_id as4630_54npe_psu_id[] = {
|
||||
{ "as4630_54npe_psu1", as4630_54npe_psu1 },
|
||||
{ "as4630_54npe_psu2", as4630_54npe_psu2 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, as4630_54npe_psu_id);
|
||||
|
||||
static struct i2c_driver as4630_54npe_psu_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "as4630_54npe_psu",
|
||||
},
|
||||
.probe = as4630_54npe_psu_probe,
|
||||
.remove = as4630_54npe_psu_remove,
|
||||
.id_table = as4630_54npe_psu_id,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int as4630_54npe_psu_read_block(struct i2c_client *client, u8 command, u8 *data,
|
||||
int data_len)
|
||||
{
|
||||
int result = 0;
|
||||
int retry_count = 5;
|
||||
|
||||
while (retry_count) {
|
||||
retry_count--;
|
||||
|
||||
result = i2c_smbus_read_i2c_block_data(client, command, data_len, data);
|
||||
|
||||
if (unlikely(result < 0)) {
|
||||
msleep(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unlikely(result != data_len)) {
|
||||
result = -EIO;
|
||||
msleep(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct as4630_54npe_psu_data *as4630_54npe_psu_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as4630_54npe_psu_data *data = i2c_get_clientdata(client);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
int status;
|
||||
int power_good = 0;
|
||||
|
||||
dev_dbg(&client->dev, "Starting as4630_54npe update\n");
|
||||
|
||||
/* Read psu status */
|
||||
status = as4630_54npe_cpld_read(0x60, 0x22);
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "cpld reg 0x60 err %d\n", status);
|
||||
}
|
||||
else {
|
||||
data->status = status;
|
||||
}
|
||||
|
||||
/* Read model name */
|
||||
#ifdef __STDC_LIB_EXT1__
|
||||
memset_s(data->model_name, sizeof(data->model_name), 0, sizeof(data->model_name));
|
||||
#else
|
||||
memset(data->model_name, 0, sizeof(data->model_name));
|
||||
#endif
|
||||
#ifdef __STDC_LIB_EXT1__
|
||||
memset_s(data->serial_number, sizeof(data->serial_number), 0, sizeof(data->serial_number));
|
||||
#else
|
||||
memset(data->serial_number, 0, sizeof(data->serial_number));
|
||||
#endif
|
||||
power_good = (data->status >> (data->index==0? 6:2)) & 0x1;
|
||||
|
||||
if (power_good) {
|
||||
status = as4630_54npe_psu_read_block(client, 0x20, data->model_name,
|
||||
ARRAY_SIZE(data->model_name)-1);
|
||||
if (status < 0) {
|
||||
data->model_name[0] = '\0';
|
||||
dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr);
|
||||
}
|
||||
else if(!strncmp(data->model_name, "YPEB1200", strlen("YPEB1200")))
|
||||
{
|
||||
if (data->model_name[9]=='A' && data->model_name[10]=='M')
|
||||
{
|
||||
data->model_name[8]='A';
|
||||
data->model_name[9]='M';
|
||||
data->model_name[strlen("YPEB1200AM")]='\0';
|
||||
}
|
||||
else
|
||||
data->model_name[strlen("YPEB1200")]='\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0';
|
||||
}
|
||||
/* Read from offset 0x35 ~ 0x46 (18 bytes) */
|
||||
status = as4630_54npe_psu_read_block(client, 0x35,data->serial_number, MAX_SERIAL_NUMBER);
|
||||
if (status < 0)
|
||||
{
|
||||
data->serial_number[0] = '\0';
|
||||
dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x35)\n", client->addr);
|
||||
}
|
||||
if (!strncmp(data->model_name, "YPEB1200AM", strlen("YPEB1200AM"))) /*for YPEB1200AM, SN length=18*/
|
||||
{
|
||||
data->serial_number[MAX_SERIAL_NUMBER-1]='\0';
|
||||
}
|
||||
else
|
||||
data->serial_number[MAX_SERIAL_NUMBER-2]='\0';
|
||||
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
module_i2c_driver(as4630_54npe_psu_driver);
|
||||
|
||||
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
|
||||
MODULE_DESCRIPTION("as4630_54npe_psu driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -0,0 +1,744 @@
|
||||
/*
|
||||
* An hwmon driver for the 3Y Power YM-2651Y Power Module
|
||||
*
|
||||
* Copyright (C) 2014 Accton Technology Corporation.
|
||||
* Brandon Chuang <brandon_chuang@accton.com.tw>
|
||||
*
|
||||
* Based on ad7414.c
|
||||
* Copyright 2006 Stefan Roese <sr at denx.de>, DENX Software Engineering
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define MAX_FAN_DUTY_CYCLE 100
|
||||
|
||||
/* Addresses scanned
|
||||
*/
|
||||
static const unsigned short normal_i2c[] = { 0x58, 0x5b, I2C_CLIENT_END };
|
||||
|
||||
enum chips {
|
||||
YM2651,
|
||||
YM2401,
|
||||
YM2851,
|
||||
YM1401A,
|
||||
YPEB1200AM
|
||||
};
|
||||
|
||||
/* Each client has this additional data
|
||||
*/
|
||||
struct ym2651y_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if registers are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
u8 chip; /* chip id */
|
||||
u8 capability; /* Register value */
|
||||
u16 status_word; /* Register value */
|
||||
u8 fan_fault; /* Register value */
|
||||
u8 over_temp; /* Register value */
|
||||
u16 v_out; /* Register value */
|
||||
u16 i_out; /* Register value */
|
||||
u16 p_out; /* Register value */
|
||||
u8 vout_mode; /* Register value */
|
||||
u16 temp; /* Register value */
|
||||
u16 fan_speed; /* Register value */
|
||||
u16 fan_duty_cycle[2]; /* Register value */
|
||||
u8 fan_dir[4]; /* Register value */
|
||||
u8 pmbus_revision; /* Register value */
|
||||
u8 mfr_serial[21]; /* Register value */
|
||||
u8 mfr_id[10]; /* Register value */
|
||||
u8 mfr_model[16]; /* Register value */
|
||||
u8 mfr_revsion[3]; /* Register value */
|
||||
u16 mfr_vin_min; /* Register value */
|
||||
u16 mfr_vin_max; /* Register value */
|
||||
u16 mfr_iin_max; /* Register value */
|
||||
u16 mfr_iout_max; /* Register value */
|
||||
u16 mfr_pin_max; /* Register value */
|
||||
u16 mfr_pout_max; /* Register value */
|
||||
u16 mfr_vout_min; /* Register value */
|
||||
u16 mfr_vout_max; /* Register value */
|
||||
};
|
||||
|
||||
static ssize_t show_vout(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
static ssize_t show_byte(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
static ssize_t show_word(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
static ssize_t show_linear(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
static ssize_t show_over_temp(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
static ssize_t show_ascii(struct device *dev, struct device_attribute *da,
|
||||
char *buf);
|
||||
static struct ym2651y_data *ym2651y_update_device(struct device *dev);
|
||||
static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count);
|
||||
static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value);
|
||||
|
||||
enum ym2651y_sysfs_attributes {
|
||||
PSU_POWER_ON = 0,
|
||||
PSU_TEMP_FAULT,
|
||||
PSU_POWER_GOOD,
|
||||
PSU_FAN1_FAULT,
|
||||
PSU_FAN_DIRECTION,
|
||||
PSU_OVER_TEMP,
|
||||
PSU_V_OUT,
|
||||
PSU_I_OUT,
|
||||
PSU_P_OUT,
|
||||
PSU_P_OUT_UV, /*In Unit of microVolt, instead of mini.*/
|
||||
PSU_TEMP1_INPUT,
|
||||
PSU_FAN1_SPEED,
|
||||
PSU_FAN1_DUTY_CYCLE,
|
||||
PSU_PMBUS_REVISION,
|
||||
PSU_SERIAL_NUM,
|
||||
PSU_MFR_ID,
|
||||
PSU_MFR_MODEL,
|
||||
PSU_MFR_REVISION,
|
||||
PSU_MFR_SERIAL,
|
||||
PSU_MFR_VIN_MIN,
|
||||
PSU_MFR_VIN_MAX,
|
||||
PSU_MFR_VOUT_MIN,
|
||||
PSU_MFR_VOUT_MAX,
|
||||
PSU_MFR_IIN_MAX,
|
||||
PSU_MFR_IOUT_MAX,
|
||||
PSU_MFR_PIN_MAX,
|
||||
PSU_MFR_POUT_MAX
|
||||
};
|
||||
|
||||
/* sysfs attributes for hwmon
|
||||
*/
|
||||
static SENSOR_DEVICE_ATTR(psu_power_on, S_IRUGO, show_word, NULL, PSU_POWER_ON);
|
||||
static SENSOR_DEVICE_ATTR(psu_temp_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT);
|
||||
static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_word, NULL, PSU_POWER_GOOD);
|
||||
static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT);
|
||||
static SENSOR_DEVICE_ATTR(psu_over_temp, S_IRUGO, show_over_temp, NULL, PSU_OVER_TEMP);
|
||||
static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_vout, NULL, PSU_V_OUT);
|
||||
static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT);
|
||||
static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT);
|
||||
static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT);
|
||||
static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED);
|
||||
static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE);
|
||||
static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_ascii, NULL, PSU_FAN_DIRECTION);
|
||||
static SENSOR_DEVICE_ATTR(psu_pmbus_revision, S_IRUGO, show_byte, NULL, PSU_PMBUS_REVISION);
|
||||
static SENSOR_DEVICE_ATTR(psu_serial_num, S_IRUGO, show_ascii, NULL, PSU_SERIAL_NUM);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, show_ascii, NULL, PSU_MFR_ID);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MFR_REVISION);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_serial, S_IRUGO, show_ascii, NULL, PSU_MFR_SERIAL);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_vout_max, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MAX);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_iin_max, S_IRUGO, show_linear, NULL, PSU_MFR_IIN_MAX);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_iout_max, S_IRUGO, show_linear, NULL, PSU_MFR_IOUT_MAX);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_pin_max, S_IRUGO, show_linear, NULL, PSU_MFR_PIN_MAX);
|
||||
static SENSOR_DEVICE_ATTR(psu_mfr_pout_max, S_IRUGO, show_linear, NULL, PSU_MFR_POUT_MAX);
|
||||
|
||||
/*Duplicate nodes for lm-sensors.*/
|
||||
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_vout, NULL, PSU_V_OUT);
|
||||
static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, show_linear, NULL, PSU_I_OUT);
|
||||
static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, show_linear, NULL, PSU_P_OUT_UV);
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT);
|
||||
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED);
|
||||
static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT);
|
||||
|
||||
static struct attribute *ym2651y_attributes[] = {
|
||||
&sensor_dev_attr_psu_power_on.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_temp_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_power_good.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_fan1_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_over_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_v_out.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_i_out.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_p_out.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_fan_dir.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_pmbus_revision.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_serial_num.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_id.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_model.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_revision.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_serial.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_vin_min.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_vin_max.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_pout_max.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_iin_max.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_pin_max.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_vout_min.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_vout_max.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_mfr_iout_max.dev_attr.attr,
|
||||
/*Duplicate nodes for lm-sensors.*/
|
||||
&sensor_dev_attr_curr2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_power2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_fault.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static ssize_t show_byte(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||
|
||||
return (attr->index == PSU_PMBUS_REVISION) ? sprintf(buf, "%d\n", data->pmbus_revision) :
|
||||
sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
static ssize_t show_word(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||
u16 status = 0;
|
||||
|
||||
switch (attr->index) {
|
||||
case PSU_POWER_ON: /* psu_power_on, low byte bit 6 of status_word, 0=>ON, 1=>OFF */
|
||||
status = (data->status_word & 0x40) ? 0 : 1;
|
||||
break;
|
||||
case PSU_TEMP_FAULT: /* psu_temp_fault, low byte bit 2 of status_word, 0=>Normal, 1=>temp fault */
|
||||
status = (data->status_word & 0x4) >> 2;
|
||||
break;
|
||||
case PSU_POWER_GOOD: /* psu_power_good, high byte bit 3 of status_word, 0=>OK, 1=>FAIL */
|
||||
status = (data->status_word & 0x800) ? 0 : 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return sprintf(buf, "%d\n", status);
|
||||
}
|
||||
|
||||
static int two_complement_to_int(u16 data, u8 valid_bit, int mask)
|
||||
{
|
||||
u16 valid_data = data & mask;
|
||||
bool is_negative = valid_data >> (valid_bit - 1);
|
||||
|
||||
return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data;
|
||||
}
|
||||
|
||||
static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ym2651y_data *data = i2c_get_clientdata(client);
|
||||
int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1;
|
||||
long speed;
|
||||
int error;
|
||||
|
||||
error = kstrtol(buf, 10, &speed);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (speed < 0 || speed > MAX_FAN_DUTY_CYCLE)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->fan_duty_cycle[nr] = speed;
|
||||
ym2651y_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_linear(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||
|
||||
u16 value = 0;
|
||||
int exponent, mantissa;
|
||||
int multiplier = 1000;
|
||||
|
||||
switch (attr->index) {
|
||||
case PSU_V_OUT:
|
||||
value = data->v_out;
|
||||
break;
|
||||
case PSU_I_OUT:
|
||||
value = data->i_out;
|
||||
break;
|
||||
case PSU_P_OUT_UV:
|
||||
multiplier = 1000000; /*For lm-sensors, unit is micro-Volt.*/
|
||||
/*Passing through*/
|
||||
case PSU_P_OUT:
|
||||
value = data->p_out;
|
||||
break;
|
||||
case PSU_TEMP1_INPUT:
|
||||
value = data->temp;
|
||||
break;
|
||||
case PSU_FAN1_SPEED:
|
||||
value = data->fan_speed;
|
||||
multiplier = 1;
|
||||
break;
|
||||
case PSU_FAN1_DUTY_CYCLE:
|
||||
value = data->fan_duty_cycle[0];
|
||||
multiplier = 1;
|
||||
break;
|
||||
case PSU_MFR_VIN_MIN:
|
||||
value = data->mfr_vin_min;
|
||||
break;
|
||||
case PSU_MFR_VIN_MAX:
|
||||
value = data->mfr_vin_max;
|
||||
break;
|
||||
case PSU_MFR_VOUT_MIN:
|
||||
value = data->mfr_vout_min;
|
||||
break;
|
||||
case PSU_MFR_VOUT_MAX:
|
||||
value = data->mfr_vout_max;
|
||||
break;
|
||||
case PSU_MFR_PIN_MAX:
|
||||
value = data->mfr_pin_max;
|
||||
break;
|
||||
case PSU_MFR_POUT_MAX:
|
||||
value = data->mfr_pout_max;
|
||||
break;
|
||||
case PSU_MFR_IOUT_MAX:
|
||||
value = data->mfr_iout_max;
|
||||
break;
|
||||
case PSU_MFR_IIN_MAX:
|
||||
value = data->mfr_iin_max;
|
||||
break;
|
||||
}
|
||||
|
||||
exponent = two_complement_to_int(value >> 11, 5, 0x1f);
|
||||
mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff);
|
||||
return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) :
|
||||
sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent));
|
||||
}
|
||||
|
||||
static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||
|
||||
u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6;
|
||||
|
||||
return sprintf(buf, "%d\n", data->fan_fault >> shift);
|
||||
}
|
||||
|
||||
static ssize_t show_over_temp(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", data->over_temp >> 7);
|
||||
}
|
||||
|
||||
static ssize_t show_ascii(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||
u8 *ptr = NULL;
|
||||
|
||||
switch (attr->index) {
|
||||
case PSU_FAN_DIRECTION: /* psu_fan_dir */
|
||||
if (data->chip==YPEB1200AM)
|
||||
{
|
||||
memcpy(data->fan_dir, "F2B", 3);
|
||||
data->fan_dir[3]='\0';
|
||||
}
|
||||
ptr = data->fan_dir;
|
||||
break;
|
||||
case PSU_MFR_SERIAL: /* psu_mfr_serial */
|
||||
ptr = data->mfr_serial+1; /* The first byte is the count byte of string. */
|
||||
break;
|
||||
case PSU_MFR_ID: /* psu_mfr_id */
|
||||
ptr = data->mfr_id+1; /* The first byte is the count byte of string. */
|
||||
break;
|
||||
case PSU_MFR_MODEL: /* psu_mfr_model */
|
||||
ptr = data->mfr_model+1; /* The first byte is the count byte of string. */
|
||||
break;
|
||||
case PSU_MFR_REVISION: /* psu_mfr_revision */
|
||||
ptr = data->mfr_revsion+1;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sprintf(buf, "%s\n", ptr);
|
||||
}
|
||||
|
||||
static ssize_t show_vout_by_mode(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct ym2651y_data *data = ym2651y_update_device(dev);
|
||||
int exponent, mantissa;
|
||||
int multiplier = 1000;
|
||||
|
||||
if (!data->valid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
exponent = two_complement_to_int(data->vout_mode, 5, 0x1f);
|
||||
switch (attr->index) {
|
||||
case PSU_MFR_VOUT_MIN:
|
||||
mantissa = data->mfr_vout_min;
|
||||
break;
|
||||
case PSU_MFR_VOUT_MAX:
|
||||
mantissa = data->mfr_vout_max;
|
||||
break;
|
||||
case PSU_V_OUT:
|
||||
mantissa = data->v_out;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (exponent > 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) :
|
||||
sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent));
|
||||
}
|
||||
|
||||
static ssize_t show_vout(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ym2651y_data *data = i2c_get_clientdata(client);
|
||||
|
||||
if (data->chip == YM2401 || data->chip==YM1401A) {
|
||||
return show_vout_by_mode(dev, da, buf);
|
||||
}
|
||||
else {
|
||||
return show_linear(dev, da, buf);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct attribute_group ym2651y_group = {
|
||||
.attrs = ym2651y_attributes,
|
||||
};
|
||||
|
||||
static int ym2651y_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *dev_id)
|
||||
{
|
||||
struct ym2651y_data *data;
|
||||
int status;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
||||
status = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
data = kzalloc(sizeof(struct ym2651y_data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
status = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
data->chip = dev_id->driver_data;
|
||||
dev_info(&client->dev, "chip found\n");
|
||||
|
||||
/* Register sysfs hooks */
|
||||
status = sysfs_create_group(&client->dev.kobj, &ym2651y_group);
|
||||
if (status) {
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
status = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "%s: psu '%s'\n",
|
||||
dev_name(data->hwmon_dev), client->name);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &ym2651y_group);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int ym2651y_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ym2651y_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &ym2651y_group);
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ym2651y_id[] = {
|
||||
{ "ym2651", YM2651 },
|
||||
{ "ym2401", YM2401 },
|
||||
{ "ym2851", YM2851 },
|
||||
{ "ym1401a",YM1401A},
|
||||
{ "ype1200am", YPEB1200AM },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ym2651y_id);
|
||||
|
||||
static struct i2c_driver ym2651y_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "ym2651",
|
||||
},
|
||||
.probe = ym2651y_probe,
|
||||
.remove = ym2651y_remove,
|
||||
.id_table = ym2651y_id,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int ym2651y_read_byte(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int ym2651y_read_word(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_word_data(client, reg);
|
||||
}
|
||||
|
||||
static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value)
|
||||
{
|
||||
return i2c_smbus_write_word_data(client, reg, value);
|
||||
}
|
||||
|
||||
static int ym2651y_read_block(struct i2c_client *client, u8 command, u8 *data,
|
||||
int data_len)
|
||||
{
|
||||
int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data);
|
||||
|
||||
if (unlikely(result < 0))
|
||||
goto abort;
|
||||
if (unlikely(result != data_len)) {
|
||||
result = -EIO;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
|
||||
abort:
|
||||
return result;
|
||||
}
|
||||
|
||||
struct reg_data_byte {
|
||||
u8 reg;
|
||||
u8 *value;
|
||||
};
|
||||
|
||||
struct reg_data_word {
|
||||
u8 reg;
|
||||
u16 *value;
|
||||
};
|
||||
|
||||
static struct ym2651y_data *ym2651y_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ym2651y_data *data = i2c_get_clientdata(client);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
int i, status, length;
|
||||
u8 command, buf;
|
||||
u8 fan_dir[5] = {0};
|
||||
struct reg_data_byte regs_byte[] = { {0x19, &data->capability},
|
||||
{0x20, &data->vout_mode},
|
||||
{0x7d, &data->over_temp},
|
||||
{0x81, &data->fan_fault},
|
||||
{0x98, &data->pmbus_revision}
|
||||
};
|
||||
struct reg_data_word regs_word[] = { {0x79, &data->status_word},
|
||||
{0x8b, &data->v_out},
|
||||
{0x8c, &data->i_out},
|
||||
{0x96, &data->p_out},
|
||||
{0x8d, &data->temp},
|
||||
{0x3b, &(data->fan_duty_cycle[0])},
|
||||
{0x3c, &(data->fan_duty_cycle[1])},
|
||||
{0x90, &data->fan_speed},
|
||||
{0xa0, &data->mfr_vin_min},
|
||||
{0xa1, &data->mfr_vin_max},
|
||||
{0xa2, &data->mfr_iin_max},
|
||||
{0xa3, &data->mfr_pin_max},
|
||||
{0xa4, &data->mfr_vout_min},
|
||||
{0xa5, &data->mfr_vout_max},
|
||||
{0xa6, &data->mfr_iout_max},
|
||||
{0xa7, &data->mfr_pout_max}
|
||||
};
|
||||
|
||||
dev_dbg(&client->dev, "Starting ym2651 update\n");
|
||||
|
||||
/* Read byte data */
|
||||
for (i = 0; i < ARRAY_SIZE(regs_byte); i++) {
|
||||
status = ym2651y_read_byte(client, regs_byte[i].reg);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n",
|
||||
regs_byte[i].reg, status);
|
||||
*(regs_byte[i].value) = 0;
|
||||
goto exit;
|
||||
}
|
||||
else {
|
||||
*(regs_byte[i].value) = status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read word data */
|
||||
for (i = 0; i < ARRAY_SIZE(regs_word); i++) {
|
||||
status = ym2651y_read_word(client, regs_word[i].reg);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n",
|
||||
regs_word[i].reg, status);
|
||||
*(regs_word[i].value) = 0;
|
||||
goto exit;
|
||||
}
|
||||
else {
|
||||
*(regs_word[i].value) = status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read fan_direction */
|
||||
command = 0xC3;
|
||||
status = ym2651y_read_block(client, command, fan_dir, ARRAY_SIZE(fan_dir)-1);
|
||||
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
strncpy(data->fan_dir, fan_dir+1, ARRAY_SIZE(data->fan_dir)-1);
|
||||
data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0';
|
||||
|
||||
/* Read mfr_id */
|
||||
command = 0x99;
|
||||
status = ym2651y_read_block(client, command, data->mfr_id,
|
||||
ARRAY_SIZE(data->mfr_id)-1);
|
||||
data->mfr_id[ARRAY_SIZE(data->mfr_id)-1] = '\0';
|
||||
|
||||
if (status < 0)
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||
|
||||
/* Read mfr_model */
|
||||
command = 0x9a;
|
||||
length = 1;
|
||||
/* Read first byte to determine the length of data */
|
||||
status = ym2651y_read_block(client, command, &buf, length);
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||
goto exit;
|
||||
}
|
||||
status = ym2651y_read_block(client, command, data->mfr_model, buf+1);
|
||||
|
||||
if ((buf+1) >= (ARRAY_SIZE(data->mfr_model)-1))
|
||||
{
|
||||
data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0';
|
||||
}
|
||||
else
|
||||
data->mfr_model[buf+1] = '\0';
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*YM-1401A PSU doens't support to get serial_num, so ignore it.
|
||||
*It's vout doesn't support linear, so let it use show_vout_by_mode().
|
||||
*/
|
||||
if(!strncmp("YM-1401A", data->mfr_model+1, strlen("YM-1401A")))
|
||||
{
|
||||
data->chip=YM1401A;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read mfr_serial */
|
||||
command = 0x9e;
|
||||
length = 1;
|
||||
/* Read first byte to determine the length of data */
|
||||
status = ym2651y_read_block(client, command, &buf, length);
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||
goto exit;
|
||||
}
|
||||
status = ym2651y_read_block(client, command, data->mfr_serial, buf+1);
|
||||
|
||||
if ((buf+1) >= (ARRAY_SIZE(data->mfr_serial)-1))
|
||||
{
|
||||
data->mfr_serial[ARRAY_SIZE(data->mfr_serial)-1] = '\0';
|
||||
}
|
||||
else
|
||||
data->mfr_serial[buf+1] = '\0';
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read mfr_revsion */
|
||||
command = 0x9b;
|
||||
status = ym2651y_read_block(client, command, data->mfr_revsion,
|
||||
ARRAY_SIZE(data->mfr_revsion)-1);
|
||||
data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0';
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
module_i2c_driver(ym2651y_driver);
|
||||
|
||||
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
|
||||
MODULE_DESCRIPTION("3Y Power YM-2651Y driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Accton AS4630-54NPE Platform handle management interface service
|
||||
After=sysinit.target systemd-udevd.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/local/bin/handle_mgmt_interface.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Accton AS4630-54NPE Platform Monitoring FAN service
|
||||
Before=pmon.service
|
||||
After=as4630-54npe-platform-monitor.service
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/accton_as4630_54npe_monitor_fan.py
|
||||
KillSignal=SIGKILL
|
||||
SuccessExitStatus=SIGKILL
|
||||
|
||||
# Resource Limitations
|
||||
LimitCORE=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Accton AS4630-54NPE Platform Monitoring PSU service
|
||||
Before=pmon.service
|
||||
After=as4630-54npe-platform-monitor.service
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/accton_as4630_54npe_monitor_psu.py
|
||||
KillSignal=SIGKILL
|
||||
SuccessExitStatus=SIGKILL
|
||||
|
||||
# Resource Limitations
|
||||
LimitCORE=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=Accton AS4630-54NPE Platform Monitoring service
|
||||
Before=pmon.service
|
||||
After=sysinit.target
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/usr/local/bin/accton_as4630_54npe_util.py install
|
||||
ExecStart=/usr/local/bin/accton_as4630_54npe_monitor.py
|
||||
KillSignal=SIGKILL
|
||||
SuccessExitStatus=SIGKILL
|
||||
|
||||
# Resource Limitations
|
||||
LimitCORE=infinity
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
from setuptools import setup
|
||||
os.listdir
|
||||
|
||||
setup(
|
||||
name='as4630_54npe',
|
||||
version='1.0',
|
||||
description='Module to initialize Accton AS4630-54NPE platforms',
|
||||
|
||||
packages=['as4630_54npe'],
|
||||
package_dir={'as4630_54npe': 'as4630-54npe/classes'},
|
||||
)
|
@ -0,0 +1,34 @@
|
||||
from setuptools import setup
|
||||
|
||||
DEVICE_NAME = 'accton'
|
||||
HW_SKU = 'x86_64-accton_as4630_54npe-r0'
|
||||
|
||||
setup(
|
||||
name='sonic-platform',
|
||||
version='1.0',
|
||||
description='SONiC platform API implementation on Accton Platforms',
|
||||
license='Apache 2.0',
|
||||
author='SONiC Team',
|
||||
author_email='linuxnetdev@microsoft.com',
|
||||
url='https://github.com/Azure/sonic-buildimage',
|
||||
maintainer='Jostar Yang',
|
||||
maintainer_email='jostar_yang@accton.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 :: 3.7',
|
||||
'Topic :: Utilities',
|
||||
],
|
||||
keywords='sonic SONiC platform PLATFORM',
|
||||
)
|
@ -0,0 +1,3 @@
|
||||
ACTION=="add", SUBSYSTEM=="net", DRIVERS=="ixgbe", KERNELS=="0000:08:00.0", NAME:="eth0"
|
||||
ACTION=="add", SUBSYSTEM=="net", DRIVERS=="ixgbe", KERNELS=="0000:06:00.1", NAME:="eth1"
|
||||
ACTION=="add", SUBSYSTEM=="net", DRIVERS=="ixgbe", KERNELS=="0000:06:00.0", NAME:="eth3"
|
@ -0,0 +1,66 @@
|
||||
Copyright (C) 2019 Accton Networks, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
It under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
All Linux kernel code is licensed under the GPLv1. All other code is
|
||||
licensed under the GPLv3. Please see the LICENSE file for copies of
|
||||
both licenses.
|
||||
|
||||
The code for integacting with Accton AS4630-54npe has 2 parts,
|
||||
kernel drivers and operational script.
|
||||
The kernel drivers of peripherals are under module/ directory.
|
||||
1. These drivers are at module dir.
|
||||
2. A operational script, accton_as4630_util.py, for device initializatian and
|
||||
peripheral accessing should be installed at /usr/bin.
|
||||
Run "accton_as4630_util.py install" to install drivers.
|
||||
|
||||
To initialize the system, run "accton_as4630_util.py install".
|
||||
To clean up the drivers & devices, run "accton_as4630_util.py clean".
|
||||
To dump information of sensors, run "accton_as4630_util.py show".
|
||||
To dump SFP EEPROM, run "accton_as4630_util.py sff".
|
||||
To set fan speed, run "accton_as4630_util.py set fan".
|
||||
To enable/disable SFP emission, run "accton_as4630_util.py set sfp".
|
||||
To set system LEDs' color, run "accton_as4630_util.py set led"
|
||||
For more information, run "accton_as4630_util.py --help".
|
||||
|
||||
====================================================================
|
||||
Besides applying accton_as4630_util.py to access peripherals, you can
|
||||
access peripherals by sysfs nodes directly after the installation is run.
|
||||
|
||||
System LED:
|
||||
There are 5 system LEDs at the lower-left corner of front panel.
|
||||
They are loc, diag, fan, ps1, and ps2.
|
||||
The sysfs interface color mappings are as follows:
|
||||
Brightness:
|
||||
0 => off
|
||||
1 => green
|
||||
2 => amber
|
||||
3 => red
|
||||
4 => blue
|
||||
But not all colors are available for each LED.
|
||||
|
||||
Fan Control:
|
||||
There are 10 fans inside 5 fan modules.
|
||||
All fans share 1 duty setting, ranged from 0~100.
|
||||
|
||||
Thermal sensers:
|
||||
3 temperature sensors are controlled by the lm75 kernel modules.
|
||||
|
||||
PSUs:
|
||||
There 2 power supplies slot at the left/right side of the back.
|
||||
Once if a PSU is not plugged, the status of it is shown failed.
|
||||
|
||||
There are 48 SFP+ and 6 QSFP modules are equipped.
|
||||
Before operating on PSU and QSFP+, please make sure it is well plugged.
|
||||
Otherwise, operation is going to fail.
|
@ -0,0 +1,270 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*
|
||||
# Copyright (c) 2019 Edgecore Networks Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
|
||||
# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
#
|
||||
# See the Apache Version 2.0 License for specific language governing
|
||||
# permissions and limitations under the License.
|
||||
#
|
||||
# HISTORY:
|
||||
# mm/dd/yyyy (A.D.)#
|
||||
# 10/24/2019:Jostar create for as4630_54npe thermal plan
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
try:
|
||||
import sys
|
||||
import getopt
|
||||
import subprocess
|
||||
import logging
|
||||
import logging.config
|
||||
import logging.handlers
|
||||
import time
|
||||
from as4630_54npe.fanutil import FanUtil
|
||||
from as4630_54npe.thermalutil import ThermalUtil
|
||||
except ImportError as e:
|
||||
raise ImportError('%s - required module not found' % str(e))
|
||||
|
||||
# Deafults
|
||||
VERSION = '1.0'
|
||||
FUNCTION_NAME = '/usr/local/bin/accton_as4630_54npe_monitor'
|
||||
|
||||
global log_file
|
||||
global log_level
|
||||
|
||||
|
||||
# Temperature Policy
|
||||
# If any fan fail , set fan speed register to 16(100%)
|
||||
# Default system fan speed set to 12(75%)
|
||||
# The max value of fan speed register is 16
|
||||
# LM77(48)+LM75(4B)+LM75(4A) > 145, Set 16
|
||||
# LM77(48)+LM75(4B)+LM75(4A) < 105, Set 12
|
||||
# Shutdown DUT:LM77(48)>=75C
|
||||
#
|
||||
class switch(object):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
self.fall = False
|
||||
|
||||
def __iter__(self):
|
||||
"""Return the match method once, then stop"""
|
||||
yield self.match
|
||||
raise StopIteration
|
||||
|
||||
def match(self, *args):
|
||||
"""Indicate whether or not to enter a case suite"""
|
||||
if self.fall or not args:
|
||||
return True
|
||||
elif self.value in args: # changed for v1.5, see below
|
||||
self.fall = True
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
fan_policy_state = 0
|
||||
fan_fail = 0
|
||||
alarm_state = 0 # 0->default or clear, 1-->alarm detect
|
||||
test_temp = 0
|
||||
test_temp_list = [0, 0, 0]
|
||||
temp_test_data = 0
|
||||
test_temp_revert = 0
|
||||
# Make a class we can use to capture stdout and sterr in the log
|
||||
LEVEL_FAN_NORMAL = 0
|
||||
LEVEL_TEMP_CRITICAL = 1
|
||||
|
||||
class device_monitor(object):
|
||||
# static temp var
|
||||
temp = 0
|
||||
new_pwm = 0
|
||||
pwm = 0
|
||||
ori_pwm = 0
|
||||
default_pwm = 0x4
|
||||
|
||||
def __init__(self, log_file, log_level):
|
||||
"""Needs a logger and a logger level."""
|
||||
|
||||
self.thermal = ThermalUtil()
|
||||
self.fan = FanUtil()
|
||||
# set up logging to file
|
||||
logging.basicConfig(
|
||||
filename=log_file,
|
||||
filemode='w',
|
||||
level=log_level,
|
||||
format='[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
|
||||
datefmt='%H:%M:%S')
|
||||
# set up logging to console
|
||||
if log_level == logging.DEBUG:
|
||||
console = logging.StreamHandler()
|
||||
console.setLevel(log_level)
|
||||
formatter = logging.Formatter(
|
||||
'%(name)-12s: %(levelname)-8s %(message)s')
|
||||
console.setFormatter(formatter)
|
||||
logging.getLogger('').addHandler(console)
|
||||
|
||||
sys_handler = logging.handlers.SysLogHandler(
|
||||
address='/dev/log')
|
||||
sys_handler.setLevel(logging.WARNING)
|
||||
logging.getLogger('').addHandler(sys_handler)
|
||||
|
||||
def get_state_from_fan_policy(self, temp, policy, ori_state):
|
||||
state = ori_state
|
||||
|
||||
# check if current state is valid
|
||||
if ori_state < LEVEL_FAN_NORMAL or ori_state > LEVEL_TEMP_CRITICAL:
|
||||
return LEVEL_FAN_NORMAL
|
||||
|
||||
if ori_state == LEVEL_FAN_NORMAL:
|
||||
if temp > policy[ori_state][3]:
|
||||
return LEVEL_TEMP_CRITICAL
|
||||
else: # LEVEL_TEMP_CRITICAL
|
||||
if temp < policy[ori_state][2]:
|
||||
return LEVEL_FAN_NORMAL
|
||||
|
||||
return state # LEVEL is not changed
|
||||
|
||||
def manage_fans(self):
|
||||
global fan_policy_state
|
||||
global fan_fail
|
||||
global test_temp
|
||||
global test_temp_list
|
||||
global alarm_state
|
||||
global temp_test_data
|
||||
global test_temp_revert
|
||||
fan_policy = {
|
||||
LEVEL_FAN_NORMAL: [75, 12, 0, 145000],
|
||||
LEVEL_TEMP_CRITICAL: [100, 16, 105000, 145000],
|
||||
}
|
||||
temp = [0, 0, 0]
|
||||
thermal = self.thermal
|
||||
fan = self.fan
|
||||
ori_duty_cycle = fan.get_fan_duty_cycle()
|
||||
new_duty_cycle = 0
|
||||
|
||||
if test_temp == 0:
|
||||
for i in range(0, 3):
|
||||
temp[i] = thermal._get_thermal_val(i + 1)
|
||||
if temp[i] == 0 or temp[i] is None:
|
||||
logging.warning("Get temp-%d fail, set pwm to 100", i)
|
||||
fan.set_fan_duty_cycle(100)
|
||||
return False
|
||||
else:
|
||||
if test_temp_revert == 0:
|
||||
temp_test_data = temp_test_data + 2000
|
||||
else:
|
||||
temp_test_data = temp_test_data - 2000
|
||||
|
||||
for i in range(0, 3):
|
||||
temp[i] = test_temp_list[i] + temp_test_data
|
||||
fan_fail = 0
|
||||
|
||||
temp_val = 0
|
||||
for i in range(0, 3):
|
||||
if temp[i] is None:
|
||||
break
|
||||
temp_val += temp[i]
|
||||
|
||||
# Check Fan status
|
||||
for i in range(fan.FAN_NUM_1_IDX, fan.FAN_NUM_ON_MAIN_BROAD + 1):
|
||||
if fan.get_fan_status(i) == 0:
|
||||
new_pwm = 100
|
||||
logging.warning('Fan_%d fail, set pwm to 100', i)
|
||||
if test_temp == 0:
|
||||
fan_fail = 1
|
||||
fan.set_fan_duty_cycle(new_pwm)
|
||||
break
|
||||
else:
|
||||
fan_fail = 0
|
||||
|
||||
ori_state = fan_policy_state
|
||||
fan_policy_state = self.get_state_from_fan_policy(temp_val, fan_policy, ori_state)
|
||||
|
||||
if fan_policy_state > LEVEL_TEMP_CRITICAL or fan_policy_state < LEVEL_FAN_NORMAL:
|
||||
logging.error("Get error fan current_state\n")
|
||||
return 0
|
||||
|
||||
# Decision : Decide new fan pwm percent.
|
||||
if fan_fail == 0 and ori_duty_cycle != fan_policy[fan_policy_state][0]:
|
||||
new_duty_cycle = fan_policy[fan_policy_state][0]
|
||||
fan.set_fan_duty_cycle(new_duty_cycle)
|
||||
|
||||
if temp[0] >= 75000: # LM77-48
|
||||
# critical case*/
|
||||
logging.critical(
|
||||
'Alarm-Critical for temperature critical is detected, disable PoE')
|
||||
cmd_str = "i2cset -f -y 16 0x20 0x06 0x0 0x0 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xFE i"
|
||||
status, output = subprocess.getstatusoutput(cmd_str) # Disable PoE
|
||||
|
||||
logging.critical(
|
||||
'Alarm-Critical for temperature critical is detected, shutdown DUT')
|
||||
cmd_str = "i2cset -y -f 3 0x60 0x4 0x74"
|
||||
time.sleep(2)
|
||||
status, output = subprocess.getstatusoutput(cmd_str) # Shutdown DUT
|
||||
|
||||
#logging.debug('ori_state=%d, current_state=%d, temp_val=%d\n\n',ori_state, fan_policy_state, temp_val)
|
||||
|
||||
if ori_state < LEVEL_TEMP_CRITICAL:
|
||||
if fan_policy_state >= LEVEL_TEMP_CRITICAL:
|
||||
if alarm_state == 0:
|
||||
logging.warning('Alarm for temperature high is detected')
|
||||
alarm_state = 1
|
||||
|
||||
if fan_policy_state <= LEVEL_FAN_NORMAL:
|
||||
if alarm_state == 1:
|
||||
logging.info('Alarm for temperature high is cleared')
|
||||
alarm_state = 0
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def main(argv):
|
||||
log_file = '%s.log' % FUNCTION_NAME
|
||||
log_level = logging.INFO
|
||||
global test_temp
|
||||
if len(sys.argv) != 1:
|
||||
try:
|
||||
opts, args = getopt.getopt(argv, 'hdlt:', ['lfile='])
|
||||
except getopt.GetoptError:
|
||||
print('Usage: %s [-d] [-l <log_file>]' % sys.argv[0])
|
||||
return 0
|
||||
for opt, arg in opts:
|
||||
if opt == '-h':
|
||||
print('Usage: %s [-d] [-l <log_file>]' % sys.argv[0])
|
||||
return 0
|
||||
elif opt in ('-d', '--debug'):
|
||||
log_level = logging.DEBUG
|
||||
elif opt in ('-l', '--lfile'):
|
||||
log_file = arg
|
||||
|
||||
if sys.argv[1] == '-t':
|
||||
if len(sys.argv) != 5:
|
||||
print("temp test, need input three temp")
|
||||
return 0
|
||||
|
||||
i = 0
|
||||
for x in range(2, 5):
|
||||
test_temp_list[i] = int(sys.argv[x]) * 1000
|
||||
i = i + 1
|
||||
test_temp = 1
|
||||
log_level = logging.DEBUG
|
||||
print(test_temp_list)
|
||||
|
||||
fan = FanUtil()
|
||||
fan.set_fan_duty_cycle(75)
|
||||
print("set default fan speed to 75%")
|
||||
monitor = device_monitor(log_file, log_level)
|
||||
# Loop forever, doing something useful hopefully:
|
||||
while True:
|
||||
monitor.manage_fans()
|
||||
time.sleep(10) # 10sec
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2018 Accton Technology Corporation
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# HISTORY:
|
||||
# mm/dd/yyyy (A.D.)
|
||||
# 5/15/2019: Jostar create for as4630-54npe
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
try:
|
||||
import sys
|
||||
import getopt
|
||||
import logging
|
||||
import logging.config
|
||||
import logging.handlers
|
||||
import time # this is only being used as part of the example
|
||||
|
||||
except ImportError as e:
|
||||
raise ImportError('%s - required module not found' % str(e))
|
||||
|
||||
# Deafults
|
||||
VERSION = '1.0'
|
||||
FUNCTION_NAME = '/usr/local/bin/accton_as4630_54npe_monitor_fan'
|
||||
|
||||
|
||||
class switch(object):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
self.fall = False
|
||||
|
||||
def __iter__(self):
|
||||
"""Return the match method once, then stop"""
|
||||
yield self.match
|
||||
raise StopIteration
|
||||
|
||||
def match(self, *args):
|
||||
"""Indicate whether or not to enter a case suite"""
|
||||
if self.fall or not args:
|
||||
return True
|
||||
elif self.value in args: # changed for v1.5, see below
|
||||
self.fall = True
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
fan_state = [2, 2, 2, 2] # init state=2, insert=1, remove=0
|
||||
fan_status_state = [2, 2, 2, 2] # init state=2, fault=1, normal=0
|
||||
# Make a class we can use to capture stdout and sterr in the log
|
||||
|
||||
|
||||
class device_monitor(object):
|
||||
|
||||
def __init__(self, log_file, log_level):
|
||||
|
||||
self.fan_num = 3
|
||||
self.fan_path = "/sys/bus/i2c/devices/3-0060/"
|
||||
self.present = {
|
||||
0: "fan_present_1",
|
||||
1: "fan_present_2",
|
||||
2: "fan_present_3",
|
||||
}
|
||||
|
||||
self.fault = {
|
||||
0: "fan_fault_1",
|
||||
1: "fan_fault_2",
|
||||
2: "fan_fault_3",
|
||||
}
|
||||
|
||||
"""Needs a logger and a logger level."""
|
||||
# set up logging to file
|
||||
logging.basicConfig(
|
||||
filename=log_file,
|
||||
filemode='w',
|
||||
level=log_level,
|
||||
format='[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
|
||||
datefmt='%H:%M:%S')
|
||||
|
||||
# set up logging to console
|
||||
if log_level == logging.DEBUG:
|
||||
console = logging.StreamHandler()
|
||||
console.setLevel(logging.DEBUG)
|
||||
formatter = logging.Formatter(
|
||||
'%(name)-12s: %(levelname)-8s %(message)s')
|
||||
console.setFormatter(formatter)
|
||||
logging.getLogger('').addHandler(console)
|
||||
|
||||
sys_handler = logging.handlers.SysLogHandler(address='/dev/log')
|
||||
# sys_handler.setLevel(logging.WARNING)
|
||||
sys_handler.setLevel(logging.INFO)
|
||||
logging.getLogger('').addHandler(sys_handler)
|
||||
|
||||
#logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
|
||||
|
||||
def manage_fan(self):
|
||||
|
||||
FAN_STATE_REMOVE = 0
|
||||
FAN_STATE_INSERT = 1
|
||||
|
||||
FAN_STATUS_FAULT = 1
|
||||
FAN_STATUS_NORMAL = 0
|
||||
|
||||
global fan_state
|
||||
global fan_status_state
|
||||
|
||||
for idx in range(0, self.fan_num):
|
||||
node = self.fan_path + self.present[idx]
|
||||
try:
|
||||
val_file = open(node)
|
||||
except IOError as e:
|
||||
print("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
content = val_file.readline().rstrip()
|
||||
val_file.close()
|
||||
# content is a string, either "0" or "1"
|
||||
if content == "1":
|
||||
if fan_state[idx] != 1:
|
||||
fan_state[idx] = FAN_STATE_INSERT
|
||||
logging.info("FAN-%d present is detected", idx + 1)
|
||||
else:
|
||||
if fan_state[idx] != 0:
|
||||
fan_state[idx] = FAN_STATE_REMOVE
|
||||
logging.warning(
|
||||
"Alarm for FAN-%d absent is detected", idx + 1)
|
||||
|
||||
for idx in range(0, self.fan_num):
|
||||
node = self.fan_path + self.fault[idx]
|
||||
try:
|
||||
val_file = open(node)
|
||||
except IOError as e:
|
||||
print("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
content = val_file.readline().rstrip()
|
||||
val_file.close()
|
||||
# content is a string, either "0" or "1"
|
||||
if content == "1":
|
||||
if fan_status_state[idx] != FAN_STATUS_FAULT:
|
||||
if fan_state[idx] == FAN_STATE_INSERT:
|
||||
logging.warning(
|
||||
"Alarm for FAN-%d failed is detected", idx + 1)
|
||||
fan_status_state[idx] = FAN_STATUS_FAULT
|
||||
else:
|
||||
fan_status_state[idx] = FAN_STATUS_NORMAL
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def main(argv):
|
||||
log_file = '%s.log' % FUNCTION_NAME
|
||||
log_level = logging.INFO
|
||||
if len(sys.argv) != 1:
|
||||
try:
|
||||
opts, args = getopt.getopt(argv, 'hdl:', ['lfile='])
|
||||
except getopt.GetoptError:
|
||||
print('Usage: %s [-d] [-l <log_file>]' % sys.argv[0])
|
||||
return 0
|
||||
for opt, arg in opts:
|
||||
if opt == '-h':
|
||||
print('Usage: %s [-d] [-l <log_file>]' % sys.argv[0])
|
||||
return 0
|
||||
elif opt in ('-d', '--debug'):
|
||||
log_level = logging.DEBUG
|
||||
elif opt in ('-l', '--lfile'):
|
||||
log_file = arg
|
||||
monitor = device_monitor(log_file, log_level)
|
||||
while True:
|
||||
monitor.manage_fan()
|
||||
time.sleep(3)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2018 Accton Technology Corporation
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# HISTORY:
|
||||
# mm/dd/yyyy (A.D.)
|
||||
# 5/15/2019: Jostar create for as4630-54npe
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
try:
|
||||
import sys
|
||||
import getopt
|
||||
import logging
|
||||
import logging.config
|
||||
import logging.handlers
|
||||
import time # this is only being used as part of the example
|
||||
except ImportError as e:
|
||||
raise ImportError('%s - required module not found' % str(e))
|
||||
|
||||
# Deafults
|
||||
VERSION = '1.0'
|
||||
FUNCTION_NAME = '/usr/local/bin/accton_as4630_54npe_monitor_psu'
|
||||
|
||||
|
||||
psu_state = [2, 2]
|
||||
psu_status_state = [2, 2]
|
||||
# Make a class we can use to capture stdout and sterr in the log
|
||||
|
||||
|
||||
class device_monitor(object):
|
||||
|
||||
def __init__(self, log_file, log_level):
|
||||
|
||||
self.psu_num = 2
|
||||
self.psu_path = "/sys/bus/i2c/devices/"
|
||||
self.presence = "/psu_present"
|
||||
self.oper_status = "/psu_power_good"
|
||||
self.mapping = {
|
||||
0: "10-0050",
|
||||
1: "11-0051",
|
||||
}
|
||||
|
||||
"""Needs a logger and a logger level."""
|
||||
# set up logging to file
|
||||
logging.basicConfig(
|
||||
filename=log_file,
|
||||
filemode='w',
|
||||
level=log_level,
|
||||
format='[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
|
||||
datefmt='%H:%M:%S')
|
||||
# set up logging to console
|
||||
|
||||
if log_level == logging.DEBUG:
|
||||
console = logging.StreamHandler()
|
||||
console.setLevel(log_level)
|
||||
formatter = logging.Formatter(
|
||||
'%(name)-12s: %(levelname)-8s %(message)s')
|
||||
console.setFormatter(formatter)
|
||||
logging.getLogger('').addHandler(console)
|
||||
|
||||
sys_handler = logging.handlers.SysLogHandler(address='/dev/log')
|
||||
# sys_handler.setLevel(logging.WARNING)
|
||||
sys_handler.setLevel(logging.INFO)
|
||||
logging.getLogger('').addHandler(sys_handler)
|
||||
|
||||
#logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
|
||||
|
||||
def manage_psu(self):
|
||||
|
||||
PSU_STATE_REMOVE = 0
|
||||
PSU_STATE_INSERT = 1
|
||||
|
||||
PSU_STATUS_NO_POWER = 0
|
||||
PSU_STATUS_POWER_GOOD = 1
|
||||
PSU_STATUS_IDLE = 2
|
||||
|
||||
global psu_state
|
||||
|
||||
for idx in range(0, self.psu_num):
|
||||
node = self.psu_path + self.mapping[idx] + self.presence
|
||||
try:
|
||||
val_file = open(node)
|
||||
except IOError as e:
|
||||
print("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
content = val_file.readline().rstrip()
|
||||
val_file.close()
|
||||
# content is a string, either "0" or "1"
|
||||
if content == "1":
|
||||
if psu_state[idx] != 1:
|
||||
psu_state[idx] = PSU_STATE_INSERT
|
||||
logging.info("PSU-%d present is detected", idx + 1)
|
||||
# psu_status_state[idx]=PSU_STATUS_POWER_GOOD #when insert,
|
||||
# assume power is good. If no_power, next code will find
|
||||
# it.
|
||||
else:
|
||||
if psu_state[idx] != 0:
|
||||
psu_state[idx] = PSU_STATE_REMOVE
|
||||
logging.warning(
|
||||
"Alarm for PSU-%d absent is detected", idx + 1)
|
||||
psu_status_state[idx] = PSU_STATUS_IDLE
|
||||
|
||||
for idx in range(0, self.psu_num):
|
||||
node = self.psu_path + self.mapping[idx] + self.oper_status
|
||||
try:
|
||||
val_file = open(node)
|
||||
except IOError as e:
|
||||
print("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
content = val_file.readline().rstrip()
|
||||
val_file.close()
|
||||
# content is a string, either "0" or "1"
|
||||
if content == "0":
|
||||
if psu_status_state[idx] != PSU_STATUS_NO_POWER:
|
||||
if psu_state[idx] == PSU_STATE_INSERT:
|
||||
logging.warning(
|
||||
"Alarm for PSU-%d failed is detected", idx + 1)
|
||||
psu_status_state[idx] = PSU_STATUS_NO_POWER
|
||||
else:
|
||||
if psu_state[idx] == PSU_STATE_INSERT:
|
||||
if psu_status_state[idx] != PSU_STATUS_POWER_GOOD:
|
||||
logging.info("PSU-%d power_good is detected", idx + 1)
|
||||
psu_status_state[idx] = PSU_STATUS_POWER_GOOD
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def main(argv):
|
||||
log_file = '%s.log' % FUNCTION_NAME
|
||||
log_level = logging.INFO
|
||||
if len(sys.argv) != 1:
|
||||
try:
|
||||
opts, args = getopt.getopt(argv, 'hdl:', ['lfile='])
|
||||
except getopt.GetoptError:
|
||||
print('Usage: %s [-d] [-l <log_file>]' % sys.argv[0])
|
||||
return 0
|
||||
for opt, arg in opts:
|
||||
if opt == '-h':
|
||||
print('Usage: %s [-d] [-l <log_file>]' % sys.argv[0])
|
||||
return 0
|
||||
elif opt in ('-d', '--debug'):
|
||||
log_level = logging.DEBUG
|
||||
elif opt in ('-l', '--lfile'):
|
||||
log_file = arg
|
||||
monitor = device_monitor(log_file, log_level)
|
||||
# Loop forever, doing something useful hopefully:
|
||||
while True:
|
||||
monitor.manage_psu()
|
||||
time.sleep(3)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
@ -0,0 +1,562 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (C) 2016 Accton Networks, Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
usage: accton_as4630_54npe_util.py [-h] [-d] [-f] {install,clean,api,api_clean,threshold} ...
|
||||
|
||||
AS4630-54NPE Platform Utility
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-d, --debug run with debug mode
|
||||
-f, --force ignore error during installation or clean
|
||||
|
||||
Utility Command:
|
||||
{install,clean,api,api_clean,threshold}
|
||||
install : install drivers and generate related sysfs nodes
|
||||
clean : uninstall drivers and remove related sysfs nodes
|
||||
api : install SONiC platform API
|
||||
api_clean : uninstall SONiC platform API
|
||||
threshold : modify thermal threshold
|
||||
"""
|
||||
import subprocess
|
||||
import sys
|
||||
import logging
|
||||
import time
|
||||
import os
|
||||
import argparse
|
||||
from sonic_py_common.general import getstatusoutput_noshell
|
||||
|
||||
PROJECT_NAME = 'as4630_54npe'
|
||||
version = '0.0.1'
|
||||
verbose = False
|
||||
DEBUG = False
|
||||
args = []
|
||||
ALL_DEVICE = {}
|
||||
|
||||
i2c_prefix = '/sys/bus/i2c/devices/'
|
||||
'''
|
||||
i2c_bus = {'fan': ['54-0066'],
|
||||
'thermal': ['54-004c', '55-0048', '55-0049', '55-004a', '55-004b'],
|
||||
'psu': ['49-0050', '50-0053'],
|
||||
'sfp': ['-0050']}
|
||||
i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'],
|
||||
'thermal': ['hwmon/hwmon*/temp1_input'],
|
||||
'psu': ['psu_present ', 'psu_power_good'],
|
||||
'sfp': ['module_present_ ', 'module_tx_disable_']}
|
||||
'''
|
||||
sfp_map = [18, 19, 20, 21, 22, 23]
|
||||
|
||||
mknod = [
|
||||
'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-1/new_device',
|
||||
'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-2/new_device',
|
||||
'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-3/new_device',
|
||||
|
||||
'echo as4630_54npe_cpld 0x60 > /sys/bus/i2c/devices/i2c-3/new_device',
|
||||
|
||||
'echo lm77 0x48 > /sys/bus/i2c/devices/i2c-14/new_device',
|
||||
'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-25/new_device',
|
||||
'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-24/new_device',
|
||||
|
||||
|
||||
# PSU-1
|
||||
'echo as4630_54npe_psu1 0x50 > /sys/bus/i2c/devices/i2c-10/new_device',
|
||||
'echo ype1200am 0x58 > /sys/bus/i2c/devices/i2c-10/new_device',
|
||||
|
||||
# PSU-2
|
||||
'echo as4630_54npe_psu2 0x51> /sys/bus/i2c/devices/i2c-11/new_device',
|
||||
'echo ype1200am 0x59 > /sys/bus/i2c/devices/i2c-11/new_device',
|
||||
|
||||
# EERPOM
|
||||
'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-1/new_device',
|
||||
]
|
||||
|
||||
# Disable CPLD debug mode
|
||||
cpld_set = [
|
||||
'i2cset -y -f 3 0x60 0x2a 0xff',
|
||||
'i2cset -y -f 3 0x60 0x2b 0xff',
|
||||
'i2cset -y -f 3 0x60 0x86 0x89'
|
||||
]
|
||||
|
||||
FORCE = 0
|
||||
logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
if DEBUG == True:
|
||||
print(sys.argv[0])
|
||||
print('ARGV :', sys.argv[1:])
|
||||
|
||||
|
||||
def main():
|
||||
global DEBUG
|
||||
global args
|
||||
global FORCE
|
||||
global THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH
|
||||
|
||||
util_parser = argparse.ArgumentParser(description="AS4630-54NPE Platform Utility")
|
||||
util_parser.add_argument("-d", "--debug", dest='debug', action='store_true', default=False,
|
||||
help="run with debug mode")
|
||||
util_parser.add_argument("-f", "--force", dest='force', action='store_true', default=False,
|
||||
help="ignore error during installation or clean")
|
||||
subcommand = util_parser.add_subparsers(dest='cmd', title='Utility Command', required=True)
|
||||
subcommand.add_parser('install', help=': install drivers and generate related sysfs nodes')
|
||||
subcommand.add_parser('clean', help=': uninstall drivers and remove related sysfs nodes')
|
||||
subcommand.add_parser('api', help=': install SONiC platform API')
|
||||
subcommand.add_parser('api_clean', help=': uninstall SONiC platform API')
|
||||
threshold_parser = subcommand.add_parser('threshold', help=': modify thermal threshold')
|
||||
threshold_parser.add_argument("-l", dest='list', action='store_true', default=False,
|
||||
help="list avaliable thermal")
|
||||
threshold_parser.add_argument("-t", dest='thermal', type=str, metavar='THERMAL_NAME',
|
||||
help="thermal name, ex: -t 'Temp sensor 1'")
|
||||
threshold_parser.add_argument("-ht", dest='high_threshold', type=restricted_float,
|
||||
metavar='THRESHOLD_VALUE',
|
||||
help="high threshold: %.1f ~ %.1f" % (THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH))
|
||||
threshold_parser.add_argument("-hct", dest='high_crit_threshold', type=restricted_float,
|
||||
metavar='THRESHOLD_VALUE',
|
||||
help="high critical threshold : %.1f ~ %.1f" % (THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH))
|
||||
args = util_parser.parse_args()
|
||||
|
||||
if DEBUG == True:
|
||||
print(args)
|
||||
print(len(sys.argv))
|
||||
|
||||
DEBUG = args.debug
|
||||
FORCE = 1 if args.force else 0
|
||||
|
||||
if args.cmd == 'install':
|
||||
do_install()
|
||||
elif args.cmd == 'clean':
|
||||
do_uninstall()
|
||||
elif args.cmd == 'api':
|
||||
do_sonic_platform_install()
|
||||
elif args.cmd == 'api_clean':
|
||||
do_sonic_platform_clean()
|
||||
elif args.cmd == 'threshold':
|
||||
do_threshold()
|
||||
|
||||
|
||||
return 0
|
||||
|
||||
def show_help():
|
||||
print( __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]})
|
||||
sys.exit(0)
|
||||
|
||||
def my_log(txt):
|
||||
if DEBUG == True:
|
||||
print("[ACCTON DBG]: ",txt)
|
||||
return
|
||||
|
||||
def log_os_system(cmd, show):
|
||||
logging.info('Run :' + cmd)
|
||||
output = ""
|
||||
status, output = subprocess.getstatusoutput(cmd)
|
||||
my_log(cmd +" with result:" + str(status))
|
||||
#my_log ("cmd:" + cmd)
|
||||
#my_log (" output:"+output)
|
||||
if status:
|
||||
logging.info('Failed :'+cmd)
|
||||
if show:
|
||||
print('Failed :'+cmd)
|
||||
return status, output
|
||||
|
||||
def driver_inserted():
|
||||
ret, lsmod = log_os_system("ls /sys/module/*accton*", 0)
|
||||
logging.info('mods:'+lsmod)
|
||||
if ret :
|
||||
return False
|
||||
else :
|
||||
return True
|
||||
|
||||
#'modprobe cpr_4011_4mxx',
|
||||
|
||||
kos = [
|
||||
'depmod -ae',
|
||||
'modprobe i2c_dev',
|
||||
'modprobe i2c_mux_pca954x',
|
||||
'modprobe ym2651y',
|
||||
'modprobe x86_64_accton_as4630_54npe_cpld',
|
||||
'modprobe x86_64_accton_as4630_54npe_leds',
|
||||
'modprobe x86_64_accton_as4630_54npe_psu',
|
||||
'modprobe optoe']
|
||||
|
||||
def driver_install():
|
||||
global FORCE
|
||||
|
||||
log_os_system("lsmod|grep i2c_ismt", 1)
|
||||
my_log("rmmond i2cismt")
|
||||
log_os_system("rmmod i2c_ismt", 1)
|
||||
log_os_system("rmmod i2c_i801", 1)
|
||||
log_os_system("modprobe i2c-i801", 1)
|
||||
time.sleep(1)
|
||||
log_os_system("modprobe i2c-ismt", 1)
|
||||
|
||||
|
||||
for i in range(0, len(kos)):
|
||||
status, output = log_os_system(kos[i], 1)
|
||||
if status:
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
print("Done driver_install")
|
||||
|
||||
return 0
|
||||
|
||||
def driver_uninstall():
|
||||
global FORCE
|
||||
for i in range(0, len(kos)):
|
||||
rm = kos[-(i + 1)].replace("modprobe", "modprobe -rq")
|
||||
lst = rm.split(" ")
|
||||
|
||||
if len(lst) > 3:
|
||||
del(lst[3])
|
||||
rm = " ".join(lst)
|
||||
status, output = log_os_system(rm, 1)
|
||||
if status:
|
||||
if FORCE == 0:
|
||||
return status
|
||||
return 0
|
||||
|
||||
def device_install():
|
||||
global FORCE
|
||||
|
||||
for i in range(0, len(mknod)):
|
||||
# for pca954x need times to built new i2c buses
|
||||
if mknod[i].find('pca954') != -1:
|
||||
time.sleep(2)
|
||||
|
||||
status, output = log_os_system(mknod[i], 1)
|
||||
if status:
|
||||
print(output)
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
# set all pca954x idle_disconnect
|
||||
cmd = 'echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state'
|
||||
status, output = log_os_system(cmd, 1)
|
||||
if status:
|
||||
print(output)
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
for i in range(0, len(sfp_map)):
|
||||
if(i < 4):
|
||||
opt = 'optoe2'
|
||||
else:
|
||||
opt = 'optoe1'
|
||||
status, output = log_os_system("echo " + str(opt) + " 0x50 > /sys/bus/i2c/devices/i2c-" +
|
||||
str(sfp_map[i]) + "/new_device", 1)
|
||||
if status:
|
||||
print(output)
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
status, output = log_os_system("echo port" + str(i + 49) +" > /sys/bus/i2c/devices/" +
|
||||
str(sfp_map[i]) + "-0050/port_name", 1)
|
||||
if status:
|
||||
print(output)
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
print("Done device_install")
|
||||
|
||||
return
|
||||
|
||||
def device_uninstall():
|
||||
global FORCE
|
||||
|
||||
for i in range(0, len(sfp_map)):
|
||||
target = "/sys/bus/i2c/devices/i2c-" + str(sfp_map[i]) + "/delete_device"
|
||||
status, output = log_os_system("echo 0x50 > " + target, 1)
|
||||
if status:
|
||||
print(output)
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
nodelist = mknod
|
||||
|
||||
for i in range(len(nodelist)):
|
||||
target = nodelist[-(i+1)]
|
||||
temp = target.split()
|
||||
del temp[1]
|
||||
temp[-1] = temp[-1].replace('new_device', 'delete_device')
|
||||
status, output = log_os_system(" ".join(temp), 1)
|
||||
if status:
|
||||
print(output)
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
return
|
||||
|
||||
def system_ready():
|
||||
if driver_inserted() == False:
|
||||
return False
|
||||
if not device_exist():
|
||||
print("not device_exist()")
|
||||
return False
|
||||
return True
|
||||
|
||||
PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
|
||||
PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl'
|
||||
def do_sonic_platform_install():
|
||||
device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0')
|
||||
SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3])
|
||||
|
||||
#Check API2.0 on py whl file
|
||||
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
|
||||
if status:
|
||||
if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3):
|
||||
status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1)
|
||||
if status:
|
||||
print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
return status
|
||||
else:
|
||||
print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
else:
|
||||
print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
else:
|
||||
print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
return
|
||||
|
||||
def do_sonic_platform_clean():
|
||||
status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0)
|
||||
if status:
|
||||
print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
else:
|
||||
status, output = log_os_system("pip3 uninstall sonic-platform -y", 0)
|
||||
if status:
|
||||
print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
return status
|
||||
else:
|
||||
print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3))
|
||||
|
||||
|
||||
return
|
||||
|
||||
def do_install():
|
||||
if driver_inserted() == False:
|
||||
status = driver_install()
|
||||
if status:
|
||||
if FORCE == 0:
|
||||
return status
|
||||
else:
|
||||
print(PROJECT_NAME.upper()+" drivers detected....")
|
||||
if not device_exist():
|
||||
status = device_install()
|
||||
if status:
|
||||
if FORCE == 0:
|
||||
return status
|
||||
else:
|
||||
print(PROJECT_NAME.upper()+" devices detected....")
|
||||
|
||||
for i in range(len(cpld_set)):
|
||||
status, output = log_os_system(cpld_set[i], 1)
|
||||
if status:
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
do_sonic_platform_install()
|
||||
return
|
||||
|
||||
def do_uninstall():
|
||||
if not device_exist():
|
||||
print(PROJECT_NAME.upper() + " has no device installed....")
|
||||
else:
|
||||
print("Removing device....")
|
||||
status = device_uninstall()
|
||||
if status:
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
if driver_inserted() == False :
|
||||
print(PROJECT_NAME.upper() + " has no driver installed....")
|
||||
else:
|
||||
print("Removing installed driver....")
|
||||
status = driver_uninstall()
|
||||
if status:
|
||||
if FORCE == 0:
|
||||
return status
|
||||
|
||||
do_sonic_platform_clean()
|
||||
return
|
||||
|
||||
def device_exist():
|
||||
ret1, log = log_os_system("ls "+i2c_prefix+"*0077", 0)
|
||||
ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0)
|
||||
return not(ret1 or ret2)
|
||||
|
||||
THRESHOLD_RANGE_LOW = 30.0
|
||||
THRESHOLD_RANGE_HIGH = 110.0
|
||||
# Code to initialize chassis object
|
||||
init_chassis_code = \
|
||||
"import sonic_platform.platform\n"\
|
||||
"platform = sonic_platform.platform.Platform()\n"\
|
||||
"chassis = platform.get_chassis()\n\n"
|
||||
|
||||
# Looking for thermal
|
||||
looking_for_thermal_code = \
|
||||
"thermal = None\n"\
|
||||
"all_thermals = chassis.get_all_thermals()\n"\
|
||||
"for psu in chassis.get_all_psus():\n"\
|
||||
" all_thermals += psu.get_all_thermals()\n"\
|
||||
"for tmp in all_thermals:\n"\
|
||||
" if '{}' == tmp.get_name():\n"\
|
||||
" thermal = tmp\n"\
|
||||
" break\n"\
|
||||
"if thermal == None:\n"\
|
||||
" print('{} not found!')\n"\
|
||||
" exit(1)\n\n"
|
||||
|
||||
def avaliable_thermals():
|
||||
global init_chassis_code
|
||||
|
||||
get_all_thermal_name_code = \
|
||||
"thermal_list = []\n"\
|
||||
"all_thermals = chassis.get_all_thermals()\n"\
|
||||
"for psu in chassis.get_all_psus():\n"\
|
||||
" all_thermals += psu.get_all_thermals()\n"\
|
||||
"for tmp in all_thermals:\n"\
|
||||
" thermal_list.append(tmp.get_name())\n"\
|
||||
"print(str(thermal_list)[1:-1])\n"
|
||||
|
||||
all_code = "{}{}".format(init_chassis_code, get_all_thermal_name_code)
|
||||
|
||||
status, output = getstatusoutput_noshell(["docker", "exec", "pmon", "python3", "-c", all_code])
|
||||
if status != 0:
|
||||
return ""
|
||||
return output
|
||||
|
||||
def restricted_float(x):
|
||||
global THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH
|
||||
|
||||
try:
|
||||
x = float(x)
|
||||
except ValueError:
|
||||
raise argparse.ArgumentTypeError("%r not a floating-point literal" % (x,))
|
||||
|
||||
if x < THRESHOLD_RANGE_LOW or x > THRESHOLD_RANGE_HIGH:
|
||||
raise argparse.ArgumentTypeError("%r not in range [%.1f ~ %.1f]" %
|
||||
(x, THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH))
|
||||
|
||||
return x
|
||||
|
||||
def get_high_threshold(name):
|
||||
global init_chassis_code, looking_for_thermal_code
|
||||
|
||||
get_high_threshold_code = \
|
||||
"try:\n"\
|
||||
" print(thermal.get_high_threshold())\n"\
|
||||
" exit(0)\n"\
|
||||
"except NotImplementedError:\n"\
|
||||
" print('Not implement the get_high_threshold method!')\n"\
|
||||
" exit(1)"
|
||||
|
||||
all_code = "{}{}{}".format(init_chassis_code, looking_for_thermal_code.format(name, name),
|
||||
get_high_threshold_code)
|
||||
|
||||
status, output = getstatusoutput_noshell(["docker", "exec", "pmon", "python3", "-c", all_code])
|
||||
if status == 1:
|
||||
return None
|
||||
|
||||
return float(output)
|
||||
|
||||
def get_high_crit_threshold(name):
|
||||
global init_chassis_code, looking_for_thermal_code
|
||||
|
||||
get_high_crit_threshold_code = \
|
||||
"try:\n"\
|
||||
" print(thermal.get_high_critical_threshold())\n"\
|
||||
" exit(0)\n"\
|
||||
"except NotImplementedError:\n"\
|
||||
" print('Not implement the get_high_critical_threshold method!')\n"\
|
||||
" exit(1)"
|
||||
|
||||
all_code = "{}{}{}".format(init_chassis_code, looking_for_thermal_code.format(name, name),
|
||||
get_high_crit_threshold_code)
|
||||
|
||||
status, output = getstatusoutput_noshell(["docker", "exec", "pmon", "python3", "-c", all_code])
|
||||
if status == 1:
|
||||
return None
|
||||
|
||||
return float(output)
|
||||
|
||||
def do_threshold():
|
||||
global args, init_chassis_code, looking_for_thermal_code
|
||||
|
||||
if args.list:
|
||||
print("Thermals: " + avaliable_thermals())
|
||||
return
|
||||
|
||||
if args.thermal is None:
|
||||
print("The following arguments are required: -t")
|
||||
return
|
||||
|
||||
set_threshold_code = ""
|
||||
if args.high_threshold is not None:
|
||||
if args.high_crit_threshold is not None and \
|
||||
args.high_threshold >= args.high_crit_threshold:
|
||||
print("Invalid Threshold!(High threshold can not be more than " \
|
||||
"or equal to high critical threshold.)")
|
||||
exit(1)
|
||||
|
||||
high_crit = get_high_crit_threshold(args.thermal)
|
||||
if high_crit is not None and \
|
||||
args.high_threshold >= high_crit:
|
||||
print("Invalid Threshold!(High threshold can not be more than " \
|
||||
"or equal to high critical threshold.)")
|
||||
exit(1)
|
||||
|
||||
set_threshold_code += \
|
||||
"try:\n"\
|
||||
" if thermal.set_high_threshold({}) is False:\n"\
|
||||
" print('{}: set_high_threshold failure!')\n"\
|
||||
" exit(1)\n"\
|
||||
"except NotImplementedError:\n"\
|
||||
" print('Not implement the set_high_threshold method!')\n"\
|
||||
"print('Apply the new high threshold successfully.')\n"\
|
||||
"\n".format(args.high_threshold, args.thermal)
|
||||
|
||||
if args.high_crit_threshold is not None:
|
||||
high = get_high_threshold(args.thermal)
|
||||
if high is not None and \
|
||||
args.high_crit_threshold <= high:
|
||||
print("Invalid Threshold!(High critical threshold can not " \
|
||||
"be less than or equal to high threshold.)")
|
||||
exit(1)
|
||||
|
||||
set_threshold_code += \
|
||||
"try:\n"\
|
||||
" if thermal.set_high_critical_threshold({}) is False:\n"\
|
||||
" print('{}: set_high_critical_threshold failure!')\n"\
|
||||
" exit(1)\n"\
|
||||
"except NotImplementedError:\n"\
|
||||
" print('Not implement the set_high_critical_threshold method!')\n"\
|
||||
"print('Apply the new high critical threshold successfully.')\n"\
|
||||
"\n".format(args.high_crit_threshold, args.thermal)
|
||||
|
||||
if set_threshold_code == "":
|
||||
return
|
||||
|
||||
all_code = "{}{}{}".format(init_chassis_code, looking_for_thermal_code.format(args.thermal, args.thermal), set_threshold_code)
|
||||
|
||||
status, output = getstatusoutput_noshell(["docker", "exec", "pmon", "python3", "-c", all_code])
|
||||
print(output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Re-install the igb and ixgbe again to make the NIC sequence follow the udev rule
|
||||
modprobe -r igb
|
||||
modprobe -r ixgbe
|
||||
modprobe igb
|
||||
modprobe ixgbe
|
@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
/etc/init.d/netfilter-persistent stop
|
||||
modprobe -r ixgbe
|
||||
udevadm control --reload-rules
|
||||
udevadm trigger
|
||||
modprobe ixgbe
|
||||
/etc/init.d/netfilter-persistent start
|
@ -49,6 +49,10 @@ Package: sonic-platform-accton-as4630-54te
|
||||
Architecture: amd64
|
||||
Description: kernel modules for platform devices such as fan, led, sfp
|
||||
|
||||
Package: sonic-platform-accton-as4630-54npe
|
||||
Architecture: amd64
|
||||
Description: kernel modules for platform devices such as fan, led, sfp
|
||||
|
||||
Package: sonic-platform-accton-minipack
|
||||
Architecture: amd64
|
||||
Description: kernel modules for platform devices such as fan, led, sfp
|
||||
|
@ -20,7 +20,7 @@ KVERSION ?= $(shell uname -r)
|
||||
KERNEL_SRC := /lib/modules/$(KVERSION)
|
||||
MOD_SRC_DIR:= $(shell pwd)
|
||||
MODULE_DIRS := as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x
|
||||
MODULE_DIRS += as7326-56x as6712-32x as7726-32x as4630-54pe as4630-54te minipack as5812-54x
|
||||
MODULE_DIRS += as7326-56x as6712-32x as7726-32x as4630-54pe as4630-54te as4630-54npe minipack as5812-54x
|
||||
MODULE_DIRS += as5835-54x as9716-32d as9726-32d as5835-54t as7312-54xs as7315-27xb as5812-54t
|
||||
MODULE_DIR := modules
|
||||
UTILS_DIR := utils
|
||||
@ -94,3 +94,4 @@ binary-indep:
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
.PHONY: build binary binary-arch binary-indep clean
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
as4630-54npe/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as4630_54npe-r0
|
Reference in New Issue
Block a user