[platform-device/haliburton] Support xcvr and sensor monitoring (#1998)
* [platform/haliburton] Fix kernel panic when remove smc module. * [platform/haliburton] Chanage sysfs to support module interrupt * [device/haliburton] Update sfputil to use new sysfs. * [device/haliburton] sfputil to support xcvrd monitoring.
This commit is contained in:
parent
929ef530ce
commit
e8db1846ad
@ -14,58 +14,58 @@ class SfpUtil(SfpUtilBase):
|
|||||||
PORT_START = 1
|
PORT_START = 1
|
||||||
PORT_END = 52
|
PORT_END = 52
|
||||||
port_to_i2c_mapping = {
|
port_to_i2c_mapping = {
|
||||||
1 : None,
|
1: None,
|
||||||
2 : None,
|
2: None,
|
||||||
3 : None,
|
3: None,
|
||||||
4 : None,
|
4: None,
|
||||||
5 : None,
|
5: None,
|
||||||
6 : None,
|
6: None,
|
||||||
7 : None,
|
7: None,
|
||||||
8 : None,
|
8: None,
|
||||||
9 : None,
|
9: None,
|
||||||
10 : None,
|
10: None,
|
||||||
11 : None,
|
11: None,
|
||||||
12 : None,
|
12: None,
|
||||||
13 : None,
|
13: None,
|
||||||
14 : None,
|
14: None,
|
||||||
15 : None,
|
15: None,
|
||||||
16 : None,
|
16: None,
|
||||||
17 : None,
|
17: None,
|
||||||
18 : None,
|
18: None,
|
||||||
19 : None,
|
19: None,
|
||||||
20 : None,
|
20: None,
|
||||||
21 : None,
|
21: None,
|
||||||
22 : None,
|
22: None,
|
||||||
23 : None,
|
23: None,
|
||||||
24 : None,
|
24: None,
|
||||||
25 : None,
|
25: None,
|
||||||
26 : None,
|
26: None,
|
||||||
27 : None,
|
27: None,
|
||||||
28 : None,
|
28: None,
|
||||||
29 : None,
|
29: None,
|
||||||
30 : None,
|
30: None,
|
||||||
31 : None,
|
31: None,
|
||||||
32 : None,
|
32: None,
|
||||||
33 : None,
|
33: None,
|
||||||
34 : None,
|
34: None,
|
||||||
35 : None,
|
35: None,
|
||||||
36 : None,
|
36: None,
|
||||||
37 : None,
|
37: None,
|
||||||
38 : None,
|
38: None,
|
||||||
39 : None,
|
39: None,
|
||||||
40 : None,
|
40: None,
|
||||||
41 : None,
|
41: None,
|
||||||
42 : None,
|
42: None,
|
||||||
43 : None,
|
43: None,
|
||||||
44 : None,
|
44: None,
|
||||||
45 : None,
|
45: None,
|
||||||
46 : None,
|
46: None,
|
||||||
47 : None,
|
47: None,
|
||||||
48 : None,
|
48: None,
|
||||||
49 : 15,
|
49: 15,
|
||||||
50 : 14,
|
50: 14,
|
||||||
51 : 17,
|
51: 17,
|
||||||
52 : 16
|
52: 16
|
||||||
}
|
}
|
||||||
_port_to_eeprom_mapping = {}
|
_port_to_eeprom_mapping = {}
|
||||||
_sfp_port = range(49, PORT_END + 1)
|
_sfp_port = range(49, PORT_END + 1)
|
||||||
@ -94,30 +94,42 @@ class SfpUtil(SfpUtilBase):
|
|||||||
self.port_to_eeprom_mapping[x] = port_eeprom_path
|
self.port_to_eeprom_mapping[x] = port_eeprom_path
|
||||||
SfpUtilBase.__init__(self)
|
SfpUtilBase.__init__(self)
|
||||||
|
|
||||||
|
|
||||||
def get_presence(self, port_num):
|
def get_presence(self, port_num):
|
||||||
sfp_modabs_path = '/sys/devices/platform/e1031.smc/SFP/SFP{0}/sfp_modabs'
|
sfp_modabs_path = '/sys/devices/platform/e1031.smc/SFP/sfp_modabs'
|
||||||
|
|
||||||
if port_num not in self._sfp_port:
|
if port_num not in self._sfp_port:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
status = 1
|
status = 1
|
||||||
try:
|
try:
|
||||||
with open(sfp_modabs_path.format(port_num - 48), 'r') as port_status:
|
with open(sfp_modabs_path, 'r') as port_status:
|
||||||
status = int(port_status.read())
|
status = int(port_status.read(), 16)
|
||||||
except IOError:
|
status = (status >> (port_num - 49)) & 1
|
||||||
|
except IOError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return status == 0
|
return status == 0
|
||||||
|
|
||||||
|
|
||||||
def get_low_power_mode(self, port_num):
|
def get_low_power_mode(self, port_num):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def set_low_power_mode(self, port_num, lpmode):
|
def set_low_power_mode(self, port_num, lpmode):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def reset(self, port_num):
|
def reset(self, port_num):
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def get_transceiver_change_event(self):
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def get_transceiver_change_event(self, timeout=0):
|
||||||
|
modabs_interrupt_path = '/sys/devices/platform/e1031.smc/SFP/modabs_int'
|
||||||
|
ports_evt = {}
|
||||||
|
try:
|
||||||
|
with open(modabs_interrupt_path, 'r') as port_changes:
|
||||||
|
changes = int(port_changes.read(), 16)
|
||||||
|
for port_num in self._sfp_port:
|
||||||
|
change = (changes >> ( port_num - 49)) & 1
|
||||||
|
if change == 1:
|
||||||
|
ports_evt[str(port_num)] = str(self.get_presence(port_num))
|
||||||
|
except IOError:
|
||||||
|
return False, {}
|
||||||
|
return True, ports_evt
|
||||||
|
@ -60,6 +60,10 @@ start)
|
|||||||
echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-16/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 optoe2 0x50 > /sys/bus/i2c/devices/i2c-17/new_device
|
||||||
|
|
||||||
|
# Enable SFP module presence interrupt
|
||||||
|
echo "both" > /sys/devices/platform/e1031.smc/SFP/modabs_trig
|
||||||
|
echo 0 > /sys/devices/platform/e1031.smc/SFP/modabs_mask
|
||||||
|
|
||||||
echo "done."
|
echo "done."
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
@ -116,6 +116,22 @@ enum MASTER_LED {
|
|||||||
#define FAN_2 1
|
#define FAN_2 1
|
||||||
#define FAN_1 0
|
#define FAN_1 0
|
||||||
|
|
||||||
|
/* SFP PORT INT TRIGGER MODE
|
||||||
|
* [7:6] RESERVED
|
||||||
|
* [5:4] RXLOS
|
||||||
|
* [3:2] MODABS
|
||||||
|
* [1:0] TXFAULT
|
||||||
|
* 00: falling edge,
|
||||||
|
* 01: rising edge,
|
||||||
|
* 10: Both edges,
|
||||||
|
* 11: low level detect
|
||||||
|
*/
|
||||||
|
#define TRIG_MODE 0x0240
|
||||||
|
#define TXFAULT_TRIG 0
|
||||||
|
#define MODABS_TRIG 2
|
||||||
|
#define RXLOS_TRIG 4
|
||||||
|
|
||||||
|
|
||||||
/* SFP PORT STATUS
|
/* SFP PORT STATUS
|
||||||
* [7:4] RESERVED
|
* [7:4] RESERVED
|
||||||
* [3:0] TX_FAULT / MODABS / RXLOS
|
* [3:0] TX_FAULT / MODABS / RXLOS
|
||||||
@ -124,6 +140,24 @@ enum MASTER_LED {
|
|||||||
#define SFP_MODABS 0x0243
|
#define SFP_MODABS 0x0243
|
||||||
#define SFP_RXLOS 0x0244
|
#define SFP_RXLOS 0x0244
|
||||||
|
|
||||||
|
/* SFP PORT INTERRUPT
|
||||||
|
* [7:4] RESERVED
|
||||||
|
* [3:0] TX_FAULT / MODABS / RXLOS
|
||||||
|
* 1: int, 0: no int
|
||||||
|
*/
|
||||||
|
#define TXFAULT_INT 0x0246
|
||||||
|
#define MODABS_INT 0x0247
|
||||||
|
#define RXLOS_INT 0x0248
|
||||||
|
|
||||||
|
/* INTERRUPT MASK REGISTER
|
||||||
|
* [7:4] RESERVED
|
||||||
|
* [3:0] TX_FAULT / MODABS / RXLOS
|
||||||
|
* 1: mask, 0: not mask
|
||||||
|
*/
|
||||||
|
#define TXFAULT_MSK 0x024A
|
||||||
|
#define MODABS_MSK 0x024B
|
||||||
|
#define RXLOS_MSK 0x024C
|
||||||
|
|
||||||
/* SFP PORT CTRL
|
/* SFP PORT CTRL
|
||||||
* [7:4] RATE SEL (RS0/RS1)
|
* [7:4] RATE SEL (RS0/RS1)
|
||||||
* [3:0] TX_DIS
|
* [3:0] TX_DIS
|
||||||
@ -250,7 +284,7 @@ static ssize_t setreg_store(struct device *dev, struct device_attribute *devattr
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show status led
|
* @brief Show status led
|
||||||
* @param dev kernel device
|
* @param dev kernel device
|
||||||
* @param devattr kernel device attribute
|
* @param devattr kernel device attribute
|
||||||
* @param buf buffer for get value
|
* @param buf buffer for get value
|
||||||
@ -269,7 +303,7 @@ static ssize_t status_led_show(struct device *dev, struct device_attribute *deva
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the status led
|
* @brief Set the status led
|
||||||
* @param dev kernel device
|
* @param dev kernel device
|
||||||
* @param devattr kernel device attribute
|
* @param devattr kernel device attribute
|
||||||
* @param buf buffer of set value - off/on/blink
|
* @param buf buffer of set value - off/on/blink
|
||||||
@ -301,7 +335,7 @@ static ssize_t status_led_store(struct device *dev, struct device_attribute *dev
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show master led
|
* @brief Show master led
|
||||||
* @param dev kernel device
|
* @param dev kernel device
|
||||||
* @param devattr kernel device attribute
|
* @param devattr kernel device attribute
|
||||||
* @param buf buffer for get value
|
* @param buf buffer for get value
|
||||||
@ -320,7 +354,7 @@ static ssize_t master_led_show(struct device *dev, struct device_attribute *deva
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the master led
|
* @brief Set the master led
|
||||||
* @param dev kernel device
|
* @param dev kernel device
|
||||||
* @param devattr kernel device attribute
|
* @param devattr kernel device attribute
|
||||||
* @param buf buffer of set value - off/green/amber
|
* @param buf buffer of set value - off/green/amber
|
||||||
@ -401,8 +435,6 @@ static ssize_t fan_dir_show(struct device *dev, struct device_attribute *devattr
|
|||||||
struct sensor_device_attribute *sa = to_sensor_dev_attr(devattr);
|
struct sensor_device_attribute *sa = to_sensor_dev_attr(devattr);
|
||||||
int index = sa->index;
|
int index = sa->index;
|
||||||
unsigned char data = 0;
|
unsigned char data = 0;
|
||||||
|
|
||||||
// Use index to determind the status bit
|
|
||||||
mutex_lock(&cpld_data->cpld_lock);
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
data = inb(DEV_STAT);
|
data = inb(DEV_STAT);
|
||||||
mutex_unlock(&cpld_data->cpld_lock);
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
@ -413,48 +445,41 @@ static ssize_t fan_dir_show(struct device *dev, struct device_attribute *devattr
|
|||||||
static ssize_t sfp_txfault_show(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t sfp_txfault_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
unsigned char data;
|
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);
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
data = inb(SFP_TXFAULT);
|
data = inb(SFP_TXFAULT);
|
||||||
|
data = data & 0x0F;
|
||||||
mutex_unlock(&cpld_data->cpld_lock);
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
return sprintf(buf, "%d\n", (data >> port_bit ) & 1U);
|
return sprintf(buf, "0x%x\n", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t sfp_modabs_show(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t sfp_modabs_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
unsigned char data;
|
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);
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
data = inb(SFP_MODABS);
|
data = inb(SFP_MODABS);
|
||||||
|
data = data & 0x0F;
|
||||||
mutex_unlock(&cpld_data->cpld_lock);
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
return sprintf(buf, "%d\n", (data >> port_bit ) & 1U);
|
return sprintf(buf, "0x%x\n", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t sfp_rxlos_show(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t sfp_rxlos_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
unsigned char data;
|
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);
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
data = inb(SFP_RXLOS);
|
data = inb(SFP_RXLOS);
|
||||||
|
data = data & 0x0F;
|
||||||
mutex_unlock(&cpld_data->cpld_lock);
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
return sprintf(buf, "%d\n", (data >> port_bit ) & 1U);
|
return sprintf(buf, "0x%x\n", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t sfp_txdis_show(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t sfp_txdis_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
unsigned char data;
|
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);
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
data = inb(SFP_TXCTRL);
|
data = inb(SFP_TXCTRL);
|
||||||
|
data = data & 0x0F;
|
||||||
mutex_unlock(&cpld_data->cpld_lock);
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
return sprintf(buf, "%d\n", (data >> port_bit ) & 1U);
|
return sprintf(buf, "0x%x\n", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t sfp_txdis_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
static ssize_t sfp_txdis_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
||||||
@ -462,18 +487,13 @@ static ssize_t sfp_txdis_store(struct device *dev, struct device_attribute *attr
|
|||||||
long value;
|
long value;
|
||||||
ssize_t status;
|
ssize_t status;
|
||||||
unsigned char data;
|
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);
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
status = kstrtol(buf, 0, &value);
|
status = kstrtol(buf, 0, &value);
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
// check if value is 0, clear
|
|
||||||
data = inb(SFP_TXCTRL);
|
data = inb(SFP_TXCTRL);
|
||||||
if (!value)
|
data = data & ~(0x0F);
|
||||||
data = data & ~( 1U << port_bit);
|
data = data | (value & 0x0F);
|
||||||
else
|
|
||||||
data = data | ( 1U << port_bit);
|
|
||||||
outb(data, SFP_TXCTRL);
|
outb(data, SFP_TXCTRL);
|
||||||
status = size;
|
status = size;
|
||||||
}
|
}
|
||||||
@ -484,15 +504,11 @@ static ssize_t sfp_txdis_store(struct device *dev, struct device_attribute *attr
|
|||||||
static ssize_t sfp_rs_show(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t sfp_rs_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
unsigned char data;
|
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);
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
data = inb(SFP_TXCTRL);
|
data = inb(SFP_TXCTRL) >> 4;
|
||||||
|
data = data & 0x0F;
|
||||||
mutex_unlock(&cpld_data->cpld_lock);
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
return sprintf(buf, "%d\n", (data >> port_bit ) & 1U);
|
return sprintf(buf, "0x%x\n", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t sfp_rs_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
static ssize_t sfp_rs_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
||||||
@ -500,20 +516,14 @@ static ssize_t sfp_rs_store(struct device *dev, struct device_attribute *attr, c
|
|||||||
long value;
|
long value;
|
||||||
ssize_t status;
|
ssize_t status;
|
||||||
unsigned char data;
|
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);
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
status = kstrtol(buf, 0, &value);
|
status = kstrtol(buf, 0, &value);
|
||||||
|
value = (value & 0x0F) << 4;
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
// check if value is 0, clear
|
|
||||||
data = inb(SFP_TXCTRL);
|
data = inb(SFP_TXCTRL);
|
||||||
if (!value)
|
data = data & ~(0xF0);
|
||||||
data = data & ~( 1U << port_bit);
|
data = data | value;
|
||||||
else
|
|
||||||
data = data | ( 1U << port_bit);
|
|
||||||
outb(data, SFP_TXCTRL);
|
outb(data, SFP_TXCTRL);
|
||||||
status = size;
|
status = size;
|
||||||
}
|
}
|
||||||
@ -521,6 +531,273 @@ static ssize_t sfp_rs_store(struct device *dev, struct device_attribute *attr, c
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Show the avaliable interrupt trigger mode.
|
||||||
|
* "none" means the interrupt is masked.
|
||||||
|
*
|
||||||
|
* @return Current trigger mode.
|
||||||
|
*/
|
||||||
|
static ssize_t txfault_trig_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
unsigned char mode;
|
||||||
|
char *mode_str[5] = {"falling", "rising", "both", "low"};
|
||||||
|
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
mode = inb(TRIG_MODE) >> TXFAULT_TRIG;
|
||||||
|
mode = mode & 0x3;
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
return sprintf(buf, "%s\n", mode_str[mode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the trigger mode of each interrupt type.
|
||||||
|
* Only one trigger mode allow in a type.
|
||||||
|
*
|
||||||
|
* @param buf The trigger mode of follwings
|
||||||
|
* "falling", "rising", "both"
|
||||||
|
*/
|
||||||
|
static ssize_t txfault_trig_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
ssize_t status;
|
||||||
|
unsigned char data, trig_mode;
|
||||||
|
|
||||||
|
if (sysfs_streq(buf, "falling")) {
|
||||||
|
trig_mode = 0;
|
||||||
|
} else if (sysfs_streq(buf, "rising")) {
|
||||||
|
trig_mode = 1;
|
||||||
|
} else if (sysfs_streq(buf, "both")) {
|
||||||
|
trig_mode = 2;
|
||||||
|
} else if (sysfs_streq(buf, "low")) {
|
||||||
|
trig_mode = 3;
|
||||||
|
} else {
|
||||||
|
status = -EINVAL;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
data = inb(TRIG_MODE);
|
||||||
|
data = data & ~(0x03 << TXFAULT_TRIG);
|
||||||
|
data = data | trig_mode << TXFAULT_TRIG;
|
||||||
|
outb(data, TRIG_MODE);
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
status = size;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Show the avaliable interrupt trigger mode.
|
||||||
|
* "none" means the interrupt is masked.
|
||||||
|
*
|
||||||
|
* @return Current trigger mode.
|
||||||
|
*/
|
||||||
|
static ssize_t modabs_trig_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
unsigned char mode;
|
||||||
|
char *mode_str[5] = {"falling", "rising", "both", "low"};
|
||||||
|
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
mode = inb(TRIG_MODE) >> MODABS_TRIG;
|
||||||
|
mode = mode & 0x3;
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
return sprintf(buf, "%s\n", mode_str[mode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the trigger mode of each interrupt type.
|
||||||
|
* Only one trigger mode allow in a type.
|
||||||
|
*
|
||||||
|
* @param buf The trigger mode of follwings
|
||||||
|
* "falling", "rising", "both", "low"
|
||||||
|
*/
|
||||||
|
static ssize_t modabs_trig_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
ssize_t status;
|
||||||
|
unsigned char data, trig_mode;
|
||||||
|
|
||||||
|
if (sysfs_streq(buf, "falling")) {
|
||||||
|
trig_mode = 0;
|
||||||
|
} else if (sysfs_streq(buf, "rising")) {
|
||||||
|
trig_mode = 1;
|
||||||
|
} else if (sysfs_streq(buf, "both")) {
|
||||||
|
trig_mode = 2;
|
||||||
|
} else if (sysfs_streq(buf, "low")) {
|
||||||
|
trig_mode = 3;
|
||||||
|
} else {
|
||||||
|
status = -EINVAL;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
data = inb(TRIG_MODE);
|
||||||
|
data = data & ~(0x03 << MODABS_TRIG);
|
||||||
|
data = data | trig_mode << MODABS_TRIG;
|
||||||
|
outb(data, TRIG_MODE);
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
status = size;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Show the avaliable interrupt trigger mode.
|
||||||
|
* "none" means the interrupt is masked.
|
||||||
|
*
|
||||||
|
* @return Current trigger mode.
|
||||||
|
*/
|
||||||
|
static ssize_t rxlos_trig_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
unsigned char mode;
|
||||||
|
char *mode_str[5] = {"falling", "rising", "both", "low"};
|
||||||
|
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
mode = inb(TRIG_MODE) >> RXLOS_TRIG;
|
||||||
|
mode = mode & 0x3;
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
return sprintf(buf, "%s\n", mode_str[mode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the trigger mode of each interrupt type.
|
||||||
|
* Only one trigger mode allow in a type.
|
||||||
|
*
|
||||||
|
* @param buf The trigger mode of follwings
|
||||||
|
* "falling", "rising", "both", "low"
|
||||||
|
*/
|
||||||
|
static ssize_t rxlos_trig_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
ssize_t status;
|
||||||
|
unsigned char data, trig_mode;
|
||||||
|
|
||||||
|
if (sysfs_streq(buf, "falling")) {
|
||||||
|
trig_mode = 0;
|
||||||
|
} else if (sysfs_streq(buf, "rising")) {
|
||||||
|
trig_mode = 1;
|
||||||
|
} else if (sysfs_streq(buf, "both")) {
|
||||||
|
trig_mode = 2;
|
||||||
|
} else if (sysfs_streq(buf, "low")) {
|
||||||
|
trig_mode = 3;
|
||||||
|
} else {
|
||||||
|
status = -EINVAL;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
data = inb(TRIG_MODE);
|
||||||
|
data = data & ~(0x03 << RXLOS_TRIG);
|
||||||
|
data = data | trig_mode << RXLOS_TRIG;
|
||||||
|
outb(data, TRIG_MODE);
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
status = size;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t txfault_int_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
unsigned char data;
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
data = inb(TXFAULT_INT);
|
||||||
|
data = data & 0x0F;
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
return sprintf(buf, "0x%x\n", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t modabs_int_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
unsigned char data;
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
data = inb(MODABS_INT);
|
||||||
|
data = data & 0x0F;
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
return sprintf(buf, "0x%x\n", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t rxlos_int_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
unsigned char data;
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
data = inb(RXLOS_INT);
|
||||||
|
data = data & 0x0F;
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
return sprintf(buf, "0x%x\n", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t txfault_mask_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
unsigned char data;
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
data = inb(TXFAULT_MSK);
|
||||||
|
data = data & 0x0F;
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
return sprintf(buf, "0x%x\n", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t txfault_mask_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
long value;
|
||||||
|
ssize_t status;
|
||||||
|
|
||||||
|
status = kstrtol(buf, 0, &value);
|
||||||
|
value = value & 0x0F;
|
||||||
|
if (status == 0) {
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
outb(value, TXFAULT_MSK);
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
status = size;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t modabs_mask_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
unsigned char data;
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
data = inb(MODABS_MSK);
|
||||||
|
data = data & 0x0F;
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
return sprintf(buf, "0x%x\n", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t modabs_mask_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
long value;
|
||||||
|
ssize_t status;
|
||||||
|
|
||||||
|
status = kstrtol(buf, 0, &value);
|
||||||
|
value = value & 0x0F;
|
||||||
|
if (status == 0) {
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
outb(value, MODABS_MSK);
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
status = size;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t rxlos_mask_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
unsigned char data;
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
data = inb(RXLOS_MSK);
|
||||||
|
data = data & 0x0F;
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
return sprintf(buf, "0x%x\n", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t rxlos_mask_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
long value;
|
||||||
|
ssize_t status;
|
||||||
|
|
||||||
|
status = kstrtol(buf, 0, &value);
|
||||||
|
value = value & 0x0F;
|
||||||
|
if (status == 0) {
|
||||||
|
mutex_lock(&cpld_data->cpld_lock);
|
||||||
|
outb(value, RXLOS_MSK);
|
||||||
|
mutex_unlock(&cpld_data->cpld_lock);
|
||||||
|
status = size;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t fan_led_show(struct device *dev, struct device_attribute *devattr,
|
static ssize_t fan_led_show(struct device *dev, struct device_attribute *devattr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
@ -578,6 +855,15 @@ static DEVICE_ATTR_RO(sfp_modabs);
|
|||||||
static DEVICE_ATTR_RO(sfp_rxlos);
|
static DEVICE_ATTR_RO(sfp_rxlos);
|
||||||
static DEVICE_ATTR_RW(sfp_txdis);
|
static DEVICE_ATTR_RW(sfp_txdis);
|
||||||
static DEVICE_ATTR_RW(sfp_rs);
|
static DEVICE_ATTR_RW(sfp_rs);
|
||||||
|
static DEVICE_ATTR_RW(txfault_trig);
|
||||||
|
static DEVICE_ATTR_RW(modabs_trig);
|
||||||
|
static DEVICE_ATTR_RW(rxlos_trig);
|
||||||
|
static DEVICE_ATTR_RO(txfault_int);
|
||||||
|
static DEVICE_ATTR_RO(modabs_int);
|
||||||
|
static DEVICE_ATTR_RO(rxlos_int);
|
||||||
|
static DEVICE_ATTR_RW(txfault_mask);
|
||||||
|
static DEVICE_ATTR_RW(modabs_mask);
|
||||||
|
static DEVICE_ATTR_RW(rxlos_mask);
|
||||||
static SENSOR_DEVICE_ATTR(fan1_dir, S_IRUGO, fan_dir_show, NULL, FAN_1);
|
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(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(fan3_dir, S_IRUGO, fan_dir_show, NULL, FAN_3);
|
||||||
@ -619,6 +905,15 @@ static struct attribute *sfp_attrs[] = {
|
|||||||
&dev_attr_sfp_rxlos.attr,
|
&dev_attr_sfp_rxlos.attr,
|
||||||
&dev_attr_sfp_txdis.attr,
|
&dev_attr_sfp_txdis.attr,
|
||||||
&dev_attr_sfp_rs.attr,
|
&dev_attr_sfp_rs.attr,
|
||||||
|
&dev_attr_txfault_trig.attr,
|
||||||
|
&dev_attr_modabs_trig.attr,
|
||||||
|
&dev_attr_rxlos_trig.attr,
|
||||||
|
&dev_attr_txfault_int.attr,
|
||||||
|
&dev_attr_modabs_int.attr,
|
||||||
|
&dev_attr_rxlos_int.attr,
|
||||||
|
&dev_attr_txfault_mask.attr,
|
||||||
|
&dev_attr_modabs_mask.attr,
|
||||||
|
&dev_attr_rxlos_mask.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -632,26 +927,6 @@ static struct resource cpld_resources[] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
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)
|
static void cpld_dev_release( struct device * dev)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -670,7 +945,7 @@ static struct platform_device cpld_dev = {
|
|||||||
static int cpld_drv_probe(struct platform_device *pdev)
|
static int cpld_drv_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int err, i = 0;
|
int err;
|
||||||
|
|
||||||
cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct cpld_data),
|
cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct cpld_data),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
@ -700,7 +975,8 @@ static int cpld_drv_probe(struct platform_device *pdev)
|
|||||||
return PTR_ERR(celplatform);
|
return PTR_ERR(celplatform);
|
||||||
}
|
}
|
||||||
|
|
||||||
cpld_data->fpp_node = device_create(celplatform, NULL, MKDEV(0, 0), NULL, "optical_ports");
|
cpld_data->fpp_node = device_create_with_groups(celplatform, NULL, MKDEV(0, 0), NULL, sfp_groups, "optical_ports");
|
||||||
|
|
||||||
if (IS_ERR(cpld_data->fpp_node)) {
|
if (IS_ERR(cpld_data->fpp_node)) {
|
||||||
class_destroy(celplatform);
|
class_destroy(celplatform);
|
||||||
sysfs_remove_group(&pdev->dev.kobj, &cpld_group);
|
sysfs_remove_group(&pdev->dev.kobj, &cpld_group);
|
||||||
@ -716,11 +992,6 @@ static int cpld_drv_probe(struct platform_device *pdev)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creae SFP devices
|
|
||||||
for ( i = 0; i < 4; i++) {
|
|
||||||
cpld_data->sfp_devices[i] = sfp_init(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear all reset signals
|
// Clear all reset signals
|
||||||
outb(0xFF, SPR_RESET);
|
outb(0xFF, SPR_RESET);
|
||||||
return 0;
|
return 0;
|
||||||
@ -728,17 +999,8 @@ static int cpld_drv_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
static int cpld_drv_remove(struct platform_device *pdev)
|
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);
|
device_unregister(cpld_data->fpp_node);
|
||||||
|
put_device(cpld_data->fpp_node);
|
||||||
sysfs_remove_group(&pdev->dev.kobj, &cpld_group);
|
sysfs_remove_group(&pdev->dev.kobj, &cpld_group);
|
||||||
class_destroy(celplatform);
|
class_destroy(celplatform);
|
||||||
return 0;
|
return 0;
|
||||||
@ -773,5 +1035,5 @@ module_exit(cpld_exit);
|
|||||||
|
|
||||||
MODULE_AUTHOR("Celestica Inc.");
|
MODULE_AUTHOR("Celestica Inc.");
|
||||||
MODULE_DESCRIPTION("Celestica E1031 SMC driver");
|
MODULE_DESCRIPTION("Celestica E1031 SMC driver");
|
||||||
MODULE_VERSION("0.0.3");
|
MODULE_VERSION("1.0.0");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
Loading…
Reference in New Issue
Block a user