Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Accton][as7926-40xfb] Add onlp_data_path_reset() to support chip reset #996

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,19 @@
#define IPMI_TIMEOUT (5 * HZ)
#define IPMI_ERR_RETRY_TIMES 1
#define IPMI_READ_MAX_LEN 128
#define IPMI_RESET_CMD 0x65
#define IPMI_RESET_CMD_LENGTH 6

#define EEPROM_NAME "eeprom"
#define EEPROM_SIZE 256 /* 256 byte eeprom */

static int as7926_40xfb_sys_probe(struct platform_device *pdev);
static int as7926_40xfb_sys_remove(struct platform_device *pdev);
static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data);
static ssize_t get_reset(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t set_reset(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);

struct ipmi_data {
struct completion read_complete;
Expand All @@ -75,6 +81,8 @@ struct as7926_40xfb_sys_data {
struct ipmi_data ipmi;
unsigned char ipmi_resp_eeprom[EEPROM_SIZE];
unsigned char ipmi_tx_data[2];
unsigned char ipmi_resp_rst[2];
unsigned char ipmi_tx_data_rst[IPMI_RESET_CMD_LENGTH];
struct bin_attribute eeprom; /* eeprom data */
};

Expand All @@ -89,6 +97,45 @@ static struct platform_driver as7926_40xfb_sys_driver = {
},
};

/* sysfs attributes */
enum as7926_40xfb_sysfs_attrs {
RESET_MUX,
RESET_MAC,
RESET_JR2,
RESET_OP2,
RESET_GEARBOX
};

#define DECLARE_RESET_SENSOR_DEVICE_ATTR() \
static SENSOR_DEVICE_ATTR(reset_mac, S_IWUSR | S_IRUGO, \
get_reset, set_reset, RESET_MAC); \
static SENSOR_DEVICE_ATTR(reset_jr2, S_IWUSR | S_IRUGO, \
get_reset, set_reset, RESET_JR2); \
static SENSOR_DEVICE_ATTR(reset_op2, S_IWUSR | S_IRUGO, \
get_reset, set_reset, RESET_OP2); \
static SENSOR_DEVICE_ATTR(reset_gb, S_IWUSR | S_IRUGO, \
get_reset, set_reset, RESET_GEARBOX); \
static SENSOR_DEVICE_ATTR(reset_mux, S_IWUSR | S_IRUGO, \
get_reset, set_reset, RESET_MUX)
#define DECLARE_RESET_ATTR() \
&sensor_dev_attr_reset_mac.dev_attr.attr, \
&sensor_dev_attr_reset_jr2.dev_attr.attr, \
&sensor_dev_attr_reset_op2.dev_attr.attr, \
&sensor_dev_attr_reset_gb.dev_attr.attr, \
&sensor_dev_attr_reset_mux.dev_attr.attr

DECLARE_RESET_SENSOR_DEVICE_ATTR();

static struct attribute *as7926_40xfb_sys_attributes[] = {
/* sysfs attributes */
DECLARE_RESET_ATTR(),
NULL
};

static const struct attribute_group as7926_40xfb_sys_group = {
.attrs = as7926_40xfb_sys_attributes,
};

/* Functions to talk to the IPMI layer */

/* Initialize IPMI address, message buffers and user data */
Expand Down Expand Up @@ -225,6 +272,71 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
complete(&ipmi->read_complete);
}

static ssize_t get_reset(struct device *dev, struct device_attribute *da,
char *buf)
{
int status = 0;

mutex_lock(&data->update_lock);
status = ipmi_send_message(&data->ipmi, IPMI_RESET_CMD, NULL, 0,
data->ipmi_resp_rst, sizeof(data->ipmi_resp_rst));
if (unlikely(status != 0))
goto exit;

if (unlikely(data->ipmi.rx_result != 0)) {
status = -EIO;
goto exit;
}

mutex_unlock(&data->update_lock);
return sprintf(buf, "0x%x 0x%x", data->ipmi_resp_rst[0], data->ipmi_resp_rst[1]);

exit:
mutex_unlock(&data->update_lock);
return status;
}

static ssize_t set_reset(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
u32 magic[2];
int status;
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);

if (sscanf(buf, "0x%x 0x%x", &magic[0], &magic[1]) != 2)
return -EINVAL;

if (magic[0] > 0xFF || magic[1] > 0xFF)
return -EINVAL;

mutex_lock(&data->update_lock);

/* Send IPMI write command */
data->ipmi_tx_data_rst[0] = 0;
data->ipmi_tx_data_rst[1] = 0;
data->ipmi_tx_data_rst[2] = (attr->index == RESET_MUX) ? 0 : (attr->index);
data->ipmi_tx_data_rst[3] = (attr->index == RESET_MUX) ? 2 : 1;
data->ipmi_tx_data_rst[4] = magic[0];
data->ipmi_tx_data_rst[5] = magic[1];

status = ipmi_send_message(&data->ipmi, IPMI_RESET_CMD,
data->ipmi_tx_data_rst,
sizeof(data->ipmi_tx_data_rst), NULL, 0);
if (unlikely(status != 0))
goto exit;

if (unlikely(data->ipmi.rx_result != 0)) {
status = -EIO;
goto exit;
}

status = count;

exit:
mutex_unlock(&data->update_lock);
return status;
}

static ssize_t sys_eeprom_read(loff_t off, char *buf, size_t count)
{
int status = 0;
Expand Down Expand Up @@ -322,19 +434,27 @@ static int as7926_40xfb_sys_probe(struct platform_device *pdev)
/* Register sysfs hooks */
status = sysfs_eeprom_init(&pdev->dev.kobj, &data->eeprom);
if (status) {
goto exit;
goto exit_eeprom;
}

status = sysfs_create_group(&pdev->dev.kobj, &as7926_40xfb_sys_group);
if (status) {
goto exit_sysfs;
}

dev_info(&pdev->dev, "device created\n");

return 0;

exit:
exit_sysfs:
sysfs_eeprom_cleanup(&pdev->dev.kobj, &data->eeprom);
exit_eeprom:
return status;
}

static int as7926_40xfb_sys_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &as7926_40xfb_sys_group);
sysfs_eeprom_cleanup(&pdev->dev.kobj, &data->eeprom);

return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,6 @@ enum fan_id {
{ 0 },\
}

#define AIM_FREE_IF_PTR(p) \
do \
{ \
if (p) { \
aim_free(p); \
p = NULL; \
} \
} while (0)

/* Static fan information */
onlp_fan_info_t finfo[] = {
{ }, /* Not used */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/************************************************************
* <bsn.cl fy=2014 v=onl>
*
* Copyright 2014 Big Switch Networks, Inc.
*
* Licensed under the Eclipse Public License, Version 1.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*
* </bsn.cl>
************************************************************
*
* Platform Library
*
***********************************************************/
#include <unistd.h>
#include <onlp/onlp.h>
#include <onlplib/file.h>
#include "platform_lib.h"

#define WARM_RESET_FORMAT "/sys/devices/platform/as7926_40xfb_sys/reset_%s"

/**
* @brief warm reset for mac, mux, op2, gb and jr2
* @param unit_id The warm reset device unit id, should be 0
* @param reset_dev The warm reset device id, should be 1 ~ (WARM_RESET_MAX-1)
* @param ret return value.
*/
int onlp_data_path_reset(uint8_t unit_id, uint8_t reset_dev)
{
int len = 0;
int ret = ONLP_STATUS_OK;
char *magic_num = NULL;
char *device_id[] = { NULL, "mac", NULL, "mux", "op2", "gb", "jr2" };

if (unit_id != 0 || reset_dev >= WARM_RESET_MAX)
return ONLP_STATUS_E_PARAM;

if (reset_dev == 0 || reset_dev == WARM_RESET_PHY)
return ONLP_STATUS_E_UNSUPPORTED;

/* Reset device */
len = onlp_file_read_str(&magic_num, WARM_RESET_FORMAT, device_id[reset_dev]);
if (magic_num && len) {
ret = onlp_file_write_str(magic_num, WARM_RESET_FORMAT, device_id[reset_dev]);
if (ret < 0) {
AIM_LOG_ERROR("Reset device-%d:(%s) failed.", reset_dev, device_id[reset_dev]);
}
}
else {
ret = ONLP_STATUS_E_INTERNAL;
}

AIM_FREE_IF_PTR(magic_num);
return ret;
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@
#define FAN_BOARD_PATH "/sys/devices/platform/as7926_40xfb_fan/"
#define IDPROM_PATH "/sys/devices/platform/as7926_40xfb_sys/eeprom"

#define AIM_FREE_IF_PTR(p) \
do \
{ \
if (p) { \
aim_free(p); \
p = NULL; \
} \
} while (0)

enum onlp_led_id
{
LED_RESERVED = 0,
Expand Down Expand Up @@ -68,4 +77,14 @@ enum onlp_thermal_id {
THERMAL_1_ON_PSU2,
};

enum reset_dev_type {
WARM_RESET_MAC = 1,
WARM_RESET_PHY, /* Not supported */
WARM_RESET_MUX,
WARM_RESET_OP2,
WARM_RESET_GB,
WARM_RESET_JR2,
WARM_RESET_MAX
};

#endif /* __PLATFORM_LIB_H__ */
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,6 @@
} \
} while(0)

#define AIM_FREE_IF_PTR(p) \
do \
{ \
if (p) { \
aim_free(p); \
p = NULL; \
} \
} while (0)

int
onlp_psui_init(void)
{
Expand Down