The slot and switch_rootsysfs driver framework module complies with s3ip sysfs specification (#12893)

Why I did it
Provide slot and switch_rootsysfs driver framework that complies with s3ip sysfs specification

How I did it
1、 The framework module provides register and unregister interface and implementation.
2、 The framework will help you create the sysfs node

How to verify it
A demo driver base on this framework will display the sysfs node wich conform to the s3ip sysfs specification
This commit is contained in:
tianshangfei 2022-12-14 22:34:27 +08:00 committed by GitHub
parent 8f124dc56d
commit 8fe4fab89f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 2506 additions and 0 deletions

View File

@ -0,0 +1,57 @@
#ifndef _SLOT_SYSFS_H_
#define _SLOT_SYSFS_H_
struct s3ip_sysfs_slot_drivers_s {
int (*get_slot_number)(void);
int (*get_slot_temp_number)(unsigned int slot_index);
int (*get_slot_vol_number)(unsigned int slot_index);
int (*get_slot_curr_number)(unsigned int slot_index);
int (*get_slot_cpld_number)(unsigned int slot_index);
int (*get_slot_fpga_number)(unsigned int slot_index);
ssize_t (*get_slot_model_name)(unsigned int slot_index, char *buf, size_t count);
ssize_t (*get_slot_serial_number)(unsigned int slot_index, char *buf, size_t count);
ssize_t (*get_slot_part_number)(unsigned int slot_index, char *buf, size_t count);
ssize_t (*get_slot_hardware_version)(unsigned int slot_index, char *buf, size_t count);
ssize_t (*get_slot_status)(unsigned int slot_index, char *buf, size_t count);
ssize_t (*get_slot_led_status)(unsigned int slot_index, char *buf, size_t count);
int (*set_slot_led_status)(unsigned int slot_index, int status);
ssize_t (*get_slot_temp_alias)(unsigned int slot_index, unsigned int temp_index, char *buf, size_t count);
ssize_t (*get_slot_temp_type)(unsigned int slot_index, unsigned int temp_index, char *buf, size_t count);
ssize_t (*get_slot_temp_max)(unsigned int slot_index, unsigned int temp_index, char *buf, size_t count);
int (*set_slot_temp_max)(unsigned int slot_index, unsigned int temp_index, const char *buf, size_t count);
ssize_t (*get_slot_temp_min)(unsigned int slot_index, unsigned int temp_index, char *buf, size_t count);
int (*set_slot_temp_min)(unsigned int slot_index, unsigned int temp_index, const char *buf, size_t count);
ssize_t (*get_slot_temp_value)(unsigned int slot_index, unsigned int temp_index, char *buf, size_t count);
ssize_t (*get_slot_vol_alias)(unsigned int slot_index, unsigned int vol_index, char *buf, size_t count);
ssize_t (*get_slot_vol_type)(unsigned int slot_index, unsigned int vol_index, char *buf, size_t count);
ssize_t (*get_slot_vol_max)(unsigned int slot_index, unsigned int vol_index, char *buf, size_t count);
int (*set_slot_vol_max)(unsigned int slot_index, unsigned int vol_index, const char *buf, size_t count);
ssize_t (*get_slot_vol_min)(unsigned int slot_index, unsigned int vol_index, char *buf, size_t count);
int (*set_slot_vol_min)(unsigned int slot_index, unsigned int vol_index, const char *buf, size_t count);
ssize_t (*get_slot_vol_range)(unsigned int slot_index, unsigned int vol_index, char *buf, size_t count);
ssize_t (*get_slot_vol_nominal_value)(unsigned int slot_index, unsigned int vol_index, char *buf, size_t count);
ssize_t (*get_slot_vol_value)(unsigned int slot_index, unsigned int vol_index, char *buf, size_t count);
ssize_t (*get_slot_curr_alias)(unsigned int slot_index, unsigned int curr_index, char *buf, size_t count);
ssize_t (*get_slot_curr_type)(unsigned int slot_index, unsigned int curr_index, char *buf, size_t count);
ssize_t (*get_slot_curr_max)(unsigned int slot_index, unsigned int curr_index, char *buf, size_t count);
int (*set_slot_curr_max)(unsigned int slot_index, unsigned int curr_index, const char *buf, size_t count);
ssize_t (*get_slot_curr_min)(unsigned int slot_index, unsigned int curr_index, char *buf, size_t count);
int (*set_slot_curr_min)(unsigned int slot_index, unsigned int curr_index, const char *buf, size_t count);
ssize_t (*get_slot_curr_value)(unsigned int slot_index, unsigned int curr_index, char *buf, size_t count);
ssize_t (*get_slot_fpga_alias)(unsigned int slot_index, unsigned int fpga_index, char *buf, size_t count);
ssize_t (*get_slot_fpga_type)(unsigned int slot_index, unsigned int fpga_index, char *buf, size_t count);
ssize_t (*get_slot_fpga_firmware_version)(unsigned int slot_index, unsigned int fpga_index, char *buf, size_t count);
ssize_t (*get_slot_fpga_board_version)(unsigned int slot_index, unsigned int fpga_index, char *buf, size_t count);
ssize_t (*get_slot_fpga_test_reg)(unsigned int slot_index, unsigned int fpga_index, char *buf, size_t count);
int (*set_slot_fpga_test_reg)(unsigned int slot_index, unsigned int fpga_index, unsigned int value);
ssize_t (*get_slot_cpld_alias)(unsigned int slot_index, unsigned int cpld_index, char *buf, size_t count);
ssize_t (*get_slot_cpld_type)(unsigned int slot_index, unsigned int cpld_index, char *buf, size_t count);
ssize_t (*get_slot_cpld_firmware_version)(unsigned int slot_index, unsigned int cpld_index, char *buf, size_t count);
ssize_t (*get_slot_cpld_board_version)(unsigned int slot_index, unsigned int cpld_index, char *buf, size_t count);
ssize_t (*get_slot_cpld_test_reg)(unsigned int slot_index, unsigned int cpld_index, char *buf, size_t count);
int (*set_slot_cpld_test_reg)(unsigned int slot_index, unsigned int cpld_index, unsigned int value);
};
extern int s3ip_sysfs_slot_drivers_register(struct s3ip_sysfs_slot_drivers_s *drv);
extern void s3ip_sysfs_slot_drivers_unregister(void);
#endif /*_SLOT_SYSFS_H_ */

View File

@ -0,0 +1,68 @@
#ifndef _SWITCH_H_
#define _SWITCH_H_
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/workqueue.h>
#include <linux/kobject.h>
#include <linux/delay.h>
#define DIR_NAME_MAX_LEN (64)
#define SYSFS_DEV_ERROR "NA"
enum LOG_LEVEL{
INFO = 0x1,
ERR = 0x2,
DBG = 0x4,
ALL = 0xf
};
extern int g_switch_loglevel;
#define check_pfun(p) do { \
if (p == NULL) { \
if (g_switch_loglevel & ERR) { \
printk( KERN_ERR "%s, %s is NULL.\n", __FUNCTION__, #p); \
} \
return -ENOSYS; \
} \
} while(0)
#define check_p(p) check_pfun(p)
#define to_switch_obj(x) container_of(x, struct switch_obj, kobj)
#define to_switch_attr(x) container_of(x, struct switch_attribute, attr)
#define to_switch_device_attr(x) container_of(x, struct switch_device_attribute, switch_attr)
#define SWITCH_ATTR(_name, _mode, _show, _store, _type) \
{ .switch_attr = __ATTR(_name, _mode, _show, _store), \
.type = _type }
#define SWITCH_DEVICE_ATTR(_name, _mode, _show, _store, _type) \
struct switch_device_attribute switch_dev_attr_##_name \
= SWITCH_ATTR(_name, _mode, _show, _store, _type)
struct switch_obj {
struct kobject kobj;
unsigned int index;
};
/* a custom attribute that works just for a struct switch_obj. */
struct switch_attribute {
struct attribute attr;
ssize_t (*show)(struct switch_obj *foo, struct switch_attribute *attr, char *buf);
ssize_t (*store)(struct switch_obj *foo, struct switch_attribute *attr, const char *buf, size_t count);
};
struct switch_device_attribute {
struct switch_attribute switch_attr;
int type;
};
struct switch_obj *switch_kobject_create(const char *name, struct kobject *parent);
void switch_kobject_delete(struct switch_obj **obj);
#endif /* _SWITCH_H_ */

View File

@ -0,0 +1,12 @@
#ifndef _SYSEEPROM_SYSFS_H_
#define _SYSEEPROM_SYSFS_H_
struct s3ip_sysfs_syseeprom_drivers_s {
int (*get_syseeprom_size)(void);
ssize_t (*read_syseeprom_data)(char *buf, loff_t offset, size_t count);
ssize_t (*write_syseeprom_data)(char *buf, loff_t offset, size_t count);
};
extern int s3ip_sysfs_syseeprom_drivers_register(struct s3ip_sysfs_syseeprom_drivers_s *drv);
extern void s3ip_sysfs_syseeprom_drivers_unregister(void);
#endif /*_SYSEEPROM_SYSFS_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,270 @@
/*
* switch.c
*
* This module create a kset in sysfs called /sys/s3ip
* Then other switch kobjects are created and assigned to this kset,
* such as "cpld", "fan", "psu", ...
*
* History
* [Version] [Date] [Description]
* * v1.0 2021-08-31 S3IP sysfs
*/
#include "switch.h"
#include "syseeprom_sysfs.h"
int g_switch_loglevel = 0;
#define SWITCH_INFO(fmt, args...) do { \
if (g_switch_loglevel & INFO) { \
printk(KERN_INFO "[SWITCH][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \
} \
} while (0)
#define SWITCH_ERR(fmt, args...) do { \
if (g_switch_loglevel & ERR) { \
printk(KERN_ERR "[SWITCH][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \
} \
} while (0)
#define SWITCH_DBG(fmt, args...) do { \
if (g_switch_loglevel & DBG) { \
printk(KERN_DEBUG "[SWITCH][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \
} \
} while (0)
struct syseeprom_s {
struct bin_attribute bin;
int creat_eeprom_bin_flag;
};
static struct s3ip_sysfs_syseeprom_drivers_s *g_syseeprom_drv = NULL;
static struct kset *switch_kset;
static struct syseeprom_s g_syseeprom;
static ssize_t switch_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
struct switch_attribute *attribute;
struct switch_obj *device;
attribute = to_switch_attr(attr);
device = to_switch_obj(kobj);
if (!attribute->show) {
return -ENOSYS;
}
return attribute->show(device, attribute, buf);
}
static ssize_t switch_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf,
size_t len)
{
struct switch_attribute *attribute;
struct switch_obj *obj;
attribute = to_switch_attr(attr);
obj = to_switch_obj(kobj);
if (!attribute->store) {
return -ENOSYS;
}
return attribute->store(obj, attribute, buf, len);
}
static const struct sysfs_ops switch_sysfs_ops = {
.show = switch_attr_show,
.store = switch_attr_store,
};
static void switch_obj_release(struct kobject *kobj)
{
struct switch_obj *obj;
obj = to_switch_obj(kobj);
kfree(obj);
return;
}
static struct kobj_type switch_ktype = {
.sysfs_ops = &switch_sysfs_ops,
.release = switch_obj_release,
.default_attrs = NULL,
};
static ssize_t syseeprom_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr,
char *buf, loff_t offset, size_t count)
{
ssize_t rd_len;
check_p(g_syseeprom_drv);
check_p(g_syseeprom_drv->read_syseeprom_data);
memset(buf, 0, count);
rd_len = g_syseeprom_drv->read_syseeprom_data(buf, offset, count);
if (rd_len < 0) {
SWITCH_ERR("read syseeprom data error, offset: 0x%llx, read len: %lu, ret: %ld.\n",
offset, count, rd_len);
return -EIO;
}
SWITCH_DBG("read syseeprom data success, offset:0x%llx, read len:%lu, really read len:%ld.\n",
offset, count, rd_len);
return rd_len;
}
static ssize_t syseeprom_write(struct file *filp, struct kobject *kobj, struct bin_attribute *attr,
char *buf, loff_t offset, size_t count)
{
ssize_t wr_len;
check_p(g_syseeprom_drv);
check_p(g_syseeprom_drv->write_syseeprom_data);
wr_len = g_syseeprom_drv->write_syseeprom_data(buf, offset, count);
if (wr_len < 0) {
SWITCH_ERR("write syseeprom data error, offset: 0x%llx, read len: %lu, ret: %ld.\n",
offset, count, wr_len);
return -EIO;
}
SWITCH_DBG("write syseeprom data success, offset:0x%llx, write len:%lu, really write len:%ld.\n",
offset, count, wr_len);
return wr_len;
}
static int syseeprom_create_eeprom_attrs(void)
{
int ret, eeprom_size;
eeprom_size = g_syseeprom_drv->get_syseeprom_size();
if (eeprom_size <= 0) {
SWITCH_ERR("syseeprom size: %d, invalid.\n", eeprom_size);
return -EINVAL;
}
sysfs_bin_attr_init(&g_syseeprom.bin);
g_syseeprom.bin.attr.name = "syseeprom";
g_syseeprom.bin.attr.mode = 0644;
g_syseeprom.bin.read = syseeprom_read;
g_syseeprom.bin.write = syseeprom_write;
g_syseeprom.bin.size = eeprom_size;
ret = sysfs_create_bin_file(&switch_kset->kobj, &g_syseeprom.bin);
if (ret) {
SWITCH_ERR("create syseeprom bin error, ret: %d. \n", ret);
return -EBADRQC;
}
SWITCH_DBG("create syseeprom bin file success, eeprom size:%d.\n", eeprom_size);
g_syseeprom.creat_eeprom_bin_flag = 1;
return 0;
}
static void syseeprom_remove_eeprom_attrs(void)
{
if (g_syseeprom.creat_eeprom_bin_flag) {
sysfs_remove_bin_file(&switch_kset->kobj, &g_syseeprom.bin);
g_syseeprom.creat_eeprom_bin_flag = 0;
}
return;
}
int s3ip_sysfs_syseeprom_drivers_register(struct s3ip_sysfs_syseeprom_drivers_s *drv)
{
int ret;
SWITCH_INFO("s3ip_sysfs_syseeprom_drivers_register...\n");
if (g_syseeprom_drv) {
SWITCH_ERR("g_syseeprom_drv is not NULL, can't register\n");
return -EPERM;
}
check_p(drv);
check_p(drv->get_syseeprom_size);
g_syseeprom_drv = drv;
ret = syseeprom_create_eeprom_attrs();
if (ret < 0) {
SWITCH_ERR("create syseeprom attributes failed, ret: %d\n", ret);
g_syseeprom_drv = NULL;
return ret;
}
SWITCH_INFO("s3ip_sysfs_syseeprom_drivers_register success.\n");
return 0;
}
void s3ip_sysfs_syseeprom_drivers_unregister(void)
{
if (g_syseeprom_drv) {
syseeprom_remove_eeprom_attrs();
g_syseeprom_drv = NULL;
SWITCH_DBG("s3ip_sysfs_syseeprom_drivers_unregister success.\n");
}
return;
}
struct switch_obj *switch_kobject_create(const char *name, struct kobject *parent)
{
struct switch_obj *obj;
int ret;
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
if (!obj) {
SWITCH_DBG("switch_kobject_create %s kzalloc error", name);
return NULL;
}
obj->kobj.kset = switch_kset;
ret = kobject_init_and_add(&obj->kobj, &switch_ktype, parent, "%s", name);
if (ret) {
kobject_put(&obj->kobj);
SWITCH_DBG("kobject_init_and_add %s error", name);
return NULL;
}
return obj;
}
void switch_kobject_delete(struct switch_obj **obj)
{
if (*obj) {
SWITCH_DBG("%s delete %s.\n", (*obj)->kobj.parent->name, (*obj)->kobj.name);
kobject_put(&((*obj)->kobj));
*obj = NULL;
}
}
static int __init switch_init(void)
{
SWITCH_INFO("switch_init...\n");
switch_kset = kset_create_and_add("s3ip", NULL, NULL);
if (!switch_kset) {
SWITCH_ERR("create switch_kset error.\n");
return -ENOMEM;
}
SWITCH_INFO("switch_init success.\n");
return 0;
}
static void __exit switch_exit(void)
{
if (switch_kset) {
kset_unregister(switch_kset);
}
SWITCH_INFO("switch_exit success.\n");
}
module_init(switch_init);
module_exit(switch_exit);
EXPORT_SYMBOL(s3ip_sysfs_syseeprom_drivers_register);
EXPORT_SYMBOL(s3ip_sysfs_syseeprom_drivers_unregister);
module_param(g_switch_loglevel, int, 0644);
MODULE_PARM_DESC(g_switch_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("sonic S3IP sysfs");
MODULE_DESCRIPTION("switch driver");