[devices]: Add support fpga drv and pimutility for minipack platform (#3053)

This commit is contained in:
jostar-yang 2019-08-15 15:50:13 +08:00 committed by lguohan
parent e19e661080
commit ff6437eaaa
8 changed files with 1184 additions and 67 deletions

View File

@ -0,0 +1,59 @@
#!/usr/bin/env python
#
# led_control.py
#
# Platform-specific LED control functionality for SONiC
#
try:
from sonic_led.led_control_base import LedControlBase
import swsssdk
import threading
import os
import logging
import struct
import time
import syslog
from socket import *
from select import *
from minipack.pimutil import PimUtil
except ImportError, e:
raise ImportError(str(e) + " - required module not found")
class LedControl(LedControlBase):
"""Platform specific LED control class"""
SONIC_PORT_NAME_PREFIX = "Ethernet"
def __init__(self):
pim=PimUtil()
pim.init_pim_fpga()
def _port_name_to_index(self, port_name):
# Strip "Ethernet" off port name
if not port_name.startswith(self.SONIC_PORT_NAME_PREFIX):
return -1
port_idx = int(port_name[len(self.SONIC_PORT_NAME_PREFIX):])
return port_idx
def _port_state_to_mode(self, port_idx, state):
if state == "up":
return 1, 4 #port linkup, led is green
else:
return 0, 0 #port linkdown, led is off
def port_link_state_change(self, portname, state):
pim=PimUtil()
port_idx = self._port_name_to_index(portname)
new_control, led_mode = self._port_state_to_mode(port_idx, state)
color, control=pim.get_port_led(port_idx)
if color==led_mode:
if control==new_control:
return
pim.set_port_led(port_idx, led_mode, new_control)#port linkup, led is green
#port linkdown, led is off

View File

@ -6,6 +6,9 @@
try:
import time
from sonic_sfp.sfputilbase import SfpUtilBase
import os
import sys, getopt
from minipack.pimutil import PimUtil
except ImportError as e:
raise ImportError("%s - required module not found" % str(e))
@ -16,7 +19,7 @@ class SfpUtil(SfpUtilBase):
PORT_START = 0
PORT_END = 128
BASE_OOM_PATH = "/sys/bus/i2c/devices/{0}-0050/"
LOCAL_OOM_PATH = "/usr/local/bin/minipack_qsfp/port%d_eeprom"
_port_to_is_present = {}
_port_to_lp_mode = {}
@ -53,42 +56,91 @@ class SfpUtil(SfpUtilBase):
def __init__(self):
eeprom_path = self.BASE_OOM_PATH + "eeprom"
for x in range(0, self.port_end+1):
bus = self.sfp_map(x)
self.port_to_eeprom_mapping[x] = eeprom_path.format(
bus)
for x in range(0, self.port_end):
self.port_to_eeprom_mapping[x] = self.LOCAL_OOM_PATH %x
SfpUtilBase.__init__(self)
pim=PimUtil()
pim.init_pim_fpga()
def __del__(self):
self.value=0
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
eeprom_path = self.port_to_eeprom_mapping[port_num]
with open(eeprom_path) as f:
try:
content = f.read(1)
except IOError as e:
#Not print any error, for if any, treat as Not present.
return False
return True
pim=PimUtil()
status=pim.get_qsfp_presence(port_num)
return status
def get_low_power_mode(self, port_num):
raise NotImplementedError
if port_num < self.port_start or port_num > self.port_end:
return False
pim=PimUtil()
return pim.get_low_power_mode(port_num)
def set_low_power_mode(self, port_num, lpmode):
raise NotImplementedError
if port_num < self.port_start or port_num > self.port_end:
return False
pim=PimUtil()
pim.set_low_power_mode(port_num, lpmode)
return True
def reset(self, port_num):
raise NotImplementedError
if port_num < self.port_start or port_num > self.port_end:
return False
pim=PimUtil()
pim.reset(port_num)
return True
def get_transceiver_change_event(self, timeout=0):
pim=PimUtil()
start_time = time.time()
port_dict = {}
forever = False
def get_transceiver_change_event(self):
"""
TODO: This function need to be implemented
when decide to support monitoring SFP(Xcvrd)
on this platform.
"""
raise NotImplementedError
if timeout == 0:
forever = True
elif timeout > 0:
timeout = timeout / float(1000) # Convert to secs
else:
print "get_transceiver_change_event:Invalid timeout value", timeout
return False, {}
end_time = start_time + timeout
if start_time > end_time:
print 'get_transceiver_change_event:' \
'time wrap / invalid timeout value', timeout
return False, {} # Time wrap or possibly incorrect timeout
while timeout >= 0:
change_status=0
port_dict = pim.get_qsfp_interrupt()
present=0
for key, value in port_dict.iteritems():
if value==1:
present=self.get_presence(key)
change_status=1
if present:
port_dict[key]='1'
else:
port_dict[key]='0'
if change_status:
return True, port_dict
if forever:
time.sleep(1)
else:
timeout = end_time - time.time()
if timeout >= 1:
time.sleep(1) # We poll at 1 second granularity
else:
if timeout > 0:
time.sleep(timeout)
return True, {}
print "get_evt_change_event: Should not reach here."
return False, {}

View File

@ -0,0 +1,578 @@
# 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.)
# 5/29/2019: Jostar create for minipack
# -----------------------------------------------------------
try:
import os
import sys, getopt
import subprocess
import click
import imp
import logging
import logging.config
import logging.handlers
import types
import time # this is only being used as part of the example
import traceback
from tabulate import tabulate
import fbfpgaio
import re
import time
from select import select
#from ctypes import fbfpgaio
except ImportError as e:
raise ImportError('%s - required module not found' % str(e))
# pimutil.py
#
# Platform-specific PIM interface for SONiC
#
iob = {
"revision": 0x0,
"scratchpad": 0x4,
"interrupt_status": 0x2C,
"pim_status": 0x40,
"pim_present_intr_mask": 0x44,
}
dom_base = [
0xFFFFFFFF, # Padding
0x40000,
0x48000,
0x50000,
0x58000,
0x60000,
0x68000,
0x70000,
0x78000,
]
dom = {
"revision": 0x0,
"system_led": 0xC,
"intr_status": 0x2C,
"qsfp_present": 0x48,
"qsfp_present_intr": 0x50,
"qsfp_present_intr_mask": 0x58,
"qsfp_intr": 0x60,
"qsfp_intr_mask": 0x68,
"qsfp_reset": 0x70,
"qsfp_lp_mode": 0x78,
"device_power_bad_status": 0x90,
"port_led_color_profile": {
0: 0x300,
1: 0x300,
2: 0x304,
3: 0x304,
4: 0x308,
5: 0x308,
6: 0x30C,
7: 0x30C,
},
"port_led_control": {
1: 0x310,
2: 0x314,
3: 0x318,
4: 0x31C,
5: 0x320,
6: 0x324,
7: 0x328,
8: 0x32C,
9: 0x330,
10: 0x334,
11: 0x338,
12: 0x33C,
13: 0x340,
14: 0x344,
15: 0x348,
16: 0x34C,
},
"dom_control_config": 0x410,
"dom_global_status": 0x414,
"dom_data": 0x4000,
"mdio": {
"config": 0x0200,
"command": 0x0204,
"write": 0x0208,
"read": 0x020C,
"status": 0x0210,
"intr_mask": 0x0214,
"source_sel": 0x0218,
}, # mdio
}
mdio_read_cmd = 0x1
mdio_write_cmd = 0x0
mdio_device_type = 0x1F
#fbfpgaio=cdll.LoadLibrary('./fbfpgaio.so')
def init_resources():
fbfpgaio.hw_init()
return
def release_resources():
fbfpgaio.hw_release()
return
def fpga_io(offset, data=None):
if data is None:
return fbfpgaio.hw_io(offset)
else:
fbfpgaio.hw_io(offset, data)
return
def pim_io(pim, offset, data=None):
global dom_base
target_offset = dom_base[pim]+offset
if data is None:
retval = fpga_io(target_offset)
#print ("0x%04X" % retval) # idebug
return retval
else:
retval = fpga_io(target_offset, data)
return retval
def show_pim_present():
pim_status = fpga_io(iob["pim_status"])
header = "PIM # "
status_str = " "
for shift in range(0,8):
status = pim_status & (0x10000 << shift) #[23:16] from pim_0 to pim_7
header += " %d " % (shift+1)
if status:
status_str += (" | ")
else:
status_str += (" X ")
print(header)
print(status_str)
def show_qsfp_present_status(pim_num):
status = fpga_io(dom_base[pim_num]+dom["qsfp_present"])
interrupt = fpga_io(dom_base[pim_num]+dom["qsfp_present_intr"])
mask = fpga_io(dom_base[pim_num]+dom["qsfp_present_intr_mask"])
print
print(" (0x48) (0x50) (0x58)")
print(" 0x%08X 0x%08X 0x%08X" %(status, interrupt, mask))
print(" Status Interrupt Mask")
for row in range(8):
output_str = str()
status_left = bool(status & (0x1 << row*2))
status_right = bool(status & (0x2 << row*2))
interrupt_left = bool(interrupt & (0x1 << row*2))
interrupt_right = bool(interrupt & (0x2 << row*2))
mask_left = bool(mask & (0x1 << row*2))
mask_right = bool(mask & (0x2 << row*2))
print("%2d: %d %d %d %d %d %d" % \
(row*2+1, status_left, status_right, \
interrupt_left, interrupt_right, \
mask_left, mask_right))
print
#pim_index start from 0 to 7
#port_index start from 0 to 127. Each 16-port is to one pim card.
class PimUtil(object):
PORT_START = 0
PORT_END = 127
def __init__(self):
self.value=1
def __del__(self):
self.value=0
def init_pim_fpga(self):
init_resources()
def release_pim_fpga(self):
release_resources()
def get_pim_by_port(self, port_num):
if port_num < self.PORT_START or port_num > self.PORT_END:
return False
pim_num=port_num/16
return True, pim_num+1
def get_onepimport_by_port(self, port_num):
if port_num < self.PORT_START or port_num > self.PORT_END:
return False
if port_num < 16:
return True, port_num
else:
return True, port_num%16
def get_pim_presence(self, pim_num):
if pim_num <0 or pim_num > 7:
return 0
pim_status = fpga_io(iob["pim_status"])
status = pim_status & (0x10000 << pim_num)
if status:
return 1 #present
else:
return 0 #not present
#return code=0:100G. return code=1:400G
def get_pim_board_id(self, pim_num):
if pim_num <0 or pim_num > 7:
return False
board_id = fpga_io(dom_base[pim_num+1]+dom["revision"])
board_id = board_id & 0x1
if board_id==0x0:
return 0
else:
return 1
def get_pim_status(self, pim_num):
if pim_num <0 or pim_num > 7:
return 0xFF
power_status =0
#device_power_bad_status
status=fpga_io(dom_base[pim_num+1]+dom["device_power_bad_status"])
for x in range(0, 5):
if status & ( (0xf) << (4*x) ) :
power_status = power_status | (0x1 << x)
if ( status & 0x1000000):
power_status=power_status | (0x1 << 5)
if ( status & 0x2000000):
power_status=power_status | (0x1 << 6)
if ( status & 0x8000000):
power_status=power_status | (0x1 << 7)
if ( status & 0x10000000):
power_status=power_status | (0x1 << 8)
if ( status & 0x40000000):
power_status=power_status | (0x1 << 9)
if ( status & 0x80000000):
power_status=power_status | (0x1 << 10)
return power_status
#path=0:MDIO path is set on TH3. path=1:MDIO path is set on FPGA.
def set_pim_mdio_source_sel(self, pim_num, path):
if pim_num <0 or pim_num > 7:
return False
status= pim_io(pim_num+1, dom["mdio"]["source_sel"])
if path==1:
status = status | 0x2
else:
status = status & 0xfffffffd
pim_io(pim_num+1, dom["mdio"]["source_sel"], status)
return True
#retrun code=0, path is TH3. retrun code=1, path is FPGA
def get_pim_mdio_source_sel(sefl, pim_num):
if pim_num <0 or pim_num > 7:
return False
path= pim_io(pim_num+1, dom["mdio"]["source_sel"])
path = path & 0x2
if path:
return 1
else:
return 0
#This api will set mdio path to MAC side.(At default, mdio path is set to FPGA side).
def pim_init(self, pim_num):
if pim_num <0 or pim_num > 7:
return False
status=self.set_pim_mdio_source_sel(pim_num, 0)
#put init phy cmd here
#return code="pim_dict[pim_num]='1' ":insert evt. return code="pim_dict[pim_num]='0' ":remove evt
def get_pim_change_event(self, timeout=0):
start_time = time.time()
pim_dict = {}
forever = False
if timeout == 0:
forever = True
elif timeout > 0:
timeout = timeout / float(1000) # Convert to secs
else:
print "get_transceiver_change_event:Invalid timeout value", timeout
return False, {}
end_time = start_time + timeout
if start_time > end_time:
print 'get_transceiver_change_event:' \
'time wrap / invalid timeout value', timeout
return False, {} # Time wrap or possibly incorrect timeout
pim_mask_status = fpga_io(iob["pim_present_intr_mask"], 0xffff00000)
while timeout >= 0:
new_pim_status=0
pim_status = fpga_io(iob["pim_status"])
present_status= pim_status & 0xff0000
change_status=pim_status & 0xff
interrupt_status = fpga_io(iob["interrupt_status"])
for pim_num in range(0,8):
if change_status & (0x1 << pim_num) :
status = present_status & (0x10000 << pim_num)
new_pim_status = new_pim_status | (0x1 << pim_num) #prepare to W1C to clear
if status:
pim_dict[pim_num]='1'
else:
pim_dict[pim_num]='0'
if change_status:
new_pim_status = pim_status | new_pim_status #Write one to clear interrupt bit
fpga_io(iob["pim_status"], new_pim_status)
return True, pim_dict
if forever:
time.sleep(1)
else:
timeout = end_time - time.time()
if timeout >= 1:
time.sleep(1) # We poll at 1 second granularity
else:
if timeout > 0:
time.sleep(timeout)
return True, {}
print "get_evt_change_event: Should not reach here."
return False, {}
def get_pim_max_number(self):
return 8
#pim_num start from 0 to 7
#color:0=amber, 1=blue
#contrl:off(0),on(1), flash(2)
def set_pim_led(self, pim_num, color, control):
if pim_num <0 or pim_num > 7:
return False
led_val=fpga_io(dom_base[pim_num+1]+dom["system_led"])
if color==1:
led_val = led_val | (0x8000 | 0x4000) #blue
elif color==0:
led_val = (led_val & ( ~ 0x8000)) | 0x4000 #amber
else:
print "Set RGB control to Green1"
led_val = led_val & (~ 0x4000)
led_val = led_val & (~ 0xfff)
led_val = led_val | 0x0f0 #B.G.R Birghtness, set to Green
if control==0:
led_val = led_val & ( ~ 0x3000) #Off
elif control==1:
led_val = led_val & ( ~ 0x3000) #Off
led_val = led_val | 0x1000 #On
else:
led_val = led_val | 0x3000 #Flash
fpga_io(dom_base[pim_num+1]+dom["system_led"], led_val)
def get_qsfp_presence(self, port_num):
#xlate port to get pim_num
status, pim_num=self.get_pim_by_port(port_num)
if status==0:
return False
else:
present = fpga_io(dom_base[pim_num]+dom["qsfp_present"])
status, shift = self.get_onepimport_by_port(port_num)
if status==0:
return False
else:
if bool(present & (0x1 << shift)):
return 1 #present
else:
return 0 #not present
#return code: low_power(1) or high_power(0)
def get_low_power_mode(self, port_num):
status, pim_num=self.get_pim_by_port(port_num)
if status==0:
return False
else:
lp_mode = fpga_io(dom_base[pim_num]+dom["qsfp_lp_mode"])
status, shift=self.get_onepimport_by_port(port_num)
if status==0:
return False
else:
if (lp_mode & (0x1 << shift)):
return 1 #low
else:
return 0 #high
#lpmode=1 to hold QSFP in low power mode. lpmode=0 to release QSFP from low power mode.
def set_low_power_mode(self, port_num, mode):
status, pim_num=self.get_pim_by_port(port_num)
if status==0:
return False
val = fpga_io(dom_base[pim_num]+dom["qsfp_lp_mode"])
status, shift=self.get_onepimport_by_port(port_num)
if status==0:
return False
else:
if mode==0:
new_val = val & (~(0x1 << shift))
else:
new_val=val|(0x1 << shift)
status=fpga_io(dom_base[pim_num]+dom["qsfp_lp_mode"], new_val)
return status
#port_dict[idx]=1 means get interrupt(change evt), port_dict[idx]=0 means no get interrupt
def get_qsfp_interrupt(self):
port_dict={}
#show_qsfp_present_status(1)
for pim_num in range(0, 8):
fpga_io(dom_base[pim_num+1]+dom["qsfp_present_intr_mask"], 0xffff0000)
fpga_io(dom_base[pim_num+1]+dom["qsfp_intr_mask"], 0xffff0000)
for pim_num in range(0, 8):
clear_bit=0
qsfp_present_intr_status = fpga_io(dom_base[pim_num+1]+dom["qsfp_present_intr"])
interrupt_status = qsfp_present_intr_status & 0xffff
#time.sleep(2)
if interrupt_status:
for idx in range (0,16):
port_idx=idx + (pim_num*16)
if interrupt_status & (0x1<<idx):
port_dict[port_idx]=1
clear_bit=clear_bit | (0x1<<idx) #W1C to clear
else:
port_dict[port_idx]=0
#W1C to clear
fpga_io(dom_base[pim_num+1]+dom["qsfp_present_intr"], qsfp_present_intr_status | clear_bit)
return port_dict
def reset(self, port_num):
status, pim=self.get_pim_by_port(port_num)
if status==0:
return False
val=fpga_io(dom_base[pim]+dom["qsfp_reset"])
status, shift=self.get_onepimport_by_port(port_num)
if status==0:
return False
else:
val = val & (~(0x1 << shift))
fpga_io(dom_base[pim]+dom["qsfp_reset"], val)
return True
#color:white(0), blue(1),red(2), orange(3),green(4)
def set_port_led(self, port_num, color, control):
status, pim_num=self.get_pim_by_port(port_num)
if status==0:
return False
status, port=self.get_onepimport_by_port(port_num)
port=port+1
led_val=fpga_io(dom_base[pim_num] + dom["port_led_control"][port])
if control==0:
led_val = led_val & (~ 0x3) #Off
elif control==1:
led_val = led_val & (~ 0x3) #Off
led_val = led_val | 0x1 #On
else:
led_val = led_val | 0x3 #Flash
led_val=led_val & (~ 0x1C)
if color==0:
led_val=led_val & (~ 0x1C) #white
elif color==1:
led_val=led_val | 0x8 #blue
elif color==2:
led_val=led_val | 0x10 #red
elif color==3:
led_val=led_val | 0x14 #oragne
else:
led_val=led_val | 0x1C #green
fpga_io(dom_base[pim_num] + dom["port_led_control"][port], led_val)
return True
def get_port_led(self, port_num):
status, pim_num=self.get_pim_by_port(port_num)
if status==0:
return False
status, port=self.get_onepimport_by_port(port_num)
led_val=fpga_io(dom_base[pim_num] + dom["port_led_control"][port+1])
control=led_val & 0x3
if control==0x3:
control=2
elif control==0x1:
control=1
else:
control=0
color = led_val & 0x1C
if color==0:
color=0 #white
elif color==0xC:
color=1 #blue
elif color==0x14:
color=2 #red
elif color==0x18:
color=3 #oragne
elif color==0x1C:
color=4 #green
print "color=%d, control=%d"%(color, control)
return color, control
def main(argv):
init_resources()
pim=PimUtil()
print "Test Board ID"
for x in range(0,8):
val=pim.get_pim_board_id(x)
print "pim=%d"%x
if val==0:
print "100G board"
else:
print "400G board"
print "Test pim presence"
for x in range(0,8):
pres=pim.get_pim_presence(x)
print "pim=%d, presence=%d"%(x, pres)
print "Test pim status"
for x in range(0,8):
power_status=pim.get_pim_status(x)
print "pim=%d power_status=0x%x"%(x, power_status)
release_resources()
if __name__ == '__main__':
main(sys.argv[1:])

View File

@ -0,0 +1,126 @@
# 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.
#include <Python.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
//#define IDEBUG(...) printf(__VA_ARGS__)
#define IDEBUG(...)
#define FPGA_RESOURCE_NODE "/sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0/resource0"
#define FPGA_RESOURCE_LENGTH 0x80000
static int hw_handle = -1;
static void *io_base = NULL;
static PyObject *fbfpgaio_hw_init(PyObject *self)
{
const char fpga_resource_node[] = FPGA_RESOURCE_NODE;
/* Open hardware resource node */
hw_handle = open(fpga_resource_node, O_RDWR|O_SYNC);
if (hw_handle == -1) {
IDEBUG("[ERROR] %s: open hw resource node\n", __func__);
return Py_False;
}
IDEBUG("[PASS] %s: open hw resource node\n", __func__);
/* Mapping hardware resource */
io_base = mmap(NULL, FPGA_RESOURCE_LENGTH, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE, hw_handle, 0);
if (io_base == MAP_FAILED) {
IDEBUG("[ERROR] %s: mapping resource node\n", __func__);
perror("map_failed");
fprintf(stderr,"%d %s\\n",errno,strerror(errno));
return Py_False;
}
IDEBUG("[PASS] %s: mapping resource node\n", __func__);
return Py_True;
}
static PyObject *fbfpgaio_hw_release(PyObject *self)
{
int retval = 0;
if ((io_base != NULL) && (io_base != MAP_FAILED)) {
retval = munmap(io_base, FPGA_RESOURCE_LENGTH);
if (retval == 0) {
IDEBUG("[PASS] %s: Unmapping hardware resources\n", __func__);
close(hw_handle);
return Py_True;
}
}
IDEBUG("[ERROR] %s: unmapping resource node\n", __func__);
return Py_False;
}
static PyObject *fbfpgaio_hw_io(PyObject *self, PyObject *args)
{
void *offset = NULL;
/* We are not able to diffrentiate the input data between an unsigned value or a
'None' object. We assume that the input data (if any) will be an unsigned integer.
The default value of 'data' is larger than the max. number of unsigned integer.
This value signify that the caller of this function does not input a data argument. */
unsigned long input_data = 0x1FFFFFFFF;
if (!PyArg_ParseTuple(args, "I|k", &offset, &input_data)) {
return NULL;
}
if (input_data == 0x1FFFFFFFF) {
// Read operation
IDEBUG("Read operation\n");
unsigned int *address = (unsigned int *) ((unsigned long) io_base + (unsigned long) offset);
return Py_BuildValue("k", *address);
} else {
// Write operation
IDEBUG("Write operation\n");
unsigned int *address = (unsigned int *) ((unsigned long) io_base + (unsigned long) offset);
unsigned int data = (unsigned int) (input_data & 0xFFFFFFFF);
*address = data;
Py_INCREF(Py_None);
return Py_None;
}
}
static PyMethodDef FbfpgaMethods[] = {
{ "hw_init", (PyCFunction) fbfpgaio_hw_init, METH_NOARGS, "Initialize resources for accessing FPGA" },
{ "hw_release", (PyCFunction) fbfpgaio_hw_release, METH_NOARGS, "Release resources for accessing FPGA" },
{ "hw_io", fbfpgaio_hw_io, METH_VARARGS, "Access FPGA" },
{ NULL, NULL, 0, NULL },
};
PyMODINIT_FUNC
initfbfpgaio(void)
{
char docstr[] = "\
1. hw_init():\n\
return value: True/False\n\
2. hw_release():\n\
return value: True/False\n\
3. hw_io(offset,[data])\n\
return value:\n\
In reading operation: data which is read from FPGA\n\
In writing operation: None\n";
(void) Py_InitModule3("fbfpgaio", FbfpgaMethods, docstr);
}

View File

@ -0,0 +1,16 @@
[Unit]
Description=Accton MiniPack Platform setup qsfp oom service
Before=pmon.service
After=minipack-platform-init.service
DefaultDependencies=no
[Service]
ExecStart=/usr/local/bin/setup_qsfp_eeprom.py
KillSignal=SIGKILL
SuccessExitStatus=SIGKILL
# Resource Limitations
LimitCORE=infinity
[Install]
WantedBy=multi-user.target

View File

@ -2,9 +2,11 @@
import os
import sys
from setuptools import setup
from setuptools import setup, Extension
os.listdir
module1 = Extension("fbfpgaio", sources = ["minipack/lib/fbfpgaiomodule.c"])
setup(
name='minipack',
version='1.0',
@ -12,5 +14,7 @@ setup(
packages=['minipack'],
package_dir={'minipack': 'minipack/classes'},
ext_modules=[module1],
)

View File

@ -238,7 +238,7 @@ def device_install():
for i in range(0,len(mknod)):
#for pca932x need times to built new i2c buses
if mknod[i].find('pca954') != -1:
time.sleep(1)
time.sleep(2)
status, output = log_os_system(mknod[i], 1)
if status:
@ -246,49 +246,14 @@ def device_install():
if FORCE == 0:
return status
# initialize multiplexer for 8 PIMs
cmdl = "echo pca9548 0x%x > /sys/bus/i2c/devices/i2c-%d/new_device"
for pim in range(2, 10):
cmdm = cmdl % (0x72, pim)
status, output =log_os_system(cmdm, 1)
cmdm = cmdl % (0x71, pim)
status, output =log_os_system(cmdm, 1)
for i in range(0, NO_QSFP):
bus = sfp_map(i)
status, output =log_os_system(
"echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-"+str(bus)+"/new_device", 1)
if status:
print output
if FORCE == 0:
return status
status, output =log_os_system(
"echo port"+str(i+1)+" > /sys/bus/i2c/devices/"+str(bus)+"-0050/port_name", 1)
if status:
print output
if FORCE == 0:
return status
rm_cmd="rm -rf /usr/local/bin/minipack_qsfp > /dev/null 2>&1"
log_os_system(rm_cmd, 1)
mk_cmd= "mkdir /usr/local/bin/minipack_qsfp"
log_os_system(mk_cmd, 1)
return
def device_uninstall():
for i in range(0,NO_QSFP):
bus = sfp_map(i)
target = "/sys/bus/i2c/devices/i2c-"+str(bus)+"/delete_device"
status, output =log_os_system("echo 0x50 > "+ target, 1)
if status:
print output
if FORCE == 0:
return status
# Multiplexer for 8 PIMs
cmdl = "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device"
for pim in range(2, 10):
cmdm = cmdl % (0x72, pim)
status, output =log_os_system(cmdm, 1)
cmdm = cmdl % (0x71, pim)
status, output =log_os_system(cmdm, 1)
nodelist = mknod
for i in range(len(nodelist)):
target = nodelist[-(i+1)]

View File

@ -0,0 +1,317 @@
#!/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.)
# 7/22/2019: Jostar create for minipack
# ------------------------------------------------------------------
try:
import os
import sys, getopt
import subprocess
import subprocess
import click
import imp
import commands
import logging
import logging.config
import logging.handlers
import types
import time # this is only being used as part of the example
import traceback
from tabulate import tabulate
from minipack.pimutil import PimUtil
except ImportError as e:
raise ImportError('%s - required module not found' % str(e))
#2:idle state. 1:insert state, 0:remove state.
pim_state=[2,2,2,2,2,2,2,2]
# port_use_i2c_bus[idx], idx means port_idx. Idx start from 0 to 127
# port_use_i2c_bus[0] means port0 use i2c-device number
# port_use_i2c_bus[1] means port1 use i2c-device number
#At default , port_use_i2c_bus are 0. When PIM insert, it will no be 0
port_use_i2c_bus= [0] * 128
#pim_port_use_bus[idx] are for 8 channel use. At default, pim_port_use_bus[idx]=0
#pim_port_use_bus[idx] will save pim_idx(0 to 7).
#setup service will check when pim insert at first time.
#It will find
# 1. Does this pim card insert or not in the past. So it will check pim_port_use_bus[idx]
# 2. If make sure that pim_port_use_bus[idx]==0. Assgin oom start i2c dev numer to pim_port_use_bus[idx].
#Never set pim_port_use_bus[idx] to 0
#So if pim next insert, it need to check whether pim_port_use_bus[idx] is 0 or not.
#if pim_port_use_bus[idx]!=0, means this pim card has setup oom sysfs
pim_port_use_bus=[0] * 8
oom_i2c_bus_table=1
pim_dev=PimUtil()
# Deafults
VERSION = '1.0'
FUNCTION_NAME = '/usr/local/bin/setup_qsfp_eeprom'
DEBUG = False
PIM_MIN=0
PIM_MAX=8
def my_log(txt):
if DEBUG == True:
print "[ACCTON DBG]: "+txt
return
def log_os_system(cmd):
logging.info('Run :'+cmd)
status = 1
output = ""
status, output = commands.getstatusoutput(cmd)
if status:
logging.info('Failed :'+cmd)
return status, output
def qsfp_map_bus(idx):
port = idx + 1
base = ((port-1)/8*8) + 10
idx = (port - 1) % 8
idx = 7 - idx
if (idx%2):
idx = idx -1
else:
idx = idx +1
bus = base + idx
return bus
def pca9548_sysfs(i2c_bus, create):
if create==1:
cmdl = "echo pca9548 0x%x > /sys/bus/i2c/devices/i2c-%d/new_device"
else:
cmdl = "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device"
cmdm = cmdl % (0x72, i2c_bus)
status1, output =log_os_system(cmdm)
cmdm = cmdl % (0x71, i2c_bus)
status2, output =log_os_system(cmdm)
return (status1 | status2)
def qsfp_eeprom_sys(pim_idx, i2c_bus_order, create):
# initialize multiplexer for 8 PIMs
global port_use_i2c_bus
start_port=pim_idx*16
end_port = (pim_idx+1)*16
start_bus=(i2c_bus_order-1)*16
end_bus = i2c_bus_order*16
k=start_port
for i in range(start_bus, end_bus):
bus = qsfp_map_bus(i)
if create==1:
status, output =log_os_system(
"echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-"+str(bus)+"/new_device")
if status:
print output
return 1
status, output =log_os_system(
"echo port"+str(k+1)+" > /sys/bus/i2c/devices/"+str(bus)+"-0050/port_name")
status, output =log_os_system(
"ln -s -f /sys/bus/i2c/devices/"+str(bus)+"-0050/eeprom" + " /usr/local/bin/minipack_qsfp/port" + str(k) + "_eeprom")
if status:
print output
return 1
else:
status, output =log_os_system(
"echo 0x50 > /sys/bus/i2c/devices/i2c-"+str(bus)+"/delete_device")
if status:
print output
k=k+1
return 0
def check_pca_active( i2c_addr, bus):
cmd = "i2cget -y -f %d 0x%x 0x0"
cmd = cmd %(bus, i2c_addr)
status, output = commands.getstatusoutput(cmd)
return status
def set_pim_port_use_bus(pim_idx):
global pim_port_use_bus
global oom_i2c_bus_table
if pim_port_use_bus[pim_idx]!=0:
return 0
pim_port_use_bus[pim_idx]=oom_i2c_bus_table
oom_i2c_bus_table=oom_i2c_bus_table+1
return pim_port_use_bus[pim_idx]
def del_pim_port_use_bus(pim_idx):
global oom_i2c_bus_table
oom_i2c_bus_table=oom_i2c_bus_table-1
pim_port_use_bus[pim_idx]=0
def device_remove():
cmd1 = "echo 0x%x > /sys/bus/i2c/devices/i2c-%d/delete_device"
for bus in range(2, 10):
#ret=check_pca_active(0x72, bus)
#if ret==0:
cmdm= cmd1 % (0x72, bus)
status, output = commands.getstatusoutput(cmdm)
print "Remove %d-0072 i2c device"%bus
cmdm= cmd1 % (0x71, bus)
status, output = commands.getstatusoutput(cmdm)
print "Remove %d-0071 i2c device"%bus
cmd="rm -f /usr/local/bin/minipack_qsfp/port*"
status, output=log_os_system(cmd)
return status
class device_monitor(object):
PIM_STATE_REMOVE = 0
PIM_STATE_INSERT = 1
PIM_STATE_IDLE=2
def __init__(self, log_file, log_level):
"""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 = handler = logging.handlers.SysLogHandler(address = '/dev/log')
sys_handler.setLevel(logging.WARNING)
logging.getLogger('').addHandler(sys_handler)
#logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level)
def manage_pim(self):
global pim_dev
global pim_state
for pim_idx in range(PIM_MIN, PIM_MAX):
presence=pim_dev.get_pim_presence(pim_idx)
if presence==1:
if pim_state[pim_idx]!=self.PIM_STATE_INSERT:
#find which i2c_device can use. It start from 2
i2c_bus_order=set_pim_port_use_bus(pim_idx)
if i2c_bus_order==0:
logging.info("pim_state[%d] PIM_STATE_INSERT", pim_idx);
pim_state[pim_idx]=self.PIM_STATE_INSERT
continue
logging.info ("pim_idx=%d oom use i2c_bus_order=%d", pim_idx, i2c_bus_order)
ready=0
retry_limit=100
retry_count=0
while retry_count < retry_limit:
ret=check_pca_active(0x72, pim_idx+2)
if ret==0:
ready=1
break
retry_count=retry_count+1
time.sleep(0.2)
if ready==1:
status=pca9548_sysfs(pim_idx+2, 1)
if status:
status=pca9548_sysfs(pim_idx+2, 0) #del pca i2c device, give up set oom at this time.
del_pim_port_use_bus(pim_idx)
continue
status=qsfp_eeprom_sys(pim_idx,i2c_bus_order, 1)
if status:
status=pca9548_sysfs(pim_idx+2, 0) #del pca i2c device, give up set oom at this time.
del_pim_port_use_bus(pim_idx)
continue
#ret_2=check_pca_active(0x72, pim_idx+2)
#ret_1=check_pca_active(0x71, pim_idx+2)
pim_state[pim_idx]=self.PIM_STATE_INSERT
logging.info("pim_state[%d] PIM_STATE_INSERT", pim_idx);
else:
print "retry check 100 times for check pca addr"
del_pim_port_use_bus(pim_idx)
else:
if pim_state[pim_idx]==self.PIM_STATE_INSERT:
#pca9548_sysfs(pim_idx+2, 0)
pim_state[pim_idx]=self.PIM_STATE_REMOVE
logging.info("pim_state[%d] PIM_STATE_REMOVE", pim_idx);
def main(argv):
log_file = '%s.log' % FUNCTION_NAME
log_level = logging.INFO
remove_dev=0
cpu_pca_i2c_ready=0
if len(sys.argv) != 1:
try:
opts, args = getopt.getopt(argv,'hdlr',['lfile='])
except getopt.GetoptError:
print 'A:Usage: %s [-d] [-l <log_file>]' % sys.argv[0]
return 0
for opt, arg in opts:
if opt == '-h':
print 'B: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
elif opt in ('-r', '--remove'):
remove_dev=1
if remove_dev==1:
device_remove()
return 0
monitor = device_monitor(log_file, log_level)
global pim_dev
pim_dev.init_pim_fpga()
while cpu_pca_i2c_ready==0:
status=check_pca_active(0x70, 1)
time.sleep(0.5)
if status==0:
cpu_pca_i2c_ready=1
print "Make sure CPU pca i2c device is ready"
break
while True:
monitor.manage_pim()
time.sleep(2)
if __name__ == "__main__":
main(sys.argv[1:])