This commit is contained in:
Roger Ho 2024-03-25 02:32:01 +00:00 committed by GitHub
commit 105b464c56
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
50 changed files with 8351 additions and 1 deletions

View File

@ -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"

View 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)'

View 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)"]
}
}
}
}

View File

@ -0,0 +1 @@
broadcom

View File

@ -0,0 +1,11 @@
{
"chassis": {
"4630-54NPE-O-AC-F": {
"component": {
"CPLD1": { },
"CPLD2": { },
"BIOS": { }
}
}
}
}

View File

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

View File

@ -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

View 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, {}

View File

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

View 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"

View File

@ -0,0 +1,2 @@
__all__ = [ "platform", "chassis", "sfp", "eeprom", "component", "psu", "thermal", "fan", "fan_drawer" ]
from . import platform

View File

@ -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()

View File

@ -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

View File

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

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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"
}
}

View File

@ -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) \

View File

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

View File

@ -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()

View File

@ -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]

View File

@ -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

View File

@ -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);

View File

@ -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, &reg))
{
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");

View File

@ -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");

View File

@ -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");

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'},
)

View File

@ -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',
)

View File

@ -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"

View File

@ -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.

View File

@ -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:])

View File

@ -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:])

View File

@ -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:])

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
as4630-54npe/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as4630_54npe-r0