[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,8 +1,8 @@
# 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

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"
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,9 +15,7 @@ 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
@ -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
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