hsr_prp_proc.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. /*
  2. * HSR/PRP Driver procfs file
  3. *
  4. * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <linux/netdevice.h>
  16. #include <linux/proc_fs.h>
  17. #include "hsr_prp_main.h"
  18. #define BUF_SIZE 64
  19. #define LRE_STAT_OFS(m) offsetof(struct lre_stats, m)
  20. const char *hsr_prp_lre_stats[] = {
  21. "lreTxA",
  22. "lreTxB",
  23. "lreTxC",
  24. "lreErrWrongLanA",
  25. "lreErrWrongLanB",
  26. "lreErrWrongLanC",
  27. "lreRxA",
  28. "lreRxB",
  29. "lreRxC",
  30. "lreErrorsA",
  31. "lreErrorsB",
  32. "lreErrorsC",
  33. "lreNodes",
  34. "lreProxyNodes",
  35. "lreUniqueRxA",
  36. "lreUniqueRxB",
  37. "lreUniqueRxC",
  38. "lreDuplicateRxA",
  39. "lreDuplicateRxB",
  40. "lreDuplicateRxC",
  41. "lreMultiRxA",
  42. "lreMultiRxB",
  43. "lreMultiRxC",
  44. "lreOwnRxA",
  45. "lreOwnRxB",
  46. };
  47. static int hsr_prp_lre_stats_show(struct seq_file *sfp, void *v)
  48. {
  49. struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
  50. struct lre_stats lower_stats, *upper_stats;
  51. int ret = 0, i;
  52. u32 *ptr;
  53. upper_stats = &priv->lre_stats;
  54. if (priv->rx_offloaded) {
  55. ret = hsr_prp_lredev_get_lre_stats(priv, &lower_stats);
  56. if (ret < 0) {
  57. seq_puts(sfp, "Error in retrieving the stats\n");
  58. return 0;
  59. }
  60. ptr = (u32 *)&lower_stats;
  61. } else {
  62. ptr = (u32 *)upper_stats;
  63. }
  64. seq_puts(sfp, "LRE statistics:\n");
  65. seq_printf(sfp, "Rx Offloaded: %d\n", priv->rx_offloaded);
  66. for (i = 0; i < ARRAY_SIZE(hsr_prp_lre_stats); i++) {
  67. /* for rx_c and tx_c, retrieve stats from hsr/prp device
  68. * lre stats. Rest of the stats are retrieved from
  69. * lower device.
  70. */
  71. if (!strcmp("lreTxC", hsr_prp_lre_stats[i])) {
  72. seq_printf(sfp, "\n %s: %d",
  73. hsr_prp_lre_stats[i],
  74. upper_stats->cnt_tx_c);
  75. continue;
  76. }
  77. if (!strcmp("lreRxC", hsr_prp_lre_stats[i])) {
  78. seq_printf(sfp, "\n %s: %d",
  79. hsr_prp_lre_stats[i],
  80. upper_stats->cnt_rx_c);
  81. continue;
  82. }
  83. seq_printf(sfp, "\n %s: %d", hsr_prp_lre_stats[i],
  84. *(ptr + i));
  85. }
  86. seq_puts(sfp, "\n");
  87. return 0;
  88. }
  89. static int hsr_prp_lre_stats_open(struct inode *inode, struct file *file)
  90. {
  91. return single_open(file, hsr_prp_lre_stats_show, PDE_DATA(inode));
  92. }
  93. static const struct file_operations hsr_prp_lre_stats_fops = {
  94. .owner = THIS_MODULE,
  95. .open = hsr_prp_lre_stats_open,
  96. .read = seq_read,
  97. .llseek = seq_lseek,
  98. .release = single_release,
  99. };
  100. static int hsr_prp_node_show(struct seq_file *sfp,
  101. int index,
  102. struct lre_node_table_entry *entry)
  103. {
  104. seq_printf(sfp, "\nNode[%u]:\n", index);
  105. seq_printf(sfp, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
  106. entry->mac_address[0],
  107. entry->mac_address[1],
  108. entry->mac_address[2],
  109. entry->mac_address[3],
  110. entry->mac_address[4],
  111. entry->mac_address[5]);
  112. switch (entry->node_type) {
  113. case IEC62439_3_DANP:
  114. seq_puts(sfp, "DANP\n");
  115. break;
  116. case IEC62439_3_REDBOXP:
  117. seq_puts(sfp, "REDBOXP\n");
  118. break;
  119. case IEC62439_3_VDANP:
  120. seq_puts(sfp, "VDANP\n");
  121. break;
  122. case IEC62439_3_DANH:
  123. seq_puts(sfp, "DANH\n");
  124. break;
  125. case IEC62439_3_REDBOXH:
  126. seq_puts(sfp, "REDBOXH\n");
  127. break;
  128. case IEC62439_3_VDANH:
  129. seq_puts(sfp, "VDANH\n");
  130. break;
  131. default:
  132. seq_printf(sfp, "Unknown node type %u\n", entry->node_type);
  133. break;
  134. };
  135. seq_printf(sfp, "Time Last Seen: RxA=%u RxB=%u\n",
  136. entry->time_last_seen_a,
  137. entry->time_last_seen_b);
  138. return 0;
  139. }
  140. static int hsr_prp_node_table_show(struct seq_file *sfp, void *v)
  141. {
  142. struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
  143. struct lre_node_table_entry *nt_table;
  144. int ret = 0, count, i;
  145. nt_table = kcalloc(LRE_MAX_NT_ENTRIES, sizeof(*nt_table), GFP_KERNEL);
  146. if (!nt_table)
  147. return -ENODEV;
  148. count = hsr_prp_lredev_get_node_table(priv, nt_table,
  149. LRE_MAX_NT_ENTRIES);
  150. if (count < 0)
  151. count = 0;
  152. seq_printf(sfp, "\nRemote nodes in network: %u\n", count);
  153. if (!count)
  154. return ret;
  155. for (i = 0; i < count; i++)
  156. hsr_prp_node_show(sfp, i, &nt_table[i]);
  157. return ret;
  158. }
  159. static int hsr_prp_node_table_open(struct inode *inode, struct file *file)
  160. {
  161. return single_open(file, hsr_prp_node_table_show, PDE_DATA(inode));
  162. }
  163. static const struct file_operations hsr_prp_node_table_fops = {
  164. .owner = THIS_MODULE,
  165. .open = hsr_prp_node_table_open,
  166. .read = seq_read,
  167. .llseek = seq_lseek,
  168. .release = single_release,
  169. };
  170. static inline int get_set_param(struct hsr_prp_priv *priv,
  171. const char __user *buffer, size_t count,
  172. enum lredev_attr_id id)
  173. {
  174. struct lredev_attr temp_attr;
  175. char cmd_buffer[BUF_SIZE];
  176. int ret = -EINVAL;
  177. u32 val;
  178. if (count > (sizeof(cmd_buffer) - 1))
  179. goto err;
  180. if (copy_from_user(cmd_buffer, buffer, count)) {
  181. ret = -EFAULT;
  182. goto err;
  183. }
  184. cmd_buffer[count] = '\0';
  185. ret = kstrtou32(cmd_buffer, 0, &val);
  186. if (ret < 0)
  187. goto err;
  188. /* TODO. Update mode. Check if anything else needed for
  189. * non offload case
  190. */
  191. temp_attr.id = id;
  192. switch (id) {
  193. case LREDEV_ATTR_ID_HSR_MODE:
  194. if (val > IEC62439_3_HSR_MODE_M) {
  195. ret = -EINVAL;
  196. goto err;
  197. }
  198. if (!priv->rx_offloaded) {
  199. priv->hsr_mode = (enum iec62439_3_hsr_modes)val;
  200. return 0;
  201. }
  202. temp_attr.mode = (enum iec62439_3_hsr_modes)val;
  203. break;
  204. case LREDEV_ATTR_ID_PRP_TR:
  205. if (val > IEC62439_3_TR_PASS_RCT) {
  206. ret = -EINVAL;
  207. goto err;
  208. }
  209. if (!priv->rx_offloaded) {
  210. priv->prp_tr = (enum iec62439_3_tr_modes)val;
  211. goto out;
  212. }
  213. temp_attr.tr_mode = (enum iec62439_3_tr_modes)val;
  214. break;
  215. case LREDEV_ATTR_ID_DD_MODE:
  216. if (val > IEC62439_3_DD) {
  217. ret = -EINVAL;
  218. goto err;
  219. }
  220. if (!priv->rx_offloaded) {
  221. priv->dd_mode = (enum iec62439_3_dd_modes)val;
  222. goto out;
  223. }
  224. temp_attr.dd_mode = (enum iec62439_3_dd_modes)val;
  225. break;
  226. case LREDEV_ATTR_ID_DLRMT:
  227. if (!priv->rx_offloaded) {
  228. priv->dlrmt = val;
  229. goto out;
  230. }
  231. temp_attr.dl_reside_max_time = val;
  232. break;
  233. case LREDEV_ATTR_ID_CLEAR_NT:
  234. if (val > IEC62439_3_CLEAR_NT) {
  235. ret = -EINVAL;
  236. goto err;
  237. }
  238. if (!priv->rx_offloaded) {
  239. priv->clear_nt_cmd =
  240. (enum iec62439_3_clear_nt_cmd)val;
  241. goto out;
  242. }
  243. temp_attr.clear_nt_cmd = (enum iec62439_3_clear_nt_cmd)val;
  244. break;
  245. default:
  246. ret = -EINVAL;
  247. goto err;
  248. }
  249. /* pass this to lower layer device, i.e slave-1 */
  250. ret = hsr_prp_lredev_attr_set(priv, &temp_attr);
  251. if (ret)
  252. return ret;
  253. /* update the local copy */
  254. switch (id) {
  255. case LREDEV_ATTR_ID_HSR_MODE:
  256. priv->hsr_mode = temp_attr.mode;
  257. break;
  258. case LREDEV_ATTR_ID_PRP_TR:
  259. priv->prp_tr = temp_attr.tr_mode;
  260. break;
  261. case LREDEV_ATTR_ID_DD_MODE:
  262. priv->dd_mode = temp_attr.dd_mode;
  263. break;
  264. case LREDEV_ATTR_ID_CLEAR_NT:
  265. priv->clear_nt_cmd = temp_attr.clear_nt_cmd;
  266. break;
  267. default: /* LREDEV_ATTR_ID_DLRMT */
  268. priv->dlrmt = temp_attr.dl_reside_max_time;
  269. break;
  270. }
  271. out:
  272. return 0;
  273. err:
  274. return ret;
  275. }
  276. static int hsr_mode_show(struct seq_file *sfp, void *v)
  277. {
  278. struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
  279. struct lredev_attr temp_attr;
  280. int err;
  281. if (!priv->rx_offloaded) {
  282. seq_printf(sfp, "%u\n", priv->hsr_mode);
  283. return 0;
  284. }
  285. temp_attr.id = LREDEV_ATTR_ID_HSR_MODE;
  286. err = hsr_prp_lredev_attr_get(priv, &temp_attr);
  287. if (err)
  288. return err;
  289. seq_printf(sfp, "%u\n", temp_attr.mode);
  290. return 0;
  291. }
  292. static int hsr_mode_open(struct inode *inode, struct file *file)
  293. {
  294. return single_open(file, hsr_mode_show, PDE_DATA(inode));
  295. }
  296. static ssize_t hsr_mode_store(struct file *file,
  297. const char __user *buffer,
  298. size_t count, loff_t *pos)
  299. {
  300. struct hsr_prp_priv *priv =
  301. (struct hsr_prp_priv *)PDE_DATA(file_inode(file));
  302. int err;
  303. err = get_set_param(priv, buffer, count, LREDEV_ATTR_ID_HSR_MODE);
  304. if (err)
  305. return err;
  306. return count;
  307. }
  308. static const struct file_operations hsr_mode_fops = {
  309. .owner = THIS_MODULE,
  310. .open = hsr_mode_open,
  311. .read = seq_read,
  312. .write = hsr_mode_store,
  313. .llseek = seq_lseek,
  314. .release = single_release,
  315. };
  316. static int prp_tr_show(struct seq_file *sfp, void *v)
  317. {
  318. struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
  319. struct lredev_attr temp_attr;
  320. int err;
  321. if (!priv->rx_offloaded) {
  322. seq_printf(sfp, "%u\n", priv->prp_tr);
  323. return 0;
  324. }
  325. temp_attr.id = LREDEV_ATTR_ID_PRP_TR;
  326. err = hsr_prp_lredev_attr_get(priv, &temp_attr);
  327. if (err)
  328. return err;
  329. seq_printf(sfp, "%u\n", temp_attr.tr_mode);
  330. return 0;
  331. }
  332. static int prp_tr_open(struct inode *inode, struct file *file)
  333. {
  334. return single_open(file, prp_tr_show, PDE_DATA(inode));
  335. }
  336. static ssize_t prp_tr_store(struct file *file,
  337. const char __user *buffer,
  338. size_t count, loff_t *pos)
  339. {
  340. struct hsr_prp_priv *priv =
  341. (struct hsr_prp_priv *)PDE_DATA(file_inode(file));
  342. int err;
  343. err = get_set_param(priv, buffer, count, LREDEV_ATTR_ID_PRP_TR);
  344. if (err)
  345. return err;
  346. return count;
  347. }
  348. static const struct file_operations prp_tr_fops = {
  349. .owner = THIS_MODULE,
  350. .open = prp_tr_open,
  351. .read = seq_read,
  352. .write = prp_tr_store,
  353. .llseek = seq_lseek,
  354. .release = single_release,
  355. };
  356. static int dlrmt_show(struct seq_file *sfp, void *v)
  357. {
  358. struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
  359. struct lredev_attr temp_attr;
  360. int err;
  361. if (!priv->rx_offloaded) {
  362. seq_printf(sfp, "%u\n", priv->dlrmt);
  363. return 0;
  364. }
  365. temp_attr.id = LREDEV_ATTR_ID_DLRMT;
  366. err = hsr_prp_lredev_attr_get(priv, &temp_attr);
  367. if (err)
  368. return err;
  369. seq_printf(sfp, "%u\n", temp_attr.dl_reside_max_time);
  370. return 0;
  371. }
  372. static int dlrmt_open(struct inode *inode, struct file *file)
  373. {
  374. return single_open(file, dlrmt_show, PDE_DATA(inode));
  375. }
  376. static ssize_t dlrmt_store(struct file *file,
  377. const char __user *buffer,
  378. size_t count, loff_t *pos)
  379. {
  380. struct hsr_prp_priv *priv =
  381. (struct hsr_prp_priv *)PDE_DATA(file_inode(file));
  382. int err;
  383. err = get_set_param(priv, buffer, count, LREDEV_ATTR_ID_DLRMT);
  384. if (err)
  385. return err;
  386. return count;
  387. }
  388. static const struct file_operations dlrmt_fops = {
  389. .owner = THIS_MODULE,
  390. .open = dlrmt_open,
  391. .read = seq_read,
  392. .write = dlrmt_store,
  393. .llseek = seq_lseek,
  394. .release = single_release,
  395. };
  396. static int dd_mode_show(struct seq_file *sfp, void *v)
  397. {
  398. struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
  399. struct lredev_attr temp_attr;
  400. int err;
  401. if (!priv->rx_offloaded) {
  402. seq_printf(sfp, "%u\n", priv->dd_mode);
  403. return 0;
  404. }
  405. temp_attr.id = LREDEV_ATTR_ID_DD_MODE;
  406. err = hsr_prp_lredev_attr_get(priv, &temp_attr);
  407. if (err)
  408. return err;
  409. seq_printf(sfp, "%u\n", temp_attr.dd_mode);
  410. return 0;
  411. }
  412. static int dd_mode_open(struct inode *inode, struct file *file)
  413. {
  414. return single_open(file, dd_mode_show, PDE_DATA(inode));
  415. }
  416. static ssize_t dd_mode_store(struct file *file,
  417. const char __user *buffer,
  418. size_t count, loff_t *pos)
  419. {
  420. struct hsr_prp_priv *priv =
  421. (struct hsr_prp_priv *)PDE_DATA(file_inode(file));
  422. int err;
  423. err = get_set_param(priv, buffer, count, LREDEV_ATTR_ID_DD_MODE);
  424. if (err)
  425. return err;
  426. return count;
  427. }
  428. static const struct file_operations dd_mode_fops = {
  429. .owner = THIS_MODULE,
  430. .open = dd_mode_open,
  431. .read = seq_read,
  432. .write = dd_mode_store,
  433. .llseek = seq_lseek,
  434. .release = single_release,
  435. };
  436. static int clear_nt_show(struct seq_file *sfp, void *v)
  437. {
  438. struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
  439. struct lredev_attr temp_attr;
  440. int err;
  441. if (!priv->rx_offloaded) {
  442. seq_printf(sfp, "%u\n", priv->clear_nt_cmd);
  443. return 0;
  444. }
  445. temp_attr.id = LREDEV_ATTR_ID_CLEAR_NT;
  446. err = hsr_prp_lredev_attr_get(priv, &temp_attr);
  447. if (err)
  448. return err;
  449. seq_printf(sfp, "%u\n", temp_attr.clear_nt_cmd);
  450. return 0;
  451. }
  452. static int clear_nt_open(struct inode *inode, struct file *file)
  453. {
  454. return single_open(file, clear_nt_show, PDE_DATA(inode));
  455. }
  456. static ssize_t clear_nt_store(struct file *file,
  457. const char __user *buffer,
  458. size_t count, loff_t *pos)
  459. {
  460. struct hsr_prp_priv *priv =
  461. (struct hsr_prp_priv *)PDE_DATA(file_inode(file));
  462. int err;
  463. err = get_set_param(priv, buffer, count, LREDEV_ATTR_ID_CLEAR_NT);
  464. if (err)
  465. return err;
  466. return count;
  467. }
  468. static const struct file_operations clear_nt_fops = {
  469. .owner = THIS_MODULE,
  470. .open = clear_nt_open,
  471. .read = seq_read,
  472. .write = clear_nt_store,
  473. .llseek = seq_lseek,
  474. .release = single_release,
  475. };
  476. static int disable_sv_show(struct seq_file *sfp, void *v)
  477. {
  478. struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
  479. seq_printf(sfp, "%u\n", priv->disable_sv_frame);
  480. return 0;
  481. }
  482. static int disable_sv_open(struct inode *inode, struct file *file)
  483. {
  484. return single_open(file, disable_sv_show, PDE_DATA(inode));
  485. }
  486. static ssize_t disable_sv_store(struct file *file,
  487. const char __user *buffer,
  488. size_t count, loff_t *pos)
  489. {
  490. struct hsr_prp_priv *priv =
  491. (struct hsr_prp_priv *)PDE_DATA(file_inode(file));
  492. char cmd_buffer[BUF_SIZE];
  493. int ret = -EINVAL;
  494. u32 val;
  495. if (count > (sizeof(cmd_buffer) - 1))
  496. goto err;
  497. if (copy_from_user(cmd_buffer, buffer, count)) {
  498. ret = -EFAULT;
  499. goto err;
  500. }
  501. cmd_buffer[count] = '\0';
  502. ret = kstrtou32(cmd_buffer, 0, &val);
  503. if (ret < 0 || val > 1)
  504. goto err;
  505. priv->disable_sv_frame = val;
  506. return count;
  507. err:
  508. return ret;
  509. }
  510. static const struct file_operations disable_sv_fops = {
  511. .owner = THIS_MODULE,
  512. .open = disable_sv_open,
  513. .read = seq_read,
  514. .write = disable_sv_store,
  515. .llseek = seq_lseek,
  516. .release = single_release,
  517. };
  518. int hsr_prp_create_procfs(struct hsr_prp_priv *priv, struct net_device *ndev)
  519. {
  520. int ret = -ENODEV;
  521. priv->dir = proc_mkdir(ndev->name, NULL);
  522. if (!priv->dir)
  523. return ret;
  524. priv->lre_stats_file = proc_create_data("lre-stats", 0444, priv->dir,
  525. &hsr_prp_lre_stats_fops,
  526. (void *)priv);
  527. if (!priv->lre_stats_file)
  528. goto fail_lre_stats;
  529. priv->node_table_file = proc_create_data("node-table", 0444, priv->dir,
  530. &hsr_prp_node_table_fops,
  531. (void *)priv);
  532. if (!priv->node_table_file)
  533. goto fail_node_table;
  534. priv->hsr_mode_file = proc_create_data("hsr-mode", 0644, priv->dir,
  535. &hsr_mode_fops, (void *)priv);
  536. if (!priv->hsr_mode_file)
  537. goto fail_hsr_mode;
  538. priv->dd_mode_file = proc_create_data("dd-mode", 0644, priv->dir,
  539. &dd_mode_fops, (void *)priv);
  540. if (!priv->dd_mode_file)
  541. goto fail_dd_mode;
  542. priv->prp_tr_file = proc_create_data("prp-tr", 0644, priv->dir,
  543. &prp_tr_fops, (void *)priv);
  544. if (!priv->prp_tr_file)
  545. goto fail_prp_tr;
  546. priv->clear_nt_file = proc_create_data("clear-nt", 0644, priv->dir,
  547. &clear_nt_fops, (void *)priv);
  548. if (!priv->clear_nt_file)
  549. goto fail_clear_nt;
  550. priv->dlrmt_file = proc_create_data("dlrmt", 0644, priv->dir,
  551. &dlrmt_fops, (void *)priv);
  552. if (!priv->dlrmt_file)
  553. goto fail_dlrmt;
  554. priv->disable_sv_file = proc_create_data("disable-sv-frame", 0644,
  555. priv->dir, &disable_sv_fops,
  556. (void *)priv);
  557. if (!priv->disable_sv_file)
  558. goto fail_disable_sv;
  559. return 0;
  560. fail_disable_sv:
  561. if (priv->dlrmt_file)
  562. remove_proc_entry("dlrmt", priv->dir);
  563. fail_dlrmt:
  564. if (priv->clear_nt_file)
  565. remove_proc_entry("clear-nt", priv->dir);
  566. fail_clear_nt:
  567. if (priv->prp_tr_file)
  568. remove_proc_entry("prp-tr", priv->dir);
  569. fail_prp_tr:
  570. if (priv->dd_mode_file)
  571. remove_proc_entry("dd-mode", priv->dir);
  572. fail_dd_mode:
  573. if (priv->hsr_mode_file)
  574. remove_proc_entry("hsr-mode", priv->dir);
  575. fail_hsr_mode:
  576. if (priv->node_table_file)
  577. remove_proc_entry("node-table", priv->dir);
  578. fail_node_table:
  579. if (priv->lre_stats_file)
  580. remove_proc_entry("lre-stats", priv->dir);
  581. fail_lre_stats:
  582. remove_proc_entry(ndev->name, NULL);
  583. return ret;
  584. }
  585. void hsr_prp_remove_procfs(struct hsr_prp_priv *priv, struct net_device *ndev)
  586. {
  587. remove_proc_entry("disable-sv-frame", priv->dir);
  588. remove_proc_entry("dlrmt", priv->dir);
  589. remove_proc_entry("clear-nt", priv->dir);
  590. remove_proc_entry("prp-tr", priv->dir);
  591. remove_proc_entry("dd-mode", priv->dir);
  592. remove_proc_entry("hsr-mode", priv->dir);
  593. remove_proc_entry("lre-stats", priv->dir);
  594. remove_proc_entry("node-table", priv->dir);
  595. remove_proc_entry(ndev->name, NULL);
  596. priv->dir = NULL;
  597. }