[platform/device] - Update Haliburton platform modules and device configuration (#1975)

* Add psuutil and sfputil support

* Fixed fancontrol issue

* Add sensor's label

* Update haliburton platform modules
This commit is contained in:
Wirut Getbamrung 2018-08-24 03:43:05 +07:00 committed by lguohan
parent a99008356b
commit 27bdc00be3
13 changed files with 1086 additions and 85 deletions

View File

@ -1,53 +1,53 @@
# name lanes speed alias autoneg
Ethernet0 2 1000 etp1 1
Ethernet1 1 1000 etp2 1
Ethernet2 4 1000 etp3 1
Ethernet3 3 1000 etp4 1
Ethernet4 6 1000 etp5 1
Ethernet5 5 1000 etp6 1
Ethernet6 8 1000 etp7 1
Ethernet7 7 1000 etp8 1
Ethernet8 10 1000 etp9 1
Ethernet9 9 1000 etp10 1
Ethernet10 12 1000 etp11 1
Ethernet11 11 1000 etp12 1
Ethernet12 14 1000 etp13 1
Ethernet13 13 1000 etp14 1
Ethernet14 16 1000 etp15 1
Ethernet15 15 1000 etp16 1
Ethernet16 18 1000 etp17 1
Ethernet17 17 1000 etp18 1
Ethernet18 20 1000 etp19 1
Ethernet19 19 1000 etp20 1
Ethernet20 22 1000 etp21 1
Ethernet21 21 1000 etp22 1
Ethernet22 24 1000 etp23 1
Ethernet23 23 1000 etp24 1
Ethernet24 26 1000 etp25 1
Ethernet25 25 1000 etp26 1
Ethernet26 28 1000 etp27 1
Ethernet27 27 1000 etp28 1
Ethernet28 30 1000 etp29 1
Ethernet29 29 1000 etp30 1
Ethernet30 32 1000 etp31 1
Ethernet31 31 1000 etp32 1
Ethernet32 34 1000 etp33 1
Ethernet33 33 1000 etp34 1
Ethernet34 36 1000 etp35 1
Ethernet35 35 1000 etp36 1
Ethernet36 38 1000 etp37 1
Ethernet37 37 1000 etp38 1
Ethernet38 40 1000 etp39 1
Ethernet39 39 1000 etp40 1
Ethernet40 42 1000 etp41 1
Ethernet41 41 1000 etp42 1
Ethernet42 44 1000 etp43 1
Ethernet43 43 1000 etp44 1
Ethernet44 46 1000 etp45 1
Ethernet45 45 1000 etp46 1
Ethernet46 48 1000 etp47 1
Ethernet47 47 1000 etp48 1
Ethernet48 54 10000 etp49 0
Ethernet49 53 10000 etp50 0
Ethernet50 56 10000 etp51 0
Ethernet51 55 10000 etp52 0
# name lanes index speed alias autoneg
Ethernet0 2 1 1000 etp1 1
Ethernet1 1 2 1000 etp2 1
Ethernet2 4 3 1000 etp3 1
Ethernet3 3 4 1000 etp4 1
Ethernet4 6 5 1000 etp5 1
Ethernet5 5 6 1000 etp6 1
Ethernet6 8 7 1000 etp7 1
Ethernet7 7 8 1000 etp8 1
Ethernet8 10 9 1000 etp9 1
Ethernet9 9 10 1000 etp10 1
Ethernet10 12 11 1000 etp11 1
Ethernet11 11 12 1000 etp12 1
Ethernet12 14 13 1000 etp13 1
Ethernet13 13 14 1000 etp14 1
Ethernet14 16 15 1000 etp15 1
Ethernet15 15 16 1000 etp16 1
Ethernet16 18 17 1000 etp17 1
Ethernet17 17 18 1000 etp18 1
Ethernet18 20 19 1000 etp19 1
Ethernet19 19 20 1000 etp20 1
Ethernet20 22 21 1000 etp21 1
Ethernet21 21 22 1000 etp22 1
Ethernet22 24 23 1000 etp23 1
Ethernet23 23 24 1000 etp24 1
Ethernet24 26 25 1000 etp25 1
Ethernet25 25 26 1000 etp26 1
Ethernet26 28 27 1000 etp27 1
Ethernet27 27 28 1000 etp28 1
Ethernet28 30 29 1000 etp29 1
Ethernet29 29 30 1000 etp30 1
Ethernet30 32 31 1000 etp31 1
Ethernet31 31 32 1000 etp32 1
Ethernet32 34 33 1000 etp33 1
Ethernet33 33 34 1000 etp34 1
Ethernet34 36 35 1000 etp35 1
Ethernet35 35 36 1000 etp36 1
Ethernet36 38 37 1000 etp37 1
Ethernet37 37 38 1000 etp38 1
Ethernet38 40 39 1000 etp39 1
Ethernet39 39 40 1000 etp40 1
Ethernet40 42 41 1000 etp41 1
Ethernet41 41 42 1000 etp42 1
Ethernet42 44 43 1000 etp43 1
Ethernet43 43 44 1000 etp44 1
Ethernet44 46 45 1000 etp45 1
Ethernet45 45 46 1000 etp46 1
Ethernet46 48 47 1000 etp47 1
Ethernet47 47 48 1000 etp48 1
Ethernet48 54 49 10000 etp49 0
Ethernet49 53 50 10000 etp50 0
Ethernet50 56 51 10000 etp51 0
Ethernet51 55 52 10000 etp52 0

View File

@ -1,12 +1,12 @@
# Configuration file generated by pwmconfig, changes will be lost
INTERVAL=2
DEVPATH=hwmon3=devices/pci0000:00/0000:00:13.0/i2c-0/i2c-8/i2c-23/23-004d/ hwmon2=devices/pci0000:00/0000:00:13.0/i2c-0/i2c-8/i2c-11/11-001a/hwmon/hwmon2
DEVPATH=hwmon3=devices/pci0000:00/0000:00:13.0/i2c-0/i2c-8/i2c-23/23-004d hwmon2=devices/pci0000:00/0000:00:13.0/i2c-0/i2c-8/i2c-11/11-001a
DEVNAME=hwmon3=emc2305 hwmon2=max6697
FCTEMPS=hwmon3/pwm1=hwmon2/temp2_input hwmon3/pwm2=hwmon2/temp2_input hwmon3/pwm4=hwmon2/temp2_input
FCTEMPS=hwmon3/device/pwm1=hwmon2/temp2_input hwmon3/device/pwm2=hwmon2/temp2_input hwmon3/device/pwm4=hwmon2/temp2_input
FCFANS=hwmon3/device/pwm1=hwmon3/device/fan1_input hwmon3/device/pwm2=hwmon3/device/fan2_input hwmon3/device/pwm4=hwmon3/device/fan4_input
MINTEMP=hwmon3/device/pwm1=29 hwmon3/device/pwm2=29 hwmon3/device/pwm4=29
MAXTEMP=hwmon3/device/pwm1=44 hwmon3/device/pwm2=44 hwmon3/device/pwm4=44
MINSTART=hwmon3/device/pwm1=102 hwmon3/device/pwm2=102 hwmon3/device/pwm4=102
MINSTOP=hwmon3/device/pwm1=102 hwmon3/device/pwm2=102 hwmon3/device/pwm4=102
MINPWM=hwmon3/device/pwm1=102 hwmon3/device/pwm2=102 hwmon3/device/pwm4=102
MINSTART=hwmon3/device/pwm1=102 hwmon3/device/pwm2=102 hwmon3/device/pwm4=102
MINSTOP=hwmon3/device/pwm1=102 hwmon3/device/pwm2=102 hwmon3/device/pwm4=102
MINPWM=hwmon3/device/pwm1=102 hwmon3/device/pwm2=102 hwmon3/device/pwm4=102
MAXPWM=hwmon3/device/pwm1=255 hwmon3/device/pwm2=255 hwmon3/device/pwm4=255

View File

@ -0,0 +1,61 @@
#!/usr/bin/env python
import os.path
try:
from sonic_psu.psu_base import PsuBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class PsuUtil(PsuBase):
"""Platform-specific PSUutil class"""
def __init__(self):
PsuBase.__init__(self)
self.psu_path = "/sys/devices/platform/e1031.smc/"
self.psu_presence = "psu{}_prs"
self.psu_oper_status = "psu{}_status"
def get_num_psus(self):
"""
Retrieves the number of PSUs available on the device
:return: An integer, the number of PSUs available on the device
"""
return 2
def get_psu_status(self, index):
"""
Retrieves the oprational status of power supply unit (PSU) defined by 1-based index <index>
:param index: An integer, 1-based index of the PSU of which to query status
:return: Boolean, True if PSU is operating properly, False if PSU is faulty
"""
psu_location = ["R", "L"]
status = 0
try:
with open(self.psu_path + self.psu_oper_status.format(psu_location[index - 1]), 'r') as power_status:
status = int(power_status.read())
except IOError:
return False
return status == 1
def get_psu_presence(self, index):
"""
Retrieves the presence status of power supply unit (PSU) defined by 1-based index <index>
:param index: An integer, 1-based index of the PSU of which to query status
:return: Boolean, True if PSU is plugged, False if not
"""
psu_location = ["R", "L"]
status = 0
try:
with open(self.psu_path + self.psu_presence.format(psu_location[index - 1]), 'r') as psu_prs:
status = int(psu_prs.read())
except IOError:
return False
return status == 1

View File

@ -0,0 +1,123 @@
#!/usr/bin/env python
try:
import time
import os
from sonic_sfp.sfputilbase import SfpUtilBase
except ImportError as e:
raise ImportError("%s - required module not found" % str(e))
class SfpUtil(SfpUtilBase):
"""Platform-specific SfpUtil class"""
PORT_START = 1
PORT_END = 52
port_to_i2c_mapping = {
1 : None,
2 : None,
3 : None,
4 : None,
5 : None,
6 : None,
7 : None,
8 : None,
9 : None,
10 : None,
11 : None,
12 : None,
13 : None,
14 : None,
15 : None,
16 : None,
17 : None,
18 : None,
19 : None,
20 : None,
21 : None,
22 : None,
23 : None,
24 : None,
25 : None,
26 : None,
27 : None,
28 : None,
29 : None,
30 : None,
31 : None,
32 : None,
33 : None,
34 : None,
35 : None,
36 : None,
37 : None,
38 : None,
39 : None,
40 : None,
41 : None,
42 : None,
43 : None,
44 : None,
45 : None,
46 : None,
47 : None,
48 : None,
49 : 15,
50 : 14,
51 : 17,
52 : 16
}
_port_to_eeprom_mapping = {}
_sfp_port = range(49, PORT_END + 1)
@property
def port_start(self):
return self.PORT_START
@property
def port_end(self):
return self.PORT_END
@property
def qsfp_ports(self):
return []
@property
def port_to_eeprom_mapping(self):
return self._port_to_eeprom_mapping
def __init__(self):
# Override port_to_eeprom_mapping for class initialization
eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom'
for x in range(self.PORT_START, self.PORT_END + 1):
port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x])
self.port_to_eeprom_mapping[x] = port_eeprom_path
SfpUtilBase.__init__(self)
def get_presence(self, port_num):
sfp_modabs_path = '/sys/devices/platform/e1031.smc/SFP/SFP{0}/sfp_modabs'
if port_num not in self._sfp_port:
return False
status = 1
try:
with open(sfp_modabs_path.format(port_num - 48), 'r') as port_status:
status = int(port_status.read())
except IOError:
return False
return status == 0
def get_low_power_mode(self, port_num):
raise NotImplementedError
def set_low_power_mode(self, port_num, lpmode):
raise NotImplementedError
def reset(self, port_num):
raise NotImplementedError
def get_transceiver_change_event(self):
raise NotImplementedError

View File

@ -1,12 +1,33 @@
# libsensors configuration file for Celestica DX010.
# libsensors configuration file for Celestica E1031.
# The i2c bus portion is omit because adapter name
# changes every time when system boot up.
chip "max6697-i2c-*-1a"
label temp1 "temp sensor 1"
label temp2 "temp sensor 2"
label temp3 "temp sensor 3"
label temp4 "temp sensor 4"
label temp5 "temp sensor 5"
ignore temp6
ignore temp7
bus "i2c-3" "i2c-0-mux (chan_id 1)"
bus "i2c-11" "i2c-8-mux (chan_id 1)"
chip "max6697-i2c-3-1a"
label temp1 "CPU board temperature sensor : 1"
label temp2 "CPU board temperature sensor : 2"
label temp3 "CPU board temperature sensor : 3"
ignore temp4
ignore temp5
ignore temp6
ignore temp7
chip "max6697-i2c-11-1a"
label temp1 "Main board temperature sensor : 1"
label temp2 "Main board temperature sensor : 2"
label temp3 "Main board temperature sensor : 3"
label temp4 "Main board temperature sensor : 4"
label temp5 "Main board temperature sensor : 5"
ignore temp6
ignore temp7
chip "emc2305-i2c-*-4d"
ignore fan3
ignore fan5
label fan4 "Fan 1 :"
label fan2 "Fan 2 :"
label fan1 "Fan 3 :"

View File

@ -1,7 +1,7 @@
# Celestica DX010 and Haliburton Platform modules
CEL_DX010_PLATFORM_MODULE_VERSION = 0.8
CEL_HALIBURTON_PLATFORM_MODULE_VERSION = 0.8
CEL_DX010_PLATFORM_MODULE_VERSION = 0.9
CEL_HALIBURTON_PLATFORM_MODULE_VERSION = 0.9
export CEL_DX010_PLATFORM_MODULE_VERSION
export CEL_HALIBURTON_PLATFORM_MODULE_VERSION

View File

@ -1,8 +1,15 @@
sonic-cel-platform-modules (0.9) unstable; urgency=low
* Add haliburton platform module.
-- Wirut Getbamrung <wgetbumr@celestica.com> Fri, 17 Aug 2018 10:10:10 +0700
sonic-cel-platform-modules (0.8) unstable; urgency=low
* Add haliburton platform
* Add dx010 platform fan led control.
* The platform gpio init moved to kernel space.
-- Supakit Fuangkaew <sfuangk@celestica.com> Thu, 5 Apr 2018 09:09:09 +0700
-- Pradchaya Phucharoen <pphuchar@celestica.com> Mon, 1 Jul 2018 11:09:13 +0700
sonic-cel-platform-modules (0.7) unstable; urgency=low

View File

@ -15,10 +15,8 @@ case "$1" in
start)
echo -n "Setting up board... "
depmod -a
modprobe i2c-dev
modprobe i2c-mux-pca954x
modprobe smc
found=0
for devnum in 0 1; do
devname=`cat /sys/bus/i2c/devices/i2c-${devnum}/name`
@ -56,15 +54,11 @@ start)
# Attach fans
echo emc2305 0x4d > /sys/bus/i2c/devices/i2c-23/new_device
# Attach PSUs
echo dps200 0x5a > /sys/bus/i2c/devices/i2c-12/new_device
echo dps200 0x5b > /sys/bus/i2c/devices/i2c-13/new_device
# Attach 4 SFP+ Uplink
echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-14/new_device
echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-15/new_device
echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-16/new_device
echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-17/new_device
# Attach 4 SFP+ Uplink
echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-14/new_device
echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-15/new_device
echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-16/new_device
echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-17/new_device
echo "done."
;;

View File

@ -1 +1,2 @@
haliburton/cfg/haliburton-modules.conf etc/modules-load.d
haliburton/systemd/platform-modules-haliburton.service lib/systemd/system

View File

@ -0,0 +1,3 @@
depmod -a
systemctl enable platform-modules-haliburton.service
systemctl start platform-modules-haliburton.service

View File

@ -1 +1 @@
obj-m := mc24lc64t.o emc2305.o
obj-m := mc24lc64t.o emc2305.o smc.o

View File

@ -0,0 +1,777 @@
/*
* smc.c - The CPLD driver for E1031 System Management.
* The driver implement sysfs to access CPLD register on the E1031 via LPC bus.
* Copyright (C) 2018 Celestica Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/hwmon-sysfs.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/types.h>
#include <uapi/linux/stat.h>
#define DRIVER_NAME "e1031.smc"
/**
* CPLD register address for read and write.
*/
#define VERSION 0x0200
#define SCRATCH 0x0201
#define BROAD_ID 0x0202
/* SEPERATE RESET
* [7:5] RESERVED
* [4] RESET PCIE
* [3] RESET USBHUB
* [2] RESET B50282
* [1] RESET PCA9548
* [0] RESET BCM54616
* 1: not reset, 0: reset
*/
#define SPR_RESET 0x0222
/* PSU STATUS
* [7] PSUR_ACOK
* [6] PSUR_PWOK
* [5] PSUR_ALRT
* [4] PSUR_PRS
* [3] PSUL_ACOK
* [2] PSUL_PWOK
* [1] PSUL_ALRT
* [0] PSUL_PRS
*/
#define PSU_STAT 0x0204
#define PSUR_ACOK 7
#define PSUR_PWOK 6
#define PSUR_ALRT 5
#define PSUR_PRS 4
#define PSUL_ACOK 3
#define PSUL_PWOK 2
#define PSUL_ALRT 1
#define PSUL_PRS 0
/* FAN LED CTRL
* [7:3] RESERVED
* [2:0] LED CTRL
*/
#define FAN_LED_1 0x0205
#define FAN_LED_2 0x0206
#define FAN_LED_3 0x0207
enum FAN_LED {
fan_led_grn = 0,
fan_led_grn_bnk,
fan_led_amb,
fan_led_amb_bnk,
fan_led_off
} fan_led;
#define LED_OPMOD 0x0208
#define LED_TEST 0x0209
/* SYSTEM LED
* [7:4] RESERVED
* [3:2] STATUS LED
* [1:0] MASTER LED
*/
#define LED_FPS 0x020a
enum STAT_LED {
stat_led_off = 0,
stat_led_grn,
stat_led_grn_bnk
} stat_led;
enum MASTER_LED {
master_led_off = 0,
master_led_grn,
master_led_amb
} master_led;
/* FAN DIRECTION STAT
* [7:4] RESERVED
* [3] USB HUB STAT
* [2:0] FAN_DIR
*/
#define DEV_STAT 0x020c
#define FAN_3 2
#define FAN_2 1
#define FAN_1 0
/* SFP PORT STATUS
* [7:4] RESERVED
* [3:0] TX_FAULT / MODABS / RXLOS
*/
#define SFP_TXFAULT 0x0242
#define SFP_MODABS 0x0243
#define SFP_RXLOS 0x0244
/* SFP PORT CTRL
* [7:4] RATE SEL (RS0/RS1)
* [3:0] TX_DIS
*/
#define SFP_TXCTRL 0x0255
struct cpld_data {
struct mutex cpld_lock;
uint16_t read_addr;
struct device *fpp_node;
struct device *sfp_devices[4];
};
struct sfp_device_data {
int portid;
};
struct class *celplatform;
struct cpld_data *cpld_data;
struct index_device_attribute {
struct device_attribute dev_attr;
int index;
};
static ssize_t scratch_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
unsigned char data = 0;
mutex_lock(&cpld_data->cpld_lock);
data = inb(SCRATCH);
mutex_unlock(&cpld_data->cpld_lock);
return sprintf(buf, "0x%2.2x\n", data);
}
static ssize_t scratch_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
unsigned long data;
char *last;
mutex_lock(&cpld_data->cpld_lock);
data = (uint16_t)strtoul(buf, &last, 16);
if (data == 0 && buf == last) {
mutex_unlock(&cpld_data->cpld_lock);
return -EINVAL;
}
outb(data, SCRATCH);
mutex_unlock(&cpld_data->cpld_lock);
return count;
}
static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int len = 0;
mutex_lock(&cpld_data->cpld_lock);
len = sprintf(buf, "0x%2.2x\n", inb(VERSION));
mutex_unlock(&cpld_data->cpld_lock);
return len;
}
static ssize_t getreg_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
uint16_t addr;
char *last;
addr = (uint16_t)strtoul(buf, &last, 16);
if (addr == 0 && buf == last) {
return -EINVAL;
}
cpld_data->read_addr = addr;
return count;
}
static ssize_t getreg_show(struct device *dev, struct device_attribute *attr, char *buf)
{
int len = 0;
mutex_lock(&cpld_data->cpld_lock);
len = sprintf(buf, "0x%2.2x\n", inb(cpld_data->read_addr));
mutex_unlock(&cpld_data->cpld_lock);
return len;
}
static ssize_t setreg_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
uint16_t addr;
uint8_t value;
char *tok;
char clone[count];
char *pclone = clone;
char *last;
strcpy(clone, buf);
mutex_lock(&cpld_data->cpld_lock);
tok = strsep((char**)&pclone, " ");
if (tok == NULL) {
mutex_unlock(&cpld_data->cpld_lock);
return -EINVAL;
}
addr = (uint16_t)strtoul(tok, &last, 16);
if (addr == 0 && tok == last) {
mutex_unlock(&cpld_data->cpld_lock);
return -EINVAL;
}
tok = strsep((char**)&pclone, " ");
if (tok == NULL) {
mutex_unlock(&cpld_data->cpld_lock);
return -EINVAL;
}
value = (uint8_t)strtoul(tok, &last, 16);
if (value == 0 && tok == last) {
mutex_unlock(&cpld_data->cpld_lock);
return -EINVAL;
}
outb(value, addr);
mutex_unlock(&cpld_data->cpld_lock);
return count;
}
/**
* Show status led
* @param dev kernel device
* @param devattr kernel device attribute
* @param buf buffer for get value
* @return led state - off/on/blink
*/
static ssize_t status_led_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
unsigned char data = 0;
mutex_lock(&cpld_data->cpld_lock);
data = inb(LED_FPS);
mutex_unlock(&cpld_data->cpld_lock);
data = data & 0xc;
return sprintf(buf, "%s\n",
data == stat_led_grn ? "on" : data == stat_led_grn_bnk ? "blink" : "off");
}
/**
* Set the status led
* @param dev kernel device
* @param devattr kernel device attribute
* @param buf buffer of set value - off/on/blink
* @param count number of bytes in buffer
* @return number of bytes written, or error code < 0.
*/
static ssize_t status_led_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
unsigned char led_status, data;
if (sysfs_streq(buf, "off")) {
led_status = stat_led_off;
} else if (sysfs_streq(buf, "on")) {
led_status = stat_led_grn;
} else if (sysfs_streq(buf, "blink")) {
led_status = stat_led_grn_bnk;
} else {
count = -EINVAL;
return count;
}
mutex_lock(&cpld_data->cpld_lock);
data = inb(LED_FPS);
data = data & ~(0xc);
data = data | ( led_status << 2 );
outb(data, LED_FPS);
mutex_unlock(&cpld_data->cpld_lock);
return count;
}
/**
* Show master led
* @param dev kernel device
* @param devattr kernel device attribute
* @param buf buffer for get value
* @return led state - off/green/amber
*/
static ssize_t master_led_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
unsigned char data = 0;
mutex_lock(&cpld_data->cpld_lock);
data = inb(LED_FPS);
mutex_unlock(&cpld_data->cpld_lock);
data = data & 0x3;
return sprintf(buf, "%s\n",
data == master_led_grn ? "on" : data == master_led_amb ? "amber" : "off");
}
/**
* Set the master led
* @param dev kernel device
* @param devattr kernel device attribute
* @param buf buffer of set value - off/green/amber
* @param count number of bytes in buffer
* @return number of bytes written, or error code < 0.
*/
static ssize_t master_led_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
unsigned char led_status, data;
if (sysfs_streq(buf, "off")) {
led_status = master_led_off;
} else if (sysfs_streq(buf, "green")) {
led_status = master_led_grn;
} else if (sysfs_streq(buf, "amber")) {
led_status = master_led_amb;
} else {
count = -EINVAL;
return count;
}
mutex_lock(&cpld_data->cpld_lock);
data = inb(LED_FPS);
data = data & ~(0x3);
data = data | led_status;
outb(data, LED_FPS);
mutex_unlock(&cpld_data->cpld_lock);
return count;
}
static ssize_t psuL_prs_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
unsigned char data = 0;
mutex_lock(&cpld_data->cpld_lock);
data = inb(PSU_STAT);
mutex_unlock(&cpld_data->cpld_lock);
return sprintf(buf, "%d\n", ~(data >> PSUL_PRS) & 1U);
}
static ssize_t psuR_prs_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
unsigned char data = 0;
mutex_lock(&cpld_data->cpld_lock);
data = inb(PSU_STAT);
mutex_unlock(&cpld_data->cpld_lock);
return sprintf(buf, "%d\n", ~(data >> PSUR_PRS) & 1U);
}
static DEVICE_ATTR_RO(psuR_prs);
static ssize_t psuL_status_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
unsigned char data = 0;
mutex_lock(&cpld_data->cpld_lock);
data = inb(PSU_STAT);
mutex_unlock(&cpld_data->cpld_lock);
data = ( data >> PSUL_PWOK ) & 0x3;
return sprintf(buf, "%d\n", data == 0x3 );
}
static ssize_t psuR_status_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
unsigned char data = 0;
mutex_lock(&cpld_data->cpld_lock);
data = inb(PSU_STAT);
mutex_unlock(&cpld_data->cpld_lock);
data = ( data >> PSUR_PWOK ) & 0x3;
return sprintf(buf, "%d\n", data == 0x3 );
}
static ssize_t fan_dir_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sensor_device_attribute *sa = to_sensor_dev_attr(devattr);
int index = sa->index;
unsigned char data = 0;
// Use index to determind the status bit
mutex_lock(&cpld_data->cpld_lock);
data = inb(DEV_STAT);
mutex_unlock(&cpld_data->cpld_lock);
data = ( data >> index ) & 1U;
return sprintf(buf, "%s\n", data ? "B2F" : "F2B" );
}
static ssize_t sfp_txfault_show(struct device *dev, struct device_attribute *attr, char *buf)
{
unsigned char data;
struct sfp_device_data *dev_data = dev_get_drvdata(dev);
unsigned int port_bit = dev_data->portid - 1;
mutex_lock(&cpld_data->cpld_lock);
data = inb(SFP_TXFAULT);
mutex_unlock(&cpld_data->cpld_lock);
return sprintf(buf, "%d\n", (data >> port_bit ) & 1U);
}
static ssize_t sfp_modabs_show(struct device *dev, struct device_attribute *attr, char *buf)
{
unsigned char data;
struct sfp_device_data *dev_data = dev_get_drvdata(dev);
unsigned int port_bit = dev_data->portid - 1;
mutex_lock(&cpld_data->cpld_lock);
data = inb(SFP_MODABS);
mutex_unlock(&cpld_data->cpld_lock);
return sprintf(buf, "%d\n", (data >> port_bit ) & 1U);
}
static ssize_t sfp_rxlos_show(struct device *dev, struct device_attribute *attr, char *buf)
{
unsigned char data;
struct sfp_device_data *dev_data = dev_get_drvdata(dev);
unsigned int port_bit = dev_data->portid - 1;
mutex_lock(&cpld_data->cpld_lock);
data = inb(SFP_RXLOS);
mutex_unlock(&cpld_data->cpld_lock);
return sprintf(buf, "%d\n", (data >> port_bit ) & 1U);
}
static ssize_t sfp_txdis_show(struct device *dev, struct device_attribute *attr, char *buf)
{
unsigned char data;
struct sfp_device_data *dev_data = dev_get_drvdata(dev);
unsigned int port_bit = dev_data->portid - 1;
mutex_lock(&cpld_data->cpld_lock);
data = inb(SFP_TXCTRL);
mutex_unlock(&cpld_data->cpld_lock);
return sprintf(buf, "%d\n", (data >> port_bit ) & 1U);
}
static ssize_t sfp_txdis_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
long value;
ssize_t status;
unsigned char data;
struct sfp_device_data *dev_data = dev_get_drvdata(dev);
unsigned int port_bit = dev_data->portid - 1;
mutex_lock(&cpld_data->cpld_lock);
status = kstrtol(buf, 0, &value);
if (status == 0) {
// check if value is 0, clear
data = inb(SFP_TXCTRL);
if (!value)
data = data & ~( 1U << port_bit);
else
data = data | ( 1U << port_bit);
outb(data, SFP_TXCTRL);
status = size;
}
mutex_unlock(&cpld_data->cpld_lock);
return status;
}
static ssize_t sfp_rs_show(struct device *dev, struct device_attribute *attr, char *buf)
{
unsigned char data;
struct sfp_device_data *dev_data = dev_get_drvdata(dev);
unsigned int port_bit = dev_data->portid - 1;
// High nibble
port_bit = port_bit + 4;
mutex_lock(&cpld_data->cpld_lock);
data = inb(SFP_TXCTRL);
mutex_unlock(&cpld_data->cpld_lock);
return sprintf(buf, "%d\n", (data >> port_bit ) & 1U);
}
static ssize_t sfp_rs_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
long value;
ssize_t status;
unsigned char data;
struct sfp_device_data *dev_data = dev_get_drvdata(dev);
unsigned int port_bit = dev_data->portid - 1;
// High nibble
port_bit = port_bit + 4;
mutex_lock(&cpld_data->cpld_lock);
status = kstrtol(buf, 0, &value);
if (status == 0) {
// check if value is 0, clear
data = inb(SFP_TXCTRL);
if (!value)
data = data & ~( 1U << port_bit);
else
data = data | ( 1U << port_bit);
outb(data, SFP_TXCTRL);
status = size;
}
mutex_unlock(&cpld_data->cpld_lock);
return status;
}
static ssize_t fan_led_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sensor_device_attribute *sa = to_sensor_dev_attr(devattr);
int index = sa->index;
unsigned char data = 0;
char *led_str[5] = {"green", "green-blink", "amber", "amber-blink", "off"};
// Use index to determind the status bit
mutex_lock(&cpld_data->cpld_lock);
data = inb(FAN_LED_1 + index);
data = data & 0x7;
mutex_unlock(&cpld_data->cpld_lock);
return sprintf(buf, "%s\n", led_str[data]);
}
static ssize_t fan_led_store(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
struct sensor_device_attribute *sa = to_sensor_dev_attr(devattr);
int index = sa->index;
unsigned char led_status = 0;
if (sysfs_streq(buf, "off")) {
led_status = fan_led_off;
} else if (sysfs_streq(buf, "green")) {
led_status = fan_led_grn;
} else if (sysfs_streq(buf, "amber")) {
led_status = fan_led_amb;
} else if (sysfs_streq(buf, "green-blink")) {
led_status = fan_led_grn_bnk;
} else if (sysfs_streq(buf, "amber-blink")) {
led_status = fan_led_amb_bnk;
} else {
count = -EINVAL;
return count;
}
mutex_lock(&cpld_data->cpld_lock);
outb(led_status, FAN_LED_1 + index);
mutex_unlock(&cpld_data->cpld_lock);
return count;
}
static DEVICE_ATTR_RO(version);
static DEVICE_ATTR_RW(scratch);
static DEVICE_ATTR_RW(getreg);
static DEVICE_ATTR_WO(setreg);
static DEVICE_ATTR_RW(status_led);
static DEVICE_ATTR_RW(master_led);
static DEVICE_ATTR_RO(psuL_prs);
static DEVICE_ATTR_RO(psuL_status);
static DEVICE_ATTR_RO(psuR_status);
static DEVICE_ATTR_RO(sfp_txfault);
static DEVICE_ATTR_RO(sfp_modabs);
static DEVICE_ATTR_RO(sfp_rxlos);
static DEVICE_ATTR_RW(sfp_txdis);
static DEVICE_ATTR_RW(sfp_rs);
static SENSOR_DEVICE_ATTR(fan1_dir, S_IRUGO, fan_dir_show, NULL, FAN_1);
static SENSOR_DEVICE_ATTR(fan2_dir, S_IRUGO, fan_dir_show, NULL, FAN_2);
static SENSOR_DEVICE_ATTR(fan3_dir, S_IRUGO, fan_dir_show, NULL, FAN_3);
static SENSOR_DEVICE_ATTR(fan1_led, S_IWUSR | S_IRUGO, fan_led_show, fan_led_store, FAN_1);
static SENSOR_DEVICE_ATTR(fan2_led, S_IWUSR | S_IRUGO, fan_led_show, fan_led_store, FAN_2);
static SENSOR_DEVICE_ATTR(fan3_led, S_IWUSR | S_IRUGO, fan_led_show, fan_led_store, FAN_3);
static struct attribute *cpld_attrs[] = {
&dev_attr_version.attr,
&dev_attr_scratch.attr,
&dev_attr_getreg.attr,
&dev_attr_setreg.attr,
// LEDs
&dev_attr_status_led.attr,
&dev_attr_master_led.attr,
// PSUs
&dev_attr_psuL_prs.attr,
&dev_attr_psuR_prs.attr,
&dev_attr_psuL_status.attr,
&dev_attr_psuR_status.attr,
// FANs
&sensor_dev_attr_fan1_dir.dev_attr.attr,
&sensor_dev_attr_fan2_dir.dev_attr.attr,
&sensor_dev_attr_fan3_dir.dev_attr.attr,
&sensor_dev_attr_fan1_led.dev_attr.attr,
&sensor_dev_attr_fan2_led.dev_attr.attr,
&sensor_dev_attr_fan3_led.dev_attr.attr,
NULL,
};
static struct attribute_group cpld_group = {
.attrs = cpld_attrs,
};
static struct attribute *sfp_attrs[] = {
// SFP
&dev_attr_sfp_txfault.attr,
&dev_attr_sfp_modabs.attr,
&dev_attr_sfp_rxlos.attr,
&dev_attr_sfp_txdis.attr,
&dev_attr_sfp_rs.attr,
NULL,
};
ATTRIBUTE_GROUPS(sfp);
static struct resource cpld_resources[] = {
{
.start = 0x0200,
.end = 0x0255,
.flags = IORESOURCE_IO,
},
};
static struct device * sfp_init(int portid) {
struct sfp_device_data *new_data;
struct device *new_device;
new_data = kzalloc(sizeof(*new_data), GFP_KERNEL);
if (!new_data) {
printk(KERN_ALERT "Cannot alloc sff device data @port%d", portid);
return NULL;
}
/* Front panel port ID start from 1 */
new_data->portid = portid + 1;
new_device = device_create_with_groups(celplatform, cpld_data->fpp_node, MKDEV(0, 0), new_data, sfp_groups, "SFP%d", new_data->portid);
if (IS_ERR(new_device)) {
printk(KERN_ALERT "Cannot create sff device @port%d", portid);
kfree(new_data);
return NULL;
}
return new_device;
}
static void cpld_dev_release( struct device * dev)
{
return;
}
static struct platform_device cpld_dev = {
.name = DRIVER_NAME,
.id = -1,
.num_resources = ARRAY_SIZE(cpld_resources),
.resource = cpld_resources,
.dev = {
.release = cpld_dev_release,
}
};
static int cpld_drv_probe(struct platform_device *pdev)
{
struct resource *res;
int err, i = 0;
cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct cpld_data),
GFP_KERNEL);
if (!cpld_data)
return -ENOMEM;
mutex_init(&cpld_data->cpld_lock);
cpld_data->read_addr = VERSION;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (unlikely(!res)) {
printk(KERN_ERR "Specified Resource Not Available...\n");
return -ENODEV;
}
err = sysfs_create_group(&pdev->dev.kobj, &cpld_group);
if (err) {
printk(KERN_ERR "Cannot create sysfs for SMC.\n");
return err;
}
celplatform = class_create(THIS_MODULE, "celplatform");
if (IS_ERR(celplatform)) {
printk(KERN_ERR "Failed to register device class\n");
sysfs_remove_group(&pdev->dev.kobj, &cpld_group);
return PTR_ERR(celplatform);
}
cpld_data->fpp_node = device_create(celplatform, NULL, MKDEV(0, 0), NULL, "optical_ports");
if (IS_ERR(cpld_data->fpp_node)) {
class_destroy(celplatform);
sysfs_remove_group(&pdev->dev.kobj, &cpld_group);
return PTR_ERR(cpld_data->fpp_node);
}
err = sysfs_create_link(&pdev->dev.kobj, &cpld_data->fpp_node->kobj, "SFP");
if (err != 0) {
put_device(cpld_data->fpp_node);
device_unregister(cpld_data->fpp_node);
class_destroy(celplatform);
sysfs_remove_group(&pdev->dev.kobj, &cpld_group);
return err;
}
// Creae SFP devices
for ( i = 0; i < 4; i++) {
cpld_data->sfp_devices[i] = sfp_init(i);
}
// Clear all reset signals
outb(0xFF, SPR_RESET);
return 0;
}
static int cpld_drv_remove(struct platform_device *pdev)
{
struct sfp_device_data *rem_data;
int i;
for ( i = 0; i < 4; i++ ) {
rem_data = dev_get_drvdata(cpld_data->sfp_devices[i]);
put_device(cpld_data->sfp_devices[i]);
device_unregister(cpld_data->sfp_devices[i]);
kzfree(rem_data);
}
put_device(cpld_data->fpp_node);
device_unregister(cpld_data->fpp_node);
sysfs_remove_group(&pdev->dev.kobj, &cpld_group);
class_destroy(celplatform);
return 0;
}
static struct platform_driver cpld_drv = {
.probe = cpld_drv_probe,
.remove = __exit_p(cpld_drv_remove),
.driver = {
.name = DRIVER_NAME,
},
};
int cpld_init(void)
{
// Register platform device and platform driver
platform_device_register(&cpld_dev);
platform_driver_register(&cpld_drv);
return 0;
}
void cpld_exit(void)
{
// Unregister platform device and platform driver
platform_driver_unregister(&cpld_drv);
platform_device_unregister(&cpld_dev);
}
module_init(cpld_init);
module_exit(cpld_exit);
MODULE_AUTHOR("Celestica Inc.");
MODULE_DESCRIPTION("Celestica E1031 SMC driver");
MODULE_VERSION("0.0.3");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,14 @@
[Unit]
Description=Celestica haliburton platform modules
After=local-fs.target
Before=pmon.service
[Service]
Type=oneshot
ExecStart=-/etc/init.d/platform-modules-haliburton start
ExecStop=-/etc/init.d/platform-modules-haliburton stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target