ccci_util_lib_sys.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. #include <mt-plat/sync_write.h>
  2. #include <mt-plat/mt_ccci_common.h>
  3. #include <linux/slab.h>
  4. #include <linux/kobject.h>
  5. #include "ccci_util_log.h"
  6. #include "ccci_util_lib_sys.h"
  7. #define CCCI_KOBJ_NAME "ccci"
  8. struct ccci_info {
  9. struct kobject kobj;
  10. unsigned int ccci_attr_count;
  11. };
  12. struct ccci_attribute {
  13. struct attribute attr;
  14. ssize_t (*show)(char *buf);
  15. ssize_t (*store)(const char *buf, size_t count);
  16. };
  17. #define CCCI_ATTR(_name, _mode, _show, _store) \
  18. static struct ccci_attribute ccci_attr_##_name = { \
  19. .attr = {.name = __stringify(_name), .mode = _mode }, \
  20. .show = _show, \
  21. .store = _store, \
  22. }
  23. static struct ccci_info *ccci_sys_info;
  24. static void ccci_obj_release(struct kobject *kobj)
  25. {
  26. struct ccci_info *ccci_info_temp = container_of(kobj, struct ccci_info, kobj);
  27. kfree(ccci_info_temp);
  28. ccci_sys_info = NULL; /* as ccci_info_temp==ccci_sys_info */
  29. }
  30. static ssize_t ccci_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
  31. {
  32. ssize_t len = 0;
  33. struct ccci_attribute *a = container_of(attr, struct ccci_attribute, attr);
  34. if (a->show)
  35. len = a->show(buf);
  36. return len;
  37. }
  38. static ssize_t ccci_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count)
  39. {
  40. ssize_t len = 0;
  41. struct ccci_attribute *a = container_of(attr, struct ccci_attribute, attr);
  42. if (a->store)
  43. len = a->store(buf, count);
  44. return len;
  45. }
  46. static const struct sysfs_ops ccci_sysfs_ops = {
  47. .show = ccci_attr_show,
  48. .store = ccci_attr_store
  49. };
  50. /*======================================= */
  51. /* CCCI common sys attribute part */
  52. /*======================================= */
  53. /* Sys -- boot status */
  54. static get_status_func_t get_status_func[MAX_MD_NUM];
  55. static boot_md_func_t boot_md_func[MAX_MD_NUM];
  56. static int get_md_status(int md_id, char val[], int size)
  57. {
  58. if ((md_id < MAX_MD_NUM) && (get_status_func[md_id] != NULL))
  59. (get_status_func[md_id]) (md_id, val, size);
  60. else
  61. snprintf(val, 32, "md%d:n/a", md_id + 1);
  62. return 0;
  63. }
  64. static int trigger_md_boot(int md_id)
  65. {
  66. if ((md_id < MAX_MD_NUM) && (boot_md_func[md_id] != NULL)) {
  67. (boot_md_func[md_id]) (md_id);
  68. return 0;
  69. }
  70. return -1;
  71. }
  72. static ssize_t boot_status_show(char *buf)
  73. {
  74. char md1_sta_str[32];
  75. char md2_sta_str[32];
  76. char md3_sta_str[32];
  77. char md5_sta_str[32];
  78. /* MD1 --- */
  79. get_md_status(MD_SYS1, md1_sta_str, 32);
  80. /* MD2 --- */
  81. get_md_status(MD_SYS2, md2_sta_str, 32);
  82. /* MD3 */
  83. get_md_status(MD_SYS3, md3_sta_str, 32);
  84. /* MD5 */
  85. get_md_status(MD_SYS5, md5_sta_str, 32);
  86. /* Final string */
  87. return snprintf(buf, 32 * 4 + 3 * 4 + 1, "%s | %s | %s | md4:n/a | %s\n", md1_sta_str, md2_sta_str, md3_sta_str,
  88. md5_sta_str);
  89. }
  90. static ssize_t boot_status_store(const char *buf, size_t count)
  91. {
  92. unsigned int md_id;
  93. md_id = buf[0] - '0';
  94. CCCI_UTIL_INF_MSG("md%d get boot store\n", md_id + 1);
  95. if (md_id < MAX_MD_NUM) {
  96. if (trigger_md_boot(md_id) != 0)
  97. CCCI_UTIL_INF_MSG("md%d n/a\n", md_id + 1);
  98. } else
  99. CCCI_UTIL_INF_MSG("invalid id(%d)\n", md_id + 1);
  100. return count;
  101. }
  102. CCCI_ATTR(boot, 0660, &boot_status_show, &boot_status_store);
  103. /* Sys -- enable status */
  104. static ssize_t ccci_md_enable_show(char *buf)
  105. {
  106. int i;
  107. char md_en[MAX_MD_NUM];
  108. for (i = 0; i < MAX_MD_NUM; i++) {
  109. if (get_modem_is_enabled(MD_SYS1 + i))
  110. md_en[i] = 'E';
  111. else
  112. md_en[i] = 'D';
  113. }
  114. /* Final string */
  115. return snprintf(buf, 32, "%c-%c-%c-%c-%c (1->5)\n", md_en[0], md_en[1], md_en[2], md_en[3], md_en[4]);
  116. }
  117. CCCI_ATTR(md_en, 0660, &ccci_md_enable_show, NULL);
  118. /* Sys -- Versin */
  119. static unsigned int ccci_port_ver = 3;
  120. static ssize_t ccci_version_show(char *buf)
  121. {
  122. return snprintf(buf, 16, "%d\n", ccci_port_ver); /* ECCCI */
  123. }
  124. void update_ccci_port_ver(unsigned int new_ver)
  125. {
  126. ccci_port_ver = new_ver;
  127. }
  128. CCCI_ATTR(version, 0644, &ccci_version_show, NULL);
  129. static ssize_t debug_enable_show(char *buf)
  130. {
  131. int curr = 0;
  132. curr = snprintf(buf, 16, "%d\n", ccci_debug_enable);
  133. return curr;
  134. }
  135. static ssize_t debug_enable_store(const char *buf, size_t count)
  136. {
  137. ccci_debug_enable = buf[0] - '0';
  138. return count;
  139. }
  140. CCCI_ATTR(debug, 0660, &debug_enable_show, &debug_enable_store);
  141. /* Sys -- Runtime register debug */
  142. static char aat_cmd[32];
  143. static unsigned long aat_para[8];
  144. static void __iomem *aat_runtime_map_base_vir;
  145. static phys_addr_t aat_runtime_map_base_phy;
  146. static unsigned int aat_err_no;
  147. static char aat_err_str[64];
  148. static int aat_show_case;
  149. static unsigned long ast_dump_start_addr;
  150. static unsigned long ast_dump_size;
  151. static unsigned long ast_dump_width;
  152. static unsigned char read8(unsigned char *addr)
  153. {
  154. return ioread8((void __iomem *)addr);
  155. }
  156. static unsigned short read16(unsigned short *addr)
  157. {
  158. return ioread16((void __iomem *)addr);
  159. }
  160. static unsigned int read32(unsigned int *addr)
  161. {
  162. return ioread32((void __iomem *)addr);
  163. }
  164. static void aat_write(unsigned long base, unsigned long val, unsigned long width)
  165. {
  166. switch (width) {
  167. case 4L:
  168. mt_reg_sync_writel(val, base);
  169. break;
  170. case 2L:
  171. mt_reg_sync_writew(val, base);
  172. break;
  173. default:
  174. mt_reg_sync_writeb(val, base);
  175. break;
  176. }
  177. }
  178. static int dump_line_with_8(unsigned long addr, char buf[], int num, int size)
  179. {
  180. int i, ch_in_line = 0;
  181. unsigned char tmp;
  182. unsigned long tag_addr =
  183. addr - ((unsigned long)aat_runtime_map_base_vir) + ((unsigned long)aat_runtime_map_base_phy);
  184. ch_in_line += snprintf(&buf[ch_in_line], size - ch_in_line, "[0x%016lX] ", tag_addr);
  185. for (i = 0; i < num; i++) {
  186. tmp = read8((unsigned char *)(addr + i));
  187. ch_in_line += snprintf(&buf[ch_in_line], size - ch_in_line, "%02x ", tmp);
  188. }
  189. ch_in_line += snprintf(&buf[ch_in_line], size - ch_in_line, "\n");
  190. return ch_in_line;
  191. }
  192. static int dump_line_with_16(unsigned long addr, char buf[], int num, int size)
  193. {
  194. int i, ch_in_line = 0;
  195. unsigned short tmp;
  196. unsigned long tag_addr =
  197. addr - ((unsigned long)aat_runtime_map_base_vir) + ((unsigned long)aat_runtime_map_base_phy);
  198. ch_in_line += snprintf(&buf[ch_in_line], size - ch_in_line, "[0x%016lX] ", tag_addr);
  199. for (i = 0; i < num; i += 2) {
  200. tmp = read16((unsigned short *)(addr + i));
  201. ch_in_line += snprintf(&buf[ch_in_line], size - ch_in_line, "%04x ", tmp);
  202. }
  203. ch_in_line += snprintf(&buf[ch_in_line], size - ch_in_line, "\n");
  204. return ch_in_line;
  205. }
  206. static int dump_line_with_32(unsigned long addr, char buf[], int num, int size)
  207. {
  208. int i, ch_in_line = 0;
  209. unsigned int tmp;
  210. unsigned long tag_addr =
  211. addr - ((unsigned long)aat_runtime_map_base_vir) + ((unsigned long)aat_runtime_map_base_phy);
  212. ch_in_line += snprintf(&buf[ch_in_line], size - ch_in_line, "[0x%016lX] ", tag_addr);
  213. for (i = 0; i < num; i += 4) {
  214. tmp = read32((unsigned int *)(addr + i));
  215. ch_in_line += snprintf(&buf[ch_in_line], size - ch_in_line, "%08x ", tmp);
  216. }
  217. ch_in_line += snprintf(&buf[ch_in_line], size - ch_in_line, "\n");
  218. return ch_in_line;
  219. }
  220. static int runtime_reg_dump(unsigned long start_addr, unsigned int size, unsigned int access_width, char out_buf[])
  221. {
  222. unsigned int i, buf_idx, dump_num_in_line, has_dumped;
  223. int (*rd_func)(unsigned long, char *, int, int);
  224. unsigned long curr_addr;
  225. if (size > 4096)
  226. size = 4096;
  227. switch (access_width) {
  228. case 4:
  229. rd_func = dump_line_with_32;
  230. size = ((size + 3) & (~0x3));
  231. break;
  232. case 2:
  233. rd_func = dump_line_with_16;
  234. size = ((size + 1) & (~0x1));
  235. break;
  236. default: /* means 1 */
  237. rd_func = dump_line_with_8;
  238. break;
  239. }
  240. curr_addr = start_addr;
  241. buf_idx = 0;
  242. dump_num_in_line = 0;
  243. has_dumped = 0;
  244. for (i = 0; i < size; i += 16) {
  245. dump_num_in_line = size - has_dumped;
  246. if (dump_num_in_line > 16)
  247. dump_num_in_line = 16;
  248. buf_idx += rd_func(curr_addr, &out_buf[buf_idx], dump_num_in_line, 4096 - buf_idx);
  249. curr_addr += dump_num_in_line;
  250. has_dumped += dump_num_in_line;
  251. }
  252. return buf_idx;
  253. }
  254. static int command_parser(const char *input_str, char cmd[], unsigned long out_put[])
  255. {
  256. int i = 0, j, k;
  257. char tmp_buf[32];
  258. char filter_str[256];
  259. int temp_valu;
  260. /* Filter out 0xD and 0xA */
  261. j = 0;
  262. i = 0;
  263. while ((i < 256) && (input_str[i] != '\0')) {
  264. if ((input_str[i] == 0xD) || (input_str[i] == 0xA)) {
  265. i++;
  266. continue;
  267. }
  268. filter_str[j] = input_str[i];
  269. i++;
  270. j++;
  271. }
  272. filter_str[j] = '\0';
  273. i = 0;
  274. /* Parse command */
  275. if (filter_str[i] == '\0')
  276. return 0;
  277. j = 0;
  278. while (filter_str[i] != '\0') {
  279. if (filter_str[i] != '_') {
  280. cmd[j] = filter_str[i];
  281. j++;
  282. i++;
  283. } else {
  284. i++;
  285. break;
  286. }
  287. }
  288. cmd[j] = '\0';
  289. /* Parse parameters */
  290. for (k = 0; k < 4; k++) {
  291. if (filter_str[i] == '\0')
  292. return k + 1;
  293. j = 0;
  294. while (filter_str[i] != '\0') {
  295. if (filter_str[i] != '_') {
  296. tmp_buf[j] = filter_str[i];
  297. j++;
  298. i++;
  299. } else {
  300. i++;
  301. break;
  302. }
  303. }
  304. tmp_buf[j] = '\0';
  305. /* change string to number */
  306. temp_valu = kstrtoul(tmp_buf, 16, &out_put[k]);
  307. if (temp_valu < 0)
  308. CCCI_UTIL_ERR_MSG("sscanf return fail: %d\n", temp_valu);
  309. }
  310. return k + 1;
  311. }
  312. static void cmd_process(char cmd[], unsigned long para[], int para_num)
  313. {
  314. if ((para_num == 2) && (strcmp(cmd, "IOR") == 0)) {
  315. CCCI_UTIL_DBG_MSG("Command:%s, Base addr:0x%p\n", cmd, (void *)para[0]);
  316. /* Do IO-REMAP here */
  317. if (aat_runtime_map_base_vir == NULL) {
  318. aat_runtime_map_base_vir = ioremap_nocache((phys_addr_t) para[0], 4096);
  319. if (aat_runtime_map_base_vir == NULL) {
  320. snprintf(aat_err_str, 64, "Map phy addr:0x%p fail\n", (void *)para[0]);
  321. aat_err_no = 0x00002100;
  322. } else {
  323. snprintf(aat_err_str, 64, "Map phy addr:0x%p OK\n", (void *)para[0]);
  324. aat_err_no = 0x00001000;
  325. aat_runtime_map_base_phy = (phys_addr_t) para[0];
  326. }
  327. } else {
  328. snprintf(aat_err_str, 64, "Please Un-map phy addr:0x%pa\n", &aat_runtime_map_base_phy);
  329. aat_err_no = 0x00002100;
  330. }
  331. aat_show_case = 0; /*Error info */
  332. } else if ((para_num == 4) && (strcmp(cmd, "WR") == 0)) {
  333. CCCI_UTIL_DBG_MSG("Command:%s, Offset:0x%p, value:0x%p, type:0x%p\n", cmd, (void *)para[0],
  334. (void *)para[1], (void *)para[2]);
  335. /* Do write operation here */
  336. if (aat_runtime_map_base_vir != NULL) {
  337. if (para[0] >= 4096L) {
  338. snprintf(aat_err_str, 64, "Offset should less than 4096\n");
  339. aat_err_no = 0x00002100;
  340. } else {
  341. aat_write(((unsigned long)aat_runtime_map_base_vir) + para[0], para[1], para[2]);
  342. snprintf(aat_err_str, 64, "Write phy addr:0x%p OK\n",
  343. (void *)((unsigned long)aat_runtime_map_base_phy + para[0]));
  344. aat_err_no = 0x00001000;
  345. }
  346. } else {
  347. snprintf(aat_err_str, 64, "Please do io map first\n");
  348. aat_err_no = 0x00002100;
  349. }
  350. aat_show_case = 0; /*Error info */
  351. } else if ((para_num == 4) && (strcmp(cmd, "QUERY") == 0)) {
  352. CCCI_UTIL_DBG_MSG("Command:%s, Offset:0x%p, value:0x%p, type:0x%p\n", cmd, (void *)para[0],
  353. (void *)para[1], (void *)para[2]);
  354. /* Do read operation here */
  355. if (aat_runtime_map_base_vir != NULL) {
  356. if (para[0] >= 4096L) {
  357. snprintf(aat_err_str, 64, "Offset should less than 4096\n");
  358. aat_err_no = 0x00002100;
  359. aat_show_case = 0; /*Error info */
  360. } else if ((para[0] + para[1]) > 4096L) {
  361. snprintf(aat_err_str, 64, "Offset + Size should less than 4096\n");
  362. aat_err_no = 0x00002100;
  363. aat_show_case = 0; /*Error info */
  364. } else {
  365. snprintf(aat_err_str, 64, "Query offset:0x%p size:0x%p OK\n", (void *)para[0],
  366. (void *)para[1]);
  367. ast_dump_start_addr = (unsigned long)aat_runtime_map_base_vir + para[0];
  368. ast_dump_size = para[1];
  369. ast_dump_width = para[2];
  370. aat_err_no = 0x00001000;
  371. aat_show_case = 1; /*Dump data */
  372. }
  373. } else {
  374. snprintf(aat_err_str, 64, "Please do io map first\n");
  375. aat_err_no = 0x00002100;
  376. aat_show_case = 0; /*Error info */
  377. }
  378. } else if ((para_num == 1) && (strcmp(cmd, "IOU") == 0)) {
  379. CCCI_UTIL_DBG_MSG("Command:%s\n", cmd);
  380. /* Do IO-UNMAP here */
  381. if (aat_runtime_map_base_vir != NULL) {
  382. iounmap(aat_runtime_map_base_vir);
  383. aat_runtime_map_base_vir = NULL;
  384. snprintf(aat_err_str, 64, "IO Un-map phy addr:0x%pa OK\n", &aat_runtime_map_base_phy);
  385. aat_err_no = 0x00001000;
  386. } else {
  387. snprintf(aat_err_str, 64, "No need Un-map\n");
  388. aat_err_no = 0x00001000;
  389. }
  390. aat_show_case = 0; /*Error info */
  391. } else if ((para_num == 1) && (strcmp(cmd, "MDFU") == 0)) { /*MD Force Unlock */
  392. CCCI_UTIL_DBG_MSG("Command:%s\n", cmd);
  393. /* Do Un-lock operation here, unlock sleep/clock here */
  394. snprintf(aat_err_str, 64, "Force MD un-lock\n");
  395. #ifndef FEATURE_FPGA_PORTING
  396. spm_ap_mdsrc_req(0);
  397. #endif
  398. aat_err_no = 0x00001000;
  399. aat_show_case = 0; /*Error info */
  400. } else if ((para_num == 1) && (strcmp(cmd, "MDFL") == 0)) { /*MD Force Lock */
  401. CCCI_UTIL_DBG_MSG("Command:%s\n", cmd);
  402. /* Do lock operation here, unlock sleep/clock here */
  403. snprintf(aat_err_str, 64, "Force MD lock\n");
  404. #ifndef FEATURE_FPGA_PORTING
  405. spm_ap_mdsrc_req(1);
  406. #endif
  407. aat_err_no = 0x00001000;
  408. aat_show_case = 0; /*Error info */
  409. } else {
  410. CCCI_UTIL_ERR_MSG("In-valid command:%s and parameter number:%d\n", cmd, para_num);
  411. snprintf(aat_err_str, 64, "In-valid command:%s and parameter number:%d\n", cmd, para_num);
  412. aat_show_case = 0; /*Error info */
  413. }
  414. }
  415. static ssize_t aat_show(char *buf)
  416. {
  417. unsigned int curr = 0;
  418. unsigned int dump_size;
  419. curr = snprintf(buf, 4096, "0x%08x: %s\n", (unsigned int)aat_err_no, aat_err_str);
  420. if (aat_show_case == 1) {
  421. dump_size = 4096 - curr;
  422. if (dump_size > ((unsigned int)ast_dump_size))
  423. dump_size = (unsigned int)ast_dump_size;
  424. curr += runtime_reg_dump(ast_dump_start_addr, dump_size, (unsigned int)ast_dump_width, &buf[curr]);
  425. }
  426. return (ssize_t) curr;
  427. }
  428. static ssize_t aat_store(const char *buf, size_t count)
  429. {
  430. int para_num = command_parser(buf, aat_cmd, aat_para);
  431. cmd_process(aat_cmd, aat_para, para_num);
  432. return count;
  433. }
  434. CCCI_ATTR(aat, 0600, &aat_show, &aat_store);
  435. static ssize_t kcfg_setting_show(char *buf)
  436. {
  437. unsigned int curr = 0;
  438. unsigned int actual_write;
  439. char md_en[MAX_MD_NUM];
  440. unsigned int md_num = 0;
  441. int i;
  442. for (i = 0; i < MAX_MD_NUM; i++) {
  443. if (get_modem_is_enabled(MD_SYS1 + i)) {
  444. md_num++;
  445. md_en[i] = '1';
  446. } else
  447. md_en[i] = '0';
  448. }
  449. /* MD enable setting part */
  450. /* Reserve 16 byte to store size info */
  451. actual_write = snprintf(&buf[curr], 4096 - 16 - curr, "[modem num]:%d\n", md_num);
  452. curr += actual_write;
  453. /* Reserve 16 byte to store size info */
  454. actual_write = snprintf(&buf[curr], 4096 - 16 - curr,
  455. "[modem en]:%c-%c-%c-%c-%c\n", md_en[0], md_en[1], md_en[2], md_en[3], md_en[4]);
  456. curr += actual_write;
  457. /* Feature option part */
  458. #ifdef CONFIG_EVDO_DT_SUPPORT
  459. actual_write = snprintf(&buf[curr], 4096 - curr, "[EVDO_DT_SUPPORT]:1\n");
  460. #else
  461. actual_write = snprintf(&buf[curr], 4096 - curr, "[EVDO_DT_SUPPORT]:0\n");
  462. #endif
  463. curr += actual_write;
  464. #ifdef CONFIG_MTK_LTE_DC_SUPPORT
  465. actual_write = snprintf(&buf[curr], 4096 - curr, "[MTK_LTE_DC_SUPPORT]:1\n");
  466. #else
  467. actual_write = snprintf(&buf[curr], 4096 - curr, "[MTK_LTE_DC_SUPPORT]:0\n");
  468. #endif
  469. curr += actual_write;
  470. #ifdef CONFIG_MTK_ECCCI_C2K
  471. actual_write = snprintf(&buf[curr], 4096 - curr, "[MTK_ECCCI_C2K]:1\n");
  472. curr += actual_write;
  473. #endif
  474. /* Add total size to tail */
  475. actual_write = snprintf(&buf[curr], 4096 - curr, "total:%d\n", curr);
  476. curr += actual_write;
  477. CCCI_UTIL_INF_MSG("cfg_info_buffer size:%d\n", curr);
  478. return (ssize_t) curr;
  479. }
  480. static ssize_t kcfg_setting_store(const char *buf, size_t count)
  481. {
  482. return count;
  483. }
  484. CCCI_ATTR(kcfg_setting, 0444, &kcfg_setting_show, &kcfg_setting_store);
  485. /* Sys -- Add to group */
  486. static struct attribute *ccci_default_attrs[] = {
  487. &ccci_attr_boot.attr,
  488. &ccci_attr_version.attr,
  489. &ccci_attr_md_en.attr,
  490. &ccci_attr_debug.attr,
  491. &ccci_attr_aat.attr,
  492. &ccci_attr_kcfg_setting.attr,
  493. NULL
  494. };
  495. static struct kobj_type ccci_ktype = {
  496. .release = ccci_obj_release,
  497. .sysfs_ops = &ccci_sysfs_ops,
  498. .default_attrs = ccci_default_attrs
  499. };
  500. int ccci_sysfs_add_modem(int md_id, void *kobj, void *ktype, get_status_func_t get_sta_func, boot_md_func_t boot_func)
  501. {
  502. int ret;
  503. static int md_add_flag;
  504. md_add_flag = 0;
  505. if (!ccci_sys_info) {
  506. CCCI_UTIL_ERR_MSG("common sys not ready\n");
  507. return -CCCI_ERR_SYSFS_NOT_READY;
  508. }
  509. if (md_add_flag & (1 << md_id)) {
  510. CCCI_UTIL_ERR_MSG("md%d sys dup add\n", md_id + 1);
  511. return -CCCI_ERR_SYSFS_NOT_READY;
  512. }
  513. ret =
  514. kobject_init_and_add((struct kobject *)kobj, (struct kobj_type *)ktype, &ccci_sys_info->kobj, "mdsys%d",
  515. md_id + 1);
  516. if (ret < 0) {
  517. kobject_put(kobj);
  518. CCCI_UTIL_ERR_MSG_WITH_ID(md_id, "fail to add md kobject\n");
  519. } else {
  520. md_add_flag |= (1 << md_id);
  521. get_status_func[md_id] = get_sta_func;
  522. boot_md_func[md_id] = boot_func;
  523. }
  524. return ret;
  525. }
  526. int ccci_common_sysfs_init(void)
  527. {
  528. int ret = 0;
  529. int i;
  530. ccci_sys_info = kmalloc(sizeof(struct ccci_info), GFP_KERNEL);
  531. if (!ccci_sys_info)
  532. return -ENOMEM;
  533. memset(ccci_sys_info, 0, sizeof(struct ccci_info));
  534. ret = kobject_init_and_add(&ccci_sys_info->kobj, &ccci_ktype, kernel_kobj, CCCI_KOBJ_NAME);
  535. if (ret < 0) {
  536. kobject_put(&ccci_sys_info->kobj);
  537. CCCI_UTIL_ERR_MSG("fail to add ccci kobject\n");
  538. return ret;
  539. }
  540. for (i = 0; i < MAX_MD_NUM; i++) {
  541. get_status_func[i] = NULL;
  542. boot_md_func[i] = NULL;
  543. }
  544. ccci_sys_info->ccci_attr_count = ARRAY_SIZE(ccci_default_attrs) - 1;
  545. CCCI_UTIL_DBG_MSG("ccci attr cnt %d\n", ccci_sys_info->ccci_attr_count);
  546. return ret;
  547. }