Skip to content

Commit 67e1b81

Browse files
tianshangfeimssonicbld
authored andcommitted
The CPLD and FPGA driver framework module complies with s3ip sysfs specification (sonic-net#12891)
Why I did it Provide CPLD and FPGA 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
1 parent f6ff26b commit 67e1b81

4 files changed

Lines changed: 763 additions & 0 deletions

File tree

Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
1+
/*
2+
* cpld_sysfs.c
3+
*
4+
* This module create cpld kobjects and attributes in /sys/s3ip/cpld
5+
*
6+
* History
7+
* [Version] [Date] [Description]
8+
* * v1.0 2021-08-31 S3IP sysfs
9+
*/
10+
11+
#include <linux/slab.h>
12+
13+
#include "switch.h"
14+
#include "cpld_sysfs.h"
15+
16+
static int g_cpld_loglevel = 0;
17+
18+
#define CPLD_INFO(fmt, args...) do { \
19+
if (g_cpld_loglevel & INFO) { \
20+
printk(KERN_INFO "[CPLD_SYSFS][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \
21+
} \
22+
} while (0)
23+
24+
#define CPLD_ERR(fmt, args...) do { \
25+
if (g_cpld_loglevel & ERR) { \
26+
printk(KERN_ERR "[CPLD_SYSFS][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \
27+
} \
28+
} while (0)
29+
30+
#define CPLD_DBG(fmt, args...) do { \
31+
if (g_cpld_loglevel & DBG) { \
32+
printk(KERN_DEBUG "[CPLD_SYSFS][func:%s line:%d]\n"fmt, __func__, __LINE__, ## args); \
33+
} \
34+
} while (0)
35+
36+
struct cpld_obj_s {
37+
struct switch_obj *obj;
38+
};
39+
40+
struct cpld_s {
41+
unsigned int cpld_number;
42+
struct cpld_obj_s *cpld;
43+
};
44+
45+
static struct cpld_s g_cpld;
46+
static struct switch_obj *g_cpld_obj = NULL;
47+
static struct s3ip_sysfs_cpld_drivers_s *g_cpld_drv = NULL;
48+
49+
static ssize_t cpld_number_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf)
50+
{
51+
return (ssize_t)snprintf(buf, PAGE_SIZE, "%u\n", g_cpld.cpld_number);
52+
}
53+
54+
static ssize_t cpld_alias_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf)
55+
{
56+
unsigned int cpld_index;
57+
int ret;
58+
59+
check_p(g_cpld_drv);
60+
check_p(g_cpld_drv->get_main_board_cpld_alias);
61+
62+
cpld_index = obj->index;
63+
CPLD_DBG("cpld index: %u\n", cpld_index);
64+
ret = g_cpld_drv->get_main_board_cpld_alias(cpld_index, buf, PAGE_SIZE);
65+
if (ret < 0) {
66+
CPLD_ERR("get cpld%u alias failed, ret: %d\n", cpld_index, ret);
67+
return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR);
68+
}
69+
return ret;
70+
}
71+
72+
static ssize_t cpld_type_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf)
73+
{
74+
unsigned int cpld_index;
75+
int ret;
76+
77+
check_p(g_cpld_drv);
78+
check_p(g_cpld_drv->get_main_board_cpld_type);
79+
80+
cpld_index = obj->index;
81+
CPLD_DBG("cpld index: %u\n", cpld_index);
82+
ret = g_cpld_drv->get_main_board_cpld_type(cpld_index, buf, PAGE_SIZE);
83+
if (ret < 0) {
84+
CPLD_ERR("get cpld%u type failed, ret: %d\n", cpld_index, ret);
85+
return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR);
86+
}
87+
return ret;
88+
}
89+
90+
static ssize_t cpld_fw_version_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf)
91+
{
92+
unsigned int cpld_index;
93+
int ret;
94+
95+
check_p(g_cpld_drv);
96+
check_p(g_cpld_drv->get_main_board_cpld_firmware_version);
97+
98+
cpld_index = obj->index;
99+
CPLD_DBG("cpld index: %u\n", cpld_index);
100+
ret = g_cpld_drv->get_main_board_cpld_firmware_version(cpld_index, buf, PAGE_SIZE);
101+
if (ret < 0) {
102+
CPLD_ERR("get cpld%u firmware version failed, ret: %d\n", cpld_index, ret);
103+
return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR);
104+
}
105+
return ret;
106+
}
107+
108+
static ssize_t cpld_board_version_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf)
109+
{
110+
unsigned int cpld_index;
111+
int ret;
112+
113+
check_p(g_cpld_drv);
114+
check_p(g_cpld_drv->get_main_board_cpld_board_version);
115+
116+
cpld_index = obj->index;
117+
CPLD_DBG("cpld index: %u\n", cpld_index);
118+
ret = g_cpld_drv->get_main_board_cpld_board_version(cpld_index, buf, PAGE_SIZE);
119+
if (ret < 0) {
120+
CPLD_ERR("get cpld%u board version failed, ret: %d\n", cpld_index, ret);
121+
return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR);
122+
}
123+
return ret;
124+
}
125+
126+
static ssize_t cpld_test_reg_show(struct switch_obj *obj, struct switch_attribute *attr, char *buf)
127+
{
128+
unsigned int cpld_index;
129+
int ret;
130+
131+
check_p(g_cpld_drv);
132+
check_p(g_cpld_drv->get_main_board_cpld_test_reg);
133+
134+
cpld_index = obj->index;
135+
CPLD_DBG("cpld index: %u\n", cpld_index);
136+
ret = g_cpld_drv->get_main_board_cpld_test_reg(cpld_index, buf, PAGE_SIZE);
137+
if (ret < 0) {
138+
CPLD_ERR("get cpld%u test register failed, ret: %d\n", cpld_index, ret);
139+
return (ssize_t)snprintf(buf, PAGE_SIZE, "%s\n", SYSFS_DEV_ERROR);
140+
}
141+
return ret;
142+
}
143+
144+
static ssize_t cpld_test_reg_store(struct switch_obj *obj, struct switch_attribute *attr,
145+
const char* buf, size_t count)
146+
{
147+
unsigned int cpld_index, value;
148+
int ret;
149+
150+
check_p(g_cpld_drv);
151+
check_p(g_cpld_drv->set_main_board_cpld_test_reg);
152+
153+
cpld_index = obj->index;
154+
sscanf(buf, "0x%x", &value);
155+
ret = g_cpld_drv->set_main_board_cpld_test_reg(cpld_index, value);
156+
if (ret < 0) {
157+
CPLD_ERR("set cpld%u test reg failed, value:0x%x, ret: %d.\n", cpld_index, value, ret);
158+
return -EIO;
159+
}
160+
CPLD_DBG("set cpld%u test reg success, value: 0x%x.\n", cpld_index, value);
161+
return count;
162+
}
163+
164+
/************************************cpld dir and attrs*******************************************/
165+
static struct switch_attribute cpld_number_att = __ATTR(number, S_IRUGO, cpld_number_show, NULL);
166+
167+
static struct attribute *cpld_dir_attrs[] = {
168+
&cpld_number_att.attr,
169+
NULL,
170+
};
171+
172+
static struct attribute_group cpld_root_attr_group = {
173+
.attrs = cpld_dir_attrs,
174+
};
175+
176+
/*******************************cpld[1-n] dir and attrs*******************************************/
177+
static struct switch_attribute cpld_alias_attr = __ATTR(alias, S_IRUGO, cpld_alias_show, NULL);
178+
static struct switch_attribute cpld_type_attr = __ATTR(type, S_IRUGO, cpld_type_show, NULL);
179+
static struct switch_attribute cpld_fw_version_attr = __ATTR(firmware_version, S_IRUGO, cpld_fw_version_show, NULL);
180+
static struct switch_attribute cpld_board_version_attr = __ATTR(board_version, S_IRUGO, cpld_board_version_show, NULL);
181+
static struct switch_attribute cpld_test_reg_attr = __ATTR(reg_test, S_IRUGO | S_IWUSR, cpld_test_reg_show, cpld_test_reg_store);
182+
183+
static struct attribute *cpld_attrs[] = {
184+
&cpld_alias_attr.attr,
185+
&cpld_type_attr.attr,
186+
&cpld_fw_version_attr.attr,
187+
&cpld_board_version_attr.attr,
188+
&cpld_test_reg_attr.attr,
189+
NULL,
190+
};
191+
192+
static struct attribute_group cpld_attr_group = {
193+
.attrs = cpld_attrs,
194+
};
195+
196+
static int cpld_sub_single_remove_kobj_and_attrs(unsigned int index)
197+
{
198+
struct cpld_obj_s *curr_cpld;
199+
200+
curr_cpld = &g_cpld.cpld[index - 1];
201+
if (curr_cpld->obj) {
202+
sysfs_remove_group(&curr_cpld->obj->kobj, &cpld_attr_group);
203+
switch_kobject_delete(&curr_cpld->obj);
204+
CPLD_DBG("delete cpld%u dir and attrs success.\n", index);
205+
}
206+
207+
return 0;
208+
}
209+
210+
static int cpld_sub_single_create_kobj_and_attrs(struct kobject *parent, unsigned int index)
211+
{
212+
char name[8];
213+
struct cpld_obj_s *curr_cpld;
214+
215+
curr_cpld = &g_cpld.cpld[index - 1];
216+
memset(name, 0, sizeof(name));
217+
snprintf(name, sizeof(name), "cpld%u", index);
218+
curr_cpld->obj = switch_kobject_create(name, parent);
219+
if (!curr_cpld->obj) {
220+
CPLD_ERR("create %s object error!\n", name);
221+
return -EBADRQC;
222+
}
223+
curr_cpld->obj->index = index;
224+
if (sysfs_create_group(&curr_cpld->obj->kobj, &cpld_attr_group) != 0) {
225+
CPLD_ERR("create %s attrs error.\n", name);
226+
switch_kobject_delete(&curr_cpld->obj);
227+
return -EBADRQC;
228+
}
229+
CPLD_DBG("create %s dir and attrs success.\n", name);
230+
return 0;
231+
}
232+
233+
static int cpld_sub_create_kobj_and_attrs(struct kobject *parent, int cpld_num)
234+
{
235+
unsigned int cpld_index, i;
236+
237+
g_cpld.cpld = kzalloc(sizeof(struct cpld_obj_s) * cpld_num, GFP_KERNEL);
238+
if (!g_cpld.cpld) {
239+
CPLD_ERR("kzalloc g_cpld.cpld error, cpld number = %d.\n", cpld_num);
240+
return -ENOMEM;
241+
}
242+
243+
for(cpld_index = 1; cpld_index <= cpld_num; cpld_index++) {
244+
if(cpld_sub_single_create_kobj_and_attrs(parent, cpld_index) != 0) {
245+
goto error;
246+
}
247+
}
248+
return 0;
249+
error:
250+
for(i = cpld_index; i > 0; i--) {
251+
cpld_sub_single_remove_kobj_and_attrs(i);
252+
}
253+
kfree(g_cpld.cpld);
254+
g_cpld.cpld = NULL;
255+
return -EBADRQC;
256+
}
257+
258+
/* create cpld[1-n] directory and attributes*/
259+
static int cpld_sub_create(void)
260+
{
261+
int ret;
262+
263+
ret = cpld_sub_create_kobj_and_attrs(&g_cpld_obj->kobj, g_cpld.cpld_number);
264+
return ret;
265+
}
266+
267+
/* delete cpld[1-n] directory and attributes*/
268+
static void cpld_sub_remove(void)
269+
{
270+
unsigned int cpld_index;
271+
272+
if (g_cpld.cpld) {
273+
for (cpld_index = g_cpld.cpld_number; cpld_index > 0; cpld_index--) {
274+
cpld_sub_single_remove_kobj_and_attrs(cpld_index);
275+
}
276+
kfree(g_cpld.cpld);
277+
g_cpld.cpld = NULL;
278+
}
279+
g_cpld.cpld_number = 0;
280+
return;
281+
}
282+
283+
/* create cpld directory and number attributes */
284+
static int cpld_root_create(void)
285+
{
286+
g_cpld_obj = switch_kobject_create("cpld", NULL);
287+
if (!g_cpld_obj) {
288+
CPLD_ERR("switch_kobject_create cpld error!\n");
289+
return -ENOMEM;
290+
}
291+
292+
if (sysfs_create_group(&g_cpld_obj->kobj, &cpld_root_attr_group) != 0) {
293+
switch_kobject_delete(&g_cpld_obj);
294+
CPLD_ERR("create cpld dir attrs error!\n");
295+
return -EBADRQC;
296+
}
297+
return 0;
298+
}
299+
300+
/* delete cpld directory and number attributes */
301+
static void cpld_root_remove(void)
302+
{
303+
if (g_cpld_obj) {
304+
sysfs_remove_group(&g_cpld_obj->kobj, &cpld_root_attr_group);
305+
switch_kobject_delete(&g_cpld_obj);
306+
}
307+
308+
return;
309+
}
310+
311+
int s3ip_sysfs_cpld_drivers_register(struct s3ip_sysfs_cpld_drivers_s *drv)
312+
{
313+
int ret, cpld_num;
314+
315+
CPLD_INFO("s3ip_sysfs_cpld_drivers_register...\n");
316+
if (g_cpld_drv) {
317+
CPLD_ERR("g_cpld_drv is not NULL, can't register\n");
318+
return -EPERM;
319+
}
320+
321+
check_p(drv);
322+
check_p(drv->get_main_board_cpld_number);
323+
g_cpld_drv = drv;
324+
325+
cpld_num = g_cpld_drv->get_main_board_cpld_number();
326+
if (cpld_num <= 0) {
327+
CPLD_ERR("cpld number: %d, don't need to create cpld dirs and attrs.\n", cpld_num);
328+
g_cpld_drv = NULL;
329+
return -EINVAL;
330+
}
331+
332+
memset(&g_cpld, 0, sizeof(struct cpld_s));
333+
g_cpld.cpld_number = cpld_num;
334+
ret = cpld_root_create();
335+
if (ret < 0) {
336+
CPLD_ERR("create cpld root dir and attrs failed, ret: %d\n", ret);
337+
g_cpld_drv = NULL;
338+
return ret;
339+
}
340+
ret = cpld_sub_create();
341+
if (ret < 0) {
342+
CPLD_ERR("create cpld sub dir and attrs failed, ret: %d\n", ret);
343+
cpld_root_remove();
344+
g_cpld_drv = NULL;
345+
return ret;
346+
}
347+
CPLD_INFO("s3ip_sysfs_cpld_drivers_register success\n");
348+
return 0;
349+
}
350+
351+
void s3ip_sysfs_cpld_drivers_unregister(void)
352+
{
353+
if (g_cpld_drv) {
354+
cpld_sub_remove();
355+
cpld_root_remove();
356+
g_cpld_drv = NULL;
357+
CPLD_DBG("s3ip_sysfs_cpld_drivers_unregister success.\n");
358+
}
359+
return;
360+
}
361+
362+
EXPORT_SYMBOL(s3ip_sysfs_cpld_drivers_register);
363+
EXPORT_SYMBOL(s3ip_sysfs_cpld_drivers_unregister);
364+
module_param(g_cpld_loglevel, int, 0644);
365+
MODULE_PARM_DESC(g_cpld_loglevel, "the log level(info=0x1, err=0x2, dbg=0x4).\n");

0 commit comments

Comments
 (0)