/* * DirectConnect provides a common interface for the network devices to achieve the full or partial acceleration services from the underlying packet acceleration engine * Copyright (c) 2017, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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. */ /* * #################################### * Head File * #################################### */ /* * Common Head File */ #include #include #include //#include #include #include #include #include #include "directconnect_dp_device.h" #include "directconnect_dp_dcmode_wrapper.h" #include "directconnect_dp_macdb.h" #define DC_DP_PROC "dc_dp" #define DC_DP_PROC_DBG "dbg" #define DC_DP_PROC_DEV "dev" #define DC_DP_PROC_DCMODE "dcmode" #define DC_DP_PROC_MACDB "macdb" /* * #################################### * Declaration * #################################### */ static int proc_read_dc_dp_dbg_seq_open(struct inode *, struct file *); static ssize_t proc_write_dc_dp_dbg(struct file *, const char __user *, size_t , loff_t *); static int proc_read_dc_dp_dev_show(struct seq_file *seq, void *v); static int proc_read_dc_dp_dev_open(struct inode *, struct file *); #if 0 static ssize_t proc_write_dc_dp_dev(struct file *, const char __user *, size_t , loff_t *); #endif static int proc_read_dc_dp_dcmode_show(struct seq_file *seq, void *v); static int proc_read_dc_dp_dcmode_open(struct inode *, struct file *); static int proc_read_dc_dp_macdb_show(struct seq_file *seq, void *v); static int proc_read_dc_dp_macdb_open(struct inode *, struct file *); #define DC_DP_F_ENUM_OR_STRING(name,value, short_name) name = value /*Note: per bit one variable */ #define DC_DP_F_FLAG_LIST \ DC_DP_F_ENUM_OR_STRING(DC_DP_F_DEREGISTER, 0x00000001, "De-Register"), \ DC_DP_F_ENUM_OR_STRING(DC_DP_F_FASTPATH, 0x00000010, "FASTPATH"), \ DC_DP_F_ENUM_OR_STRING(DC_DP_F_DIRECTPATH, 0x00000020, "LITEPATH"),\ DC_DP_F_ENUM_OR_STRING(DC_DP_F_SWPATH, 0x00000040, "SWPATH"),\ DC_DP_F_ENUM_OR_STRING(DC_DP_F_QOS, 0x00001000, "QoS") /* * #################################### * Global Variable * #################################### */ #undef DC_DP_F_ENUM_OR_STRING #define DC_DP_F_ENUM_OR_STRING(name,value, short_name) short_name static int8_t *g_dc_dp_port_type_str[] = { DC_DP_F_FLAG_LIST }; #undef DC_DP_F_ENUM_OR_STRING #undef DC_DP_F_ENUM_OR_STRING #define DC_DP_F_ENUM_OR_STRING(name,value, short_name) value static uint32_t g_dc_dp_port_flag[] = { DC_DP_F_FLAG_LIST }; #undef DC_DP_F_ENUM_OR_STRING static int8_t *g_dc_dp_port_status_str[] = { "PORT_FREE", "PORT_ALLOCATED", "PORT_DEV_REGISTERED", "PORT_SUBIF_REGISTERED", "Invalid" }; static int8_t *g_dc_dp_dbg_flag_str[] = { "dbg", /*DC_DP_DBG_FLAG_DBG */ "rx", /*DC_DP_DBG_FLAG_DUMP_RX */ "rx_data", /*DC_DP_DBG_FLAG_DUMP_RX_DATA*/ "rx_desc", /*DC_DP_DBG_FLAG_DUMP_RX_DESCRIPTOR */ "tx", /*DC_DP_DBG_FLAG_DUMP_TX */ "tx_data", /*DC_DP_DBG_FLAG_DUMP_TX_DATA */ "tx_desc", /*DC_DP_DBG_FLAG_DUMP_TX_DESCRIPTOR */ /*the last one*/ "err" }; static uint32_t g_dc_dp_dbg_flag_list[] = { DC_DP_DBG_FLAG_DBG, DC_DP_DBG_FLAG_DUMP_RX, DC_DP_DBG_FLAG_DUMP_RX_DATA, DC_DP_DBG_FLAG_DUMP_RX_DESCRIPTOR, DC_DP_DBG_FLAG_DUMP_TX, DC_DP_DBG_FLAG_DUMP_TX_DATA, DC_DP_DBG_FLAG_DUMP_TX_DESCRIPTOR, /*The last one*/ DC_DP_DBG_FLAG_ERR }; static inline int32_t _dc_dp_get_port_type_str_size(void) { return ARRAY_SIZE(g_dc_dp_port_type_str); } static inline int32_t _dc_dp_get_dbg_flag_str_size(void) { return ARRAY_SIZE(g_dc_dp_dbg_flag_str); } static inline int32_t _dc_dp_get_port_status_str_size(void) { return ARRAY_SIZE(g_dc_dp_port_status_str); } static struct proc_dir_entry *g_dc_dp_proc = NULL; static struct file_operations g_dc_dp_dbg_proc_fops = { .owner = THIS_MODULE, .open = proc_read_dc_dp_dbg_seq_open, .read = seq_read, .write = proc_write_dc_dp_dbg, .llseek = seq_lseek, .release = seq_release, }; static struct file_operations g_dc_dp_dev_proc_fops = { .owner = THIS_MODULE, .open = proc_read_dc_dp_dev_open, .read = seq_read, #if 0 .write = proc_write_dc_dp_dev, #endif .llseek = seq_lseek, .release = single_release, }; static struct file_operations g_dc_dp_dcmode_proc_fops = { .owner = THIS_MODULE, .open = proc_read_dc_dp_dcmode_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static struct file_operations g_dc_dp_macdb_proc_fops = { .owner = THIS_MODULE, .open = proc_read_dc_dp_macdb_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; /* * #################################### * Extern Variable * #################################### */ /* * #################################### * Extern Function * #################################### */ /* * #################################### * Local Function * #################################### */ static void proc_write_dc_dp_dbg_usage(void) { pr_info("usage:\n"); pr_info(" echo [enable|disable] dbg tx tx_data tx_desc rx rx_data rx_desc > /proc/%s/%s\n", DC_DP_PROC, DC_DP_PROC_DBG); } #if 0 static void proc_write_dc_dp_dev_usage(void) { pr_info("usage:\n"); //pr_info(" echo show dev > /proc/%s/%s\n", DC_DP_PROC, DC_DP_PROC_DEV); pr_info(" echo set dev umt_period > /proc/%s/%s\n", DC_DP_PROC, DC_DP_PROC_DEV); pr_info(" echo set dev umt <0|1> > /proc/%s/%s\n", DC_DP_PROC, DC_DP_PROC_DEV); pr_info(" echo set dev dma <0|1> > /proc/%s/%s\n", DC_DP_PROC, DC_DP_PROC_DEV); } #endif static int proc_read_dc_dp_dbg(struct seq_file *seq, void *v) { int i; if (!capable(CAP_NET_ADMIN)) { printk("Read Permission denied"); return 0; } seq_printf(seq, "dbg_flag=0x%08x\n", dc_dp_get_dbg_flag()); seq_printf(seq, "Supported Flags =%d\n", _dc_dp_get_dbg_flag_str_size()); seq_printf(seq, "Enabled Flags(0x%0x):", dc_dp_get_dbg_flag()); for (i = 0; i < _dc_dp_get_dbg_flag_str_size(); i++) if ((dc_dp_get_dbg_flag() & g_dc_dp_dbg_flag_list[i]) == g_dc_dp_dbg_flag_list[i]) seq_printf(seq, "%s ", g_dc_dp_dbg_flag_str[i]); seq_printf(seq, "\n"); return 0; } static int proc_read_dc_dp_dbg_seq_open(struct inode *inode, struct file *file) { return single_open(file, proc_read_dc_dp_dbg, NULL); } static ssize_t proc_write_dc_dp_dbg(struct file *file, const char __user *buf, size_t count, loff_t *data) { int len; char str[40]; char *p; int f_enable; if (!capable(CAP_NET_ADMIN)) { printk("Write Permission denied"); return 0; } len = min(count, (size_t)(sizeof(str) - 1)); len -= copy_from_user(str, buf, len); while ( len && str[len - 1] <= ' ' ) len--; str[len] = 0; for ( p = str; *p && *p <= ' '; p++, len-- ); if ( !*p ) { goto help; } if (!strncmp(p, "enable", 6)) { f_enable = 1; } else if (!strncmp(p, "disable", 7)) { f_enable = 0; } else { goto help; } #if 0 for (i = 1; i < num; i++) { for (j = 0; j < _dc_dp_get_dbg_flag_str_size(); j++) { if (!strncmp(param_list[i], g_dc_dp_dbg_flag_str[j])) { set_ltq_dbg_flag(dc_dp_get_dbg_flag(), f_enable, g_dc_dp_dbg_flag_list[j]); break; } } } #endif return len; help: proc_write_dc_dp_dbg_usage(); return count; } static int proc_read_dc_dp_dev_show(struct seq_file *seq, void *v) { int32_t dev_idx = 0; int i; struct dc_dp_priv_dev_info *p_hw_dev_info = dc_dp_get_hw_device_head(); struct dc_dp_priv_dev_info *p_sw_dev_info = dc_dp_get_sw_device_head(); struct dc_dp_priv_dev_info *dev_info = NULL; if (!capable(CAP_NET_ADMIN)) { printk ("Read Permission denied"); return 0; } for (dev_idx = 0; dev_idx < DC_DP_MAX_HW_DEVICE + DC_DP_MAX_SW_DEVICE; dev_idx++) { if (dev_idx < DC_DP_MAX_HW_DEVICE) dev_info = &p_hw_dev_info[dev_idx]; else dev_info = &p_sw_dev_info[dev_idx - DC_DP_MAX_HW_DEVICE]; if (dev_info->flags == DC_DP_DEV_FREE) { seq_printf(seq, "%d: Not registered\n", dev_idx); continue; } seq_printf(seq, "%d: module=0x%px(name:%8s) dev_port=%02d dp_port=%02d\n", dev_idx, dev_info->owner, dev_info->owner->name, dev_info->dev_port, dev_info->port_id); seq_printf(seq, " status: %s\n", g_dc_dp_port_status_str[dev_info->flags]); seq_printf(seq, " allocate_flags: "); for (i = 0; i < _dc_dp_get_port_type_str_size(); i++) { if (dev_info->alloc_flags & g_dc_dp_port_flag[i]) seq_printf(seq, "%s ", g_dc_dp_port_type_str[i]); } seq_printf(seq, "\n"); seq_printf(seq, " cb->rx_fn: %pf\n", dev_info->cb.rx_fn); seq_printf(seq, " cb->stop_fn: %pf\n", dev_info->cb.stop_fn); seq_printf(seq, " cb->restart_fn: %pf\n", dev_info->cb.restart_fn); seq_printf(seq, " cb->get_subif_fn: %pf\n", dev_info->cb.get_subif_fn); seq_printf(seq, " cb->get_desc_info_fn: %pf\n", dev_info->cb.get_desc_info_fn); seq_printf(seq, " cb->reset_mib_fn: %pf\n", dev_info->cb.reset_mib_fn); seq_printf(seq, " cb->get_mib_fn: %pf\n", dev_info->cb.reset_mib_fn); seq_printf(seq, " cb->recovery_fn: %pf\n", dev_info->cb.recovery_fn); seq_printf(seq, " class2prio: "); for (i = 0; i < DC_DP_MAX_SOC_CLASS; i++) { seq_printf(seq, "[%d->%d],", i, dev_info->class2prio[i]); } seq_printf(seq, "\n"); seq_printf(seq, " prio2devqos: "); for (i = 0; i < DC_DP_MAX_DEV_CLASS; i++) { seq_printf(seq, "[%d->%d],", i, dev_info->prio2qos[i]); } seq_printf(seq, "\n"); dc_dp_dcmode_wrapper_dump_proc(dev_info, seq); seq_printf(seq, " num_subif: %02d\n", dev_info->num_subif); for (i = 0; i < DC_DP_MAX_SUBIF_PER_DEV; i++) { if (dev_info->subif_info[i].flags) { seq_printf(seq, " [%02d]: subif=0x%04x(vap=%d) netif=0x%px(name=%s), device_name=%s\n", i, dev_info->subif_info[i].subif, (dev_info->subif_info[i].subif >> DC_DP_SUBIFID_OFFSET) & DC_DP_SUBIFID_MASK, dev_info->subif_info[i].netif, dev_info->subif_info[i].netif ? dev_info->subif_info[i].netif->name : "NULL", dev_info->subif_info[i].device_name); } } } return 0; } static int proc_read_dc_dp_dev_open(struct inode *inode, struct file *file) { return single_open(file, proc_read_dc_dp_dev_show, NULL); } #if 0 static __always_inline char *parse_token(char **str, char *delim) { *str = strim(*str); return strsep(str, delim); } static uint32_t btoi(char *str) { unsigned int sum = 0; signed len = 0, i = 0; len = strlen(str); len = len - 1; while (len >= 0) { if (*(str + len) == '1') sum = (sum | (1 << i)); i++; len--; } return sum; } static int32_t dc_dp_atoi(uint8_t *str) { uint32_t n = 0; int32_t i = 0; int32_t nega_sign = 0; if (!str) return 0; //dp_replace_ch(str, strlen(str), '.', 0); //dp_replace_ch(str, strlen(str), ' ', 0); //dp_replace_ch(str, strlen(str), '\r', 0); //dp_replace_ch(str, strlen(str), '\n', 0); if (str[0] == 0) return 0; if (str[0] == 'b' || str[0] == 'B') { /*binary format */ n = btoi(str + 1); } else if ((str[0] == '0') && ((str[1] == 'x') || (str[1] == 'X'))) { /*hex format */ str += 2; while (str[i]) { n = n * 16; if (('0' <= str[i] && str[i] <= '9')) { n += str[i] - '0'; } else if (('A' <= str[i] && str[i] <= 'F')) { n += str[i] - 'A' + 10; ; } else if (('a' <= str[i] && str[i] <= 'f')) { n += str[i] - 'a' + 10; ; } else DC_DP_ERROR("Wrong value:%u\n", str[i]); i++; } } else { if (str[i] == '-') { /*negative sign */ nega_sign = 1; i++; } while (str[i]) { n *= 10; n += str[i] - '0'; i++; } } if (nega_sign) n = -(int)n; return n; } static ssize_t proc_write_dc_dp_dev(struct file *file, const char __user *buf, size_t count, loff_t *data) { int len; char str[40] = {0}; char *p, *param_name = NULL, *param_val = NULL; int32_t dev_idx; char *delim = " \t\n\v\f\r"; int32_t value; len = min(count, (size_t)(sizeof(str) - 1)); len -= copy_from_user(str, buf, len); p = str; if (!strncmp(p, "set", 3)) { /* set ... */ parse_token(&p, delim); //Skip command 'set' if (!p) { goto help; } param_name = parse_token(&p, delim); if (!p) { goto help; } if (strncmp(param_name, "dev", 3)) { goto help; } param_val = parse_token(&p, delim); if (!p) { goto help; } dev_idx = dc_dp_atoi(param_val); if (dev_idx >= DC_DP_MAX_DEV_NUM) { goto help; } param_name = parse_token(&p, delim); if (!p) { goto help; } param_val = parse_token(&p, delim); value = dc_dp_atoi(param_val); if (!strncmp(param_name, "umt_period", strlen("umt_period"))) { g_priv_info[dev_idx].umt_period = value; #if defined(CONFIG_LTQ_UMT_EXPAND_MODE) && CONFIG_LTQ_UMT_EXPAND_MODE ltq_umt_set_period(g_priv_info[dev_idx].umt_id, g_priv_info[dev_idx].port_id, value); #else /* #if defined(CONFIG_LTQ_UMT_EXPAND_MODE) && CONFIG_LTQ_UMT_EXPAND_MODE */ ltq_umt_set_period(value); #endif /* #else */ } else if (!strncmp(param_name, "umt", 3)) { if (value == 0) { #if defined(CONFIG_LTQ_UMT_EXPAND_MODE) && CONFIG_LTQ_UMT_EXPAND_MODE ltq_umt_enable(g_priv_info[dev_idx].umt_id, g_priv_info[dev_idx].port_id, 0); #else /* #if defined(CONFIG_LTQ_UMT_EXPAND_MODE) && CONFIG_LTQ_UMT_EXPAND_MODE */ ltq_umt_enable(0); #endif /* #else */ } else { #if defined(CONFIG_LTQ_UMT_EXPAND_MODE) && CONFIG_LTQ_UMT_EXPAND_MODE ltq_umt_enable(g_priv_info[dev_idx].umt_id, g_priv_info[dev_idx].port_id, 1); #else /* #if defined(CONFIG_LTQ_UMT_EXPAND_MODE) && CONFIG_LTQ_UMT_EXPAND_MODE */ ltq_umt_enable(1); #endif /* #else */ } } else if (!strncmp(param_name, "dma", 3)) { if (value == 0) { ltq_dma_chan_off(g_priv_info[dev_idx].dma_ch); } else { ltq_dma_chan_on(g_priv_info[dev_idx].dma_ch); } } else { goto help; } } else { goto help; } return len; help: proc_write_dc_dp_dev_usage(); return count; } #endif extern struct dc_dp_dcmode **dc_dp_get_dcmode_head(void); static int proc_read_dc_dp_dcmode_show(struct seq_file *seq, void *v) { int32_t dcmode_idx; struct dc_dp_dcmode **dcmode = dc_dp_get_dcmode_head(); if (!capable(CAP_NET_ADMIN)) { printk("Read Permission denied"); return 0; } for (dcmode_idx = 0; dcmode_idx < DC_DP_DCMODE_MAX; dcmode_idx++) { if (dcmode[dcmode_idx] == NULL) { seq_printf(seq, "%d: Not registered\n", dcmode_idx); continue; } seq_printf(seq, "%d:\n", dcmode_idx); seq_printf(seq, " dcmode_cap: 0x%0x\n", (uint32_t) dcmode[dcmode_idx]->dcmode_cap); seq_printf(seq, " register_dev: %pf\n", dcmode[dcmode_idx]->dcmode_ops->register_dev); seq_printf(seq, " register_subif: %pf\n", dcmode[dcmode_idx]->dcmode_ops->register_subif); seq_printf(seq, " xmit: %pf\n", dcmode[dcmode_idx]->dcmode_ops->xmit); seq_printf(seq, " handle_ring_sw: %pf\n", dcmode[dcmode_idx]->dcmode_ops->handle_ring_sw); seq_printf(seq, " add_session_shortcut_forward: %pf\n", dcmode[dcmode_idx]->dcmode_ops->add_session_shortcut_forward); seq_printf(seq, " disconn_if: %pf\n", dcmode[dcmode_idx]->dcmode_ops->disconn_if); seq_printf(seq, " get_netif_stats: %pf\n", dcmode[dcmode_idx]->dcmode_ops->get_netif_stats); seq_printf(seq, " clear_netif_stats: %pf\n", dcmode[dcmode_idx]->dcmode_ops->clear_netif_stats); seq_printf(seq, " register_qos_class2prio_cb: %pf\n", dcmode[dcmode_idx]->dcmode_ops->register_qos_class2prio_cb); seq_printf(seq, " map_class2devqos: %pf\n", dcmode[dcmode_idx]->dcmode_ops->map_class2devqos); seq_printf(seq, " alloc_skb: %pf\n", dcmode[dcmode_idx]->dcmode_ops->alloc_skb); seq_printf(seq, " free_skb: %pf\n", dcmode[dcmode_idx]->dcmode_ops->free_skb); seq_printf(seq, " change_dev_status: %pf\n", dcmode[dcmode_idx]->dcmode_ops->change_dev_status); seq_printf(seq, " get_wol_cfg: %pf\n", dcmode[dcmode_idx]->dcmode_ops->get_wol_cfg); seq_printf(seq, " set_wol_cfg: %pf\n", dcmode[dcmode_idx]->dcmode_ops->set_wol_cfg); seq_printf(seq, " set_wol_ctrl: %pf\n", dcmode[dcmode_idx]->dcmode_ops->set_wol_ctrl); seq_printf(seq, " get_wol_ctrl_status: %pf\n", dcmode[dcmode_idx]->dcmode_ops->get_wol_ctrl_status); seq_printf(seq, " dump_proc: %pf\n", dcmode[dcmode_idx]->dcmode_ops->dump_proc); } return 0; } static int proc_read_dc_dp_dcmode_open(struct inode *inode, struct file *file) { return single_open(file, proc_read_dc_dp_dcmode_show, NULL); } static int proc_read_dc_dp_macdb_show(struct seq_file *seq, void *v) { if (!capable(CAP_NET_ADMIN)) { printk("Read Permission denied"); return 0; } dc_dp_macdb_seq_dump(seq); return 0; } static int proc_read_dc_dp_macdb_open(struct inode *inode, struct file *file) { return single_open(file, proc_read_dc_dp_macdb_show, NULL); } int32_t dc_dp_proc_init(void) { struct proc_dir_entry *entry; g_dc_dp_proc = proc_mkdir(DC_DP_PROC, NULL); if (!g_dc_dp_proc) return -ENOMEM; entry = proc_create_data(DC_DP_PROC_DBG, 0, g_dc_dp_proc, &g_dc_dp_dbg_proc_fops, NULL); if (!entry) goto __dbg_proc_err; entry = proc_create_data(DC_DP_PROC_DEV, 0, g_dc_dp_proc, &g_dc_dp_dev_proc_fops, NULL); if (!entry) goto __dev_proc_err; entry = proc_create_data(DC_DP_PROC_DCMODE, 0, g_dc_dp_proc, &g_dc_dp_dcmode_proc_fops, NULL); if (!entry) goto __dcmode_proc_err; entry = proc_create_data(DC_DP_PROC_MACDB, 0, g_dc_dp_proc, &g_dc_dp_macdb_proc_fops, NULL); if (!entry) goto __macdb_proc_err; return 0; __macdb_proc_err: remove_proc_entry(DC_DP_PROC_DCMODE, g_dc_dp_proc); __dcmode_proc_err: remove_proc_entry(DC_DP_PROC_DEV, g_dc_dp_proc); __dev_proc_err: remove_proc_entry(DC_DP_PROC_DBG, g_dc_dp_proc); __dbg_proc_err: proc_remove(g_dc_dp_proc); return -ENOMEM; } void dc_dp_proc_exit(void) { remove_proc_entry(DC_DP_PROC_MACDB, g_dc_dp_proc); remove_proc_entry(DC_DP_PROC_DCMODE, g_dc_dp_proc); remove_proc_entry(DC_DP_PROC_DEV, g_dc_dp_proc); remove_proc_entry(DC_DP_PROC_DBG, g_dc_dp_proc); proc_remove(g_dc_dp_proc); g_dc_dp_proc = NULL; }