[Juniper] Re-organizing sonic_platform modules (#4448)

This patch set implements the following:
 - Fixes the conflicts in chassis.py / platform.py in sonic_platfrom
 - Consolidating the common library files in sonic_platform
 - Moving QFX5210 specific drivers to qfx5210/modules
 - Moving Juniper common fpga drivers to common/modules
 - Cleaning up the platform driver files
 - Bug fixes in QFX5210 platform monitor & initialiazation script
 - Fixing the bugs in QFX5210 eeprom parsing

Signed-off-by: Ciju Rajan K <crajank@juniper.net>
This commit is contained in:
ciju-juniper 2020-04-21 14:55:51 +05:30 committed by GitHub
parent 13bef09889
commit d1940b2cf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 4924 additions and 5222 deletions

View File

View File

View File

View File

View File

View File

View File

View File

View File

@ -0,0 +1,331 @@
#!/usr/bin/env python
#
# Name: juniper_qfx5210_eepromconv.py version: 1.0
#
# Description: This file contains the code to store the contents of Board EEPROM in file
#
# Copyright (c) 2020, Juniper Networks, Inc.
# All rights reserved.
#
# Notice and Disclaimer: This code is licensed to you under the GNU General
# Public License as published by the Free Software Foundation, version 3 or
# any later version. This code is not an official Juniper product. You can
# obtain a copy of the License at <https://www.gnu.org/licenses/>
#
# OSS License:
#
# 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 <https://www.gnu.org/licenses/>.
#
# Third-Party Code: This code may depend on other components under separate
# copyright notice and license terms. Your use of the source code for those
# components is subject to the terms and conditions of the respective license
# as noted in the Third-Party source code file.
import os
import commands
import binascii
from sonic_eeprom import eeprom_tlvinfo
def main():
eeprom_qfx5210 = Eeprom()
FANTYPE_PATH = '/sys/bus/i2c/devices/17-0068/fan1_direction'
isPlatformAFO = False
try:
fan_type_file = open(FANTYPE_PATH)
except IOError as e:
print "Error: unable to open file: %s" % str(e)
fan_type = -1
else:
fan_type = fan_type_file.read()
fan_type_file.close()
if (int(fan_type) == -1 or int(fan_type) == 0):
if (int(fan_type) == -1):
print "unable to open sys file for fan handling, defaulting it to AFO"
isPlatformAFO = True
else:
isPlatformAFO = False
# creating the "/var/run/eeprom" file and storing values of CPU board EEPROM in this file.
eeprom_file = open ("/var/run/eeprom", "a+")
eeprom_file.write("\n")
if isPlatformAFO == True:
eeprom_file.write("Fan Type=AFO\r\n")
else:
eeprom_file.write("Fan Type=AFI\r\n")
eeprom_file.write("\n")
# Write the contents of CPU Board EEPROM to file
eeprom_file.write("CPU Board EEPROM (0x56)\r\n")
eeprom_file.write("===============================\r\n")
eeprom_file.write("Product Name=%s\r\n" % eeprom_qfx5210.modelstr())
eeprom_file.write("Part Number=%s\r\n" % eeprom_qfx5210.part_number_str())
eeprom_file.write("Serial Number=%s\r\n" % eeprom_qfx5210.serial_number_str())
eeprom_file.write("MAC Address=%s\r\n" % eeprom_qfx5210.base_mac_address())
eeprom_file.write("Manufacture Date=%s\r\n" % eeprom_qfx5210.manuDate_str())
eeprom_file.write("Platform Name=%s\r\n" % eeprom_qfx5210.platform_str())
eeprom_file.write("Number of MAC Addresses=%s\r\n" % eeprom_qfx5210.MACsize_str())
eeprom_file.write("Vendor Name=%s\r\n" % eeprom_qfx5210.vendor_name_str())
eeprom_file.write("Manufacture Name=%s\r\n" % eeprom_qfx5210.manufacture_name_str())
CPUeepromFileCmd = 'cat /sys/devices/pci0000:00/0000:00:1f.3/i2c-0/0-0056/eeprom > /etc/init.d/eeprom_qfx5210_ascii'
# Write the contents of CPU EEPROM to file
try:
os.system(CPUeepromFileCmd)
except OSError:
print 'Error: Execution of "%s" failed', CPUeepromFileCmd
return False
eeprom_ascii = '/etc/init.d/eeprom_qfx5210_ascii'
# Read file contents in Hex format
with open(eeprom_ascii, 'rb') as Hexformat:
content = Hexformat.read()
Hexformatoutput = binascii.hexlify(content)
eeprom_hex = '/etc/init.d/eeprom_qfx5210_hex'
with open(eeprom_hex, 'wb+') as Hexfile:
Hexfile.write(Hexformatoutput)
#Write contents of CPU EEPROM to new file in hexa format
with open(eeprom_hex, 'rb') as eeprom_hexfile:
eeprom_hexfile.seek(350, 0)
vendorext_read = eeprom_hexfile.read(124)
vendorext=""
vendorext += "0x" + vendorext_read[0:2]
for i in range(2,124,2):
vendorext += " 0x" + vendorext_read[i:i+2]
eeprom_file.write("Vendor Extension=%s\r\n" % str(vendorext))
eeprom_hexfile.seek(350, 0)
IANA_read = eeprom_hexfile.read(8)
IANAName = binascii.unhexlify(IANA_read)
eeprom_file.write("IANA=%s\r\n" % str(IANAName))
eeprom_hexfile.seek(358, 0)
ASMpartrev_read = eeprom_hexfile.read(4)
ASMpartrev = binascii.unhexlify(ASMpartrev_read)
eeprom_file.write("Assembly Part Number Rev=%s\r\n" % str(ASMpartrev))
eeprom_hexfile.seek(374, 0)
ASMpartnum_read = eeprom_hexfile.read(20)
ASMpartnum_read = binascii.unhexlify(ASMpartnum_read)
eeprom_file.write("Assembly Part Number=%s\r\n" % str(ASMpartnum_read))
eeprom_hexfile.seek(402, 0)
ASMID_read = eeprom_hexfile.read(4)
ASMID_read_upper = ASMID_read.upper()
eeprom_file.write("Assembly ID=0x%s\r\n" % str(ASMID_read_upper))
ASMHWMajRev_position = eeprom_hexfile.seek(410, 0)
ASMHWMajRev_read = eeprom_hexfile.read(2)
eeprom_file.write("Assembly Major Revision=0x%s\r\n" % str(ASMHWMajRev_read))
eeprom_hexfile.seek(416, 0)
ASMHWMinRev_read = eeprom_hexfile.read(2)
eeprom_file.write("Assembly Minor Revision=0x%s\r\n" % str(ASMHWMinRev_read))
eeprom_hexfile.seek(422, 0)
Deviation_read = eeprom_hexfile.read(28)
Deviation_read_upper = Deviation_read.upper()
eeprom_file.write("Deviation=0x%s\r\n" % str(Deviation_read_upper))
eeprom_hexfile.seek(450, 0)
CLEI_read = eeprom_hexfile.read(20)
CLEI_name = binascii.unhexlify(CLEI_read)
eeprom_file.write("CLEI code=%s\r\n" % str(CLEI_name))
eeprom_dict = eeprom_qfx5210.system_eeprom_info()
key = '0x29'
if key in eeprom_dict.keys():
onie_version_str = eeprom_dict.get('0x29', None)
else:
onie_version_str = "N/A"
eeprom_file.write("ONIE Version=%s\r\n" % onie_version_str)
crc_str = eeprom_dict.get('0xFE', None)
eeprom_file.write("CRC=%s\r\n" % crc_str)
eeprom_file.close()
return True
class Eeprom(eeprom_tlvinfo.TlvInfoDecoder):
def __init__(self):
self.__eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0056/eeprom"
super(Eeprom, self).__init__(self.__eeprom_path, 0, '', True)
self.__eeprom_tlv_dict = dict()
try:
self.__eeprom_data = self.read_eeprom()
except:
self.__eeprom_data = "N/A"
raise RuntimeError("Eeprom is not Programmed")
else:
eeprom = self.__eeprom_data
if not self.is_valid_tlvinfo_header(eeprom):
return
total_length = (ord(eeprom[9]) << 8) | ord(eeprom[10])
tlv_index = self._TLV_INFO_HDR_LEN
tlv_end = self._TLV_INFO_HDR_LEN + total_length
while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end:
if not self.is_valid_tlv(eeprom[tlv_index:]):
break
tlv = eeprom[tlv_index:tlv_index + 2
+ ord(eeprom[tlv_index + 1])]
code = "0x%02X" % (ord(tlv[0]))
if ord(tlv[0]) == self._TLV_CODE_VENDOR_EXT:
value = str((ord(tlv[2]) << 24) | (ord(tlv[3]) << 16) |
(ord(tlv[4]) << 8) | ord(tlv[5]))
value += str(tlv[6:6 + ord(tlv[1])])
else:
name, value = self.decoder(None, tlv)
self.__eeprom_tlv_dict[code] = value
if ord(eeprom[tlv_index]) == self._TLV_CODE_CRC_32:
break
tlv_index += ord(eeprom[tlv_index+1]) + 2
def serial_number_str(self):
(is_valid, results) = self.get_tlv_field(
self.__eeprom_data, self._TLV_CODE_SERIAL_NUMBER)
if not is_valid:
return "N/A"
return results[2]
def base_mac_address(self):
(is_valid, t) = self.get_tlv_field(
self.__eeprom_data, self._TLV_CODE_MAC_BASE)
if not is_valid or t[1] != 6:
return super(eeprom_tlvinfo.TlvInfoDecoder, self).switchaddrstr(self.__eeprom_data)
return ":".join([binascii.b2a_hex(T) for T in t[2]])
def modelstr(self):
(is_valid, results) = self.get_tlv_field(
self.__eeprom_data, self._TLV_CODE_PRODUCT_NAME)
if not is_valid:
return "N/A"
return results[2]
def part_number_str(self):
(is_valid, results) = self.get_tlv_field(
self.__eeprom_data, self._TLV_CODE_PART_NUMBER)
if not is_valid:
return "N/A"
return results[2]
def serial_tag_str(self):
(is_valid, results) = self.get_tlv_field(
self.__eeprom_data, self._TLV_CODE_SERVICE_TAG)
if not is_valid:
return "N/A"
return results[2]
def revision_str(self):
(is_valid, results) = self.get_tlv_field(
self.__eeprom_data, self._TLV_CODE_DEVICE_VERSION)
if not is_valid:
return "N/A"
return results[2]
def manuDate_str(self):
(is_valid, results) = self.get_tlv_field(
self.__eeprom_data, self._TLV_CODE_MANUF_DATE)
if not is_valid:
return "N/A"
return results[2]
def platform_str(self):
(is_valid, results) = self.get_tlv_field(
self.__eeprom_data, self._TLV_CODE_PLATFORM_NAME)
if not is_valid:
return "N/A"
return results[2]
def MACsize_str(self):
(is_valid, t) = self.get_tlv_field(self.__eeprom_data, self._TLV_CODE_MAC_SIZE)
if not is_valid:
return "N/A"
return str((ord(t[2][0]) << 8) | ord(t[2][1]))
def vendor_name_str(self):
(is_valid, results) = self.get_tlv_field(
self.__eeprom_data, self._TLV_CODE_VENDOR_NAME)
if not is_valid:
return "N/A"
return results[2]
def manufacture_name_str(self):
(is_valid, results) = self.get_tlv_field(
self.__eeprom_data, self._TLV_CODE_MANUF_NAME)
if not is_valid:
return "N/A"
return results[2]
def onie_version_str(self):
value = ""
(is_valid, results) = self.get_tlv_field(
self.__eeprom_data, self._TLV_CODE_ONIE_VERSION)
if not is_valid:
return "N/A"
for c in results[2:2 + ord(results[1])]:
value += "0x%02X " % (ord(c),)
return value
def vendor_ext_str(self):
(is_valid, results) = self.get_tlv_field(
self.__eeprom_data, self._TLV_CODE_VENDOR_EXT)
if not is_valid:
return "N/A"
vendor_value_formatted = ''.join( [ " 0x" + "%02X " % ord( x ) for x in results[2] ] ).strip()
vendor_value_hexvalue = ''.join( ["%02X" % ord( x ) for x in results[2] ] ).strip()
return vendor_value_formatted, vendor_value_hexvalue
def crc_str(self):
(is_valid, results) = self.get_tlv_field(
self.__eeprom_data, self._TLV_CODE_CRC_32)
if not is_valid:
return "N/A"
def system_eeprom_info(self):
"""
Returns a dictionary, where keys are the type code defined in
ONIE EEPROM format and values are their corresponding values
found in the system EEPROM.
"""
return self.__eeprom_tlv_dict
if __name__ == "__main__":
main()

View File

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

View File

@ -0,0 +1,661 @@
/*
* Juniper Networks TMC GPIO driver
*
* Copyright (C) 2020 Juniper Networks
* Author: Ashish Bhensdadia <bashish@juniper.net>
*
* This driver implement the GPIO set/get functionality
*
* 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; version 2 of the License.
*
* 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.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include "jnx-tmc.h"
#define TMC_GPIO_MAX_BITS_PER_REG 16
#define TMC_GPIO_SFP_MAX_BITS_PER_REG 2
#define TMC_GPIO_PTPCFG_MAX_BITS_PER_REG 8
#define TMC_GPIO_FIND_GROUP(gpio) \
((gpio) / TMC_GPIO_MAX_BITS_PER_REG)
#define TMC_GPIO_FIND_GPIO(gpio) \
((gpio) % TMC_GPIO_MAX_BITS_PER_REG)
#define TMC_GPIO_SFP_FIND_GROUP(gpio) \
((gpio) / TMC_GPIO_SFP_MAX_BITS_PER_REG)
#define TMC_GPIO_SFP_FIND_GPIO(gpio) \
((gpio) % TMC_GPIO_SFP_MAX_BITS_PER_REG)
#define TMC_GPIO_PTPCFG_FIND_GPIO(gpio) \
((gpio) % TMC_GPIO_PTPCFG_MAX_BITS_PER_REG)
#define TMC_GPIO_MAX_NGPIO_PER_GROUP 320
#define TMC_PFE_QSFP_RESET_OFFSET 0x4
#define TMC_PFE_QSFP_PRESENT_OFFSET 0x8
#define TMC_PFE_QSFP_PHY_RESET_OFFSET 0x10
#define TMC_PFE_QSFP_LPMOD_OFFSET 0x78
#define TMC_PFE_QSFP_LED_CTRL_OFFSET 0x20
#define TMC_PFE_LANES_GREEN_LED_VALUE 0x3
#define TMC_PFE_LANE0_GREEN_LED_BIT_POSITION 0
#define TMC_PFE_LANE1_GREEN_LED_BIT_POSITION 2
#define TMC_PFE_LANE2_GREEN_LED_BIT_POSITION 4
#define TMC_PFE_LANE3_GREEN_LED_BIT_POSITION 6
#define TMC_PFE_LANES_BEACON_LED_VALUE 0x2
#define TMC_PFE_LANE0_BEACON_LED_BIT_POSITION 0
#define TMC_PFE_LANE1_BEACON_LED_BIT_POSITION 2
#define TMC_PFE_LANE2_BEACON_LED_BIT_POSITION 4
#define TMC_PFE_LANE3_BEACON_LED_BIT_POSITION 6
#define TMC_PFE_LANES_FAULT_LED_VALUE 0x1
#define TMC_PFE_LANE0_FAULT_LED_BIT_POSITION 0
#define TMC_PFE_LANE1_FAULT_LED_BIT_POSITION 2
#define TMC_PFE_LANE2_FAULT_LED_BIT_POSITION 4
#define TMC_PFE_LANE3_FAULT_LED_BIT_POSITION 6
#define TMC_PFE_SFPSB0_TX_DISABLE_OFFSET 0x0
#define TMC_PFE_SFPSB0_LED_CTRL_OFFSET 0xC
#define TMC_PFE_SFPSB0_LED_ACTIVITY_OFFSET 0x14
#define TMC_PFE_SFPSB0_PRESENT_OFFSET 0x18
#define TMC_PFE_SFPSB0_LOSS_OFFSET 0x1C
#define TMC_PFE_SFPSB0_TX_FAULT_OFFSET 0x20
#define TMC_PFE_SFPSB1_TX_DISABLE_OFFSET 0x0
#define TMC_PFE_SFPSB1_LED_CTRL_OFFSET 0x8
#define TMC_PFE_SFPSB1_LED_ACTIVITY_OFFSET 0x10
#define TMC_PFE_SFPSB1_PRESENT_OFFSET 0x14
#define TMC_PFE_SFPSB1_LOSS_OFFSET 0x18
#define TMC_PFE_SFPSB1_TX_FAULT_OFFSET 0x1C
/*
* Index 4 to 15 is used for QSFP starting with
* QSFP_LED_LANE0_GREEN. To keep multibit set/get common
* starting SFP_LED_LANE0_GREEN with 16 which will avoid
* conflict with QSFP enums.
*/
#define SFP_LED_OP_START_INDEX 16
/*
* Used for off-setting SFP led op index
*/
#define SFP_LED_OP_OFFSET 0xB
/*
* SFP slave blocks
*/
#define SFP_SLAVE0_BLOCK 0x1
#define SFP_SLAVE1_BLOCK 0x2
/*
* each group represent the 16 gpios.
* QSFP_RST - QSFP_LPMODE
* each bit represent the one gpio
* exemple: bits[0:15] - bit0 - gpio0
* QSFP_LED_LANE0_GREEN - QSFP_LED_LANE3_FAULT
* here, number represent the one gpio
* exemple: bits[0:1]
* 00 - gpio off, 01 - gpio on [ gpio0]
* 00 - gpio off, 10 - gpio on [ gpio1]
* 00 - gpio off, 11 - gpio on [ gpio2]
*
*/
enum {
QSFP_RST,
QSFP_PRESENT,
QSFP_PHY_RST,
QSFP_LPMOD,
QSFP_LED_LANE0_GREEN,
QSFP_LED_LANE1_GREEN,
QSFP_LED_LANE2_GREEN,
QSFP_LED_LANE3_GREEN,
QSFP_LED_LANE0_BEACON,
QSFP_LED_LANE1_BEACON,
QSFP_LED_LANE2_BEACON,
QSFP_LED_LANE3_BEACON,
QSFP_LED_LANE0_FAULT,
QSFP_LED_LANE1_FAULT,
QSFP_LED_LANE2_FAULT,
QSFP_LED_LANE3_FAULT,
TMC_PFE_GPIO_GROUP_MAX
};
enum sfp_op {
SFP_TX_DISABLE,
SFP_LED_ACTIVITY,
SFP_PRESENT,
SFP_SFP_LOS,
SFP_TX_FAULT,
SFP_LED_LANE0_GREEN = SFP_LED_OP_START_INDEX,
SFP_LED_LANE1_GREEN,
SFP_LED_LANE2_GREEN,
SFP_LED_LANE3_GREEN,
SFP_LED_LANE0_BEACON,
SFP_LED_LANE1_BEACON,
SFP_LED_LANE2_BEACON,
SFP_LED_LANE3_BEACON,
SFP_LED_LANE0_FAULT,
SFP_LED_LANE1_FAULT,
SFP_LED_LANE2_FAULT,
SFP_LED_LANE3_FAULT,
TMC_PFE_SFP_GPIO_GROUP_MAX
};
static const u32 group_offset[TMC_PFE_GPIO_GROUP_MAX] = {
TMC_PFE_QSFP_RESET_OFFSET,
TMC_PFE_QSFP_PRESENT_OFFSET,
TMC_PFE_QSFP_PHY_RESET_OFFSET,
TMC_PFE_QSFP_LPMOD_OFFSET,
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE0 GREEN */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE1 GREEN */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE2 GREEN */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE3 GREEN */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE0 BEACON */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE1 BEACON */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE2 BEACON */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE3 BEACON */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE0 FAULT */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE1 FAULT */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE2 FAULT */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE3 FAULT */
};
static const u32 sfp_slaveb0_group_offset[TMC_PFE_SFP_GPIO_GROUP_MAX] = {
TMC_PFE_SFPSB0_TX_DISABLE_OFFSET,
TMC_PFE_SFPSB0_LED_ACTIVITY_OFFSET,
TMC_PFE_SFPSB0_PRESENT_OFFSET,
TMC_PFE_SFPSB0_LOSS_OFFSET,
TMC_PFE_SFPSB0_TX_FAULT_OFFSET,
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE0 GREEN */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE1 GREEN */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE2 GREEN */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE3 GREEN */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE0 BEACON */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE1 BEACON */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE2 BEACON */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE3 BEACON */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE0 FAULT */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE1 FAULT */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE2 FAULT */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE3 FAULT */
};
static const u32 sfp_slaveb1_group_offset[TMC_PFE_SFP_GPIO_GROUP_MAX] = {
TMC_PFE_SFPSB1_TX_DISABLE_OFFSET,
TMC_PFE_SFPSB1_LED_ACTIVITY_OFFSET,
TMC_PFE_SFPSB1_PRESENT_OFFSET,
TMC_PFE_SFPSB1_LOSS_OFFSET,
TMC_PFE_SFPSB1_TX_FAULT_OFFSET,
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE0 GREEN */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE1 GREEN */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE2 GREEN */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE3 GREEN */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE0 BEACON */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE1 BEACON */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE2 BEACON */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE3 BEACON */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE0 FAULT */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE1 FAULT */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE2 FAULT */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE3 FAULT */
};
struct tmc_gpio_info {
int (*get)(struct gpio_chip *, unsigned int);
void (*set)(struct gpio_chip *, unsigned int, int);
int (*dirin)(struct gpio_chip *, unsigned int);
int (*dirout)(struct gpio_chip *, unsigned int, int);
};
struct tmc_gpio_chip {
const struct tmc_gpio_info *info;
void __iomem *base;
struct device *dev;
struct gpio_chip gpio;
int ngpio;
spinlock_t gpio_lock; /* gpio lock */
int sfp_slave_block;
};
/* slave gpio max */
static int gpio_max = 320;
module_param(gpio_max, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(gpio_max, "Maximum number of gpio for SLAVE TMC GPIO");
/*
* generic bit operation functions
*/
static u32 tmc_gpio_reset_bits(u32 state, u32 val, u32 shift)
{
state &= ~(val << shift);
return state;
};
static u32 tmc_gpio_set_bits(u32 state, u32 val, u32 shift)
{
state |= (val << shift);
return state;
};
static u32 tmc_gpio_find_bits_val(u32 state, u32 shift, u32 mask)
{
return ((state >> shift)) & mask;
};
#define to_tmc_chip(chip) \
container_of((chip), struct tmc_gpio_chip, gpio)
/*
* tmc_gpio_multiple_bitsop - Generic TMC GPIO multiple bits operation
*/
static void tmc_gpio_multiple_bitsop(struct tmc_gpio_chip *chip,
unsigned int gpiono, u32 group, u32 offset, bool set)
{
u32 gpio_state, led_val, bit_shift;
unsigned long flags;
void __iomem *iobase;
iobase = chip->base + offset;
dev_dbg(chip->dev, "TMC GPIO multiple bitop group=%u, "
"gpiono=%u, offet:=%u, set=%u\n", group, gpiono, offset, set);
spin_lock_irqsave(&chip->gpio_lock, flags);
switch (group) {
case QSFP_LED_LANE0_GREEN:
case SFP_LED_LANE0_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_GREEN_LED_VALUE;
bit_shift = TMC_PFE_LANE0_GREEN_LED_BIT_POSITION;
break;
case QSFP_LED_LANE1_GREEN:
case SFP_LED_LANE1_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_GREEN_LED_VALUE;
bit_shift = TMC_PFE_LANE1_GREEN_LED_BIT_POSITION;
break;
case QSFP_LED_LANE2_GREEN:
case SFP_LED_LANE2_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_GREEN_LED_VALUE;
bit_shift = TMC_PFE_LANE2_GREEN_LED_BIT_POSITION;
break;
case QSFP_LED_LANE3_GREEN:
case SFP_LED_LANE3_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_GREEN_LED_VALUE;
bit_shift = TMC_PFE_LANE3_GREEN_LED_BIT_POSITION;
break;
case QSFP_LED_LANE0_BEACON:
case SFP_LED_LANE0_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_BEACON_LED_VALUE;
bit_shift = TMC_PFE_LANE0_BEACON_LED_BIT_POSITION;
break;
case QSFP_LED_LANE1_BEACON:
case SFP_LED_LANE1_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_BEACON_LED_VALUE;
bit_shift = TMC_PFE_LANE1_BEACON_LED_BIT_POSITION;
break;
case QSFP_LED_LANE2_BEACON:
case SFP_LED_LANE2_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_BEACON_LED_VALUE;
bit_shift = TMC_PFE_LANE2_BEACON_LED_BIT_POSITION;
break;
case QSFP_LED_LANE3_BEACON:
case SFP_LED_LANE3_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_BEACON_LED_VALUE;
bit_shift = TMC_PFE_LANE3_BEACON_LED_BIT_POSITION;
break;
case QSFP_LED_LANE0_FAULT:
case SFP_LED_LANE0_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_FAULT_LED_VALUE;
bit_shift = TMC_PFE_LANE0_FAULT_LED_BIT_POSITION;
break;
case QSFP_LED_LANE1_FAULT:
case SFP_LED_LANE1_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_FAULT_LED_VALUE;
bit_shift = TMC_PFE_LANE1_FAULT_LED_BIT_POSITION;
break;
case QSFP_LED_LANE2_FAULT:
case SFP_LED_LANE2_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_FAULT_LED_VALUE;
bit_shift = TMC_PFE_LANE2_FAULT_LED_BIT_POSITION;
break;
case QSFP_LED_LANE3_FAULT:
case SFP_LED_LANE3_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_FAULT_LED_VALUE;
bit_shift = TMC_PFE_LANE3_FAULT_LED_BIT_POSITION;
break;
default:
spin_unlock_irqrestore(&chip->gpio_lock, flags);
return;
}
if (set) {
gpio_state = tmc_gpio_reset_bits(gpio_state, 0x3, bit_shift);
gpio_state = tmc_gpio_set_bits(gpio_state, led_val, bit_shift);
} else {
gpio_state = tmc_gpio_reset_bits(gpio_state, 0x3, bit_shift);
}
iowrite32(gpio_state, (iobase+(0x004*gpiono)));
spin_unlock_irqrestore(&chip->gpio_lock, flags);
return;
};
/*
* tmc_gpio_one_bitop - Generic TMC GPIO single bit operation
*/
static void tmc_gpio_one_bitop(struct tmc_gpio_chip *chip,
unsigned int bit, u32 offset, bool set)
{
u32 gpio_state;
unsigned long flags;
void __iomem *iobase;
iobase = chip->base + offset;
dev_dbg(chip->dev, "TMC GPIO one bitop bit=%u, offset=%x, "
"set=%u\n", bit, offset, set);
spin_lock_irqsave(&chip->gpio_lock, flags);
gpio_state = ioread32(iobase);
if (set)
gpio_state |= BIT(bit);
else
gpio_state &= ~BIT(bit);
iowrite32(gpio_state, iobase);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
return;
}
/*
* tmc_gpio_get_multiple_bitsop - Generic TMC get GPIO multiple bits operation
*/
static int tmc_gpio_get_multiple_bitsop(struct tmc_gpio_chip *chip,
unsigned int gpiono, u32 group, u32 offset)
{
u32 gpio_state;
void __iomem *iobase;
iobase = chip->base + offset;
dev_dbg(chip->dev, "TMC GPIO get multiple bitsop group=%u, "
"gpiono=%u, offset=%u\n", group, gpiono, offset);
switch (group) {
case QSFP_LED_LANE0_GREEN:
case SFP_LED_LANE0_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_GREEN_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE0_GREEN_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE1_GREEN:
case SFP_LED_LANE1_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_GREEN_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE1_GREEN_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE2_GREEN:
case SFP_LED_LANE2_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_GREEN_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE2_GREEN_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE3_GREEN:
case SFP_LED_LANE3_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_GREEN_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE3_GREEN_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE0_BEACON:
case SFP_LED_LANE0_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_BEACON_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE0_BEACON_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE1_BEACON:
case SFP_LED_LANE1_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_BEACON_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE1_BEACON_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE2_BEACON:
case SFP_LED_LANE2_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_BEACON_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE2_BEACON_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE3_BEACON:
case SFP_LED_LANE3_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_BEACON_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE3_BEACON_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE0_FAULT:
case SFP_LED_LANE0_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_FAULT_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE0_FAULT_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE1_FAULT:
case SFP_LED_LANE1_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_FAULT_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE1_FAULT_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE2_FAULT:
case SFP_LED_LANE2_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_FAULT_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE2_FAULT_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE3_FAULT:
case SFP_LED_LANE3_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_FAULT_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE3_FAULT_LED_BIT_POSITION, 0x3));
default:
return 0;
}
};
/*
* tmc_gpio_get - Read the specified signal of the GPIO device.
*/
static int tmc_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct tmc_gpio_chip *chip = to_tmc_chip(gc);
unsigned int group = TMC_GPIO_FIND_GROUP(gpio);
unsigned int bit = TMC_GPIO_FIND_GPIO(gpio);
if (group >= TMC_PFE_GPIO_GROUP_MAX)
return 0;
switch (group) {
case QSFP_RST:
case QSFP_PRESENT:
case QSFP_PHY_RST:
case QSFP_LPMOD:
dev_dbg(chip->dev, "TMC GPIO get one bitop group=%u, gpio=%u, "
"bit=%u\n", group, gpio, bit);
return !!(ioread32(chip->base + group_offset[group])
& BIT(bit));
default:
return tmc_gpio_get_multiple_bitsop(chip, bit, group, group_offset[group]);
}
}
/*
* tmc_gpio_set - Write the specified signal of the GPIO device.
*/
static void tmc_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct tmc_gpio_chip *chip = to_tmc_chip(gc);
unsigned int group = TMC_GPIO_FIND_GROUP(gpio);
unsigned int bit = TMC_GPIO_FIND_GPIO(gpio);
if (group >= TMC_PFE_GPIO_GROUP_MAX)
return;
switch (group) {
case QSFP_RST:
case QSFP_PRESENT:
case QSFP_PHY_RST:
case QSFP_LPMOD:
dev_dbg(chip->dev, "TMC GPIO one bitop group=%d\n", group);
tmc_gpio_one_bitop(chip, bit, group_offset[group], val);
break;
default:
tmc_gpio_multiple_bitsop(chip, bit, group, group_offset[group], val);
break;
}
}
static struct tmc_gpio_info tmc_gpios[] = {
{
.get = tmc_gpio_get,
.set = tmc_gpio_set,
},
};
static void tmc_gpio_setup(struct tmc_gpio_chip *sgc, int id)
{
struct gpio_chip *chip = &sgc->gpio;
const struct tmc_gpio_info *info = sgc->info;
chip->get = info->get;
chip->set = info->set;
chip->direction_input = info->dirin;
chip->direction_output = info->dirout;
chip->dbg_show = NULL;
chip->can_sleep = 0;
if (id == 0) {
chip->base = 0;
} else if (id == 1) {
chip->base = (gpio_max * id);
} else {
chip->base = -1;
}
chip->ngpio = sgc->ngpio;
chip->label = dev_name(sgc->dev);
chip->parent = sgc->dev;
chip->owner = THIS_MODULE;
}
static int tmc_gpio_of_init(struct device *dev,
struct tmc_gpio_chip *chip)
{
chip->info = &tmc_gpios[0];
chip->ngpio = gpio_max;
return 0;
}
static int tmc_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct tmc_gpio_chip *chip;
struct resource *res;
int ret;
const struct mfd_cell *cell = mfd_get_cell(pdev);
dev_dbg(dev, "TMC GPIO probe\n");
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
dev_info(dev, "TMC GPIO resource 0x%llx, %llu\n",
res->start, resource_size(res));
chip->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!chip->base)
return -ENOMEM;
ret = tmc_gpio_of_init(dev, chip);
if (ret)
return ret;
chip->dev = dev;
spin_lock_init(&chip->gpio_lock);
tmc_gpio_setup(chip, cell->id);
ret = gpiochip_add(&chip->gpio);
if (ret) {
dev_err(dev,
"Failed to register TMC gpiochip : %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, chip);
dev_info(dev, "TMC GPIO registered at 0x%lx, gpiobase: %d\n",
(long unsigned)chip->base, chip->gpio.base);
return 0;
}
static int tmc_gpio_remove(struct platform_device *pdev)
{
struct tmc_gpio_chip *chip = platform_get_drvdata(pdev);
gpiochip_remove(&chip->gpio);
return 0;
}
static struct platform_driver tmc_gpio_driver = {
.driver = {
.name = "gpioslave-tmc",
.owner = THIS_MODULE,
},
.probe = tmc_gpio_probe,
.remove = tmc_gpio_remove,
};
module_platform_driver(tmc_gpio_driver);
MODULE_DESCRIPTION("Juniper Networks TMC FPGA GPIO driver");
MODULE_AUTHOR("Ashish Bhensdadia <bashish@juniper.net>");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,603 @@
/*
* Juniper Networks RE-FPGA qfx platform specific driver
*
* Copyright (C) 2020 Juniper Networks
* Author: Ciju Rajan K <crajank@juniper.net>
*
* This driver implements various features such as
* - ALARM led driver
* - Fan full speed reset control
* - FAN precense detection
* - FAN type detection
* - Any new QFX specific features which uses RE-FPGA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/delay.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#define NUM_LEDS 7 /* Max number of Alarm + FAN LEDs */
#define ALARM_MINOR_LED 0
#define ALARM_MAJOR_LED 1
#define REFPGA_PCIE_RESET_CTRL 0x13
#define REFPGA_PCIE_ALARM 0x33
#define REFPGA_FAN0_CTRL_STAT 0x28
#define REFPGA_RESET_FAN_SPEED BIT(3)
#define REFPGA_OPER_TYPE BIT(0)
#define REFPGA_OPER_START BIT(1)
#define REFPGA_OPER_DONE BIT(2)
#define TMC_REFPGA_ADDR_REG 0x0 /* TMC offset: 0x228 */
#define TMC_REFPGA_DATA_REG 0x4 /* TMC offset: 0x22C */
#define TMC_REFPGA_CTRL_REG 0x8 /* TMC offset: 0x230 */
#define TMC_REFPGA_READ_CMD 0x3
#define TMC_REFPGA_WRITE_CMD 0x2
#define REFPGA_INTR_NR_GROUPS 1
#define REFPGA_INTR_MAX_IRQS_PG 32
#define MAX_FANS 5
#define REFPGA_IRQ_MAX_BITS_PER_REG 32
#define POLL_INTERVAL 5000
#define AFI_MASK (0x01)
#define AFO_MASK (0x02)
#define AFI_AFO_MASK (0x03)
/*
* LED specific data structures
*/
struct refpga_led {
struct led_classdev lc;
struct work_struct work;
int blink;
int on;
int bit;
void __iomem *addr;
};
struct refpga_led_data {
int num_leds;
struct refpga_led *leds;
};
static DEFINE_MUTEX(alarm_led_lock);
/*
* Common routines
*/
struct refpga_chip {
struct refpga_led_data *led;
};
static struct refpga_chip *refpga;
static DEFINE_MUTEX(refpga_lock);
static void __iomem *tmc_membase;
static void wait_for_refpga_oper(void __iomem *base_addr)
{
volatile u32 done = ~(-1);
unsigned long int timeout;
void __iomem *addr;
addr = base_addr + (TMC_REFPGA_CTRL_REG);
/*
* Wait till the transaction is complete
*/
timeout = jiffies + msecs_to_jiffies(100);
do {
usleep_range(50, 100);
done = ioread32(addr);
if (done & (REFPGA_OPER_DONE))
break;
} while(time_before(jiffies, timeout));
}
static u32 refpga_read(void __iomem *base_addr, u32 refpga_offset)
{
u32 value;
mutex_lock(&refpga_lock);
iowrite32(refpga_offset, base_addr + (TMC_REFPGA_ADDR_REG));
iowrite32(TMC_REFPGA_READ_CMD, base_addr + (TMC_REFPGA_CTRL_REG));
wait_for_refpga_oper(base_addr);
value = ioread32(base_addr + (TMC_REFPGA_DATA_REG));
mutex_unlock(&refpga_lock);
return value;
}
static void refpga_write(void __iomem *base_addr, u32 refpga_offset, u32 val)
{
mutex_lock(&refpga_lock);
iowrite32(refpga_offset, base_addr + (TMC_REFPGA_ADDR_REG));
iowrite32(val, base_addr + (TMC_REFPGA_DATA_REG));
iowrite32(TMC_REFPGA_WRITE_CMD, base_addr + (TMC_REFPGA_CTRL_REG));
wait_for_refpga_oper(base_addr);
mutex_unlock(&refpga_lock);
}
static bool get_fan_presense(u8 idx)
{
u8 value = 0x00;
u8 offset = REFPGA_FAN0_CTRL_STAT;
bool ret = 0;
value = refpga_read(tmc_membase, (offset + (idx * 2)));
/*
* Get the last two bits of REFPGA_FANx_CTRL_STAT.
* REFPGA_FANx_CTRL_STAT register of REFPGA gives the fan airflow
* status. There are 5 fans in QFX5200. Last two bits give the AFI
* & AFO status. If any of these bits are set, fan is present.
*/
value = (value & BIT(0)) | (value & BIT(1));
if (value)
ret = 1;
return ret;
}
static int get_fan_type(u8 idx)
{
u8 value = 0x00;
u8 offset = REFPGA_FAN0_CTRL_STAT;
int ret = -1;
value = refpga_read(tmc_membase, (offset + (idx * 2)));
/*
* Get the last two bits of REFPGA_FANx_CTRL_STAT.
* REFPGA_FANx_CTRL_STAT register of REFPGA gives the fan airflow
* status. There are 5 fans in QFX5200. Last two bits give the AFI
* & AFO status. If bit1 is set, it's AFO and if bit 0 is set,
* it's AFI.
*
* This function will return '1' for AFO, '0' for AFI, and '-1'
* if there is no fan or if both AFI & AFO bits are set.
*/
value &= AFI_AFO_MASK;
switch(value) {
case AFI_MASK:
ret = 0;
break;
case AFO_MASK:
ret = 1;
break;
default:
ret = -1;
break;
};
return ret;
}
enum sysfs_fan_attributes {
FAN0_PRESENT,
FAN1_PRESENT,
FAN2_PRESENT,
FAN3_PRESENT,
FAN4_PRESENT,
};
enum sysfs_fan_type_attributes {
FAN0_TYPE,
FAN1_TYPE,
FAN2_TYPE,
FAN3_TYPE,
FAN4_TYPE,
};
/*
* The sysfs files will be present in this path
* /sys/devices/pci0000:00/0000:00:1c.0/0000:0f:00.0/refpga-tmc.15/fan*_present
* /sys/devices/pci0000:00/0000:00:1c.0/0000:0f:00.0/refpga-tmc.15/fan*_type
*/
#define DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(index) \
static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, refpga_fan_presense_show, NULL, FAN##index##_PRESENT)
#define DECLARE_FAN_PRESENT_ATTR(index) &sensor_dev_attr_fan##index##_present.dev_attr.attr
#define DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(index) \
static SENSOR_DEVICE_ATTR(fan##index##_type, S_IRUGO, refpga_fan_type_show, NULL, FAN##index##_TYPE)
#define DECLARE_FAN_TYPE_ATTR(index) &sensor_dev_attr_fan##index##_type.dev_attr.attr
static ssize_t refpga_fan_presense_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr);
return sprintf(buf, "%d\n", get_fan_presense(s_attr->index));
}
static ssize_t refpga_fan_type_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr);
return sprintf(buf, "%d\n", get_fan_type(s_attr->index));
}
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(0);
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(1);
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(2);
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(3);
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(4);
DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(0);
DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(1);
DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(2);
DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(3);
DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(4);
static struct attribute *refpga_fan_attrs[] = {
DECLARE_FAN_PRESENT_ATTR(0),
DECLARE_FAN_PRESENT_ATTR(1),
DECLARE_FAN_PRESENT_ATTR(2),
DECLARE_FAN_PRESENT_ATTR(3),
DECLARE_FAN_PRESENT_ATTR(4),
DECLARE_FAN_TYPE_ATTR(0),
DECLARE_FAN_TYPE_ATTR(1),
DECLARE_FAN_TYPE_ATTR(2),
DECLARE_FAN_TYPE_ATTR(3),
DECLARE_FAN_TYPE_ATTR(4),
NULL
};
static struct attribute_group refpga_fan_attr_group = {
.attrs = refpga_fan_attrs,
};
/*
* There is only a single ALARM led in QFX5200 and that
* is used for both Major & Minor alarm indicator.
* These are represented by two different bits in RE-FPGA
* PCIE_ALARM register. Only one of the bit (either Red or
* Yellow) should be set a time. If both the bits are set,
* it's an undefined behaviour.
*
* The following table describes how the conditions are
* handled in the driver as there can be both Major & Minor
* alarms can be triggered from userspace.
*
* Major Minor Colour
*
* 0 0 Nil
* 0 1 Yellow
* 1 1 Red
* 1 0 Red
*
*/
static void manage_alarm_led(void __iomem *addr, int led_type, int value)
{
static int alarm_major = 0, alarm_minor = 0;
u32 reg = 0x0;
mutex_lock(&alarm_led_lock);
reg = refpga_read(addr, REFPGA_PCIE_ALARM);
(led_type == ALARM_MAJOR_LED) ?
((value == 1) ? (alarm_major = 1) : (alarm_major = 0)) :
((value == 1) ? (alarm_minor = 1) : (alarm_minor = 0));
if (alarm_major) {
reg &= ~BIT(ALARM_MINOR_LED);
reg |= BIT(ALARM_MAJOR_LED);
} else {
if (alarm_minor) {
reg &= ~BIT(ALARM_MAJOR_LED);
reg |= BIT(ALARM_MINOR_LED);
} else {
reg &= ~BIT(ALARM_MINOR_LED);
reg &= ~BIT(ALARM_MAJOR_LED);
}
}
refpga_write(addr, REFPGA_PCIE_ALARM, reg);
mutex_unlock(&alarm_led_lock);
}
static void manage_fan_led(void __iomem *addr, int fan_slot, int value)
{
u8 offset = REFPGA_FAN0_CTRL_STAT + (fan_slot * 2);
u32 reg = 0x0;
reg = refpga_read(addr, offset);
if(value) {
/* Turn on s/w control */
reg = reg | BIT(4);
/* Turn off green led */
reg &= ~BIT(5);
/* Turn on yellow led & make it blink */
reg |= (BIT(6) | BIT(7));
} else {
/* Clear yellow led & stop blink */
reg &= ~(BIT(6) | BIT(7));
/* Stop s/w control */
reg &= ~BIT(4);
}
refpga_write(addr, offset, reg);
}
static void refpga_led_work(struct work_struct *work)
{
struct refpga_led *led = container_of(work, struct refpga_led, work);
void __iomem *addr;
addr = led->addr;
if(strstr(led->lc.name, "fan"))
manage_fan_led(addr, led->bit, led->on);
else
manage_alarm_led(addr, led->bit, led->on);
}
static void refpga_led_brightness_set(struct led_classdev *lc,
enum led_brightness brightness)
{
struct refpga_led *led = container_of(lc, struct refpga_led, lc);
led->on = (brightness != LED_OFF);
led->blink = 0; /* always turn off hw blink on brightness_set() */
schedule_work(&led->work);
}
struct led_table
{
const char *name;
int reg;
};
static struct led_table qfx5200_led_data[] = {
{
.name = "alarm-minor",
.reg = 0,
},
{
.name = "alarm-major",
.reg = 1,
},
{
.name = "fan0-fault",
.reg = 0,
},
{
.name = "fan1-fault",
.reg = 1,
},
{
.name = "fan2-fault",
.reg = 2,
},
{
.name = "fan3-fault",
.reg = 3,
},
{
.name = "fan4-fault",
.reg = 4,
}
};
static int refpga_led_init_one(struct device *dev,
struct refpga_led_data *ild,
int num)
{
struct refpga_led *led;
int ret = 0;
led = &ild->leds[num];
led->addr = tmc_membase;
led->lc.name = qfx5200_led_data[num].name;
led->bit = qfx5200_led_data[num].reg;
led->lc.brightness = LED_OFF;
led->lc.brightness_set = refpga_led_brightness_set;
ret = devm_led_classdev_register(dev, &led->lc);
if (ret) {
dev_err(dev, "devm_led_classdev_register failed\n");
return ret;
}
INIT_WORK(&led->work, refpga_led_work);
return 0;
}
static int refpga_led_qfx5200_init(struct device *dev, struct refpga_led_data *ild)
{
int ret = 0, idx = 0;
if (!dev->parent) {
dev_err(dev, "dev->parent is null\n");
return -ENODEV;
}
ild->num_leds = NUM_LEDS;
ild->leds = devm_kzalloc(dev, sizeof(struct refpga_led) * NUM_LEDS,
GFP_KERNEL);
if (!ild->leds) {
dev_err(dev, "LED allocation failed\n");
return -ENOMEM;
}
for(idx=0; idx<NUM_LEDS; idx++){
ret = refpga_led_init_one(dev, ild, idx);
if (ret)
return ret;
}
return 0;
}
static int jnx_refpga_led_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct refpga_led_data *ild;
int ret;
ild = devm_kzalloc(dev, sizeof(*ild), GFP_KERNEL);
if (!ild) {
dev_err(dev, "ild allocation failed\n");
return -ENOMEM;
}
ret = refpga_led_qfx5200_init(dev, ild);
if (ret < 0)
return ret;
refpga->led = ild;
return 0;
}
static int jnx_refpga_led_remove(struct platform_device *pdev)
{
struct refpga_chip *drv_data = platform_get_drvdata(pdev);
struct refpga_led_data *ild = drv_data->led;
int i;
for (i = 0; i < ild->num_leds; i++) {
devm_led_classdev_unregister(&pdev->dev, &ild->leds[i].lc);
cancel_work_sync(&ild->leds[i].work);
}
if (ild) {
if (ild->leds)
devm_kfree(&pdev->dev, ild->leds);
devm_kfree(&pdev->dev, ild);
}
return 0;
}
static void reset_fan_full_speed(struct device *dev)
{
u32 val = ~(-1), tmp = ~(-1);
/*
* Reading the REFPGA_PCIE_RESET_CTRL register
*/
val = refpga_read(tmc_membase, REFPGA_PCIE_RESET_CTRL);
/*
* Clearing the fan full_speed bit
*/
val &= ~(REFPGA_RESET_FAN_SPEED);
/*
* Writing the REFPGA_PCIE_RESET_CTRL register
*/
refpga_write(tmc_membase, REFPGA_PCIE_RESET_CTRL, val);
/*
* Reading the REFPGA_PCIE_RESET_CTRL register
*/
tmp = refpga_read(tmc_membase, REFPGA_PCIE_RESET_CTRL);
dev_info(dev, "After resetting fan full speed control: %X\n", tmp);
}
static int jnx_refpga_tmc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
int ret = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "resource allocation failed\n");
return -ENODEV;
}
tmc_membase = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!tmc_membase) {
dev_err(dev, "ioremap failed\n");
return -ENOMEM;
}
refpga = devm_kzalloc(dev, sizeof(*refpga), GFP_KERNEL);
if (!refpga) {
dev_err(dev, "refpga memory allocation failed\n");
return -ENOMEM;
}
reset_fan_full_speed(dev);
ret = jnx_refpga_led_probe(pdev);
if (ret != 0) {
dev_err(dev, "Refpga LED probe failed\n");
return ret;
}
dev_info(dev, "Refpga LED probe successful: TMC memoy base: %p\n",
tmc_membase);
ret = sysfs_create_group(&dev->kobj, &refpga_fan_attr_group);
if (ret != 0) {
dev_err(dev, "sysfs_create_group failed: %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, refpga);
return 0;
}
static int jnx_refpga_tmc_remove(struct platform_device *pdev)
{
jnx_refpga_led_remove(pdev);
sysfs_remove_group(&pdev->dev.kobj, &refpga_fan_attr_group);
return 0;
}
static struct platform_driver jnx_refpga_tmc_driver = {
.driver = {
.name = "refpga-tmc",
.owner = THIS_MODULE,
},
.probe = jnx_refpga_tmc_probe,
.remove = jnx_refpga_tmc_remove,
};
static int __init jnx_refpga_tmc_driver_init(void)
{
int ret = -1;
ret = platform_driver_register(&jnx_refpga_tmc_driver);
return ret;
}
static void __exit jnx_refpga_tmc_driver_exit(void)
{
platform_driver_unregister(&jnx_refpga_tmc_driver);
}
module_init(jnx_refpga_tmc_driver_init);
module_exit(jnx_refpga_tmc_driver_exit);
MODULE_DESCRIPTION("Juniper Networks REFPGA / TMC driver");
MODULE_AUTHOR("Ciju Rajan K <crajank@juniper.net>");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,477 @@
/*
* Juniper Networks TMC-FPGA MFD Core driver for qfx platform
*
* Copyright (c) 2020, Juniper Networks
* Author: Ashish Bhensdadia <bashish@juniper.net>
*
* This driver implement the resource publish for below devices
* - I2C
* - GPIO
* - RE FPGA
* - PSU
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/irqdomain.h>
#include <linux/mfd/core.h>
#include "jnx-tmc.h"
#define TMC_DO_SCRATCH_TEST 1
/*
* TMC FPGA Device IDs
*/
#define PCI_VENDOR_ID_JUNIPER 0x1304
#define PCI_DEVICE_ID_JNX_TMC_CHD 0x007B
#define PCI_DEVICE_ID_JNX_TMC_PFE 0x007C
/*
* TMC resources
*/
static struct resource tmc_resource_i2c[] = {
/* I2C AUTOMATION Block */
{
.name = "i2c-tmc",
.start = TMC_I2C_AUTOMATION_I2C_CONTROL_START,
.end = TMC_I2C_AUTOMATION_I2C_CONTROL_END,
.flags = IORESOURCE_MEM,
},
/* I2C DPMEM */
{
.name = "i2c-tmc-mem",
.start = TMC_I2C_DPMEM_ENTRY_START,
.end = TMC_I2C_DPMEM_ENTRY_END,
.flags = IORESOURCE_MEM,
},
};
#define TMC_RES_I2C_NR ARRAY_SIZE(tmc_resource_i2c)
/*
* LED resources
*/
static struct resource tmc_resource_leds[] = {
{
.name = "leds-tmc",
.start = TMC_LED_CONTROL_START,
.end = TMC_LED_CONTROL_END,
.flags = IORESOURCE_MEM,
},
};
#define TMC_RES_LEDS_NR ARRAY_SIZE(tmc_resource_leds)
/*
* TMC RE-FPGA devices
*/
static struct resource tmc_resource_refpga[] = {
{
.name = "refpga-tmc",
.start = TMC_REFPGA_ACCESS_START,
.end = TMC_REFPGA_ACCESS_END,
.flags = IORESOURCE_MEM,
},
};
#define TMC_RES_REFPGA_NR ARRAY_SIZE(tmc_resource_refpga)
static struct resource tmc_resource_gpioslave0[] = {
/* SLAVE0 Block */
{
.name = "gpioslave-tmc",
.start = TMC_GPIO_SLAVE0_START,
.end = TMC_GPIO_SLAVE0_END,
.flags = IORESOURCE_MEM,
}
};
#define TMC_RES_GPIOSLAVE0_NR ARRAY_SIZE(tmc_resource_gpioslave0)
static struct resource tmc_resource_gpioslave1[] = {
/* SLAVE1 Block */
{
.name = "gpioslave-tmc",
.start = TMC_GPIO_SLAVE1_START,
.end = TMC_GPIO_SLAVE1_END,
.flags = IORESOURCE_MEM,
}
};
#define TMC_RES_GPIOSLAVE1_NR ARRAY_SIZE(tmc_resource_gpioslave1)
static struct resource tmc_resource_psu[] = {
/* PSU Block */
{
.name = "psu-tmc",
.start = TMC_PSU_START,
.end = TMC_PSU_END,
.flags = IORESOURCE_MEM,
}
};
#define TMC_RES_PSU_NR ARRAY_SIZE(tmc_resource_psu)
/*
* CHASSISD TMC MFD devices
*/
static struct mfd_cell chassisd_tmc_mfd_devs[] = {
{
.name = "i2c-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_i2c),
.resources = &tmc_resource_i2c[0],
.of_compatible = "jnx,i2c-tmc",
.id = 0,
},
{
.name = "leds-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_leds),
.resources = &tmc_resource_leds[0],
.of_compatible = "jnx,leds-tmc",
.id = 0,
},
{
.name = "refpga-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_refpga),
.resources = &tmc_resource_refpga[0],
.of_compatible = "jnx,refpga-tmc",
.id = 0,
},
{
.name = "psu-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_psu),
.resources = &tmc_resource_psu[0],
.of_compatible = "jnx,psu-tmc",
.id = 0,
},
};
/*
* PFE TMC MFD devices
*/
static struct mfd_cell pfe_tmc_mfd_devs[] = {
{
.name = "i2c-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_i2c),
.resources = &tmc_resource_i2c[0],
.of_compatible = "jnx,i2c-tmc",
.id = 1,
},
{
.name = "gpioslave-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_gpioslave0),
.resources = &tmc_resource_gpioslave0[0],
.of_compatible = "jnx,gpioslave-tmc",
.id = 0,
},
{
.name = "gpioslave-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_gpioslave1),
.resources = &tmc_resource_gpioslave1[0],
.of_compatible = "jnx,gpioslave-tmc",
.id = 1,
},
};
struct tmc_fpga_data {
void __iomem *membase;
struct pci_dev *pdev;
u32 major; /* Device id & Major version*/
u32 minor; /* Minor version */
u32 optic_cpld_major; /* optic cpld major version */
u32 optic_cpld_minor; /* optic cpld minor version */
u32 optic_cpld_devid; /* optic cpld device id */
};
/* sysfs entries */
static ssize_t major_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(dev);
return sprintf(buf, "0x%02X_%06X\n",
(tmc->major >> 24) & 0xff,
tmc->major & 0xffffff);
}
static ssize_t minor_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(dev);
return sprintf(buf, "%02X\n", (tmc->minor) & 0xff);
}
static ssize_t optic_cpld_major_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(dev);
return sprintf(buf, "%01X\n", tmc->optic_cpld_major & 0xf);
}
static ssize_t optic_cpld_devid_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(dev);
return sprintf(buf, "%01X\n",
(tmc->optic_cpld_major >> 4) & 0xf);
}
static ssize_t optic_cpld_minor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(dev);
return sprintf(buf, "%02X\n", tmc->optic_cpld_minor & 0xff);
}
static ssize_t set_sys_shutdown(struct device *dev,
struct device_attribute *devattr,
const char *buf,
size_t len)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(dev);
unsigned long val;
int ret;
ret = kstrtoul(buf, 0, &val);
if (ret < 0)
return ret;
if (val != 1)
return -EINVAL;
/* Unlock the shutdown register */
iowrite32(0x12345678, tmc->membase + TMC_SYS_SHUTDOWN_LOCK);
iowrite32(0x1, tmc->membase + TMC_SYS_SHUTDOWN);
return len;
}
static DEVICE_ATTR(major, S_IRUGO, major_show, NULL);
static DEVICE_ATTR(minor, S_IRUGO, minor_show, NULL);
static DEVICE_ATTR(optic_cpld_major, S_IRUGO, optic_cpld_major_show, NULL);
static DEVICE_ATTR(optic_cpld_devid, S_IRUGO, optic_cpld_devid_show, NULL);
static DEVICE_ATTR(optic_cpld_minor, S_IRUGO, optic_cpld_minor_show, NULL);
static DEVICE_ATTR(shutdown, S_IWUSR, NULL, set_sys_shutdown);
static struct attribute *tmc_attrs[] = {
&dev_attr_major.attr,
&dev_attr_minor.attr,
&dev_attr_optic_cpld_major.attr,
&dev_attr_optic_cpld_devid.attr,
&dev_attr_optic_cpld_minor.attr,
&dev_attr_shutdown.attr,
NULL,
};
static struct attribute_group tmc_attr_group = {
.attrs = tmc_attrs,
};
#if defined TMC_DO_SCRATCH_TEST
/* Do a quick scratch access test */
static int tmc_do_test_scratch(struct tmc_fpga_data *tmc)
{
struct pci_dev *pdev = tmc->pdev;
struct device *dev = &pdev->dev;
int offset = TMC_SCRATCH;
u32 acc, val = 0xdeadbeaf;
/*
* Check rw register access -> use the scratch reg.
*/
iowrite32(val, tmc->membase + offset);
acc = ioread32(tmc->membase + offset);
if (acc != val) {
dev_err(dev, "Tmc scratch(0x%x) failed: %08x.%08x!\n",
offset, val, acc);
return -EIO;
}
for (val = 0; val < 0xf0000000; val += 0x01010101) {
iowrite32(val, tmc->membase + offset);
acc = ioread32(tmc->membase + offset);
if (acc != val) {
dev_err(dev, "Tmc scratch(0x%x) failed: %08x.%08x!\n",
offset, val, acc);
return -EIO;
}
}
/*
* Write a sig before leaving..
*/
val = 0xcafebabe;
iowrite32(val, tmc->membase + offset);
dev_dbg(dev, "Tmc scratch result: 0x%08x\n",
ioread32(tmc->membase + offset));
return 0;
}
#endif /* TMC_DO_SCRATCH_TEST */
static int tmc_fpga_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
int err;
struct tmc_fpga_data *tmc;
struct device *dev = &pdev->dev;
dev_dbg(dev, "Tmc FPGA Probe called\n");
tmc = devm_kzalloc(dev, sizeof(*tmc), GFP_KERNEL);
if (!tmc)
return -ENOMEM;
err = pcim_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "Failed to enable device %d\n", err);
return err;
}
err = pcim_iomap_regions(pdev, 1 << 0, "tmc-core");
if (err) {
dev_err(&pdev->dev, "Failed to iomap regions %d\n", err);
goto err_disable;
}
tmc->membase = pcim_iomap_table(pdev)[0];
if (IS_ERR(tmc->membase)) {
dev_err(dev, "pci_ioremap_bar() failed\n");
err = -ENOMEM;
goto err_release;
}
tmc->pdev = pdev;
pci_set_drvdata(pdev, tmc);
/* All Tmc uses MSI interrupts - enable bus mastering */
pci_set_master(pdev);
#if defined TMC_DO_SCRATCH_TEST
/* Check IO before proceeding */
dev_dbg(dev, "Tmc FPGA starting scratch test\n");
err = tmc_do_test_scratch(tmc);
if (err)
goto err_unmap;
dev_dbg(dev, "Tmc FPGA scratch test passed !!!\n");
#endif /* TMC_DO_SCRATCH_TEST */
switch (id->device) {
case PCI_DEVICE_ID_JNX_TMC_CHD:
err = mfd_add_devices(dev, pdev->bus->number,
&chassisd_tmc_mfd_devs[0],
ARRAY_SIZE(chassisd_tmc_mfd_devs),
&pdev->resource[0],
0, NULL /* tmc->irq_domain */);
break;
case PCI_DEVICE_ID_JNX_TMC_PFE:
err = mfd_add_devices(dev, pdev->bus->number,
&pfe_tmc_mfd_devs[0],
ARRAY_SIZE(pfe_tmc_mfd_devs),
&pdev->resource[0],
0, NULL /* tmc->irq_domain */);
break;
default:
dev_err(&pdev->dev, "Invalid PCI Device ID id:%d\n",
id->device);
goto err_unmap;
}
if (err < 0) {
dev_err(&pdev->dev, "Failed to add mfd devices %d\n", err);
goto err_unmap;
}
err = sysfs_create_group(&pdev->dev.kobj, &tmc_attr_group);
if (err) {
sysfs_remove_group(&pdev->dev.kobj, &tmc_attr_group);
dev_err(&pdev->dev, "Failed to create attr group\n");
goto err_remove_mfd;
}
tmc->major = ioread32(tmc->membase + TMC_REVISION);
tmc->minor = ioread32(tmc->membase + TMC_MINOR);
tmc->optic_cpld_major = ioread32(tmc->membase + TMC_OPTIC_CPLD_MAJOR);
tmc->optic_cpld_minor = ioread32(tmc->membase + TMC_OPTIC_CPLD_MINOR);
dev_info(dev, "Tmc FPGA Revision: 0x%02X_%06X, Minor: %02X\n",
(tmc->major >> 24) & 0xff,
tmc->major & 0xffffff,
(tmc->minor) & 0xff);
dev_info(dev, "Tmc FPGA optic cpld Major: 0x%01X, Minor: 0x%02X "
"Devid: 0x%01X\n", (tmc->optic_cpld_major) & 0xf,
(tmc->optic_cpld_minor) & 0xff,
(tmc->optic_cpld_major >> 4) & 0xf);
dev_info(dev, "Tmc FPGA mem:0x%lx\n",
(unsigned long)tmc->membase);
return 0;
err_remove_mfd:
mfd_remove_devices(dev);
err_unmap:
pci_iounmap(pdev, tmc->membase);
err_release:
pci_release_regions(pdev);
err_disable:
pci_disable_device(pdev);
return err;
}
static void tmc_fpga_remove(struct pci_dev *pdev)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(&pdev->dev);
sysfs_remove_group(&pdev->dev.kobj, &tmc_attr_group);
mfd_remove_devices(&pdev->dev);
}
static const struct pci_device_id tmc_fpga_id_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_JUNIPER, PCI_DEVICE_ID_JNX_TMC_CHD) },
{ PCI_DEVICE(PCI_VENDOR_ID_JUNIPER, PCI_DEVICE_ID_JNX_TMC_PFE) },
{ }
};
MODULE_DEVICE_TABLE(pci, tmc_fpga_id_tbl);
static struct pci_driver tmc_fpga_driver = {
.name = "tmc-core",
.id_table = tmc_fpga_id_tbl,
.probe = tmc_fpga_probe,
.remove = tmc_fpga_remove,
};
module_pci_driver(tmc_fpga_driver);
MODULE_DESCRIPTION("Juniper Networks TMC FPGA MFD core driver");
MODULE_AUTHOR("Ashish Bhensdadia <bashish@juniper.net>");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,93 @@
/*
* Juniper Tmc FPGA register definitions
*
* Copyright (C) 2018 Juniper Networks
* Author: Ashish Bhensdadia <bashish@juniper.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __JNX_TMC_H__
#define __JNX_TMC_H__
#define TMC_REVISION 0x00064
#define TMC_MINOR 0x00068
#define TMC_SCRATCH 0x00098
#define TMC_OPTIC_CPLD_MAJOR 0x00104
#define TMC_OPTIC_CPLD_MINOR 0x00108
/*
* I2C Master Block
*/
#define TMC_I2C_AUTOMATION_I2C_CONTROL_START 0x07000
#define TMC_I2C_AUTOMATION_I2C_CONTROL_END 0x07500
#define TMC_I2C_DPMEM_ENTRY_START 0x10000
#define TMC_I2C_DPMEM_ENTRY_END 0x13FFC
#define TMC_LED_CONTROL_START 0x58
#define TMC_LED_CONTROL_END 0x5B
/*
* RE-FPGA block
*/
#define TMC_REFPGA_ACCESS_START 0x228
#define TMC_REFPGA_ACCESS_END 0x233
#define TMC_I2C_MASTER_NR_MSTRS 16
#define TMC_I2C_MSTR_MAX_GROUPS 66
/*
* TMC GPIO SLAVE Block
*/
#define TMC_GPIO_PTP_RESET_START 0x94
#define TMC_GPIO_PTP_RESET_END 0x97
#define TMC_GPIO_PTP_CFG_START 0xa4
#define TMC_GPIO_PTP_CFG_END 0xa7
#define TMC_GPIO_PTP_DATA_START 0xa8
#define TMC_GPIO_PTP_DATA_END 0xab
#define TMC_GPIO_SLAVE0_START 0xf0
#define TMC_GPIO_SLAVE0_END 0x16b
#define TMC_GPIO_SLAVE1_START 0x170
#define TMC_GPIO_SLAVE1_END 0x1eb
#define TMC_GPIO_SLAVE2_START 0x1f0
#define TMC_GPIO_SLAVE2_END 0x213
#define TMC_GPIO_SLAVE3_START 0x280
#define TMC_GPIO_SLAVE3_END 0x2eb
#define TMC_GPIO_SFP_SLAVE0_START 0x308
#define TMC_GPIO_SFP_SLAVE0_END 0x32b
#define TMC_GPIO_SFP_SLAVE1_START 0x32c
#define TMC_GPIO_SFP_SLAVE1_END 0x34b
/*
* TMC PSU Block
*/
#define TMC_PSU_START 0x240
#define TMC_PSU_END 0x243
/*
* TMC SHUTDOWN REG
*/
#define TMC_SYS_SHUTDOWN_LOCK 0x254
#define TMC_SYS_SHUTDOWN 0x250
/*
* TMC DS100 MUX Block
*/
#define TMC_GPIO_MUX_SLAVE_START 0x26c
#define TMC_GPIO_MUX_SLAVE_END 0x26f
#endif /* __JNX_TMC_H__ */

View File

@ -1,892 +0,0 @@
/*
* A hwmon driver for the juniper_i2c_cpld
*
* Tested and validated on Juniper QFX5210
* Ciju Rajan K <crajank@juniper.net>
*
* Copyright (C) 2013 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/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/list.h>
#define MAX_PORT_NUM 64
#define I2C_RW_RETRY_COUNT 10
#define I2C_RW_RETRY_INTERVAL 60 /* ms */
#define I2C_ADDR_CPLD1 0x60
#define I2C_ADDR_CPLD2 0x62
#define I2C_ADDR_CPLD3 0x64
#define CPLD_ADDRS {I2C_ADDR_CPLD1, I2C_ADDR_CPLD2, I2C_ADDR_CPLD3}
/*
* Number of additional attribute pointers to allocate
* with each call to krealloc
*/
#define ATTR_ALLOC_SIZE 1 /*For last attribute which is NUll.*/
#define NAME_SIZE 24
#define MAX_RESP_LENGTH 48
typedef ssize_t (*show_func)( struct device *dev,
struct device_attribute *attr,
char *buf);
typedef ssize_t (*store_func)(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
enum models {
AS7712_32X,
AS7716_32X,
qfx5210_64X,
AS7312_54X,
PLAIN_CPLD, /*No attribute but add i2c addr to the list.*/
NUM_MODEL
};
enum sfp_func {
HAS_SFP = 1<<0 ,
HAS_QSFP = 1<<1 ,
};
enum common_attrs {
CMN_VERSION,
CMN_ACCESS,
CMN_PRESENT_ALL,
NUM_COMMON_ATTR
};
enum sfp_attrs {
SFP_PRESENT,
SFP_RESET,
SFP_LP_MODE,
NUM_SFP_ATTR
};
struct cpld_sensor {
struct cpld_sensor *next;
char name[NAME_SIZE+1]; /* sysfs sensor name */
struct device_attribute attribute;
bool update; /* runtime sensor update needed */
int data; /* Sensor data. Negative if there was a read error */
u8 reg; /* register */
u8 mask; /* bit mask */
bool invert; /* inverted value*/
};
#define to_cpld_sensor(_attr) \
container_of(_attr, struct cpld_sensor, attribute)
struct cpld_data {
struct device *dev;
struct device *hwmon_dev;
int num_attributes;
struct attribute_group group;
enum models model;
struct cpld_sensor *sensors;
struct mutex update_lock;
bool valid;
unsigned long last_updated; /* in jiffies */
int attr_index;
u16 sfp_num;
u8 sfp_types;
struct model_attrs *cmn_attr;
};
struct cpld_client_node {
struct i2c_client *client;
struct list_head list;
};
struct base_attrs {
const char *name;
umode_t mode;
show_func get;
store_func set;
};
struct attrs {
int reg;
bool invert;
struct base_attrs *base;
};
struct model_attrs {
struct attrs **cmn;
struct attrs **portly;
};
static ssize_t show_bit(struct device *dev,
struct device_attribute *devattr, char *buf);
static ssize_t show_presnet_all(struct device *dev,
struct device_attribute *devattr, char *buf);
static ssize_t set_1bit(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static ssize_t set_byte(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);
int juniper_i2c_cpld_read(u8 cpld_addr, u8 reg);
int juniper_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
struct base_attrs common_attrs[NUM_COMMON_ATTR] =
{
[CMN_VERSION] = {"version", S_IRUGO, show_bit, NULL},
[CMN_ACCESS] = {"access", S_IWUSR, NULL, set_byte},
[CMN_PRESENT_ALL] = {"module_present_all", S_IRUGO, show_presnet_all, NULL},
};
struct attrs as7712_common[] = {
[CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]},
[CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]},
[CMN_PRESENT_ALL] = {0x30, false, &common_attrs[CMN_PRESENT_ALL]},
};
struct attrs qfx5210_common[] = {
[CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]},
[CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]},
[CMN_PRESENT_ALL] = {0x30, false, &common_attrs[CMN_PRESENT_ALL]},
};
struct attrs as7312_common[] = {
[CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]},
[CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]},
[CMN_PRESENT_ALL] = {-1, false, &common_attrs[CMN_PRESENT_ALL]},
};
struct attrs plain_common[] = {
[CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]},
};
struct base_attrs portly_attrs[] =
{
[SFP_PRESENT] = {"module_present", S_IRUGO, show_bit, NULL},
// Only root user will have the privilege to write to sysfs
// [SFP_RESET] = {"module_reset", S_IRUGO|S_IWUGO, show_bit, set_1bit},
[SFP_RESET] = {"module_reset", S_IRUGO|S_IWUSR, show_bit, set_1bit},
};
struct attrs as7712_port[] = {
{0x30, true, &portly_attrs[SFP_PRESENT]},
{0x04, true, &portly_attrs[SFP_RESET]},
};
struct attrs qfx5210_port[] = {
{0x70, true, &portly_attrs[SFP_PRESENT]},
{0x40, true, &portly_attrs[SFP_RESET]},
};
struct attrs *as7712_cmn_list[] = {
&as7712_common[CMN_VERSION],
&as7712_common[CMN_ACCESS],
&as7712_common[CMN_PRESENT_ALL],
NULL
};
struct attrs *qfx5210_cmn_list[] = {
&qfx5210_common[CMN_VERSION],
&qfx5210_common[CMN_ACCESS],
&qfx5210_common[CMN_PRESENT_ALL],
NULL
};
struct attrs *as7312_cmn_list[] = {
&as7312_common[CMN_VERSION],
&as7312_common[CMN_ACCESS],
&as7312_common[CMN_PRESENT_ALL],
NULL
};
struct attrs *plain_cmn_list[] = {
&plain_common[CMN_VERSION],
NULL
};
struct attrs *as7712_port_list[] = {
&as7712_port[SFP_PRESENT],
&as7712_port[SFP_RESET],
NULL
};
struct attrs *qfx5210_port_list[] = {
&qfx5210_port[SFP_PRESENT],
&qfx5210_port[SFP_RESET],
NULL
};
struct model_attrs models_attr[NUM_MODEL] = {
{.cmn = as7712_cmn_list, .portly=as7712_port_list},
{.cmn = as7712_cmn_list, .portly=as7712_port_list}, /*7716's as 7712*/
{.cmn = qfx5210_cmn_list, .portly=qfx5210_port_list},
{.cmn = as7312_cmn_list, .portly=qfx5210_port_list},
{.cmn = plain_cmn_list, .portly=NULL},
};
static LIST_HEAD(cpld_client_list);
static struct mutex list_lock;
/* Addresses scanned for juniper_i2c_cpld
*/
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
static int get_sfp_spec(int model, u16 *num, u8 *types)
{
switch (model) {
case AS7712_32X:
case AS7716_32X:
*num = 32;
*types = HAS_QSFP;
break;
case qfx5210_64X:
*num = 64;
*types = HAS_QSFP;
break;
case AS7312_54X:
*num = 54;
*types = HAS_QSFP|HAS_SFP;
default:
*types = 0;
*num = 0;
break;
}
return 0;
}
static int get_present_reg(int model, u8 port, u8 *cpld_addr, u8 *reg, u8 *num)
{
u8 cpld_address[] = CPLD_ADDRS;
switch (model) {
case AS7312_54X:
if (port < 48) {
*cpld_addr = cpld_address[1 + port/24];
*reg = 0x09 + (port%24)/8;
*num = 8;
}
else
{
*reg = 0x18;
*num = 4;
*cpld_addr = ( port < 52)? cpld_address[1]: cpld_address[2];
}
break;
default:
return -EINVAL;
}
}
/*Assume the bits for ports are listed in-a-row.*/
static int get_reg_bit(u8 reg_start, int port,
u8 *reg ,u8 *mask)
{
*reg = reg_start + ((port)/8);
*mask = 1 << ((port)%8);
return 0;
}
static int 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;
}
static int 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;
}
/*Turn a numberic array into string with " " between each element.
* e.g., {0x11, 0x33, 0xff, 0xf1} => "11 33 ff f1"
*/
static ssize_t array_stringify(char *buf, u8 *input, size_t size) {
int i;
char t[MAX_RESP_LENGTH+1];
buf[0] = '\0';
for (i = 0; i < size; i++) {
snprintf(t, MAX_RESP_LENGTH, "%x ", input[i]);
strncat(buf, t, MAX_RESP_LENGTH);
}
if (strlen(buf) > 0)
buf[strlen(buf)-1] = '\0'; /*Remove tailing blank*/
return snprintf(buf, MAX_RESP_LENGTH, "%s\n", buf);
}
static ssize_t show_presnet_all_distinct(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct cpld_data *data = i2c_get_clientdata(client);
u8 i, value, reg;
u8 cpld_addr, num;
u8 _value[8];
u64 *values = (u64 *)_value;
values = 0;
mutex_lock(&data->update_lock);
while(i < data->sfp_num)
{
get_present_reg(data->model, i, &cpld_addr, &reg, &num);
if(cpld_addr == client->addr)
value = cpld_read_internal(client, reg);
else
value = juniper_i2c_cpld_read(cpld_addr, reg);
if (unlikely(value < 0)) {
goto exit;
}
*values |= (value&((1<<(num))-1)) << i;
i += num;
}
mutex_unlock(&data->update_lock);
*values = cpu_to_le64(*values);
return array_stringify(buf, _value, i);
exit:
mutex_unlock(&data->update_lock);
return value;
}
static ssize_t show_presnet_all(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct cpld_data *data = i2c_get_clientdata(client);
struct cpld_sensor *sensor = to_cpld_sensor(devattr);
u8 i, values[MAX_RESP_LENGTH/8];
if (sensor->reg < 0) {
return show_presnet_all_distinct(dev, devattr, buf);
}
mutex_lock(&data->update_lock);
for (i = 0; i < ((data->sfp_num+7)/8); i++) {
values[i] = cpld_read_internal(client, sensor->reg + i);
if (unlikely(values[i] < 0)) {
goto exit;
}
}
mutex_unlock(&data->update_lock);
return array_stringify(buf, values, i);
exit:
mutex_unlock(&data->update_lock);
return values[i];
}
static ssize_t show_bit(struct device *dev,
struct device_attribute *devattr, char *buf)
{
int value;
struct i2c_client *client = to_i2c_client(dev);
struct cpld_data *data = i2c_get_clientdata(client);
struct cpld_sensor *sensor = to_cpld_sensor(devattr);
mutex_lock(&data->update_lock);
value = cpld_read_internal(client, sensor->reg);
value = value & sensor->mask;
if (sensor->invert)
value = !value;
mutex_unlock(&data->update_lock);
return snprintf(buf, PAGE_SIZE, "%x\n", value);
}
static ssize_t set_1bit(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
long is_reset;
int value, status;
struct i2c_client *client = to_i2c_client(dev);
struct cpld_data *data = i2c_get_clientdata(client);
struct cpld_sensor *sensor = to_cpld_sensor(devattr);
u8 cpld_bit, reg;
status = kstrtol(buf, 10, &is_reset);
if (status) {
return status;
}
reg = sensor->reg;
cpld_bit = sensor->mask;
mutex_lock(&data->update_lock);
value = cpld_read_internal(client, reg);
if (unlikely(status < 0)) {
goto exit;
}
if (sensor->invert)
is_reset = !is_reset;
if (is_reset) {
value |= cpld_bit;
}
else {
value &= ~cpld_bit;
}
status = cpld_write_internal(client, reg, value);
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_byte(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
return access(dev, da, buf, count);
}
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 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 = 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 juniper_i2c_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 juniper_i2c_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 int cpld_add_attribute(struct cpld_data *data, struct attribute *attr)
{
int new_max_attrs = ++data->num_attributes + ATTR_ALLOC_SIZE;
void *new_attrs = krealloc(data->group.attrs,
new_max_attrs * sizeof(void *),
GFP_KERNEL);
if (!new_attrs)
return -ENOMEM;
data->group.attrs = new_attrs;
data->group.attrs[data->num_attributes-1] = attr;
data->group.attrs[data->num_attributes] = NULL;
return 0;
}
static void cpld_dev_attr_init(struct device_attribute *dev_attr,
const char *name, umode_t mode,
show_func show, store_func store)
{
sysfs_attr_init(&dev_attr->attr);
dev_attr->attr.name = name;
dev_attr->attr.mode = mode;
dev_attr->show = show;
dev_attr->store = store;
}
static struct cpld_sensor * add_sensor(struct cpld_data *data,
const char *name,
u8 reg, u8 mask, bool invert,
bool update, umode_t mode,
show_func get, store_func set)
{
struct cpld_sensor *sensor;
struct device_attribute *a;
sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor)
return NULL;
a = &sensor->attribute;
snprintf(sensor->name, sizeof(sensor->name), name);
sensor->reg = reg;
sensor->mask = mask;
sensor->update = update;
sensor->invert = invert;
cpld_dev_attr_init(a, sensor->name,
mode,
get, set);
if (cpld_add_attribute(data, &a->attr))
return NULL;
sensor->next = data->sensors;
data->sensors = sensor;
return sensor;
}
static int add_attributes_cmn(struct cpld_data *data, struct attrs **cmn)
{
u8 reg, i ;
bool invert;
struct attrs *a;
struct base_attrs *b;
if (NULL == cmn)
return -1;
for (i = 0; cmn[i]; i++)
{
a = cmn[i];
reg = a->reg;
invert = a->invert;
b = a->base;
if (NULL == b)
break;
if (add_sensor(data, b->name,
reg, 0xff, invert,
true, b->mode,
b->get, b->set) == NULL)
{
return -ENOMEM;
}
}
return 0;
}
static int add_attributes_portly(struct cpld_data *data, struct attrs **pa)
{
char name[NAME_SIZE+1];
int i, j;
u8 reg, mask, invert;
struct attrs *a;
struct base_attrs *b;
if (NULL == pa)
return -1;
for (i = 0; pa[i]; i++) {
a = pa[i];
invert = a->invert;
b = a->base;
if (b == NULL)
break;
for (j = 0; j < data->sfp_num; j++)
{
snprintf(name, NAME_SIZE, "%s_%d", b->name, j+1);
get_reg_bit(a->reg, j, &reg, &mask);
if (add_sensor(data, name, reg, mask, invert,
true, b->mode, b->get, b->set) == NULL)
{
return -ENOMEM;
}
}
}
return 0;
}
static int add_attributes(struct i2c_client *client,
struct cpld_data *data)
{
struct model_attrs *m = data->cmn_attr;
if (m == NULL)
return -EINVAL;
/* Common attributes.*/
add_attributes_cmn(data, m->cmn);
/* Port-wise attributes.*/
add_attributes_portly(data, m->portly);
return 0;
}
static int juniper_i2c_cpld_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
int status;
struct cpld_data *data = NULL;
struct device *dev = &client->dev;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_dbg(dev, "i2c_check_functionality failed (0x%x)\n", client->addr);
return -EIO;
}
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data) {
return -ENOMEM;
}
data->model = dev_id->driver_data;
data->cmn_attr = &models_attr[data->model];
get_sfp_spec(data->model, &data->sfp_num, &data->sfp_types);
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
data->dev = dev;
dev_info(dev, "chip found\n");
status = add_attributes(client, data);
if (status)
goto out_kfree;
/*
* If there are no attributes, something is wrong.
* Bail out instead of trying to register nothing.
*/
if (!data->num_attributes) {
dev_err(dev, "No attributes found\n");
status = -ENODEV;
goto out_kfree;
}
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &data->group);
if (status) {
goto out_kfree;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
status = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
juniper_i2c_cpld_add_client(client);
dev_info(dev, "%s: cpld '%s'\n",
dev_name(data->hwmon_dev), client->name);
return 0;
exit_remove:
sysfs_remove_group(&client->dev.kobj, &data->group);
out_kfree:
kfree(data->group.attrs);
return status;
}
static int juniper_i2c_cpld_remove(struct i2c_client *client)
{
struct cpld_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->group);
kfree(data->group.attrs);
juniper_i2c_cpld_remove_client(client);
return 0;
}
int juniper_i2c_cpld_read(u8 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 = i2c_smbus_read_byte_data(cpld_node->client, reg);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(juniper_i2c_cpld_read);
int juniper_i2c_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 = i2c_smbus_write_byte_data(cpld_node->client, reg, value);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(juniper_i2c_cpld_write);
static const struct i2c_device_id juniper_i2c_cpld_id[] = {
{ "cpld_as7712", AS7712_32X},
{ "cpld_as7716", AS7716_32X},
{ "cpld_qfx5210", qfx5210_64X},
{ "cpld_as7312", AS7312_54X},
{ "cpld_plain", PLAIN_CPLD},
{ },
};
MODULE_DEVICE_TABLE(i2c, juniper_i2c_cpld_id);
static struct i2c_driver juniper_i2c_cpld_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "juniper_i2c_cpld",
},
.probe = juniper_i2c_cpld_probe,
.remove = juniper_i2c_cpld_remove,
.id_table = juniper_i2c_cpld_id,
.address_list = normal_i2c,
};
static int __init juniper_i2c_cpld_init(void)
{
mutex_init(&list_lock);
return i2c_add_driver(&juniper_i2c_cpld_driver);
}
static void __exit juniper_i2c_cpld_exit(void)
{
i2c_del_driver(&juniper_i2c_cpld_driver);
}
module_init(juniper_i2c_cpld_init);
module_exit(juniper_i2c_cpld_exit);
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("juniper_i2c_cpld driver");
MODULE_LICENSE("GPL");

View File

@ -1,622 +0,0 @@
/*
* An hwmon driver for the 3Y Power YM-2651Y Power Module
*
* Tested and validated on Juniper QFX5210
* Ciju Rajan K <crajank@juniper.net>
*
* 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,
};
/* 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 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 */
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_id[10]; /* Register value */
u8 mfr_model[10]; /* 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_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_MFR_ID,
PSU_MFR_MODEL,
PSU_MFR_REVISION,
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_linear, 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_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_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_linear, 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_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_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 */
ptr = data->fan_dir;
break;
case PSU_MFR_ID: /* psu_mfr_id */
ptr = data->mfr_id;
break;
case PSU_MFR_MODEL: /* psu_mfr_model */
ptr = data->mfr_model;
break;
case PSU_MFR_REVISION: /* psu_mfr_revision */
ptr = data->mfr_revsion;
break;
default:
return 0;
}
return sprintf(buf, "%s\n", ptr);
}
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);
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 },
{}
};
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;
u8 command;
u8 fan_dir[5] = {0};
struct reg_data_byte regs_byte[] = { {0x19, &data->capability},
{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;
}
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;
}
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);
}
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;
status = ym2651y_read_block(client, command, data->mfr_model,
ARRAY_SIZE(data->mfr_model)-1);
data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0';
if (status < 0)
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
/* 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);
data->last_updated = jiffies;
data->valid = 1;
}
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

@ -23,7 +23,6 @@ MODULE_DIRS:= qfx5210 qfx5200
MODULE_DIR := modules
UTILS_DIR := utils
SERVICE_DIR := service
PLATFORM_DIR := sonic_platform
CONF_DIR := conf
%:
@ -38,7 +37,7 @@ build:
#make modules -C $(KERNEL_SRC)/build M=$(MODULE_SRC)
(for mod in $(MODULE_DIRS); do \
make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules || exit 1; \
$(PYTHON) $${mod}/setup.py build; \
$(PYTHON) setup.py build; \
done)
binary: binary-arch binary-indep
@ -65,7 +64,7 @@ binary-indep:
cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \
cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \
$(PYTHON) $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \
$(PYTHON) setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \
done)
# Resuming debhelper scripts
dh_testroot

View File

@ -1,5 +1,3 @@
qfx5200/utils/juniper_qfx5200_util.py usr/local/bin
qfx5200/utils/juniper_qfx5200_monitor.py usr/local/bin
qfx5200/sonic_platform/chassis.py usr/lib/python2.7/dist-packages/sonic_platform
qfx5200/sonic_platform/platform.py usr/lib/python2.7/dist-packages/sonic_platform
qfx5200/service/qfx5200-platform-init.service etc/systemd/system

View File

@ -1,661 +0,0 @@
/*
* Juniper Networks TMC GPIO driver
*
* Copyright (C) 2020 Juniper Networks
* Author: Ashish Bhensdadia <bashish@juniper.net>
*
* This driver implement the GPIO set/get functionality
*
* 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; version 2 of the License.
*
* 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.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include "jnx-tmc.h"
#define TMC_GPIO_MAX_BITS_PER_REG 16
#define TMC_GPIO_SFP_MAX_BITS_PER_REG 2
#define TMC_GPIO_PTPCFG_MAX_BITS_PER_REG 8
#define TMC_GPIO_FIND_GROUP(gpio) \
((gpio) / TMC_GPIO_MAX_BITS_PER_REG)
#define TMC_GPIO_FIND_GPIO(gpio) \
((gpio) % TMC_GPIO_MAX_BITS_PER_REG)
#define TMC_GPIO_SFP_FIND_GROUP(gpio) \
((gpio) / TMC_GPIO_SFP_MAX_BITS_PER_REG)
#define TMC_GPIO_SFP_FIND_GPIO(gpio) \
((gpio) % TMC_GPIO_SFP_MAX_BITS_PER_REG)
#define TMC_GPIO_PTPCFG_FIND_GPIO(gpio) \
((gpio) % TMC_GPIO_PTPCFG_MAX_BITS_PER_REG)
#define TMC_GPIO_MAX_NGPIO_PER_GROUP 320
#define TMC_PFE_QSFP_RESET_OFFSET 0x4
#define TMC_PFE_QSFP_PRESENT_OFFSET 0x8
#define TMC_PFE_QSFP_PHY_RESET_OFFSET 0x10
#define TMC_PFE_QSFP_LPMOD_OFFSET 0x78
#define TMC_PFE_QSFP_LED_CTRL_OFFSET 0x20
#define TMC_PFE_LANES_GREEN_LED_VALUE 0x3
#define TMC_PFE_LANE0_GREEN_LED_BIT_POSITION 0
#define TMC_PFE_LANE1_GREEN_LED_BIT_POSITION 2
#define TMC_PFE_LANE2_GREEN_LED_BIT_POSITION 4
#define TMC_PFE_LANE3_GREEN_LED_BIT_POSITION 6
#define TMC_PFE_LANES_BEACON_LED_VALUE 0x2
#define TMC_PFE_LANE0_BEACON_LED_BIT_POSITION 0
#define TMC_PFE_LANE1_BEACON_LED_BIT_POSITION 2
#define TMC_PFE_LANE2_BEACON_LED_BIT_POSITION 4
#define TMC_PFE_LANE3_BEACON_LED_BIT_POSITION 6
#define TMC_PFE_LANES_FAULT_LED_VALUE 0x1
#define TMC_PFE_LANE0_FAULT_LED_BIT_POSITION 0
#define TMC_PFE_LANE1_FAULT_LED_BIT_POSITION 2
#define TMC_PFE_LANE2_FAULT_LED_BIT_POSITION 4
#define TMC_PFE_LANE3_FAULT_LED_BIT_POSITION 6
#define TMC_PFE_SFPSB0_TX_DISABLE_OFFSET 0x0
#define TMC_PFE_SFPSB0_LED_CTRL_OFFSET 0xC
#define TMC_PFE_SFPSB0_LED_ACTIVITY_OFFSET 0x14
#define TMC_PFE_SFPSB0_PRESENT_OFFSET 0x18
#define TMC_PFE_SFPSB0_LOSS_OFFSET 0x1C
#define TMC_PFE_SFPSB0_TX_FAULT_OFFSET 0x20
#define TMC_PFE_SFPSB1_TX_DISABLE_OFFSET 0x0
#define TMC_PFE_SFPSB1_LED_CTRL_OFFSET 0x8
#define TMC_PFE_SFPSB1_LED_ACTIVITY_OFFSET 0x10
#define TMC_PFE_SFPSB1_PRESENT_OFFSET 0x14
#define TMC_PFE_SFPSB1_LOSS_OFFSET 0x18
#define TMC_PFE_SFPSB1_TX_FAULT_OFFSET 0x1C
/*
* Index 4 to 15 is used for QSFP starting with
* QSFP_LED_LANE0_GREEN. To keep multibit set/get common
* starting SFP_LED_LANE0_GREEN with 16 which will avoid
* conflict with QSFP enums.
*/
#define SFP_LED_OP_START_INDEX 16
/*
* Used for off-setting SFP led op index
*/
#define SFP_LED_OP_OFFSET 0xB
/*
* SFP slave blocks
*/
#define SFP_SLAVE0_BLOCK 0x1
#define SFP_SLAVE1_BLOCK 0x2
/*
* each group represent the 16 gpios.
* QSFP_RST - QSFP_LPMODE
* each bit represent the one gpio
* exemple: bits[0:15] - bit0 - gpio0
* QSFP_LED_LANE0_GREEN - QSFP_LED_LANE3_FAULT
* here, number represent the one gpio
* exemple: bits[0:1]
* 00 - gpio off, 01 - gpio on [ gpio0]
* 00 - gpio off, 10 - gpio on [ gpio1]
* 00 - gpio off, 11 - gpio on [ gpio2]
*
*/
enum {
QSFP_RST,
QSFP_PRESENT,
QSFP_PHY_RST,
QSFP_LPMOD,
QSFP_LED_LANE0_GREEN,
QSFP_LED_LANE1_GREEN,
QSFP_LED_LANE2_GREEN,
QSFP_LED_LANE3_GREEN,
QSFP_LED_LANE0_BEACON,
QSFP_LED_LANE1_BEACON,
QSFP_LED_LANE2_BEACON,
QSFP_LED_LANE3_BEACON,
QSFP_LED_LANE0_FAULT,
QSFP_LED_LANE1_FAULT,
QSFP_LED_LANE2_FAULT,
QSFP_LED_LANE3_FAULT,
TMC_PFE_GPIO_GROUP_MAX
};
enum sfp_op {
SFP_TX_DISABLE,
SFP_LED_ACTIVITY,
SFP_PRESENT,
SFP_SFP_LOS,
SFP_TX_FAULT,
SFP_LED_LANE0_GREEN = SFP_LED_OP_START_INDEX,
SFP_LED_LANE1_GREEN,
SFP_LED_LANE2_GREEN,
SFP_LED_LANE3_GREEN,
SFP_LED_LANE0_BEACON,
SFP_LED_LANE1_BEACON,
SFP_LED_LANE2_BEACON,
SFP_LED_LANE3_BEACON,
SFP_LED_LANE0_FAULT,
SFP_LED_LANE1_FAULT,
SFP_LED_LANE2_FAULT,
SFP_LED_LANE3_FAULT,
TMC_PFE_SFP_GPIO_GROUP_MAX
};
static const u32 group_offset[TMC_PFE_GPIO_GROUP_MAX] = {
TMC_PFE_QSFP_RESET_OFFSET,
TMC_PFE_QSFP_PRESENT_OFFSET,
TMC_PFE_QSFP_PHY_RESET_OFFSET,
TMC_PFE_QSFP_LPMOD_OFFSET,
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE0 GREEN */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE1 GREEN */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE2 GREEN */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE3 GREEN */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE0 BEACON */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE1 BEACON */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE2 BEACON */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE3 BEACON */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE0 FAULT */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE1 FAULT */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE2 FAULT */
TMC_PFE_QSFP_LED_CTRL_OFFSET, /* LANE3 FAULT */
};
static const u32 sfp_slaveb0_group_offset[TMC_PFE_SFP_GPIO_GROUP_MAX] = {
TMC_PFE_SFPSB0_TX_DISABLE_OFFSET,
TMC_PFE_SFPSB0_LED_ACTIVITY_OFFSET,
TMC_PFE_SFPSB0_PRESENT_OFFSET,
TMC_PFE_SFPSB0_LOSS_OFFSET,
TMC_PFE_SFPSB0_TX_FAULT_OFFSET,
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE0 GREEN */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE1 GREEN */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE2 GREEN */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE3 GREEN */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE0 BEACON */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE1 BEACON */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE2 BEACON */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE3 BEACON */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE0 FAULT */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE1 FAULT */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE2 FAULT */
TMC_PFE_SFPSB0_LED_CTRL_OFFSET, /* LANE3 FAULT */
};
static const u32 sfp_slaveb1_group_offset[TMC_PFE_SFP_GPIO_GROUP_MAX] = {
TMC_PFE_SFPSB1_TX_DISABLE_OFFSET,
TMC_PFE_SFPSB1_LED_ACTIVITY_OFFSET,
TMC_PFE_SFPSB1_PRESENT_OFFSET,
TMC_PFE_SFPSB1_LOSS_OFFSET,
TMC_PFE_SFPSB1_TX_FAULT_OFFSET,
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE0 GREEN */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE1 GREEN */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE2 GREEN */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE3 GREEN */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE0 BEACON */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE1 BEACON */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE2 BEACON */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE3 BEACON */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE0 FAULT */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE1 FAULT */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE2 FAULT */
TMC_PFE_SFPSB1_LED_CTRL_OFFSET, /* LANE3 FAULT */
};
struct tmc_gpio_info {
int (*get)(struct gpio_chip *, unsigned int);
void (*set)(struct gpio_chip *, unsigned int, int);
int (*dirin)(struct gpio_chip *, unsigned int);
int (*dirout)(struct gpio_chip *, unsigned int, int);
};
struct tmc_gpio_chip {
const struct tmc_gpio_info *info;
void __iomem *base;
struct device *dev;
struct gpio_chip gpio;
int ngpio;
spinlock_t gpio_lock; /* gpio lock */
int sfp_slave_block;
};
/* slave gpio max */
static int gpio_max = 320;
module_param(gpio_max, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(gpio_max, "Maximum number of gpio for SLAVE TMC GPIO");
/*
* generic bit operation functions
*/
static u32 tmc_gpio_reset_bits(u32 state, u32 val, u32 shift)
{
state &= ~(val << shift);
return state;
};
static u32 tmc_gpio_set_bits(u32 state, u32 val, u32 shift)
{
state |= (val << shift);
return state;
};
static u32 tmc_gpio_find_bits_val(u32 state, u32 shift, u32 mask)
{
return ((state >> shift)) & mask;
};
#define to_tmc_chip(chip) \
container_of((chip), struct tmc_gpio_chip, gpio)
/*
* tmc_gpio_multiple_bitsop - Generic TMC GPIO multiple bits operation
*/
static void tmc_gpio_multiple_bitsop(struct tmc_gpio_chip *chip,
unsigned int gpiono, u32 group, u32 offset, bool set)
{
u32 gpio_state, led_val, bit_shift;
unsigned long flags;
void __iomem *iobase;
iobase = chip->base + offset;
dev_dbg(chip->dev, "TMC GPIO multiple bitop group=%u, "
"gpiono=%u, offet:=%u, set=%u\n", group, gpiono, offset, set);
spin_lock_irqsave(&chip->gpio_lock, flags);
switch (group) {
case QSFP_LED_LANE0_GREEN:
case SFP_LED_LANE0_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_GREEN_LED_VALUE;
bit_shift = TMC_PFE_LANE0_GREEN_LED_BIT_POSITION;
break;
case QSFP_LED_LANE1_GREEN:
case SFP_LED_LANE1_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_GREEN_LED_VALUE;
bit_shift = TMC_PFE_LANE1_GREEN_LED_BIT_POSITION;
break;
case QSFP_LED_LANE2_GREEN:
case SFP_LED_LANE2_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_GREEN_LED_VALUE;
bit_shift = TMC_PFE_LANE2_GREEN_LED_BIT_POSITION;
break;
case QSFP_LED_LANE3_GREEN:
case SFP_LED_LANE3_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_GREEN_LED_VALUE;
bit_shift = TMC_PFE_LANE3_GREEN_LED_BIT_POSITION;
break;
case QSFP_LED_LANE0_BEACON:
case SFP_LED_LANE0_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_BEACON_LED_VALUE;
bit_shift = TMC_PFE_LANE0_BEACON_LED_BIT_POSITION;
break;
case QSFP_LED_LANE1_BEACON:
case SFP_LED_LANE1_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_BEACON_LED_VALUE;
bit_shift = TMC_PFE_LANE1_BEACON_LED_BIT_POSITION;
break;
case QSFP_LED_LANE2_BEACON:
case SFP_LED_LANE2_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_BEACON_LED_VALUE;
bit_shift = TMC_PFE_LANE2_BEACON_LED_BIT_POSITION;
break;
case QSFP_LED_LANE3_BEACON:
case SFP_LED_LANE3_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_BEACON_LED_VALUE;
bit_shift = TMC_PFE_LANE3_BEACON_LED_BIT_POSITION;
break;
case QSFP_LED_LANE0_FAULT:
case SFP_LED_LANE0_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_FAULT_LED_VALUE;
bit_shift = TMC_PFE_LANE0_FAULT_LED_BIT_POSITION;
break;
case QSFP_LED_LANE1_FAULT:
case SFP_LED_LANE1_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_FAULT_LED_VALUE;
bit_shift = TMC_PFE_LANE1_FAULT_LED_BIT_POSITION;
break;
case QSFP_LED_LANE2_FAULT:
case SFP_LED_LANE2_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_FAULT_LED_VALUE;
bit_shift = TMC_PFE_LANE2_FAULT_LED_BIT_POSITION;
break;
case QSFP_LED_LANE3_FAULT:
case SFP_LED_LANE3_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
led_val = TMC_PFE_LANES_FAULT_LED_VALUE;
bit_shift = TMC_PFE_LANE3_FAULT_LED_BIT_POSITION;
break;
default:
spin_unlock_irqrestore(&chip->gpio_lock, flags);
return;
}
if (set) {
gpio_state = tmc_gpio_reset_bits(gpio_state, 0x3, bit_shift);
gpio_state = tmc_gpio_set_bits(gpio_state, led_val, bit_shift);
} else {
gpio_state = tmc_gpio_reset_bits(gpio_state, 0x3, bit_shift);
}
iowrite32(gpio_state, (iobase+(0x004*gpiono)));
spin_unlock_irqrestore(&chip->gpio_lock, flags);
return;
};
/*
* tmc_gpio_one_bitop - Generic TMC GPIO single bit operation
*/
static void tmc_gpio_one_bitop(struct tmc_gpio_chip *chip,
unsigned int bit, u32 offset, bool set)
{
u32 gpio_state;
unsigned long flags;
void __iomem *iobase;
iobase = chip->base + offset;
dev_dbg(chip->dev, "TMC GPIO one bitop bit=%u, offset=%x, "
"set=%u\n", bit, offset, set);
spin_lock_irqsave(&chip->gpio_lock, flags);
gpio_state = ioread32(iobase);
if (set)
gpio_state |= BIT(bit);
else
gpio_state &= ~BIT(bit);
iowrite32(gpio_state, iobase);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
return;
}
/*
* tmc_gpio_get_multiple_bitsop - Generic TMC get GPIO multiple bits operation
*/
static int tmc_gpio_get_multiple_bitsop(struct tmc_gpio_chip *chip,
unsigned int gpiono, u32 group, u32 offset)
{
u32 gpio_state;
void __iomem *iobase;
iobase = chip->base + offset;
dev_dbg(chip->dev, "TMC GPIO get multiple bitsop group=%u, "
"gpiono=%u, offset=%u\n", group, gpiono, offset);
switch (group) {
case QSFP_LED_LANE0_GREEN:
case SFP_LED_LANE0_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_GREEN_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE0_GREEN_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE1_GREEN:
case SFP_LED_LANE1_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_GREEN_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE1_GREEN_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE2_GREEN:
case SFP_LED_LANE2_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_GREEN_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE2_GREEN_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE3_GREEN:
case SFP_LED_LANE3_GREEN:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_GREEN_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE3_GREEN_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE0_BEACON:
case SFP_LED_LANE0_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_BEACON_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE0_BEACON_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE1_BEACON:
case SFP_LED_LANE1_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_BEACON_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE1_BEACON_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE2_BEACON:
case SFP_LED_LANE2_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_BEACON_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE2_BEACON_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE3_BEACON:
case SFP_LED_LANE3_BEACON:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_BEACON_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE3_BEACON_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE0_FAULT:
case SFP_LED_LANE0_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_FAULT_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE0_FAULT_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE1_FAULT:
case SFP_LED_LANE1_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_FAULT_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE1_FAULT_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE2_FAULT:
case SFP_LED_LANE2_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_FAULT_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE2_FAULT_LED_BIT_POSITION, 0x3));
case QSFP_LED_LANE3_FAULT:
case SFP_LED_LANE3_FAULT:
gpio_state = ioread32(iobase+(0x004*gpiono));
return (TMC_PFE_LANES_FAULT_LED_VALUE ==
tmc_gpio_find_bits_val(gpio_state,
TMC_PFE_LANE3_FAULT_LED_BIT_POSITION, 0x3));
default:
return 0;
}
};
/*
* tmc_gpio_get - Read the specified signal of the GPIO device.
*/
static int tmc_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct tmc_gpio_chip *chip = to_tmc_chip(gc);
unsigned int group = TMC_GPIO_FIND_GROUP(gpio);
unsigned int bit = TMC_GPIO_FIND_GPIO(gpio);
if (group >= TMC_PFE_GPIO_GROUP_MAX)
return 0;
switch (group) {
case QSFP_RST:
case QSFP_PRESENT:
case QSFP_PHY_RST:
case QSFP_LPMOD:
dev_dbg(chip->dev, "TMC GPIO get one bitop group=%u, gpio=%u, "
"bit=%u\n", group, gpio, bit);
return !!(ioread32(chip->base + group_offset[group])
& BIT(bit));
default:
return tmc_gpio_get_multiple_bitsop(chip, bit, group, group_offset[group]);
}
}
/*
* tmc_gpio_set - Write the specified signal of the GPIO device.
*/
static void tmc_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct tmc_gpio_chip *chip = to_tmc_chip(gc);
unsigned int group = TMC_GPIO_FIND_GROUP(gpio);
unsigned int bit = TMC_GPIO_FIND_GPIO(gpio);
if (group >= TMC_PFE_GPIO_GROUP_MAX)
return;
switch (group) {
case QSFP_RST:
case QSFP_PRESENT:
case QSFP_PHY_RST:
case QSFP_LPMOD:
dev_dbg(chip->dev, "TMC GPIO one bitop group=%d\n", group);
tmc_gpio_one_bitop(chip, bit, group_offset[group], val);
break;
default:
tmc_gpio_multiple_bitsop(chip, bit, group, group_offset[group], val);
break;
}
}
static struct tmc_gpio_info tmc_gpios[] = {
{
.get = tmc_gpio_get,
.set = tmc_gpio_set,
},
};
static void tmc_gpio_setup(struct tmc_gpio_chip *sgc, int id)
{
struct gpio_chip *chip = &sgc->gpio;
const struct tmc_gpio_info *info = sgc->info;
chip->get = info->get;
chip->set = info->set;
chip->direction_input = info->dirin;
chip->direction_output = info->dirout;
chip->dbg_show = NULL;
chip->can_sleep = 0;
if (id == 0) {
chip->base = 0;
} else if (id == 1) {
chip->base = (gpio_max * id);
} else {
chip->base = -1;
}
chip->ngpio = sgc->ngpio;
chip->label = dev_name(sgc->dev);
chip->parent = sgc->dev;
chip->owner = THIS_MODULE;
}
static int tmc_gpio_of_init(struct device *dev,
struct tmc_gpio_chip *chip)
{
chip->info = &tmc_gpios[0];
chip->ngpio = gpio_max;
return 0;
}
static int tmc_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct tmc_gpio_chip *chip;
struct resource *res;
int ret;
const struct mfd_cell *cell = mfd_get_cell(pdev);
dev_dbg(dev, "TMC GPIO probe\n");
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
dev_info(dev, "TMC GPIO resource 0x%llx, %llu\n",
res->start, resource_size(res));
chip->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!chip->base)
return -ENOMEM;
ret = tmc_gpio_of_init(dev, chip);
if (ret)
return ret;
chip->dev = dev;
spin_lock_init(&chip->gpio_lock);
tmc_gpio_setup(chip, cell->id);
ret = gpiochip_add(&chip->gpio);
if (ret) {
dev_err(dev,
"Failed to register TMC gpiochip : %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, chip);
dev_info(dev, "TMC GPIO registered at 0x%lx, gpiobase: %d\n",
(long unsigned)chip->base, chip->gpio.base);
return 0;
}
static int tmc_gpio_remove(struct platform_device *pdev)
{
struct tmc_gpio_chip *chip = platform_get_drvdata(pdev);
gpiochip_remove(&chip->gpio);
return 0;
}
static struct platform_driver tmc_gpio_driver = {
.driver = {
.name = "gpioslave-tmc",
.owner = THIS_MODULE,
},
.probe = tmc_gpio_probe,
.remove = tmc_gpio_remove,
};
module_platform_driver(tmc_gpio_driver);
MODULE_DESCRIPTION("Juniper Networks TMC FPGA GPIO driver");
MODULE_AUTHOR("Ashish Bhensdadia <bashish@juniper.net>");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1 @@
../../common/modules/gpio-tmc.c

View File

@ -0,0 +1 @@
../../common/modules/i2c-tmc.c

View File

@ -1,603 +0,0 @@
/*
* Juniper Networks RE-FPGA qfx platform specific driver
*
* Copyright (C) 2020 Juniper Networks
* Author: Ciju Rajan K <crajank@juniper.net>
*
* This driver implements various features such as
* - ALARM led driver
* - Fan full speed reset control
* - FAN precense detection
* - FAN type detection
* - Any new QFX specific features which uses RE-FPGA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/delay.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#define NUM_LEDS 7 /* Max number of Alarm + FAN LEDs */
#define ALARM_MINOR_LED 0
#define ALARM_MAJOR_LED 1
#define REFPGA_PCIE_RESET_CTRL 0x13
#define REFPGA_PCIE_ALARM 0x33
#define REFPGA_FAN0_CTRL_STAT 0x28
#define REFPGA_RESET_FAN_SPEED BIT(3)
#define REFPGA_OPER_TYPE BIT(0)
#define REFPGA_OPER_START BIT(1)
#define REFPGA_OPER_DONE BIT(2)
#define TMC_REFPGA_ADDR_REG 0x0 /* TMC offset: 0x228 */
#define TMC_REFPGA_DATA_REG 0x4 /* TMC offset: 0x22C */
#define TMC_REFPGA_CTRL_REG 0x8 /* TMC offset: 0x230 */
#define TMC_REFPGA_READ_CMD 0x3
#define TMC_REFPGA_WRITE_CMD 0x2
#define REFPGA_INTR_NR_GROUPS 1
#define REFPGA_INTR_MAX_IRQS_PG 32
#define MAX_FANS 5
#define REFPGA_IRQ_MAX_BITS_PER_REG 32
#define POLL_INTERVAL 5000
#define AFI_MASK (0x01)
#define AFO_MASK (0x02)
#define AFI_AFO_MASK (0x03)
/*
* LED specific data structures
*/
struct refpga_led {
struct led_classdev lc;
struct work_struct work;
int blink;
int on;
int bit;
void __iomem *addr;
};
struct refpga_led_data {
int num_leds;
struct refpga_led *leds;
};
static DEFINE_MUTEX(alarm_led_lock);
/*
* Common routines
*/
struct refpga_chip {
struct refpga_led_data *led;
};
static struct refpga_chip *refpga;
static DEFINE_MUTEX(refpga_lock);
static void __iomem *tmc_membase;
static void wait_for_refpga_oper(void __iomem *base_addr)
{
volatile u32 done = ~(-1);
unsigned long int timeout;
void __iomem *addr;
addr = base_addr + (TMC_REFPGA_CTRL_REG);
/*
* Wait till the transaction is complete
*/
timeout = jiffies + msecs_to_jiffies(100);
do {
usleep_range(50, 100);
done = ioread32(addr);
if (done & (REFPGA_OPER_DONE))
break;
} while(time_before(jiffies, timeout));
}
static u32 refpga_read(void __iomem *base_addr, u32 refpga_offset)
{
u32 value;
mutex_lock(&refpga_lock);
iowrite32(refpga_offset, base_addr + (TMC_REFPGA_ADDR_REG));
iowrite32(TMC_REFPGA_READ_CMD, base_addr + (TMC_REFPGA_CTRL_REG));
wait_for_refpga_oper(base_addr);
value = ioread32(base_addr + (TMC_REFPGA_DATA_REG));
mutex_unlock(&refpga_lock);
return value;
}
static void refpga_write(void __iomem *base_addr, u32 refpga_offset, u32 val)
{
mutex_lock(&refpga_lock);
iowrite32(refpga_offset, base_addr + (TMC_REFPGA_ADDR_REG));
iowrite32(val, base_addr + (TMC_REFPGA_DATA_REG));
iowrite32(TMC_REFPGA_WRITE_CMD, base_addr + (TMC_REFPGA_CTRL_REG));
wait_for_refpga_oper(base_addr);
mutex_unlock(&refpga_lock);
}
static bool get_fan_presense(u8 idx)
{
u8 value = 0x00;
u8 offset = REFPGA_FAN0_CTRL_STAT;
bool ret = 0;
value = refpga_read(tmc_membase, (offset + (idx * 2)));
/*
* Get the last two bits of REFPGA_FANx_CTRL_STAT.
* REFPGA_FANx_CTRL_STAT register of REFPGA gives the fan airflow
* status. There are 5 fans in QFX5200. Last two bits give the AFI
* & AFO status. If any of these bits are set, fan is present.
*/
value = (value & BIT(0)) | (value & BIT(1));
if (value)
ret = 1;
return ret;
}
static int get_fan_type(u8 idx)
{
u8 value = 0x00;
u8 offset = REFPGA_FAN0_CTRL_STAT;
int ret = -1;
value = refpga_read(tmc_membase, (offset + (idx * 2)));
/*
* Get the last two bits of REFPGA_FANx_CTRL_STAT.
* REFPGA_FANx_CTRL_STAT register of REFPGA gives the fan airflow
* status. There are 5 fans in QFX5200. Last two bits give the AFI
* & AFO status. If bit1 is set, it's AFO and if bit 0 is set,
* it's AFI.
*
* This function will return '1' for AFO, '0' for AFI, and '-1'
* if there is no fan or if both AFI & AFO bits are set.
*/
value &= AFI_AFO_MASK;
switch(value) {
case AFI_MASK:
ret = 0;
break;
case AFO_MASK:
ret = 1;
break;
default:
ret = -1;
break;
};
return ret;
}
enum sysfs_fan_attributes {
FAN0_PRESENT,
FAN1_PRESENT,
FAN2_PRESENT,
FAN3_PRESENT,
FAN4_PRESENT,
};
enum sysfs_fan_type_attributes {
FAN0_TYPE,
FAN1_TYPE,
FAN2_TYPE,
FAN3_TYPE,
FAN4_TYPE,
};
/*
* The sysfs files will be present in this path
* /sys/devices/pci0000:00/0000:00:1c.0/0000:0f:00.0/refpga-tmc.15/fan*_present
* /sys/devices/pci0000:00/0000:00:1c.0/0000:0f:00.0/refpga-tmc.15/fan*_type
*/
#define DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(index) \
static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, refpga_fan_presense_show, NULL, FAN##index##_PRESENT)
#define DECLARE_FAN_PRESENT_ATTR(index) &sensor_dev_attr_fan##index##_present.dev_attr.attr
#define DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(index) \
static SENSOR_DEVICE_ATTR(fan##index##_type, S_IRUGO, refpga_fan_type_show, NULL, FAN##index##_TYPE)
#define DECLARE_FAN_TYPE_ATTR(index) &sensor_dev_attr_fan##index##_type.dev_attr.attr
static ssize_t refpga_fan_presense_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr);
return sprintf(buf, "%d\n", get_fan_presense(s_attr->index));
}
static ssize_t refpga_fan_type_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr);
return sprintf(buf, "%d\n", get_fan_type(s_attr->index));
}
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(0);
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(1);
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(2);
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(3);
DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(4);
DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(0);
DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(1);
DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(2);
DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(3);
DECLARE_FAN_TYPE_SENSOR_DEV_ATTR(4);
static struct attribute *refpga_fan_attrs[] = {
DECLARE_FAN_PRESENT_ATTR(0),
DECLARE_FAN_PRESENT_ATTR(1),
DECLARE_FAN_PRESENT_ATTR(2),
DECLARE_FAN_PRESENT_ATTR(3),
DECLARE_FAN_PRESENT_ATTR(4),
DECLARE_FAN_TYPE_ATTR(0),
DECLARE_FAN_TYPE_ATTR(1),
DECLARE_FAN_TYPE_ATTR(2),
DECLARE_FAN_TYPE_ATTR(3),
DECLARE_FAN_TYPE_ATTR(4),
NULL
};
static struct attribute_group refpga_fan_attr_group = {
.attrs = refpga_fan_attrs,
};
/*
* There is only a single ALARM led in QFX5200 and that
* is used for both Major & Minor alarm indicator.
* These are represented by two different bits in RE-FPGA
* PCIE_ALARM register. Only one of the bit (either Red or
* Yellow) should be set a time. If both the bits are set,
* it's an undefined behaviour.
*
* The following table describes how the conditions are
* handled in the driver as there can be both Major & Minor
* alarms can be triggered from userspace.
*
* Major Minor Colour
*
* 0 0 Nil
* 0 1 Yellow
* 1 1 Red
* 1 0 Red
*
*/
static void manage_alarm_led(void __iomem *addr, int led_type, int value)
{
static int alarm_major = 0, alarm_minor = 0;
u32 reg = 0x0;
mutex_lock(&alarm_led_lock);
reg = refpga_read(addr, REFPGA_PCIE_ALARM);
(led_type == ALARM_MAJOR_LED) ?
((value == 1) ? (alarm_major = 1) : (alarm_major = 0)) :
((value == 1) ? (alarm_minor = 1) : (alarm_minor = 0));
if (alarm_major) {
reg &= ~BIT(ALARM_MINOR_LED);
reg |= BIT(ALARM_MAJOR_LED);
} else {
if (alarm_minor) {
reg &= ~BIT(ALARM_MAJOR_LED);
reg |= BIT(ALARM_MINOR_LED);
} else {
reg &= ~BIT(ALARM_MINOR_LED);
reg &= ~BIT(ALARM_MAJOR_LED);
}
}
refpga_write(addr, REFPGA_PCIE_ALARM, reg);
mutex_unlock(&alarm_led_lock);
}
static void manage_fan_led(void __iomem *addr, int fan_slot, int value)
{
u8 offset = REFPGA_FAN0_CTRL_STAT + (fan_slot * 2);
u32 reg = 0x0;
reg = refpga_read(addr, offset);
if(value) {
/* Turn on s/w control */
reg = reg | BIT(4);
/* Turn off green led */
reg &= ~BIT(5);
/* Turn on yellow led & make it blink */
reg |= (BIT(6) | BIT(7));
} else {
/* Clear yellow led & stop blink */
reg &= ~(BIT(6) | BIT(7));
/* Stop s/w control */
reg &= ~BIT(4);
}
refpga_write(addr, offset, reg);
}
static void refpga_led_work(struct work_struct *work)
{
struct refpga_led *led = container_of(work, struct refpga_led, work);
void __iomem *addr;
addr = led->addr;
if(strstr(led->lc.name, "fan"))
manage_fan_led(addr, led->bit, led->on);
else
manage_alarm_led(addr, led->bit, led->on);
}
static void refpga_led_brightness_set(struct led_classdev *lc,
enum led_brightness brightness)
{
struct refpga_led *led = container_of(lc, struct refpga_led, lc);
led->on = (brightness != LED_OFF);
led->blink = 0; /* always turn off hw blink on brightness_set() */
schedule_work(&led->work);
}
struct led_table
{
const char *name;
int reg;
};
static struct led_table qfx5200_led_data[] = {
{
.name = "alarm-minor",
.reg = 0,
},
{
.name = "alarm-major",
.reg = 1,
},
{
.name = "fan0-fault",
.reg = 0,
},
{
.name = "fan1-fault",
.reg = 1,
},
{
.name = "fan2-fault",
.reg = 2,
},
{
.name = "fan3-fault",
.reg = 3,
},
{
.name = "fan4-fault",
.reg = 4,
}
};
static int refpga_led_init_one(struct device *dev,
struct refpga_led_data *ild,
int num)
{
struct refpga_led *led;
int ret = 0;
led = &ild->leds[num];
led->addr = tmc_membase;
led->lc.name = qfx5200_led_data[num].name;
led->bit = qfx5200_led_data[num].reg;
led->lc.brightness = LED_OFF;
led->lc.brightness_set = refpga_led_brightness_set;
ret = devm_led_classdev_register(dev, &led->lc);
if (ret) {
dev_err(dev, "devm_led_classdev_register failed\n");
return ret;
}
INIT_WORK(&led->work, refpga_led_work);
return 0;
}
static int refpga_led_qfx5200_init(struct device *dev, struct refpga_led_data *ild)
{
int ret = 0, idx = 0;
if (!dev->parent) {
dev_err(dev, "dev->parent is null\n");
return -ENODEV;
}
ild->num_leds = NUM_LEDS;
ild->leds = devm_kzalloc(dev, sizeof(struct refpga_led) * NUM_LEDS,
GFP_KERNEL);
if (!ild->leds) {
dev_err(dev, "LED allocation failed\n");
return -ENOMEM;
}
for(idx=0; idx<NUM_LEDS; idx++){
ret = refpga_led_init_one(dev, ild, idx);
if (ret)
return ret;
}
return 0;
}
static int jnx_refpga_led_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct refpga_led_data *ild;
int ret;
ild = devm_kzalloc(dev, sizeof(*ild), GFP_KERNEL);
if (!ild) {
dev_err(dev, "ild allocation failed\n");
return -ENOMEM;
}
ret = refpga_led_qfx5200_init(dev, ild);
if (ret < 0)
return ret;
refpga->led = ild;
return 0;
}
static int jnx_refpga_led_remove(struct platform_device *pdev)
{
struct refpga_chip *drv_data = platform_get_drvdata(pdev);
struct refpga_led_data *ild = drv_data->led;
int i;
for (i = 0; i < ild->num_leds; i++) {
devm_led_classdev_unregister(&pdev->dev, &ild->leds[i].lc);
cancel_work_sync(&ild->leds[i].work);
}
if (ild) {
if (ild->leds)
devm_kfree(&pdev->dev, ild->leds);
devm_kfree(&pdev->dev, ild);
}
return 0;
}
static void reset_fan_full_speed(struct device *dev)
{
u32 val = ~(-1), tmp = ~(-1);
/*
* Reading the REFPGA_PCIE_RESET_CTRL register
*/
val = refpga_read(tmc_membase, REFPGA_PCIE_RESET_CTRL);
/*
* Clearing the fan full_speed bit
*/
val &= ~(REFPGA_RESET_FAN_SPEED);
/*
* Writing the REFPGA_PCIE_RESET_CTRL register
*/
refpga_write(tmc_membase, REFPGA_PCIE_RESET_CTRL, val);
/*
* Reading the REFPGA_PCIE_RESET_CTRL register
*/
tmp = refpga_read(tmc_membase, REFPGA_PCIE_RESET_CTRL);
dev_info(dev, "After resetting fan full speed control: %X\n", tmp);
}
static int jnx_refpga_tmc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
int ret = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "resource allocation failed\n");
return -ENODEV;
}
tmc_membase = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!tmc_membase) {
dev_err(dev, "ioremap failed\n");
return -ENOMEM;
}
refpga = devm_kzalloc(dev, sizeof(*refpga), GFP_KERNEL);
if (!refpga) {
dev_err(dev, "refpga memory allocation failed\n");
return -ENOMEM;
}
reset_fan_full_speed(dev);
ret = jnx_refpga_led_probe(pdev);
if (ret != 0) {
dev_err(dev, "Refpga LED probe failed\n");
return ret;
}
dev_info(dev, "Refpga LED probe successful: TMC memoy base: %p\n",
tmc_membase);
ret = sysfs_create_group(&dev->kobj, &refpga_fan_attr_group);
if (ret != 0) {
dev_err(dev, "sysfs_create_group failed: %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, refpga);
return 0;
}
static int jnx_refpga_tmc_remove(struct platform_device *pdev)
{
jnx_refpga_led_remove(pdev);
sysfs_remove_group(&pdev->dev.kobj, &refpga_fan_attr_group);
return 0;
}
static struct platform_driver jnx_refpga_tmc_driver = {
.driver = {
.name = "refpga-tmc",
.owner = THIS_MODULE,
},
.probe = jnx_refpga_tmc_probe,
.remove = jnx_refpga_tmc_remove,
};
static int __init jnx_refpga_tmc_driver_init(void)
{
int ret = -1;
ret = platform_driver_register(&jnx_refpga_tmc_driver);
return ret;
}
static void __exit jnx_refpga_tmc_driver_exit(void)
{
platform_driver_unregister(&jnx_refpga_tmc_driver);
}
module_init(jnx_refpga_tmc_driver_init);
module_exit(jnx_refpga_tmc_driver_exit);
MODULE_DESCRIPTION("Juniper Networks REFPGA / TMC driver");
MODULE_AUTHOR("Ciju Rajan K <crajank@juniper.net>");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1 @@
../../common/modules/jnx-refpga-tmc.c

View File

@ -1,477 +0,0 @@
/*
* Juniper Networks TMC-FPGA MFD Core driver for qfx platform
*
* Copyright (c) 2020, Juniper Networks
* Author: Ashish Bhensdadia <bashish@juniper.net>
*
* This driver implement the resource publish for below devices
* - I2C
* - GPIO
* - RE FPGA
* - PSU
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/irqdomain.h>
#include <linux/mfd/core.h>
#include "jnx-tmc.h"
#define TMC_DO_SCRATCH_TEST 1
/*
* TMC FPGA Device IDs
*/
#define PCI_VENDOR_ID_JUNIPER 0x1304
#define PCI_DEVICE_ID_JNX_TMC_CHD 0x007B
#define PCI_DEVICE_ID_JNX_TMC_PFE 0x007C
/*
* TMC resources
*/
static struct resource tmc_resource_i2c[] = {
/* I2C AUTOMATION Block */
{
.name = "i2c-tmc",
.start = TMC_I2C_AUTOMATION_I2C_CONTROL_START,
.end = TMC_I2C_AUTOMATION_I2C_CONTROL_END,
.flags = IORESOURCE_MEM,
},
/* I2C DPMEM */
{
.name = "i2c-tmc-mem",
.start = TMC_I2C_DPMEM_ENTRY_START,
.end = TMC_I2C_DPMEM_ENTRY_END,
.flags = IORESOURCE_MEM,
},
};
#define TMC_RES_I2C_NR ARRAY_SIZE(tmc_resource_i2c)
/*
* LED resources
*/
static struct resource tmc_resource_leds[] = {
{
.name = "leds-tmc",
.start = TMC_LED_CONTROL_START,
.end = TMC_LED_CONTROL_END,
.flags = IORESOURCE_MEM,
},
};
#define TMC_RES_LEDS_NR ARRAY_SIZE(tmc_resource_leds)
/*
* TMC RE-FPGA devices
*/
static struct resource tmc_resource_refpga[] = {
{
.name = "refpga-tmc",
.start = TMC_REFPGA_ACCESS_START,
.end = TMC_REFPGA_ACCESS_END,
.flags = IORESOURCE_MEM,
},
};
#define TMC_RES_REFPGA_NR ARRAY_SIZE(tmc_resource_refpga)
static struct resource tmc_resource_gpioslave0[] = {
/* SLAVE0 Block */
{
.name = "gpioslave-tmc",
.start = TMC_GPIO_SLAVE0_START,
.end = TMC_GPIO_SLAVE0_END,
.flags = IORESOURCE_MEM,
}
};
#define TMC_RES_GPIOSLAVE0_NR ARRAY_SIZE(tmc_resource_gpioslave0)
static struct resource tmc_resource_gpioslave1[] = {
/* SLAVE1 Block */
{
.name = "gpioslave-tmc",
.start = TMC_GPIO_SLAVE1_START,
.end = TMC_GPIO_SLAVE1_END,
.flags = IORESOURCE_MEM,
}
};
#define TMC_RES_GPIOSLAVE1_NR ARRAY_SIZE(tmc_resource_gpioslave1)
static struct resource tmc_resource_psu[] = {
/* PSU Block */
{
.name = "psu-tmc",
.start = TMC_PSU_START,
.end = TMC_PSU_END,
.flags = IORESOURCE_MEM,
}
};
#define TMC_RES_PSU_NR ARRAY_SIZE(tmc_resource_psu)
/*
* CHASSISD TMC MFD devices
*/
static struct mfd_cell chassisd_tmc_mfd_devs[] = {
{
.name = "i2c-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_i2c),
.resources = &tmc_resource_i2c[0],
.of_compatible = "jnx,i2c-tmc",
.id = 0,
},
{
.name = "leds-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_leds),
.resources = &tmc_resource_leds[0],
.of_compatible = "jnx,leds-tmc",
.id = 0,
},
{
.name = "refpga-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_refpga),
.resources = &tmc_resource_refpga[0],
.of_compatible = "jnx,refpga-tmc",
.id = 0,
},
{
.name = "psu-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_psu),
.resources = &tmc_resource_psu[0],
.of_compatible = "jnx,psu-tmc",
.id = 0,
},
};
/*
* PFE TMC MFD devices
*/
static struct mfd_cell pfe_tmc_mfd_devs[] = {
{
.name = "i2c-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_i2c),
.resources = &tmc_resource_i2c[0],
.of_compatible = "jnx,i2c-tmc",
.id = 1,
},
{
.name = "gpioslave-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_gpioslave0),
.resources = &tmc_resource_gpioslave0[0],
.of_compatible = "jnx,gpioslave-tmc",
.id = 0,
},
{
.name = "gpioslave-tmc",
.num_resources = ARRAY_SIZE(tmc_resource_gpioslave1),
.resources = &tmc_resource_gpioslave1[0],
.of_compatible = "jnx,gpioslave-tmc",
.id = 1,
},
};
struct tmc_fpga_data {
void __iomem *membase;
struct pci_dev *pdev;
u32 major; /* Device id & Major version*/
u32 minor; /* Minor version */
u32 optic_cpld_major; /* optic cpld major version */
u32 optic_cpld_minor; /* optic cpld minor version */
u32 optic_cpld_devid; /* optic cpld device id */
};
/* sysfs entries */
static ssize_t major_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(dev);
return sprintf(buf, "0x%02X_%06X\n",
(tmc->major >> 24) & 0xff,
tmc->major & 0xffffff);
}
static ssize_t minor_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(dev);
return sprintf(buf, "%02X\n", (tmc->minor) & 0xff);
}
static ssize_t optic_cpld_major_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(dev);
return sprintf(buf, "%01X\n", tmc->optic_cpld_major & 0xf);
}
static ssize_t optic_cpld_devid_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(dev);
return sprintf(buf, "%01X\n",
(tmc->optic_cpld_major >> 4) & 0xf);
}
static ssize_t optic_cpld_minor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(dev);
return sprintf(buf, "%02X\n", tmc->optic_cpld_minor & 0xff);
}
static ssize_t set_sys_shutdown(struct device *dev,
struct device_attribute *devattr,
const char *buf,
size_t len)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(dev);
unsigned long val;
int ret;
ret = kstrtoul(buf, 0, &val);
if (ret < 0)
return ret;
if (val != 1)
return -EINVAL;
/* Unlock the shutdown register */
iowrite32(0x12345678, tmc->membase + TMC_SYS_SHUTDOWN_LOCK);
iowrite32(0x1, tmc->membase + TMC_SYS_SHUTDOWN);
return len;
}
static DEVICE_ATTR(major, S_IRUGO, major_show, NULL);
static DEVICE_ATTR(minor, S_IRUGO, minor_show, NULL);
static DEVICE_ATTR(optic_cpld_major, S_IRUGO, optic_cpld_major_show, NULL);
static DEVICE_ATTR(optic_cpld_devid, S_IRUGO, optic_cpld_devid_show, NULL);
static DEVICE_ATTR(optic_cpld_minor, S_IRUGO, optic_cpld_minor_show, NULL);
static DEVICE_ATTR(shutdown, S_IWUSR, NULL, set_sys_shutdown);
static struct attribute *tmc_attrs[] = {
&dev_attr_major.attr,
&dev_attr_minor.attr,
&dev_attr_optic_cpld_major.attr,
&dev_attr_optic_cpld_devid.attr,
&dev_attr_optic_cpld_minor.attr,
&dev_attr_shutdown.attr,
NULL,
};
static struct attribute_group tmc_attr_group = {
.attrs = tmc_attrs,
};
#if defined TMC_DO_SCRATCH_TEST
/* Do a quick scratch access test */
static int tmc_do_test_scratch(struct tmc_fpga_data *tmc)
{
struct pci_dev *pdev = tmc->pdev;
struct device *dev = &pdev->dev;
int offset = TMC_SCRATCH;
u32 acc, val = 0xdeadbeaf;
/*
* Check rw register access -> use the scratch reg.
*/
iowrite32(val, tmc->membase + offset);
acc = ioread32(tmc->membase + offset);
if (acc != val) {
dev_err(dev, "Tmc scratch(0x%x) failed: %08x.%08x!\n",
offset, val, acc);
return -EIO;
}
for (val = 0; val < 0xf0000000; val += 0x01010101) {
iowrite32(val, tmc->membase + offset);
acc = ioread32(tmc->membase + offset);
if (acc != val) {
dev_err(dev, "Tmc scratch(0x%x) failed: %08x.%08x!\n",
offset, val, acc);
return -EIO;
}
}
/*
* Write a sig before leaving..
*/
val = 0xcafebabe;
iowrite32(val, tmc->membase + offset);
dev_dbg(dev, "Tmc scratch result: 0x%08x\n",
ioread32(tmc->membase + offset));
return 0;
}
#endif /* TMC_DO_SCRATCH_TEST */
static int tmc_fpga_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
int err;
struct tmc_fpga_data *tmc;
struct device *dev = &pdev->dev;
dev_dbg(dev, "Tmc FPGA Probe called\n");
tmc = devm_kzalloc(dev, sizeof(*tmc), GFP_KERNEL);
if (!tmc)
return -ENOMEM;
err = pcim_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "Failed to enable device %d\n", err);
return err;
}
err = pcim_iomap_regions(pdev, 1 << 0, "tmc-core");
if (err) {
dev_err(&pdev->dev, "Failed to iomap regions %d\n", err);
goto err_disable;
}
tmc->membase = pcim_iomap_table(pdev)[0];
if (IS_ERR(tmc->membase)) {
dev_err(dev, "pci_ioremap_bar() failed\n");
err = -ENOMEM;
goto err_release;
}
tmc->pdev = pdev;
pci_set_drvdata(pdev, tmc);
/* All Tmc uses MSI interrupts - enable bus mastering */
pci_set_master(pdev);
#if defined TMC_DO_SCRATCH_TEST
/* Check IO before proceeding */
dev_dbg(dev, "Tmc FPGA starting scratch test\n");
err = tmc_do_test_scratch(tmc);
if (err)
goto err_unmap;
dev_dbg(dev, "Tmc FPGA scratch test passed !!!\n");
#endif /* TMC_DO_SCRATCH_TEST */
switch (id->device) {
case PCI_DEVICE_ID_JNX_TMC_CHD:
err = mfd_add_devices(dev, pdev->bus->number,
&chassisd_tmc_mfd_devs[0],
ARRAY_SIZE(chassisd_tmc_mfd_devs),
&pdev->resource[0],
0, NULL /* tmc->irq_domain */);
break;
case PCI_DEVICE_ID_JNX_TMC_PFE:
err = mfd_add_devices(dev, pdev->bus->number,
&pfe_tmc_mfd_devs[0],
ARRAY_SIZE(pfe_tmc_mfd_devs),
&pdev->resource[0],
0, NULL /* tmc->irq_domain */);
break;
default:
dev_err(&pdev->dev, "Invalid PCI Device ID id:%d\n",
id->device);
goto err_unmap;
}
if (err < 0) {
dev_err(&pdev->dev, "Failed to add mfd devices %d\n", err);
goto err_unmap;
}
err = sysfs_create_group(&pdev->dev.kobj, &tmc_attr_group);
if (err) {
sysfs_remove_group(&pdev->dev.kobj, &tmc_attr_group);
dev_err(&pdev->dev, "Failed to create attr group\n");
goto err_remove_mfd;
}
tmc->major = ioread32(tmc->membase + TMC_REVISION);
tmc->minor = ioread32(tmc->membase + TMC_MINOR);
tmc->optic_cpld_major = ioread32(tmc->membase + TMC_OPTIC_CPLD_MAJOR);
tmc->optic_cpld_minor = ioread32(tmc->membase + TMC_OPTIC_CPLD_MINOR);
dev_info(dev, "Tmc FPGA Revision: 0x%02X_%06X, Minor: %02X\n",
(tmc->major >> 24) & 0xff,
tmc->major & 0xffffff,
(tmc->minor) & 0xff);
dev_info(dev, "Tmc FPGA optic cpld Major: 0x%01X, Minor: 0x%02X "
"Devid: 0x%01X\n", (tmc->optic_cpld_major) & 0xf,
(tmc->optic_cpld_minor) & 0xff,
(tmc->optic_cpld_major >> 4) & 0xf);
dev_info(dev, "Tmc FPGA mem:0x%lx\n",
(unsigned long)tmc->membase);
return 0;
err_remove_mfd:
mfd_remove_devices(dev);
err_unmap:
pci_iounmap(pdev, tmc->membase);
err_release:
pci_release_regions(pdev);
err_disable:
pci_disable_device(pdev);
return err;
}
static void tmc_fpga_remove(struct pci_dev *pdev)
{
struct tmc_fpga_data *tmc = dev_get_drvdata(&pdev->dev);
sysfs_remove_group(&pdev->dev.kobj, &tmc_attr_group);
mfd_remove_devices(&pdev->dev);
}
static const struct pci_device_id tmc_fpga_id_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_JUNIPER, PCI_DEVICE_ID_JNX_TMC_CHD) },
{ PCI_DEVICE(PCI_VENDOR_ID_JUNIPER, PCI_DEVICE_ID_JNX_TMC_PFE) },
{ }
};
MODULE_DEVICE_TABLE(pci, tmc_fpga_id_tbl);
static struct pci_driver tmc_fpga_driver = {
.name = "tmc-core",
.id_table = tmc_fpga_id_tbl,
.probe = tmc_fpga_probe,
.remove = tmc_fpga_remove,
};
module_pci_driver(tmc_fpga_driver);
MODULE_DESCRIPTION("Juniper Networks TMC FPGA MFD core driver");
MODULE_AUTHOR("Ashish Bhensdadia <bashish@juniper.net>");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1 @@
../../common/modules/jnx-tmc-core.c

View File

@ -1,93 +0,0 @@
/*
* Juniper Tmc FPGA register definitions
*
* Copyright (C) 2018 Juniper Networks
* Author: Ashish Bhensdadia <bashish@juniper.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __JNX_TMC_H__
#define __JNX_TMC_H__
#define TMC_REVISION 0x00064
#define TMC_MINOR 0x00068
#define TMC_SCRATCH 0x00098
#define TMC_OPTIC_CPLD_MAJOR 0x00104
#define TMC_OPTIC_CPLD_MINOR 0x00108
/*
* I2C Master Block
*/
#define TMC_I2C_AUTOMATION_I2C_CONTROL_START 0x07000
#define TMC_I2C_AUTOMATION_I2C_CONTROL_END 0x07500
#define TMC_I2C_DPMEM_ENTRY_START 0x10000
#define TMC_I2C_DPMEM_ENTRY_END 0x13FFC
#define TMC_LED_CONTROL_START 0x58
#define TMC_LED_CONTROL_END 0x5B
/*
* RE-FPGA block
*/
#define TMC_REFPGA_ACCESS_START 0x228
#define TMC_REFPGA_ACCESS_END 0x233
#define TMC_I2C_MASTER_NR_MSTRS 16
#define TMC_I2C_MSTR_MAX_GROUPS 66
/*
* TMC GPIO SLAVE Block
*/
#define TMC_GPIO_PTP_RESET_START 0x94
#define TMC_GPIO_PTP_RESET_END 0x97
#define TMC_GPIO_PTP_CFG_START 0xa4
#define TMC_GPIO_PTP_CFG_END 0xa7
#define TMC_GPIO_PTP_DATA_START 0xa8
#define TMC_GPIO_PTP_DATA_END 0xab
#define TMC_GPIO_SLAVE0_START 0xf0
#define TMC_GPIO_SLAVE0_END 0x16b
#define TMC_GPIO_SLAVE1_START 0x170
#define TMC_GPIO_SLAVE1_END 0x1eb
#define TMC_GPIO_SLAVE2_START 0x1f0
#define TMC_GPIO_SLAVE2_END 0x213
#define TMC_GPIO_SLAVE3_START 0x280
#define TMC_GPIO_SLAVE3_END 0x2eb
#define TMC_GPIO_SFP_SLAVE0_START 0x308
#define TMC_GPIO_SFP_SLAVE0_END 0x32b
#define TMC_GPIO_SFP_SLAVE1_START 0x32c
#define TMC_GPIO_SFP_SLAVE1_END 0x34b
/*
* TMC PSU Block
*/
#define TMC_PSU_START 0x240
#define TMC_PSU_END 0x243
/*
* TMC SHUTDOWN REG
*/
#define TMC_SYS_SHUTDOWN_LOCK 0x254
#define TMC_SYS_SHUTDOWN 0x250
/*
* TMC DS100 MUX Block
*/
#define TMC_GPIO_MUX_SLAVE_START 0x26c
#define TMC_GPIO_MUX_SLAVE_END 0x26f
#endif /* __JNX_TMC_H__ */

View File

@ -0,0 +1 @@
../../common/modules/jnx-tmc.h

View File

@ -1,144 +0,0 @@
/*
* Juniper PCI ID(s) - for devices on Juniper Boards
*
* Rajat Jain <rajatjain@juniper.net>
* Copyright 2014 Juniper Networks
*
* 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.
*/
#ifndef __JNX_PCI_IDS_H__
#define __JNX_PCI_IDS_H__
#define PCI_VENDOR_ID_JUNIPER 0x1304
#define PCI_VENDOR_ID_ERICSSON 0x1519
#define PCI_VENDOR_ID_ERICSSON_AS 0x1a25
/*
* PTX SAM FPGA, device ID as present on various Juniper boards, such as
* - Sangria FPC
* - Hendricks FPC
* - Sangria 24x10GE PIC
* - Gladiator FPC
*/
#define PCI_DEVICE_ID_JNX_SAM 0x0004
/* Juniper Broadway ASIC family */
#define PCI_DEVICE_ID_JNX_TF 0x003c
#define PCI_DEVICE_ID_JNX_TL 0x003d
#define PCI_DEVICE_ID_JNX_TQ 0x003e
#define PCI_DEVICE_ID_JNX_OTN_FRAMER 0x0055
#define PCI_DEVICE_ID_JNX_PE 0x005e
#define PCI_DEVICE_ID_JNX_PF 0x005f /* Juniper Paradise ASIC */
#define PCI_DEVICE_ID_JNX_ZF 0x008d /* Juniper ZF Fabric ASIC */
#define PCI_DEVICE_ID_JNX_ZX 0x008e /* Juniper ZX ASIC */
#define PCI_DEVICE_ID_JNX_ZT 0x0090 /* Juniper ZT ASIC */
#define PCI_DEVICE_ID_JNX_BT 0x00B2 /* Juniper BT ASIC */
/* Juniper SAM FPGA - Omega SIB, Sochu SHAM, Gladiator SIB */
#define PCI_DEVICE_ID_JNX_SAM_OMEGA 0x006a
/* Juniper SAM FPGA - present on GLD FPC board */
#define PCI_DEVICE_ID_JNX_SAM_X 0x006b
/* Juniper PAM FPGA - present on PTX MLC board */
#define PCI_DEVICE_ID_JNX_PAM 0x006c
/* Juniper CBC FPGA - present on PTX1K RCB */
#define PCI_DEVICE_ID_JNX_CBC 0x006e
#define PCI_DEVICE_ID_JNX_CBC_P2 0x0079
#define PCI_DEVICE_ID_JNX_OMG_CBC 0x0083
/* Juniper Summit FPGA */
#define PCI_DEVICE_ID_JNX_SUMMIT 0x009B
/* Juniper DOON FPGA */
#define PCI_DEVICE_ID_JNX_DOON_RCB_CBC 0x0098
/* Juniper CBC FPGA in PTX-5K MTRCB */
#define PCI_DEVICE_ID_JNX_PTX5K_MTRCB_CBC 0x0071
/* Other Vendors' devices */
#define PCI_DEVICE_ID_IDT_PES12NT3_TRANS_AB 0x8058
#define PCI_DEVICE_ID_IDT_PES12NT3_TRANS_C 0x8059
#define PCI_DEVICE_ID_IDT_PES12NT3_INT_NTB_C 0x805a
#define PCI_DEVICE_ID_IDT_48H12G2 0x807a
#define PCI_DEVICE_ID_IDT_PES24NT24G2 0x808e
#define PCI_DEVICE_ID_IDT_PES16NT16G2 0x8090
#define PCI_DEVICE_ID_PLX_8614 0x8614
#define PCI_DEVICE_ID_PLX_8618 0x8618
#define PCI_DEVICE_ID_PLX_8713 0x8713
#define PCI_DEVICE_ID_PLX_8725 0x8725
#define PCI_DEVICE_ID_PLX_8749 0x8749
#define PCI_DEVICE_ID_PLX_8796 0x8796
#define PCI_DEVICE_ID_PLX_8608 0x8608
/*
* Juniper CBD FPGA Device ID(s)
*/
#define JNX_CBD_FPGA_DID_09B3 0x004D
#define JNX_CBD_FPGA_DID_0BA8 0x005A
/*
* Juniper Brackla FPGA Device IDs
* - UBAM, MBAM, PBAM, QBAM
*/
#define PCI_DEVICE_ID_JNX_UBAM 0x00A7
#define PCI_DEVICE_ID_JNX_PBAM 0x00A8
#define PCI_DEVICE_ID_JNX_MBAM 0x00A9
#define PCI_DEVICE_ID_JNX_QBAM 0x00AA
/*
* Juniper MPC11E Supercon and WAN FPGA IDs
*/
#define PCI_DEVICE_ID_JNX_MPC11CON 0x00A1
#define PCI_DEVICE_ID_JNX_MPC11WAN 0x00C4
/*
* Juniper Attella TMC and Supercon FPGA IDs
*/
#define PCI_DEVICE_ID_JNX_ARGUS 0x00B0
#define PCI_DEVICE_ID_JNX_ATIC 0x00C0
#define PCI_DEVICE_ID_JNX_ATMC_CHD 0x00C1
#define PCI_DEVICE_ID_JNX_ATMC_PFE 0x00C2
#define PCI_DEVICE_ID_JNX_AOHIO 0x00C3
/*
* Juniper TMC FPGA Device IDs
*/
#define PCI_DEVICE_ID_JNX_TMC_CHD 0x007B
#define PCI_DEVICE_ID_JNX_TMC_PFE 0x007C
#define PCI_DEVICE_ID_XILINX_1588_FPGA 0x0505
/*
* Juniper Scapa SIB/LC Supercon FPGA IDs
*/
#define PCI_DEVICE_ID_JNX_SCAPA_SIB_CTRL 0x00BA
#define PCI_DEVICE_ID_JNX_SDLC_CTRL 0x00BE
#define PCI_DEVICE_ID_JNX_LLC_CTRL 0x00C8
/*
* Deanston WANIO FPGA
*/
#define PCI_DEVICE_ID_JNX_DEANSTON_WAN 0x00C6
/*
* Juniper Ardbeg Supercon FPGA IDs
*/
#define PCI_DEVICE_ID_JNX_ARDBEG_CTRL 0x00C5
/*
* Ericsson CCM FPGA ID used in Bolan (ACX753)
*/
#define PCI_DEVICE_ID_ERIC_CCM_FPGA 0x0020
/*
* Ericsson OAM FPGA ID used in Bolan (ACX753)
*/
#define PCI_DEVICE_ID_ERIC_OAM_FPGA 0x7021
#endif /* __JNX_PCI_IDS_H__ */

View File

@ -1,15 +0,0 @@
#!/usr/bin/env python
import os
from setuptools import setup
os.listdir
setup(
name='sonic_platform',
version='1.0',
description='Module to initialize Juniper QFX5200-32C-S platforms',
packages=['sonic_platform'],
package_dir={'sonic_platform': 'qfx5200/sonic_platform'},
)

View File

@ -1,260 +0,0 @@
#!/usr/bin/env python
#
# Name: chassis.py, version: 1.0
#
# Description: Module contains the definitions of SONiC platform APIs
# which provide the chassis specific details
#
# Copyright (c) 2020, Juniper Networks, Inc.
# All rights reserved.
#
# Notice and Disclaimer: This code is licensed to you under the GNU General
# Public License as published by the Free Software Foundation, version 3 or
# any later version. This code is not an official Juniper product. You can
# obtain a copy of the License at <https://www.gnu.org/licenses/>
#
# OSS License:
#
# 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 <https://www.gnu.org/licenses/>.
#
# Third-Party Code: This code may depend on other components under separate
# copyright notice and license terms. Your use of the source code for those
# components is subject to the terms and conditions of the respective license
# as noted in the Third-Party source code file.
#
try:
import commands
import time
from sonic_platform_base.chassis_base import ChassisBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Chassis(ChassisBase):
"""
JUNIPER QFX5200 Platform-specific Chassis class
"""
def __init__(self):
ChassisBase.__init__(self)
def get_qfx5200_parameter_value(self,parameter_name):
try:
with open("/var/run/eeprom", "r") as file:
for item in file:
content = item.split('=')
if content[0] == parameter_name:
return content[1:]
return "False"
except IOError:
print "Error: File not found"
return "False"
def get_product_name(self):
product_name_list = self.get_qfx5200_parameter_value('Product Name')
if product_name_list:
product_name = ''.join(product_name_list)
return product_name
else:
return False
def get_part_number(self):
part_number_list = self.get_qfx5200_parameter_value('Part Number')
if part_number_list:
part_number = ''.join(part_number_list)
return part_number
else:
return False
def get_serial_number(self):
serial_number_list = self.get_qfx5200_parameter_value('Serial Number')
if serial_number_list:
serial_number = ''.join(serial_number_list)
return serial_number
else:
return False
def get_base_mac(self):
mac_list = self.get_qfx5200_parameter_value('MAC Address')
if mac_list:
mac = ''.join(mac_list)
return mac
else:
return False
def get_mfg_date(self):
mfgdate_list = self.get_qfx5200_parameter_value('Manufacture Date')
if mfgdate_list:
mfgdate = ''.join(mfgdate_list)
return mfgdate
else:
return False
def get_platform_name(self):
platform_name_list = self.get_qfx5200_parameter_value('Platform Name')
if platform_name_list:
platform_name = ''.join(platform_name_list)
return platform_name
else:
return False
def get_MACnumber_name(self):
MACnumber_name_list = self.get_qfx5200_parameter_value('Number of MAC Addresses')
if MACnumber_name_list:
MACnumber_name = ''.join(MACnumber_name_list)
return MACnumber_name
else:
return False
def get_vendor_name(self):
vendor_name_list = self.get_qfx5200_parameter_value('Vendor Name')
if vendor_name_list:
vendor_name = ''.join(vendor_name_list)
return vendor_name
else:
return False
def get_mfg_name(self):
mfg_name_list = self.get_qfx5200_parameter_value('Manufacture Name')
if mfg_name_list:
mfg_name = ''.join(mfg_name_list)
return mfg_name
else:
return False
def get_vendorext_name(self):
vendorext_list = self.get_qfx5200_parameter_value('Vendor Extension')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
else:
return False
def get_vendorextIANA_name(self):
vendorext_list = self.get_qfx5200_parameter_value('IANA')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
else:
return False
def get_vendorextASMREV_name(self):
vendorext_list = self.get_qfx5200_parameter_value('Assembly Part Number Revision')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
else:
return False
def get_vendorextASMPartNum_name(self):
vendorext_list = self.get_qfx5200_parameter_value('Assembly Part Number')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
else:
return False
def get_vendorextASMID_name(self):
vendorext_list = self.get_qfx5200_parameter_value('Assembly ID')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
else:
return False
def get_vendorextASMMajNum_name(self):
vendorext_list = self.get_qfx5200_parameter_value('Assembly Major Revision')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
else:
return False
def get_vendorextASMMinNum_name(self):
vendorext_list = self.get_qfx5200_parameter_value('Assembly Minor Revision')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
else:
return False
def get_vendorextCLEI_name(self):
vendorext_list = self.get_qfx5200_parameter_value('CLEI code')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
else:
return False
def get_onieversion_name(self):
onieversion_name_list = self.get_qfx5200_parameter_value('ONIE Version')
if onieversion_name_list:
onieversion_name = ''.join(onieversion_name_list)
return onieversion_name
else:
return False
def get_crc_name(self):
crc_list = self.get_qfx5200_parameter_value('CRC')
if crc_list:
crc_name = ''.join(crc_list)
return crc_name
else:
return False
def get_fan_type(self):
fantype_list = self.get_qfx5200_parameter_value('Fan Type')
if fantype_list:
fantype_name = ''.join(fantype_list)
return fantype_name
else:
return False
def get_reboot_cause(self):
"""
Retrieves the cause of the previous reboot
"""
status, last_reboot_reason = commands.getstatusoutput("busybox devmem 0xFED50004 8")
if (status == 0):
if last_reboot_reason == "0x80":
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None)
elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08":
return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None)
elif last_reboot_reason == "0x20":
return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None)
elif last_reboot_reason == "0x10":
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset")
else:
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason")
else:
time.sleep(3)
status, last_reboot_reason = commands.getstatusoutput("busybox devmem 0xFED50004 8")
if last_reboot_reason == "0x80":
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None)
elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08":
return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None)
elif last_reboot_reason == "0x20":
return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None)
elif last_reboot_reason == "0x10":
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset")
else:
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason")

View File

@ -1 +0,0 @@
../../common/modules/juniper_i2c_cpld.c

View File

@ -0,0 +1,892 @@
/*
* A hwmon driver for the juniper_i2c_cpld
*
* Tested and validated on Juniper QFX5210
* Ciju Rajan K <crajank@juniper.net>
*
* Copyright (C) 2013 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/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/list.h>
#define MAX_PORT_NUM 64
#define I2C_RW_RETRY_COUNT 10
#define I2C_RW_RETRY_INTERVAL 60 /* ms */
#define I2C_ADDR_CPLD1 0x60
#define I2C_ADDR_CPLD2 0x62
#define I2C_ADDR_CPLD3 0x64
#define CPLD_ADDRS {I2C_ADDR_CPLD1, I2C_ADDR_CPLD2, I2C_ADDR_CPLD3}
/*
* Number of additional attribute pointers to allocate
* with each call to krealloc
*/
#define ATTR_ALLOC_SIZE 1 /*For last attribute which is NUll.*/
#define NAME_SIZE 24
#define MAX_RESP_LENGTH 48
typedef ssize_t (*show_func)( struct device *dev,
struct device_attribute *attr,
char *buf);
typedef ssize_t (*store_func)(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
enum models {
AS7712_32X,
AS7716_32X,
qfx5210_64X,
AS7312_54X,
PLAIN_CPLD, /*No attribute but add i2c addr to the list.*/
NUM_MODEL
};
enum sfp_func {
HAS_SFP = 1<<0 ,
HAS_QSFP = 1<<1 ,
};
enum common_attrs {
CMN_VERSION,
CMN_ACCESS,
CMN_PRESENT_ALL,
NUM_COMMON_ATTR
};
enum sfp_attrs {
SFP_PRESENT,
SFP_RESET,
SFP_LP_MODE,
NUM_SFP_ATTR
};
struct cpld_sensor {
struct cpld_sensor *next;
char name[NAME_SIZE+1]; /* sysfs sensor name */
struct device_attribute attribute;
bool update; /* runtime sensor update needed */
int data; /* Sensor data. Negative if there was a read error */
u8 reg; /* register */
u8 mask; /* bit mask */
bool invert; /* inverted value*/
};
#define to_cpld_sensor(_attr) \
container_of(_attr, struct cpld_sensor, attribute)
struct cpld_data {
struct device *dev;
struct device *hwmon_dev;
int num_attributes;
struct attribute_group group;
enum models model;
struct cpld_sensor *sensors;
struct mutex update_lock;
bool valid;
unsigned long last_updated; /* in jiffies */
int attr_index;
u16 sfp_num;
u8 sfp_types;
struct model_attrs *cmn_attr;
};
struct cpld_client_node {
struct i2c_client *client;
struct list_head list;
};
struct base_attrs {
const char *name;
umode_t mode;
show_func get;
store_func set;
};
struct attrs {
int reg;
bool invert;
struct base_attrs *base;
};
struct model_attrs {
struct attrs **cmn;
struct attrs **portly;
};
static ssize_t show_bit(struct device *dev,
struct device_attribute *devattr, char *buf);
static ssize_t show_presnet_all(struct device *dev,
struct device_attribute *devattr, char *buf);
static ssize_t set_1bit(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static ssize_t set_byte(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);
int juniper_i2c_cpld_read(u8 cpld_addr, u8 reg);
int juniper_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
struct base_attrs common_attrs[NUM_COMMON_ATTR] =
{
[CMN_VERSION] = {"version", S_IRUGO, show_bit, NULL},
[CMN_ACCESS] = {"access", S_IWUSR, NULL, set_byte},
[CMN_PRESENT_ALL] = {"module_present_all", S_IRUGO, show_presnet_all, NULL},
};
struct attrs as7712_common[] = {
[CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]},
[CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]},
[CMN_PRESENT_ALL] = {0x30, false, &common_attrs[CMN_PRESENT_ALL]},
};
struct attrs qfx5210_common[] = {
[CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]},
[CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]},
[CMN_PRESENT_ALL] = {0x30, false, &common_attrs[CMN_PRESENT_ALL]},
};
struct attrs as7312_common[] = {
[CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]},
[CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]},
[CMN_PRESENT_ALL] = {-1, false, &common_attrs[CMN_PRESENT_ALL]},
};
struct attrs plain_common[] = {
[CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]},
};
struct base_attrs portly_attrs[] =
{
[SFP_PRESENT] = {"module_present", S_IRUGO, show_bit, NULL},
// Only root user will have the privilege to write to sysfs
// [SFP_RESET] = {"module_reset", S_IRUGO|S_IWUGO, show_bit, set_1bit},
[SFP_RESET] = {"module_reset", S_IRUGO|S_IWUSR, show_bit, set_1bit},
};
struct attrs as7712_port[] = {
{0x30, true, &portly_attrs[SFP_PRESENT]},
{0x04, true, &portly_attrs[SFP_RESET]},
};
struct attrs qfx5210_port[] = {
{0x70, true, &portly_attrs[SFP_PRESENT]},
{0x40, true, &portly_attrs[SFP_RESET]},
};
struct attrs *as7712_cmn_list[] = {
&as7712_common[CMN_VERSION],
&as7712_common[CMN_ACCESS],
&as7712_common[CMN_PRESENT_ALL],
NULL
};
struct attrs *qfx5210_cmn_list[] = {
&qfx5210_common[CMN_VERSION],
&qfx5210_common[CMN_ACCESS],
&qfx5210_common[CMN_PRESENT_ALL],
NULL
};
struct attrs *as7312_cmn_list[] = {
&as7312_common[CMN_VERSION],
&as7312_common[CMN_ACCESS],
&as7312_common[CMN_PRESENT_ALL],
NULL
};
struct attrs *plain_cmn_list[] = {
&plain_common[CMN_VERSION],
NULL
};
struct attrs *as7712_port_list[] = {
&as7712_port[SFP_PRESENT],
&as7712_port[SFP_RESET],
NULL
};
struct attrs *qfx5210_port_list[] = {
&qfx5210_port[SFP_PRESENT],
&qfx5210_port[SFP_RESET],
NULL
};
struct model_attrs models_attr[NUM_MODEL] = {
{.cmn = as7712_cmn_list, .portly=as7712_port_list},
{.cmn = as7712_cmn_list, .portly=as7712_port_list}, /*7716's as 7712*/
{.cmn = qfx5210_cmn_list, .portly=qfx5210_port_list},
{.cmn = as7312_cmn_list, .portly=qfx5210_port_list},
{.cmn = plain_cmn_list, .portly=NULL},
};
static LIST_HEAD(cpld_client_list);
static struct mutex list_lock;
/* Addresses scanned for juniper_i2c_cpld
*/
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
static int get_sfp_spec(int model, u16 *num, u8 *types)
{
switch (model) {
case AS7712_32X:
case AS7716_32X:
*num = 32;
*types = HAS_QSFP;
break;
case qfx5210_64X:
*num = 64;
*types = HAS_QSFP;
break;
case AS7312_54X:
*num = 54;
*types = HAS_QSFP|HAS_SFP;
default:
*types = 0;
*num = 0;
break;
}
return 0;
}
static int get_present_reg(int model, u8 port, u8 *cpld_addr, u8 *reg, u8 *num)
{
u8 cpld_address[] = CPLD_ADDRS;
switch (model) {
case AS7312_54X:
if (port < 48) {
*cpld_addr = cpld_address[1 + port/24];
*reg = 0x09 + (port%24)/8;
*num = 8;
}
else
{
*reg = 0x18;
*num = 4;
*cpld_addr = ( port < 52)? cpld_address[1]: cpld_address[2];
}
break;
default:
return -EINVAL;
}
}
/*Assume the bits for ports are listed in-a-row.*/
static int get_reg_bit(u8 reg_start, int port,
u8 *reg ,u8 *mask)
{
*reg = reg_start + ((port)/8);
*mask = 1 << ((port)%8);
return 0;
}
static int 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;
}
static int 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;
}
/*Turn a numberic array into string with " " between each element.
* e.g., {0x11, 0x33, 0xff, 0xf1} => "11 33 ff f1"
*/
static ssize_t array_stringify(char *buf, u8 *input, size_t size) {
int i;
char t[MAX_RESP_LENGTH+1];
buf[0] = '\0';
for (i = 0; i < size; i++) {
snprintf(t, MAX_RESP_LENGTH, "%x ", input[i]);
strncat(buf, t, MAX_RESP_LENGTH);
}
if (strlen(buf) > 0)
buf[strlen(buf)-1] = '\0'; /*Remove tailing blank*/
return snprintf(buf, MAX_RESP_LENGTH, "%s\n", buf);
}
static ssize_t show_presnet_all_distinct(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct cpld_data *data = i2c_get_clientdata(client);
u8 i, value, reg;
u8 cpld_addr, num;
u8 _value[8];
u64 *values = (u64 *)_value;
values = 0;
mutex_lock(&data->update_lock);
while(i < data->sfp_num)
{
get_present_reg(data->model, i, &cpld_addr, &reg, &num);
if(cpld_addr == client->addr)
value = cpld_read_internal(client, reg);
else
value = juniper_i2c_cpld_read(cpld_addr, reg);
if (unlikely(value < 0)) {
goto exit;
}
*values |= (value&((1<<(num))-1)) << i;
i += num;
}
mutex_unlock(&data->update_lock);
*values = cpu_to_le64(*values);
return array_stringify(buf, _value, i);
exit:
mutex_unlock(&data->update_lock);
return value;
}
static ssize_t show_presnet_all(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct cpld_data *data = i2c_get_clientdata(client);
struct cpld_sensor *sensor = to_cpld_sensor(devattr);
u8 i, values[MAX_RESP_LENGTH/8];
if (sensor->reg < 0) {
return show_presnet_all_distinct(dev, devattr, buf);
}
mutex_lock(&data->update_lock);
for (i = 0; i < ((data->sfp_num+7)/8); i++) {
values[i] = cpld_read_internal(client, sensor->reg + i);
if (unlikely(values[i] < 0)) {
goto exit;
}
}
mutex_unlock(&data->update_lock);
return array_stringify(buf, values, i);
exit:
mutex_unlock(&data->update_lock);
return values[i];
}
static ssize_t show_bit(struct device *dev,
struct device_attribute *devattr, char *buf)
{
int value;
struct i2c_client *client = to_i2c_client(dev);
struct cpld_data *data = i2c_get_clientdata(client);
struct cpld_sensor *sensor = to_cpld_sensor(devattr);
mutex_lock(&data->update_lock);
value = cpld_read_internal(client, sensor->reg);
value = value & sensor->mask;
if (sensor->invert)
value = !value;
mutex_unlock(&data->update_lock);
return snprintf(buf, PAGE_SIZE, "%x\n", value);
}
static ssize_t set_1bit(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
long is_reset;
int value, status;
struct i2c_client *client = to_i2c_client(dev);
struct cpld_data *data = i2c_get_clientdata(client);
struct cpld_sensor *sensor = to_cpld_sensor(devattr);
u8 cpld_bit, reg;
status = kstrtol(buf, 10, &is_reset);
if (status) {
return status;
}
reg = sensor->reg;
cpld_bit = sensor->mask;
mutex_lock(&data->update_lock);
value = cpld_read_internal(client, reg);
if (unlikely(status < 0)) {
goto exit;
}
if (sensor->invert)
is_reset = !is_reset;
if (is_reset) {
value |= cpld_bit;
}
else {
value &= ~cpld_bit;
}
status = cpld_write_internal(client, reg, value);
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_byte(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
return access(dev, da, buf, count);
}
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 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 = 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 juniper_i2c_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 juniper_i2c_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 int cpld_add_attribute(struct cpld_data *data, struct attribute *attr)
{
int new_max_attrs = ++data->num_attributes + ATTR_ALLOC_SIZE;
void *new_attrs = krealloc(data->group.attrs,
new_max_attrs * sizeof(void *),
GFP_KERNEL);
if (!new_attrs)
return -ENOMEM;
data->group.attrs = new_attrs;
data->group.attrs[data->num_attributes-1] = attr;
data->group.attrs[data->num_attributes] = NULL;
return 0;
}
static void cpld_dev_attr_init(struct device_attribute *dev_attr,
const char *name, umode_t mode,
show_func show, store_func store)
{
sysfs_attr_init(&dev_attr->attr);
dev_attr->attr.name = name;
dev_attr->attr.mode = mode;
dev_attr->show = show;
dev_attr->store = store;
}
static struct cpld_sensor * add_sensor(struct cpld_data *data,
const char *name,
u8 reg, u8 mask, bool invert,
bool update, umode_t mode,
show_func get, store_func set)
{
struct cpld_sensor *sensor;
struct device_attribute *a;
sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor)
return NULL;
a = &sensor->attribute;
snprintf(sensor->name, sizeof(sensor->name), name);
sensor->reg = reg;
sensor->mask = mask;
sensor->update = update;
sensor->invert = invert;
cpld_dev_attr_init(a, sensor->name,
mode,
get, set);
if (cpld_add_attribute(data, &a->attr))
return NULL;
sensor->next = data->sensors;
data->sensors = sensor;
return sensor;
}
static int add_attributes_cmn(struct cpld_data *data, struct attrs **cmn)
{
u8 reg, i ;
bool invert;
struct attrs *a;
struct base_attrs *b;
if (NULL == cmn)
return -1;
for (i = 0; cmn[i]; i++)
{
a = cmn[i];
reg = a->reg;
invert = a->invert;
b = a->base;
if (NULL == b)
break;
if (add_sensor(data, b->name,
reg, 0xff, invert,
true, b->mode,
b->get, b->set) == NULL)
{
return -ENOMEM;
}
}
return 0;
}
static int add_attributes_portly(struct cpld_data *data, struct attrs **pa)
{
char name[NAME_SIZE+1];
int i, j;
u8 reg, mask, invert;
struct attrs *a;
struct base_attrs *b;
if (NULL == pa)
return -1;
for (i = 0; pa[i]; i++) {
a = pa[i];
invert = a->invert;
b = a->base;
if (b == NULL)
break;
for (j = 0; j < data->sfp_num; j++)
{
snprintf(name, NAME_SIZE, "%s_%d", b->name, j+1);
get_reg_bit(a->reg, j, &reg, &mask);
if (add_sensor(data, name, reg, mask, invert,
true, b->mode, b->get, b->set) == NULL)
{
return -ENOMEM;
}
}
}
return 0;
}
static int add_attributes(struct i2c_client *client,
struct cpld_data *data)
{
struct model_attrs *m = data->cmn_attr;
if (m == NULL)
return -EINVAL;
/* Common attributes.*/
add_attributes_cmn(data, m->cmn);
/* Port-wise attributes.*/
add_attributes_portly(data, m->portly);
return 0;
}
static int juniper_i2c_cpld_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
int status;
struct cpld_data *data = NULL;
struct device *dev = &client->dev;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_dbg(dev, "i2c_check_functionality failed (0x%x)\n", client->addr);
return -EIO;
}
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data) {
return -ENOMEM;
}
data->model = dev_id->driver_data;
data->cmn_attr = &models_attr[data->model];
get_sfp_spec(data->model, &data->sfp_num, &data->sfp_types);
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
data->dev = dev;
dev_info(dev, "chip found\n");
status = add_attributes(client, data);
if (status)
goto out_kfree;
/*
* If there are no attributes, something is wrong.
* Bail out instead of trying to register nothing.
*/
if (!data->num_attributes) {
dev_err(dev, "No attributes found\n");
status = -ENODEV;
goto out_kfree;
}
/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &data->group);
if (status) {
goto out_kfree;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
status = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
juniper_i2c_cpld_add_client(client);
dev_info(dev, "%s: cpld '%s'\n",
dev_name(data->hwmon_dev), client->name);
return 0;
exit_remove:
sysfs_remove_group(&client->dev.kobj, &data->group);
out_kfree:
kfree(data->group.attrs);
return status;
}
static int juniper_i2c_cpld_remove(struct i2c_client *client)
{
struct cpld_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->group);
kfree(data->group.attrs);
juniper_i2c_cpld_remove_client(client);
return 0;
}
int juniper_i2c_cpld_read(u8 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 = i2c_smbus_read_byte_data(cpld_node->client, reg);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(juniper_i2c_cpld_read);
int juniper_i2c_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 = i2c_smbus_write_byte_data(cpld_node->client, reg, value);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(juniper_i2c_cpld_write);
static const struct i2c_device_id juniper_i2c_cpld_id[] = {
{ "cpld_as7712", AS7712_32X},
{ "cpld_as7716", AS7716_32X},
{ "cpld_qfx5210", qfx5210_64X},
{ "cpld_as7312", AS7312_54X},
{ "cpld_plain", PLAIN_CPLD},
{ },
};
MODULE_DEVICE_TABLE(i2c, juniper_i2c_cpld_id);
static struct i2c_driver juniper_i2c_cpld_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "juniper_i2c_cpld",
},
.probe = juniper_i2c_cpld_probe,
.remove = juniper_i2c_cpld_remove,
.id_table = juniper_i2c_cpld_id,
.address_list = normal_i2c,
};
static int __init juniper_i2c_cpld_init(void)
{
mutex_init(&list_lock);
return i2c_add_driver(&juniper_i2c_cpld_driver);
}
static void __exit juniper_i2c_cpld_exit(void)
{
i2c_del_driver(&juniper_i2c_cpld_driver);
}
module_init(juniper_i2c_cpld_init);
module_exit(juniper_i2c_cpld_exit);
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("juniper_i2c_cpld driver");
MODULE_LICENSE("GPL");

View File

@ -1 +0,0 @@
../../common/modules/ym2651y.c

View File

@ -0,0 +1,622 @@
/*
* An hwmon driver for the 3Y Power YM-2651Y Power Module
*
* Tested and validated on Juniper QFX5210
* Ciju Rajan K <crajank@juniper.net>
*
* 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,
};
/* 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 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 */
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_id[10]; /* Register value */
u8 mfr_model[10]; /* 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_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_MFR_ID,
PSU_MFR_MODEL,
PSU_MFR_REVISION,
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_linear, 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_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_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_linear, 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_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_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 */
ptr = data->fan_dir;
break;
case PSU_MFR_ID: /* psu_mfr_id */
ptr = data->mfr_id;
break;
case PSU_MFR_MODEL: /* psu_mfr_model */
ptr = data->mfr_model;
break;
case PSU_MFR_REVISION: /* psu_mfr_revision */
ptr = data->mfr_revsion;
break;
default:
return 0;
}
return sprintf(buf, "%s\n", ptr);
}
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);
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 },
{}
};
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;
u8 command;
u8 fan_dir[5] = {0};
struct reg_data_byte regs_byte[] = { {0x19, &data->capability},
{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;
}
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;
}
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);
}
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;
status = ym2651y_read_block(client, command, data->mfr_model,
ARRAY_SIZE(data->mfr_model)-1);
data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0';
if (status < 0)
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
/* 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);
data->last_updated = jiffies;
data->valid = 1;
}
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

@ -1,67 +0,0 @@
#!/usr/bin/env python
#
# Name: platform.py, version: 1.0
#
# Description: Module contains the definitions of SONiC platform APIs
# which provide the platform specific details
#
# Copyright (c) 2019, Juniper Networks, Inc.
# All rights reserved.
#
# Notice and Disclaimer: This code is licensed to you under the GNU General
# Public License as published by the Free Software Foundation, version 3 or
# any later version. This code is not an official Juniper product. You can
# obtain a copy of the License at <https://www.gnu.org/licenses/>
#
# OSS License:
#
# 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 <https://www.gnu.org/licenses/>.
#
# Third-Party Code: This code may depend on other components under separate
# copyright notice and license terms. Your use of the source code for those
# components is subject to the terms and conditions of the respective license
# as noted in the Third-Party source code file.
#
import sys
try:
from sonic_platform_base.platform_base import PlatformBase
except ImportError as e:
raise ImportError("%s - required module not found" % e)
platformDict = {'platform':'QFX5210-64C'}
class Platform(PlatformBase):
def __init__(self):
self.platform = self.getPlatform()
def getPlatformDict(self):
global platformDict
if platformDict:
return platformDict
def readPlatformName(self):
return self.getPlatformDict().get('platform')
def getPlatform(self):
platformCls = self.readPlatformName()
return platformCls
def get_chassis(self):
from chassis import Chassis
chassis = Chassis()
return chassis

View File

@ -35,20 +35,12 @@
try:
import os
import commands
import sys, getopt
import subprocess
import click
import imp
import logging
import logging.config
import logging.handlers
import types
import time
import traceback
import glob
import collections
import StringIO
from tabulate import tabulate
except ImportError as e:
raise ImportError('%s - required module not found' % str(e))
@ -58,17 +50,16 @@ FUNCTION_NAME = '/var/log/juniper_qfx5210_monitor'
verbose = False
DEBUG = False
global log_file
global log_level
log_file = '%s.log' % FUNCTION_NAME
log_level = logging.DEBUG
global isPlatformAFI
global is80PerFlag
global is60PerFlag
global isFireThresholdReached
global isFireThresholdPrint
global PrevASICValue
global FireThresholdSecsRemaining
isPlatformAFI = False
is80PerFlag = True
is60PerFlag = True
isFireThresholdReached = False
isFireThresholdPrint = True
PrevASICValue = 0
FireThresholdSecsRemaining = 120
temp_policy_AFI = {
0: [[70, 0, 48000], [70, 48000, 53000], [80, 53000, 0], [80, 53000, 58000], [100, 58000, 0], ['Yellow Alarm', 64000, 70000], ['Red Alarm', 70000, 75000], ['Fire Shut Alarm', 75000, 0]],
@ -201,7 +192,7 @@ class QFX5210_ThermalUtil(object):
try:
val_file.close()
except:
except IOError as e:
logging.debug('get_sensor_node_val: unable to close file. device_path:%s', device_path)
return None
@ -227,8 +218,8 @@ class QFX5210_ThermalUtil(object):
return None
try:
val_file.close()
except:
val_file.close()
except IOError as e:
logging.debug('get_coretemp_node_val: unable to close file. device_path:%s', device_path)
return None
@ -326,7 +317,7 @@ class QFX5210_ThermalUtil(object):
isFireThresholdReached == False
time.sleep(20)
cmd = "poweroff"
returned_value = os.system(cmd)
os.system(cmd)
for x in range(self.SENSOR_CORETEMP_NUM_ON_MAIN_BOARD):
if x < self.SENSOR_NUM_ON_MAIN_BOARD:
@ -340,7 +331,7 @@ class QFX5210_ThermalUtil(object):
proc = subprocess.Popen("bcmcmd \"show temp\" | grep \"maximum peak temperature\" | awk '{ print $5 }' > /var/log/asic_value 2>&1 & ",shell=True)
time.sleep(2)
cmd = "kill -9 %s"%(proc.pid)
status, cmd_out = commands.getstatusoutput(cmd)
commands.getstatusoutput(cmd)
if os.stat("/var/log/asic_value").st_size == 0:
value = PrevASICValue
@ -531,13 +522,6 @@ class device_monitor(object):
def __init__(self, log_file, log_level):
global DEBUG
global isPlatformAFI
global isFireThresholdReached
global is80PerFlag
global is60PerFlag
global isFireThresholdPrint
global PrevASICValue
global FireThresholdSecsRemaining
MASTER_LED_PATH = '/sys/class/leds/master/brightness'
SYSTEM_LED_PATH = '/sys/class/leds/system/brightness'
FANTYPE_PATH = '/sys/bus/i2c/devices/17-0068/fan1_direction'
@ -561,27 +545,26 @@ class device_monitor(object):
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)
import sonic_platform
platform = sonic_platform.platform.Platform()
chassis = platform.get_chassis()
fan_type = chassis.get_fan_type(FANTYPE_PATH)
try:
fan_type_file = open(FANTYPE_PATH)
except IOError as e:
print "Error: unable to open file: %s" % str(e)
fan_type = -1
else:
fan_type = fan_type_file.read()
fan_type_file.close()
# the return value of get_fan_type is AFO = 0, AFI = 1 and for error condition it is -1
# In the error condition also, we are making default platform as AFO, to continue with Energy Monitoring
if (int(fan_type) == -1 or int(fan_type) == 0):
logging.debug('FANTYPE_PATH. fan_type %d', int(fan_type))
if (int(fan_type) == -1):
logging.error('device_monitor: unable to open sys file for fan handling, defaulting it to AFO')
isPlatformAFI = False
else:
isPlatformAFI = True
isFireThresholdReached = False
is80PerFlag = True
is60PerFlag = True
isFireThresholdPrint = True
FireThresholdSecsRemaining = 120
PrevASICValue = 0
master_led_value = 1
try:
masterLED_file = open(MASTER_LED_PATH, 'r+')
@ -605,9 +588,7 @@ class device_monitor(object):
thermal.getSensorTemp()
def main():
log_file = '%s.log' % FUNCTION_NAME
log_level = logging.DEBUG
#Introducing sleep of 150 seconds to wait for all the docker containers to start before starting the EM policy.
time.sleep(150)
monitor = device_monitor(log_file, log_level)

View File

@ -39,11 +39,7 @@ import commands
import sys, getopt
import binascii
import logging
import re
import time
import random
import optparse
from collections import namedtuple
@ -138,145 +134,16 @@ def main():
except OSError:
print 'Error: Execution of "%s" failed', DisableWatchDogCmd
return False
CPUeepromFileCmd = 'cat /sys/devices/pci0000:00/0000:00:1f.3/i2c-0/0-0056/eeprom > /etc/init.d/eeprom_qfx5210_ascii'
# Write the contents of CPU EEPROM to file
time.sleep(1)
# Invoking the script which retrieves the data from Board EEPROM and storing in file
EEPROMDataCmd = 'python /usr/share/sonic/device/x86_64-juniper_qfx5210-r0/plugins/qfx5210_eeprom_data.py'
try:
os.system(CPUeepromFileCmd)
os.system(EEPROMDataCmd)
except OSError:
print 'Error: Execution of "%s" failed', CPUeepromFileCmd
print 'Error: Execution of "%s" failed', EEPROMDataCmd
return False
eeprom_ascii = '/etc/init.d/eeprom_qfx5210_ascii'
# Read file contents in Hex format
with open(eeprom_ascii, 'rb') as Hexformat:
content = Hexformat.read()
Hexformatoutput = binascii.hexlify(content)
eeprom_hex = '/etc/init.d/eeprom_qfx5210_hex'
#Write contents of CPU EEPROM to new file in hexa format
with open(eeprom_hex, 'wb+') as Hexfile:
Hexfile.write(Hexformatoutput)
# Read from EEPROM Hex file and extract the different fields like Product name,
# Part Number, Serial Number MAC Address, Mfg Date ... etc and store in /var/run/eeprom file
with open(eeprom_hex, 'rb') as eeprom_hexfile:
# moving the file pointer to required position where product name is stored in EEPROM file and reading the required bytes from this position
product_position = eeprom_hexfile.seek(26, 0)
product_read = eeprom_hexfile.read(36)
product_name = binascii.unhexlify(product_read)
# creating the "/var/run/eeprom" file and storing all the values of different fields in this file.
eeprom_file = open ("/var/run/eeprom", "a+")
eeprom_file.write("Product Name=%s\r\n" % str(product_name))
# like wise we are moving the file pointer to respective position where other fields are stored and extract these fields and store in /var/run/eeprom file
partnumber_position = eeprom_hexfile.seek(66, 0)
partnumber_read = eeprom_hexfile.read(20)
partnumber_name = binascii.unhexlify(partnumber_read)
eeprom_file.write("Part Number=%s\r\n" % str(partnumber_name))
serialnumber_position = eeprom_hexfile.seek(90, 0)
serialnumber_read = eeprom_hexfile.read(24)
serialnumber_name = binascii.unhexlify(serialnumber_read)
eeprom_file.write("Serial Number=%s\r\n" % str(serialnumber_name))
macaddress_position = eeprom_hexfile.seek(118, 0)
macaddress_read = eeprom_hexfile.read(12)
macaddress_name=""
for i in range(0,12,2):
macaddress_name += macaddress_read[i:i+2] + ":"
macaddress_name=macaddress_name[:-1]
eeprom_file.write("MAC Address=%s\r\n" % str(macaddress_name))
mfgdate_position = eeprom_hexfile.seek(132, 0)
mfgdate_read = eeprom_hexfile.read(40)
mfgdate_name = binascii.unhexlify(mfgdate_read)
eeprom_file.write("Manufacture Date=%s\r\n" % str(mfgdate_name))
devversion_position = eeprom_hexfile.seek(176, 0)
devversion_read = eeprom_hexfile.read(2)
eeprom_file.write("Device Version=%s\r\n" % str(devversion_read))
platform_position = eeprom_hexfile.seek(182, 0)
platform_read = eeprom_hexfile.read(68)
platform_name = binascii.unhexlify(platform_read)
eeprom_file.write("Platform Name=%s\r\n" % str(platform_name))
MACnumber_position = eeprom_hexfile.seek(254, 0)
MACnumber_read = eeprom_hexfile.read(4)
MACnumber = int(MACnumber_read, 16)
eeprom_file.write("Number of MAC Addresses=%s\r\n" % str(MACnumber))
vendorName_position = eeprom_hexfile.seek(262, 0)
vendorName_read = eeprom_hexfile.read(40)
vendorName = binascii.unhexlify(vendorName_read)
eeprom_file.write("Vendor Name=%s\r\n" % str(vendorName))
mfgname_position = eeprom_hexfile.seek(306, 0)
mfgname_read = eeprom_hexfile.read(40)
mfgname = binascii.unhexlify(mfgname_read)
eeprom_file.write("Manufacture Name=%s\r\n" % str(mfgname))
vendorext_position = eeprom_hexfile.seek(350, 0)
vendorext_read = eeprom_hexfile.read(124)
vendorext=""
vendorext += "0x" + vendorext_read[0:2]
for i in range(2,124,2):
vendorext += " 0x" + vendorext_read[i:i+2]
eeprom_file.write("Vendor Extension=%s\r\n" % str(vendorext))
IANA_position = eeprom_hexfile.seek(350, 0)
IANA_read = eeprom_hexfile.read(8)
IANAName = binascii.unhexlify(IANA_read)
eeprom_file.write("IANA=%s\r\n" % str(IANAName))
ASMpartrev_position = eeprom_hexfile.seek(358, 0)
ASMpartrev_read = eeprom_hexfile.read(4)
ASMpartrev = binascii.unhexlify(ASMpartrev_read)
eeprom_file.write("Assembly Part Number Rev=%s\r\n" % str(ASMpartrev))
ASMpartnum_position = eeprom_hexfile.seek(374, 0)
ASMpartnum_read = eeprom_hexfile.read(20)
ASMpartnum_read = binascii.unhexlify(ASMpartnum_read)
eeprom_file.write("Assembly Part Number=%s\r\n" % str(ASMpartnum_read))
ASMID_position = eeprom_hexfile.seek(402, 0)
ASMID_read = eeprom_hexfile.read(4)
ASMID_read_upper = ASMID_read.upper()
eeprom_file.write("Assembly ID=0x%s\r\n" % str(ASMID_read_upper))
ASMHWMajRev_position = eeprom_hexfile.seek(410, 0)
ASMHWMajRev_read = eeprom_hexfile.read(2)
eeprom_file.write("Assembly Major Revision=0x%s\r\n" % str(ASMHWMajRev_read))
ASMHWMinRev_position = eeprom_hexfile.seek(416, 0)
ASMHWMinRev_read = eeprom_hexfile.read(2)
eeprom_file.write("Assembly Minor Revision=0x%s\r\n" % str(ASMHWMinRev_read))
Deviation_position = eeprom_hexfile.seek(422, 0)
Deviation_read = eeprom_hexfile.read(28)
Deviation_read_upper = Deviation_read.upper()
eeprom_file.write("Deviation=0x%s\r\n" % str(Deviation_read_upper))
CLEI_position = eeprom_hexfile.seek(450, 0)
CLEI_read = eeprom_hexfile.read(20)
CLEI_name = binascii.unhexlify(CLEI_read)
eeprom_file.write("CLEI code=%s\r\n" % str(CLEI_name))
ONIEversion_position = eeprom_hexfile.seek(478, 0)
ONIEversion_read = eeprom_hexfile.read(22)
ONIEversion = binascii.unhexlify(ONIEversion_read)
eeprom_file.write("ONIE Version=%s\r\n" % str(ONIEversion))
CRC_position = eeprom_hexfile.seek(504, 0)
CRC = eeprom_hexfile.read(8)
eeprom_file.write("CRC=%s\r\n" % str(CRC))
eeprom_file.close()
return True
def show_help():

View File

@ -8,9 +8,9 @@ os.listdir
setup(
name='sonic_platform',
version='1.0',
description='Module to initialize Juniper QFX5210-64X platforms',
description='Module to initialize Juniper platforms',
packages=['sonic_platform'],
package_dir={'sonic_platform': 'qfx5210/sonic_platform'},
package_dir={'sonic_platform': 'sonic_platform'},
)

View File

@ -5,7 +5,7 @@
# Description: Module contains the definitions of SONiC platform APIs
# which provide the chassis specific details
#
# Copyright (c) 2019, Juniper Networks, Inc.
# Copyright (c) 2020, Juniper Networks, Inc.
# All rights reserved.
#
# Notice and Disclaimer: This code is licensed to you under the GNU General
@ -39,26 +39,24 @@ try:
import commands
import sys
import time
import syslog
from sonic_platform_base.chassis_base import ChassisBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
SYSLOG_IDENTIFIER = "Juniper-Chassis"
def log_info(msg):
syslog.openlog(SYSLOG_IDENTIFIER)
syslog.syslog(syslog.LOG_INFO, msg)
syslog.closelog()
class Chassis(ChassisBase):
"""
JUNIPER QFX5210 Platform-specific Chassis class
"""
# Find the last reboot reason out of following
# CPLD_WATCHDOG_RESET 0x08
# POWER_ON_RESET 0x20
# CPU_WATCHDOG_RESET 0x40
# SOFTWARE_RESET 0x80
def __init__(self):
ChassisBase.__init__(self)
def get_qfx5210_parameter_value(self,parameter_name):
def get_parameter_value(self,parameter_name):
try:
with open("/var/run/eeprom", "r") as file:
for item in file:
@ -71,7 +69,7 @@ class Chassis(ChassisBase):
return "False"
def get_product_name(self):
product_name_list = self.get_qfx5210_parameter_value('Product Name')
product_name_list = self.get_parameter_value('Product Name')
if product_name_list:
product_name = ''.join(product_name_list)
return product_name
@ -80,7 +78,7 @@ class Chassis(ChassisBase):
def get_part_number(self):
part_number_list = self.get_qfx5210_parameter_value('Part Number')
part_number_list = self.get_parameter_value('Part Number')
if part_number_list:
part_number = ''.join(part_number_list)
return part_number
@ -89,7 +87,7 @@ class Chassis(ChassisBase):
def get_serial_number(self):
serial_number_list = self.get_qfx5210_parameter_value('Serial Number')
serial_number_list = self.get_parameter_value('Serial Number')
if serial_number_list:
serial_number = ''.join(serial_number_list)
return serial_number
@ -98,7 +96,7 @@ class Chassis(ChassisBase):
def get_base_mac(self):
mac_list = self.get_qfx5210_parameter_value('MAC')
mac_list = self.get_parameter_value('MAC')
if mac_list:
mac = ''.join(mac_list)
return mac
@ -107,7 +105,7 @@ class Chassis(ChassisBase):
def get_mfg_date(self):
mfgdate_list = self.get_qfx5210_parameter_value('Manufacture Date')
mfgdate_list = self.get_parameter_value('Manufacture Date')
if mfgdate_list:
mfgdate = ''.join(mfgdate_list)
return mfgdate
@ -115,7 +113,7 @@ class Chassis(ChassisBase):
return False
def get_deviceversion_name(self):
device_version_list = self.get_qfx5210_parameter_value('Device Version')
device_version_list = self.get_parameter_value('Device Version')
if device_version_list:
deviceversion_name = ''.join(device_version_list)
return deviceversion_name
@ -123,7 +121,7 @@ class Chassis(ChassisBase):
return False
def get_platform_name(self):
platform_name_list = self.get_qfx5210_parameter_value('Platform Name')
platform_name_list = self.get_parameter_value('Platform Name')
if platform_name_list:
platform_name = ''.join(platform_name_list)
return platform_name
@ -131,7 +129,7 @@ class Chassis(ChassisBase):
return False
def get_MACnumber_name(self):
MACnumber_name_list = self.get_qfx5210_parameter_value('Number of MAC Addresses')
MACnumber_name_list = self.get_parameter_value('Number of MAC Addresses')
if MACnumber_name_list:
MACnumber_name = ''.join(MACnumber_name_list)
return MACnumber_name
@ -139,7 +137,7 @@ class Chassis(ChassisBase):
return False
def get_vendor_name(self):
vendor_name_list = self.get_qfx5210_parameter_value('Vendor Name')
vendor_name_list = self.get_parameter_value('Vendor Name')
if vendor_name_list:
vendor_name = ''.join(vendor_name_list)
return vendor_name
@ -147,7 +145,7 @@ class Chassis(ChassisBase):
return False
def get_mfg_name(self):
mfg_name_list = self.get_qfx5210_parameter_value('Manufacture Name')
mfg_name_list = self.get_parameter_value('Manufacture Name')
if mfg_name_list:
mfg_name = ''.join(mfg_name_list)
return mfg_name
@ -155,7 +153,7 @@ class Chassis(ChassisBase):
return False
def get_vendorext_name(self):
vendorext_list = self.get_qfx5210_parameter_value('Vendor Extension')
vendorext_list = self.get_parameter_value('Vendor Extension')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
@ -163,7 +161,7 @@ class Chassis(ChassisBase):
return False
def get_vendorextIANA_name(self):
vendorext_list = self.get_qfx5210_parameter_value('IANA')
vendorext_list = self.get_parameter_value('IANA')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
@ -171,7 +169,7 @@ class Chassis(ChassisBase):
return False
def get_vendorextASMREV_name(self):
vendorext_list = self.get_qfx5210_parameter_value('Assembly Part Number Rev')
vendorext_list = self.get_parameter_value('Assembly Part Number Rev')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
@ -179,7 +177,7 @@ class Chassis(ChassisBase):
return False
def get_vendorextASMPartNum_name(self):
vendorext_list = self.get_qfx5210_parameter_value('Assembly Part Number')
vendorext_list = self.get_parameter_value('Assembly Part Number')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
@ -187,7 +185,7 @@ class Chassis(ChassisBase):
return False
def get_vendorextASMID_name(self):
vendorext_list = self.get_qfx5210_parameter_value('Assembly ID')
vendorext_list = self.get_parameter_value('Assembly ID')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
@ -195,7 +193,7 @@ class Chassis(ChassisBase):
return False
def get_vendorextASMMajNum_name(self):
vendorext_list = self.get_qfx5210_parameter_value('Assembly Major Revision')
vendorext_list = self.get_parameter_value('Assembly Major Revision')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
@ -203,7 +201,7 @@ class Chassis(ChassisBase):
return False
def get_vendorextASMMinNum_name(self):
vendorext_list = self.get_qfx5210_parameter_value('Assembly Minor Revision')
vendorext_list = self.get_parameter_value('Assembly Minor Revision')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
@ -211,7 +209,7 @@ class Chassis(ChassisBase):
return False
def get_vendorextCLEI_name(self):
vendorext_list = self.get_qfx5210_parameter_value('CLEI code')
vendorext_list = self.get_parameter_value('CLEI code')
if vendorext_list:
vendorext = ''.join(vendorext_list)
return vendorext
@ -219,7 +217,7 @@ class Chassis(ChassisBase):
return False
def get_onieversion_name(self):
onieversion_name_list = self.get_qfx5210_parameter_value('ONIE Version')
onieversion_name_list = self.get_parameter_value('ONIE Version')
if onieversion_name_list:
onieversion_name = ''.join(onieversion_name_list)
return onieversion_name
@ -227,51 +225,75 @@ class Chassis(ChassisBase):
return False
def get_crc_name(self):
crc_list = self.get_qfx5210_parameter_value('CRC')
crc_list = self.get_parameter_value('CRC')
if crc_list:
crc_name = ''.join(crc_list)
return crc_name
else:
return False
def get_fan_type(self, fantype_path):
try:
fan_type_file = open(fantype_path)
except IOError as e:
print "Error: unable to open file: %s" % str(e)
return "-1"
else:
fan_type = fan_type_file.read()
fan_type_file.close()
return str(fan_type)
def get_reboot_cause(self):
"""
Retrieves the cause of the previous reboot
"""
status, last_reboot_reason = commands.getstatusoutput("i2cget -y 0 0x65 0x24")
if (status == 0):
if last_reboot_reason == "0x80":
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None)
elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08":
return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None)
elif last_reboot_reason == "0x20":
return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None)
elif last_reboot_reason == "0x10":
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset")
platform_name = self.get_platform_name()
platform_name = platform_name.replace("\r","")
platform_name = platform_name.replace("\n","")
log_info("Juniper Platform name: {} and {}".format(self.get_platform_name(), platform_name))
if str(platform_name) == "x86_64-juniper_networks_qfx5210-r0":
log_info("Juniper Platform QFX5210 ")
status, last_reboot_reason = commands.getstatusoutput("i2cget -f -y 0 0x65 0x24")
if (status == 0):
if last_reboot_reason == "0x80":
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None)
elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08":
return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None)
elif last_reboot_reason == "0x20":
return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None)
elif last_reboot_reason == "0x10":
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset")
else:
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason")
else:
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason")
time.sleep(3)
status, last_reboot_reason = commands.getstatusoutput("i2cget -f -y 0 0x65 0x24")
if last_reboot_reason == "0x80":
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None)
elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08":
return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None)
elif last_reboot_reason == "0x20":
return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None)
elif last_reboot_reason == "0x10":
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset")
else:
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason")
elif str(platform_name) == "x86_64-juniper_networks_qfx5200-r0" :
log_info("Juniper Platform QFX5200 ")
status, last_reboot_reason = commands.getstatusoutput("busybox devmem 0xFED50004 8")
if (status == 0):
if last_reboot_reason == "0x80":
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None)
elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08":
return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None)
elif last_reboot_reason == "0x20":
return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None)
elif last_reboot_reason == "0x10":
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset")
else:
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason")
else:
time.sleep(3)
status, last_reboot_reason = commands.getstatusoutput("busybox devmem 0xFED50004 8")
if last_reboot_reason == "0x80":
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None)
elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08":
return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None)
elif last_reboot_reason == "0x20":
return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None)
elif last_reboot_reason == "0x10":
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset")
else:
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason")
else:
time.sleep(3)
status, last_reboot_reason = commands.getstatusoutput("i2cget -y 0 0x65 0x24")
if last_reboot_reason == "0x80":
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None)
elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08":
return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None)
elif last_reboot_reason == "0x20":
return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None)
elif last_reboot_reason == "0x10":
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Swizzle Reset")
else:
return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason")
log_info("Juniper QFX5200 and QFX5210 platforms are supported")

View File

@ -2,7 +2,7 @@
#
# Name: platform.py, version: 1.0
#
# Description: Module contains the definitions of SONiC platform APIs
# Description: Module contains the definition of SONiC platform API
# which provide the platform specific details
#
# Copyright (c) 2020, Juniper Networks, Inc.
@ -35,31 +35,18 @@
#
import sys
try:
from sonic_platform_base.platform_base import PlatformBase
from sonic_platform.chassis import Chassis
except ImportError as e:
raise ImportError("%s - required module not found" % e)
platformDict = {'platform':'QFX5200-32C'}
class Platform(PlatformBase):
"""
Juniper Platform-specific class
"""
def __init__(self):
self.platform = self.getPlatform()
def getPlatformDict(self):
global platformDict
if platformDict:
return platformDict
def readPlatformName(self):
return self.getPlatformDict().get('platform')
def getPlatform(self):
platformCls = self.readPlatformName()
return platformCls
def get_chassis(self):
from chassis import Chassis
chassis = Chassis()
return chassis
PlatformBase.__init__(self)
self._chassis = Chassis()