| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692 |
- /*
- * HSR/PRP Driver procfs file
- *
- * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/netdevice.h>
- #include <linux/proc_fs.h>
- #include "hsr_prp_main.h"
- #define BUF_SIZE 64
- #define LRE_STAT_OFS(m) offsetof(struct lre_stats, m)
- const char *hsr_prp_lre_stats[] = {
- "lreTxA",
- "lreTxB",
- "lreTxC",
- "lreErrWrongLanA",
- "lreErrWrongLanB",
- "lreErrWrongLanC",
- "lreRxA",
- "lreRxB",
- "lreRxC",
- "lreErrorsA",
- "lreErrorsB",
- "lreErrorsC",
- "lreNodes",
- "lreProxyNodes",
- "lreUniqueRxA",
- "lreUniqueRxB",
- "lreUniqueRxC",
- "lreDuplicateRxA",
- "lreDuplicateRxB",
- "lreDuplicateRxC",
- "lreMultiRxA",
- "lreMultiRxB",
- "lreMultiRxC",
- "lreOwnRxA",
- "lreOwnRxB",
- };
- static int hsr_prp_lre_stats_show(struct seq_file *sfp, void *v)
- {
- struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
- struct lre_stats lower_stats, *upper_stats;
- int ret = 0, i;
- u32 *ptr;
- upper_stats = &priv->lre_stats;
- if (priv->rx_offloaded) {
- ret = hsr_prp_lredev_get_lre_stats(priv, &lower_stats);
- if (ret < 0) {
- seq_puts(sfp, "Error in retrieving the stats\n");
- return 0;
- }
- ptr = (u32 *)&lower_stats;
- } else {
- ptr = (u32 *)upper_stats;
- }
- seq_puts(sfp, "LRE statistics:\n");
- seq_printf(sfp, "Rx Offloaded: %d\n", priv->rx_offloaded);
- for (i = 0; i < ARRAY_SIZE(hsr_prp_lre_stats); i++) {
- /* for rx_c and tx_c, retrieve stats from hsr/prp device
- * lre stats. Rest of the stats are retrieved from
- * lower device.
- */
- if (!strcmp("lreTxC", hsr_prp_lre_stats[i])) {
- seq_printf(sfp, "\n %s: %d",
- hsr_prp_lre_stats[i],
- upper_stats->cnt_tx_c);
- continue;
- }
- if (!strcmp("lreRxC", hsr_prp_lre_stats[i])) {
- seq_printf(sfp, "\n %s: %d",
- hsr_prp_lre_stats[i],
- upper_stats->cnt_rx_c);
- continue;
- }
- seq_printf(sfp, "\n %s: %d", hsr_prp_lre_stats[i],
- *(ptr + i));
- }
- seq_puts(sfp, "\n");
- return 0;
- }
- static int hsr_prp_lre_stats_open(struct inode *inode, struct file *file)
- {
- return single_open(file, hsr_prp_lre_stats_show, PDE_DATA(inode));
- }
- static const struct file_operations hsr_prp_lre_stats_fops = {
- .owner = THIS_MODULE,
- .open = hsr_prp_lre_stats_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- };
- static int hsr_prp_node_show(struct seq_file *sfp,
- int index,
- struct lre_node_table_entry *entry)
- {
- seq_printf(sfp, "\nNode[%u]:\n", index);
- seq_printf(sfp, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
- entry->mac_address[0],
- entry->mac_address[1],
- entry->mac_address[2],
- entry->mac_address[3],
- entry->mac_address[4],
- entry->mac_address[5]);
- switch (entry->node_type) {
- case IEC62439_3_DANP:
- seq_puts(sfp, "DANP\n");
- break;
- case IEC62439_3_REDBOXP:
- seq_puts(sfp, "REDBOXP\n");
- break;
- case IEC62439_3_VDANP:
- seq_puts(sfp, "VDANP\n");
- break;
- case IEC62439_3_DANH:
- seq_puts(sfp, "DANH\n");
- break;
- case IEC62439_3_REDBOXH:
- seq_puts(sfp, "REDBOXH\n");
- break;
- case IEC62439_3_VDANH:
- seq_puts(sfp, "VDANH\n");
- break;
- default:
- seq_printf(sfp, "Unknown node type %u\n", entry->node_type);
- break;
- };
- seq_printf(sfp, "Time Last Seen: RxA=%u RxB=%u\n",
- entry->time_last_seen_a,
- entry->time_last_seen_b);
- return 0;
- }
- static int hsr_prp_node_table_show(struct seq_file *sfp, void *v)
- {
- struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
- struct lre_node_table_entry *nt_table;
- int ret = 0, count, i;
- nt_table = kcalloc(LRE_MAX_NT_ENTRIES, sizeof(*nt_table), GFP_KERNEL);
- if (!nt_table)
- return -ENODEV;
- count = hsr_prp_lredev_get_node_table(priv, nt_table,
- LRE_MAX_NT_ENTRIES);
- if (count < 0)
- count = 0;
- seq_printf(sfp, "\nRemote nodes in network: %u\n", count);
- if (!count)
- return ret;
- for (i = 0; i < count; i++)
- hsr_prp_node_show(sfp, i, &nt_table[i]);
- return ret;
- }
- static int hsr_prp_node_table_open(struct inode *inode, struct file *file)
- {
- return single_open(file, hsr_prp_node_table_show, PDE_DATA(inode));
- }
- static const struct file_operations hsr_prp_node_table_fops = {
- .owner = THIS_MODULE,
- .open = hsr_prp_node_table_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- };
- static inline int get_set_param(struct hsr_prp_priv *priv,
- const char __user *buffer, size_t count,
- enum lredev_attr_id id)
- {
- struct lredev_attr temp_attr;
- char cmd_buffer[BUF_SIZE];
- int ret = -EINVAL;
- u32 val;
- if (count > (sizeof(cmd_buffer) - 1))
- goto err;
- if (copy_from_user(cmd_buffer, buffer, count)) {
- ret = -EFAULT;
- goto err;
- }
- cmd_buffer[count] = '\0';
- ret = kstrtou32(cmd_buffer, 0, &val);
- if (ret < 0)
- goto err;
- /* TODO. Update mode. Check if anything else needed for
- * non offload case
- */
- temp_attr.id = id;
- switch (id) {
- case LREDEV_ATTR_ID_HSR_MODE:
- if (val > IEC62439_3_HSR_MODE_M) {
- ret = -EINVAL;
- goto err;
- }
- if (!priv->rx_offloaded) {
- priv->hsr_mode = (enum iec62439_3_hsr_modes)val;
- return 0;
- }
- temp_attr.mode = (enum iec62439_3_hsr_modes)val;
- break;
- case LREDEV_ATTR_ID_PRP_TR:
- if (val > IEC62439_3_TR_PASS_RCT) {
- ret = -EINVAL;
- goto err;
- }
- if (!priv->rx_offloaded) {
- priv->prp_tr = (enum iec62439_3_tr_modes)val;
- goto out;
- }
- temp_attr.tr_mode = (enum iec62439_3_tr_modes)val;
- break;
- case LREDEV_ATTR_ID_DD_MODE:
- if (val > IEC62439_3_DD) {
- ret = -EINVAL;
- goto err;
- }
- if (!priv->rx_offloaded) {
- priv->dd_mode = (enum iec62439_3_dd_modes)val;
- goto out;
- }
- temp_attr.dd_mode = (enum iec62439_3_dd_modes)val;
- break;
- case LREDEV_ATTR_ID_DLRMT:
- if (!priv->rx_offloaded) {
- priv->dlrmt = val;
- goto out;
- }
- temp_attr.dl_reside_max_time = val;
- break;
- case LREDEV_ATTR_ID_CLEAR_NT:
- if (val > IEC62439_3_CLEAR_NT) {
- ret = -EINVAL;
- goto err;
- }
- if (!priv->rx_offloaded) {
- priv->clear_nt_cmd =
- (enum iec62439_3_clear_nt_cmd)val;
- goto out;
- }
- temp_attr.clear_nt_cmd = (enum iec62439_3_clear_nt_cmd)val;
- break;
- default:
- ret = -EINVAL;
- goto err;
- }
- /* pass this to lower layer device, i.e slave-1 */
- ret = hsr_prp_lredev_attr_set(priv, &temp_attr);
- if (ret)
- return ret;
- /* update the local copy */
- switch (id) {
- case LREDEV_ATTR_ID_HSR_MODE:
- priv->hsr_mode = temp_attr.mode;
- break;
- case LREDEV_ATTR_ID_PRP_TR:
- priv->prp_tr = temp_attr.tr_mode;
- break;
- case LREDEV_ATTR_ID_DD_MODE:
- priv->dd_mode = temp_attr.dd_mode;
- break;
- case LREDEV_ATTR_ID_CLEAR_NT:
- priv->clear_nt_cmd = temp_attr.clear_nt_cmd;
- break;
- default: /* LREDEV_ATTR_ID_DLRMT */
- priv->dlrmt = temp_attr.dl_reside_max_time;
- break;
- }
- out:
- return 0;
- err:
- return ret;
- }
- static int hsr_mode_show(struct seq_file *sfp, void *v)
- {
- struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
- struct lredev_attr temp_attr;
- int err;
- if (!priv->rx_offloaded) {
- seq_printf(sfp, "%u\n", priv->hsr_mode);
- return 0;
- }
- temp_attr.id = LREDEV_ATTR_ID_HSR_MODE;
- err = hsr_prp_lredev_attr_get(priv, &temp_attr);
- if (err)
- return err;
- seq_printf(sfp, "%u\n", temp_attr.mode);
- return 0;
- }
- static int hsr_mode_open(struct inode *inode, struct file *file)
- {
- return single_open(file, hsr_mode_show, PDE_DATA(inode));
- }
- static ssize_t hsr_mode_store(struct file *file,
- const char __user *buffer,
- size_t count, loff_t *pos)
- {
- struct hsr_prp_priv *priv =
- (struct hsr_prp_priv *)PDE_DATA(file_inode(file));
- int err;
- err = get_set_param(priv, buffer, count, LREDEV_ATTR_ID_HSR_MODE);
- if (err)
- return err;
- return count;
- }
- static const struct file_operations hsr_mode_fops = {
- .owner = THIS_MODULE,
- .open = hsr_mode_open,
- .read = seq_read,
- .write = hsr_mode_store,
- .llseek = seq_lseek,
- .release = single_release,
- };
- static int prp_tr_show(struct seq_file *sfp, void *v)
- {
- struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
- struct lredev_attr temp_attr;
- int err;
- if (!priv->rx_offloaded) {
- seq_printf(sfp, "%u\n", priv->prp_tr);
- return 0;
- }
- temp_attr.id = LREDEV_ATTR_ID_PRP_TR;
- err = hsr_prp_lredev_attr_get(priv, &temp_attr);
- if (err)
- return err;
- seq_printf(sfp, "%u\n", temp_attr.tr_mode);
- return 0;
- }
- static int prp_tr_open(struct inode *inode, struct file *file)
- {
- return single_open(file, prp_tr_show, PDE_DATA(inode));
- }
- static ssize_t prp_tr_store(struct file *file,
- const char __user *buffer,
- size_t count, loff_t *pos)
- {
- struct hsr_prp_priv *priv =
- (struct hsr_prp_priv *)PDE_DATA(file_inode(file));
- int err;
- err = get_set_param(priv, buffer, count, LREDEV_ATTR_ID_PRP_TR);
- if (err)
- return err;
- return count;
- }
- static const struct file_operations prp_tr_fops = {
- .owner = THIS_MODULE,
- .open = prp_tr_open,
- .read = seq_read,
- .write = prp_tr_store,
- .llseek = seq_lseek,
- .release = single_release,
- };
- static int dlrmt_show(struct seq_file *sfp, void *v)
- {
- struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
- struct lredev_attr temp_attr;
- int err;
- if (!priv->rx_offloaded) {
- seq_printf(sfp, "%u\n", priv->dlrmt);
- return 0;
- }
- temp_attr.id = LREDEV_ATTR_ID_DLRMT;
- err = hsr_prp_lredev_attr_get(priv, &temp_attr);
- if (err)
- return err;
- seq_printf(sfp, "%u\n", temp_attr.dl_reside_max_time);
- return 0;
- }
- static int dlrmt_open(struct inode *inode, struct file *file)
- {
- return single_open(file, dlrmt_show, PDE_DATA(inode));
- }
- static ssize_t dlrmt_store(struct file *file,
- const char __user *buffer,
- size_t count, loff_t *pos)
- {
- struct hsr_prp_priv *priv =
- (struct hsr_prp_priv *)PDE_DATA(file_inode(file));
- int err;
- err = get_set_param(priv, buffer, count, LREDEV_ATTR_ID_DLRMT);
- if (err)
- return err;
- return count;
- }
- static const struct file_operations dlrmt_fops = {
- .owner = THIS_MODULE,
- .open = dlrmt_open,
- .read = seq_read,
- .write = dlrmt_store,
- .llseek = seq_lseek,
- .release = single_release,
- };
- static int dd_mode_show(struct seq_file *sfp, void *v)
- {
- struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
- struct lredev_attr temp_attr;
- int err;
- if (!priv->rx_offloaded) {
- seq_printf(sfp, "%u\n", priv->dd_mode);
- return 0;
- }
- temp_attr.id = LREDEV_ATTR_ID_DD_MODE;
- err = hsr_prp_lredev_attr_get(priv, &temp_attr);
- if (err)
- return err;
- seq_printf(sfp, "%u\n", temp_attr.dd_mode);
- return 0;
- }
- static int dd_mode_open(struct inode *inode, struct file *file)
- {
- return single_open(file, dd_mode_show, PDE_DATA(inode));
- }
- static ssize_t dd_mode_store(struct file *file,
- const char __user *buffer,
- size_t count, loff_t *pos)
- {
- struct hsr_prp_priv *priv =
- (struct hsr_prp_priv *)PDE_DATA(file_inode(file));
- int err;
- err = get_set_param(priv, buffer, count, LREDEV_ATTR_ID_DD_MODE);
- if (err)
- return err;
- return count;
- }
- static const struct file_operations dd_mode_fops = {
- .owner = THIS_MODULE,
- .open = dd_mode_open,
- .read = seq_read,
- .write = dd_mode_store,
- .llseek = seq_lseek,
- .release = single_release,
- };
- static int clear_nt_show(struct seq_file *sfp, void *v)
- {
- struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
- struct lredev_attr temp_attr;
- int err;
- if (!priv->rx_offloaded) {
- seq_printf(sfp, "%u\n", priv->clear_nt_cmd);
- return 0;
- }
- temp_attr.id = LREDEV_ATTR_ID_CLEAR_NT;
- err = hsr_prp_lredev_attr_get(priv, &temp_attr);
- if (err)
- return err;
- seq_printf(sfp, "%u\n", temp_attr.clear_nt_cmd);
- return 0;
- }
- static int clear_nt_open(struct inode *inode, struct file *file)
- {
- return single_open(file, clear_nt_show, PDE_DATA(inode));
- }
- static ssize_t clear_nt_store(struct file *file,
- const char __user *buffer,
- size_t count, loff_t *pos)
- {
- struct hsr_prp_priv *priv =
- (struct hsr_prp_priv *)PDE_DATA(file_inode(file));
- int err;
- err = get_set_param(priv, buffer, count, LREDEV_ATTR_ID_CLEAR_NT);
- if (err)
- return err;
- return count;
- }
- static const struct file_operations clear_nt_fops = {
- .owner = THIS_MODULE,
- .open = clear_nt_open,
- .read = seq_read,
- .write = clear_nt_store,
- .llseek = seq_lseek,
- .release = single_release,
- };
- static int disable_sv_show(struct seq_file *sfp, void *v)
- {
- struct hsr_prp_priv *priv = (struct hsr_prp_priv *)sfp->private;
- seq_printf(sfp, "%u\n", priv->disable_sv_frame);
- return 0;
- }
- static int disable_sv_open(struct inode *inode, struct file *file)
- {
- return single_open(file, disable_sv_show, PDE_DATA(inode));
- }
- static ssize_t disable_sv_store(struct file *file,
- const char __user *buffer,
- size_t count, loff_t *pos)
- {
- struct hsr_prp_priv *priv =
- (struct hsr_prp_priv *)PDE_DATA(file_inode(file));
- char cmd_buffer[BUF_SIZE];
- int ret = -EINVAL;
- u32 val;
- if (count > (sizeof(cmd_buffer) - 1))
- goto err;
- if (copy_from_user(cmd_buffer, buffer, count)) {
- ret = -EFAULT;
- goto err;
- }
- cmd_buffer[count] = '\0';
- ret = kstrtou32(cmd_buffer, 0, &val);
- if (ret < 0 || val > 1)
- goto err;
- priv->disable_sv_frame = val;
- return count;
- err:
- return ret;
- }
- static const struct file_operations disable_sv_fops = {
- .owner = THIS_MODULE,
- .open = disable_sv_open,
- .read = seq_read,
- .write = disable_sv_store,
- .llseek = seq_lseek,
- .release = single_release,
- };
- int hsr_prp_create_procfs(struct hsr_prp_priv *priv, struct net_device *ndev)
- {
- int ret = -ENODEV;
- priv->dir = proc_mkdir(ndev->name, NULL);
- if (!priv->dir)
- return ret;
- priv->lre_stats_file = proc_create_data("lre-stats", 0444, priv->dir,
- &hsr_prp_lre_stats_fops,
- (void *)priv);
- if (!priv->lre_stats_file)
- goto fail_lre_stats;
- priv->node_table_file = proc_create_data("node-table", 0444, priv->dir,
- &hsr_prp_node_table_fops,
- (void *)priv);
- if (!priv->node_table_file)
- goto fail_node_table;
- priv->hsr_mode_file = proc_create_data("hsr-mode", 0644, priv->dir,
- &hsr_mode_fops, (void *)priv);
- if (!priv->hsr_mode_file)
- goto fail_hsr_mode;
- priv->dd_mode_file = proc_create_data("dd-mode", 0644, priv->dir,
- &dd_mode_fops, (void *)priv);
- if (!priv->dd_mode_file)
- goto fail_dd_mode;
- priv->prp_tr_file = proc_create_data("prp-tr", 0644, priv->dir,
- &prp_tr_fops, (void *)priv);
- if (!priv->prp_tr_file)
- goto fail_prp_tr;
- priv->clear_nt_file = proc_create_data("clear-nt", 0644, priv->dir,
- &clear_nt_fops, (void *)priv);
- if (!priv->clear_nt_file)
- goto fail_clear_nt;
- priv->dlrmt_file = proc_create_data("dlrmt", 0644, priv->dir,
- &dlrmt_fops, (void *)priv);
- if (!priv->dlrmt_file)
- goto fail_dlrmt;
- priv->disable_sv_file = proc_create_data("disable-sv-frame", 0644,
- priv->dir, &disable_sv_fops,
- (void *)priv);
- if (!priv->disable_sv_file)
- goto fail_disable_sv;
- return 0;
- fail_disable_sv:
- if (priv->dlrmt_file)
- remove_proc_entry("dlrmt", priv->dir);
- fail_dlrmt:
- if (priv->clear_nt_file)
- remove_proc_entry("clear-nt", priv->dir);
- fail_clear_nt:
- if (priv->prp_tr_file)
- remove_proc_entry("prp-tr", priv->dir);
- fail_prp_tr:
- if (priv->dd_mode_file)
- remove_proc_entry("dd-mode", priv->dir);
- fail_dd_mode:
- if (priv->hsr_mode_file)
- remove_proc_entry("hsr-mode", priv->dir);
- fail_hsr_mode:
- if (priv->node_table_file)
- remove_proc_entry("node-table", priv->dir);
- fail_node_table:
- if (priv->lre_stats_file)
- remove_proc_entry("lre-stats", priv->dir);
- fail_lre_stats:
- remove_proc_entry(ndev->name, NULL);
- return ret;
- }
- void hsr_prp_remove_procfs(struct hsr_prp_priv *priv, struct net_device *ndev)
- {
- remove_proc_entry("disable-sv-frame", priv->dir);
- remove_proc_entry("dlrmt", priv->dir);
- remove_proc_entry("clear-nt", priv->dir);
- remove_proc_entry("prp-tr", priv->dir);
- remove_proc_entry("dd-mode", priv->dir);
- remove_proc_entry("hsr-mode", priv->dir);
- remove_proc_entry("lre-stats", priv->dir);
- remove_proc_entry("node-table", priv->dir);
- remove_proc_entry(ndev->name, NULL);
- priv->dir = NULL;
- }
|