blob: 3c50c88cf9f7d77b374dafbc483dd1a5bee5cfd2 [file] [log] [blame]
/************************************************************************
* Copyright (C) 2010, Marvell Technology Group Ltd.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Marvell Technology Group;
* the contents of this file may not be disclosed to third parties, copied
* or duplicated in any form, in whole or in part, without the prior
* written permission of Marvell Technology Group.
*
*********************************************************************************
* Marvell GPL License Option
*
* If you received this File from Marvell, you may opt to use, redistribute and/or
* modify this File in accordance with the terms and conditions of the General
* Public License Version 2, June 1991 (the "GPL License"), a copy of which is
* available along with the File in the license.txt file or by writing to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
* on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
* WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
* DISCLAIMED. The GPL License provides additional details about this warranty
* disclaimer.
*
*********************************************************************************
* mv_cust_sysfs.c
*
* DESCRIPTION:
*
*
*******************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/capability.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/netdevice.h>
#include <gbe/mvNeta.h>
#include <pnc/mvPnc.h>
#include "mv_cust_dev.h"
#include "mv_cust_netdev.h"
#include "mv_cust_flow_map.h"
#include "mv_cust_mng_if.h"
static int eoam_txq = 0;
static uint8_t eoam_mac[6] = {0};
static ssize_t mv_cust_spec_proc_help(char *buf)
{
int off = 0;
off += sprintf(buf+off, "cat help - show this help\n");
#ifdef CONFIG_MV_CUST_UDP_SAMPLE_HANDLE
off += sprintf(buf+off, "cat udp_ports - show special udp source and dest. port configuration\n");
#endif
#ifdef CONFIG_MV_CUST_FLOW_MAP_HANDLE
off += sprintf(buf+off, "cat flow_map - show flow mapping configuration\n");
off += sprintf(buf+off, "cat flow_map_show - show flow mapping rules \n");
off += sprintf(buf+off, "cat flow_map_clear - clear all flow mapping rules\n");
off += sprintf(buf+off, "cat dscp_map_del - delete DSCP to P-bits mapping rules\n");
#endif
off += sprintf(buf+off, "cat tcont_show - Show all T-CONT state\n");
off += sprintf(buf+off, "echo tcont state > tcont_set - Set T-CONT tatus, tcont(0~7), state(1:enable, 0:disable) \n");
off += sprintf(buf+off, "echo hex > debug - Set Customized module debug information \n");
off += sprintf(buf+off, "echo app_type > app_show - Show application configuration. 0:igmp, 1:mld, 2:lpbk, 3:eoam, 4:omci\n");
off += sprintf(buf+off, "echo app_type enable > app_flag_set - Enable/disable application. 0:igmp, 1:mld, 2:lpbk, 3:eoam, 4:omci, 1:enable, 0:disable\n");
off += sprintf(buf+off, "echo app_type hex > app_etype_set- Set application Eth type. 0:igmp, 1:mld, 2:lpbk, 3:eoam, 4:omci\n");
off += sprintf(buf+off, "echo tc txq gem keep_mh > omci_set - set udp source port special Tx behavior\n");
off += sprintf(buf+off, "echo keep_mh > eoam_gh_keep - Keep or not keep GH for eOAM packets, 1:keep, 0:do not keep\n");
off += sprintf(buf+off, "echo txq > eoam_txq - set TX queue into sw_buffer for EOAM llid command\n");
off += sprintf(buf+off, "echo mac[0]-mac[5] > eoam_mac - set LLID mac into sw_buffer for EOAM llid command\n");
off += sprintf(buf+off, "echo llid > eoam_write - Write EOAM txq and mac address from sw_buffer into LLID\n");
#ifdef CONFIG_MV_CUST_UDP_SAMPLE_HANDLE
off += sprintf(buf+off, "echo p udp_src(dec) txp txq flags hw_cmd > udp_src - set udp source port special Tx behavior\n");
off += sprintf(buf+off, "echo p udp_dst(dec) txp txq flags hw_cmd > udp_dst - set udp dest. port special Tx behavior\n");
#endif
#ifdef CONFIG_MV_CUST_FLOW_MAP_HANDLE
off += sprintf(buf+off, "echo hex > flow_map_debug - Set flow mapping debug flag, 1:enable, 0:disable \n");
off += sprintf(buf+off, "echo vid pbits mod_vid mod_pbits trg_port trg_queue trg_hwf_queue gem_port > flow_map_us_set - set U/S flow mapping rule\n");
off += sprintf(buf+off, "echo vid pbits mod_vid mod_pbits > flow_map_ds_set - set D/S flow mapping rule\n");
off += sprintf(buf+off, "echo pbits0 pbits1 ... pbits62 pbits63 > dscp_map_set - set DSCP to P-bits mapping rules\n");
off += sprintf(buf+off, "echo vlan pbits dir(0:U/S, 1:D/S) > flow_map_del - delete flow mapping rule\n");
off += sprintf(buf+off, "echo vlan pbits dir(0:U/S, 1:D/S) > tag_flow_get - get tagged flow mapping rule\n");
off += sprintf(buf+off, "echo dscp dir(0:U/S, 1:D/S) > untag_flow_get - get untagged flow mapping rule\n");
#endif
return off;
}
static ssize_t mv_cust_spec_proc_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int off = 0;
int index = 0;
bool state;
const char* name = attr->attr.name;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (!strcmp(name, "help") ) {
off = mv_cust_spec_proc_help(buf);
}
#ifdef CONFIG_MV_CUST_UDP_SAMPLE_HANDLE
else if (!strcmp(name, "udp_ports")) {
mv_cust_udp_spec_print_all();
}
#endif
#ifdef CONFIG_MV_CUST_FLOW_MAP_HANDLE
else if (!strcmp(name, "flow_map")) {
mv_cust_flow_map_print();
}
else if (!strcmp(name, "flow_map_show")) {
mv_cust_map_table_print();
}
else if (!strcmp(name, "flow_map_clear")) {
mv_cust_map_rule_clear();
}
else if (!strcmp(name, "dscp_map_del")) {
mv_cust_dscp_map_del();
}
#endif
else if (!strcmp(name, "tcont_show")) {
printk(KERN_INFO "MV_CUST T-CONT state table\n");
printk(KERN_INFO "Default invalid Txq:%d \n", CPH_INVALID_TRGT_QUEUE);
printk(KERN_INFO "--------------------------\n");
for (index = 0; index < CPH_MAX_TCONT_NUM; index++)
{
state = mv_cust_get_tcont_state(index);
printk(KERN_INFO "T-CONT%1.1d: %s\n", index, (state==true)?"enabled":"disabled");
}
}
else
off = mv_cust_spec_proc_help(buf);
return off;
}
static ssize_t mv_cust_spec_proc_1_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
const char* name = attr->attr.name;
unsigned int v;
unsigned long flags;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Read input */
v = 0;
sscanf(buf, "%x", &v);
raw_local_irq_save(flags);
if (!strcmp(name, "debug")) {
mv_cust_debug_info_set(v);
}
else if (!strcmp(name, "app_show")) {
mv_cust_print(v);
}
else if (!strcmp(name, "eoam_gh_keep")) {
mv_cust_oam_rx_gh_set(v);
}
else if (!strcmp(name, "eoam_txq")) {
eoam_txq = v;
}
else if (!strcmp(name, "eoam_write")) {
mv_cust_eoam_llid_set((int)v, &eoam_mac[0], eoam_txq);
}
else
printk("%s: illegal operation <%s>\n", __FUNCTION__, attr->attr.name);
raw_local_irq_restore(flags);
return len;
}
static ssize_t mv_cust_spec_proc_2_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
const char* name = attr->attr.name;
unsigned int p, v;
unsigned long flags;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Read input */
p = 0;
v = 0;
sscanf(buf, "%d %x", &p, &v);
raw_local_irq_save(flags);
if (!strcmp(name, "app_flag_set")) {
mv_cust_app_flag_set(p, v);
}
else if (!strcmp(name, "app_etype_set")) {
mv_cust_app_etype_set(p, v);
}
else if (!strcmp(name, "tcont_set")) {
if (v)
mv_cust_set_tcont_state(p, true);
else
mv_cust_set_tcont_state(p, false);
}
else
printk("%s: illegal operation <%s>\n", __FUNCTION__, attr->attr.name);
raw_local_irq_restore(flags);
return len;
}
static ssize_t mv_cust_spec_proc_6_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
const char* name = attr->attr.name;
unsigned int p, v1=0, v2=0, v3=0, v4=0, v5=0;
unsigned long flags;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Read input */
sscanf(buf, "%d %d %x %x %x %x", &p, &v1, &v2, &v3, &v4, &v5);
raw_local_irq_save(flags);
if (!strcmp(name, "udp_src")) {
#ifdef CONFIG_MV_CUST_UDP_SAMPLE_HANDLE
mv_cust_udp_src_spec_set(p, v1, v2, v3, v4, v5);
#else
printk("mv_cust module was not compiled with UDP SAMPLE Config Support\n");
#endif
}
else if (!strcmp(name, "udp_dst")) {
#ifdef CONFIG_MV_CUST_UDP_SAMPLE_HANDLE
mv_cust_udp_dest_spec_set(p, v1, v2, v3, v4, v5);
#else
printk("mv_cust module was not compiled with UDP SAMPLE Config Support\n");
#endif
}
else if (!strcmp(name, "omci_set")) {
mv_cust_omci_set(p, v1, v2, v3);
}
else
printk("%s: illegal operation <%s>\n", __FUNCTION__, attr->attr.name);
raw_local_irq_restore(flags);
return len;
}
static ssize_t mv_cust_spec_proc_flow_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
const char* name = attr->attr.name;
unsigned int v1=0, v2=0, v3=0, v4=0, v5=0, v6=0, v7=0, v8=0;
unsigned long flags;
mv_cust_ioctl_flow_map_t cust_flow;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Read input */
sscanf(buf, "%d %d %d %d %d %d %d %d", &v1, &v2, &v3, &v4, &v5, &v6, &v7, &v8);
raw_local_irq_save(flags);
#ifdef CONFIG_MV_CUST_FLOW_MAP_HANDLE
if (!strcmp(name, "flow_map_debug")) {
mv_cust_set_trace_flag((uint32_t)v1);
}
else if (!strcmp(name, "flow_map_us_set")) {
memset(&cust_flow, 0, sizeof(cust_flow));
cust_flow.dir = MV_CUST_FLOW_DIR_US;
cust_flow.vid = v1;
cust_flow.pbits = v2;
cust_flow.mod_vid = v3;
cust_flow.mod_pbits = v4;
cust_flow.pkt_frwd.in_use = 1;
cust_flow.pkt_frwd.trg_port = (mv_cust_trg_port_type_t)v5;
cust_flow.pkt_frwd.trg_queue = (uint32_t)v6;
cust_flow.pkt_frwd.trg_hwf_queue = (uint32_t)v7;
cust_flow.pkt_frwd.gem_port = (mv_cust_gem_port_key_t)v8;
mv_cust_map_rule_set(&cust_flow);
}
else if (!strcmp(name, "flow_map_ds_set")) {
memset(&cust_flow, 0, sizeof(cust_flow));
cust_flow.dir = MV_CUST_FLOW_DIR_DS;
cust_flow.vid = v1;
cust_flow.pbits = v2;
cust_flow.mod_vid = v3;
cust_flow.mod_pbits = v4;
cust_flow.pkt_frwd.in_use = 1;
mv_cust_map_rule_set(&cust_flow);
}
else if (!strcmp(name, "flow_map_del")) {
mv_cust_map_rule_del((uint16_t)v1, (uint8_t)v2, (mv_cust_flow_dir_e)v3);
}
else if (!strcmp(name, "tag_flow_get")) {
memset(&cust_flow, 0, sizeof(cust_flow));
cust_flow.vid = v1;
cust_flow.pbits = v2;
cust_flow.dir = (mv_cust_flow_dir_e)v3;
mv_cust_tag_map_rule_get(&cust_flow);
printk("in_use[%d], mod_vid[%d] mod_pbits[%d] trg_port[%d], trg_queue[%d], gem_port[%d]\r\n",
cust_flow.pkt_frwd.in_use, cust_flow.mod_vid,
cust_flow.mod_pbits, cust_flow.pkt_frwd.trg_port,
cust_flow.pkt_frwd.trg_queue, cust_flow.pkt_frwd.gem_port);
}
else if (!strcmp(name, "untag_flow_get")) {
memset(&cust_flow, 0, sizeof(cust_flow));
cust_flow.dscp = v1;
cust_flow.dir = (mv_cust_flow_dir_e)v2;
mv_cust_untag_map_rule_get(&cust_flow);
printk("in_use[%d], mod_vid[%d] mod_pbits[%d] trg_port[%d], trg_queue[%d], gem_port[%d]\r\n",
cust_flow.pkt_frwd.in_use, cust_flow.mod_vid,
cust_flow.mod_pbits, cust_flow.pkt_frwd.trg_port,
cust_flow.pkt_frwd.trg_queue, cust_flow.pkt_frwd.gem_port);
}
else
printk("%s: illegal operation <%s>\n", __FUNCTION__, attr->attr.name);
#endif
raw_local_irq_restore(flags);
return len;
}
static ssize_t mv_cust_spec_proc_6h_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
const char* name = attr->attr.name;
unsigned int v1=0, v2=0, v3=0, v4=0, v5=0, v6=0;
unsigned long flags;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Read input */
sscanf(buf, "%x %x %x %x %x %x", &v1, &v2, &v3, &v4, &v5, &v6);
raw_local_irq_save(flags);
if (!strcmp(name, "eoam_mac")) {
eoam_mac[0] = (uint8_t)v1;
eoam_mac[1] = (uint8_t)v2;
eoam_mac[2] = (uint8_t)v3;
eoam_mac[3] = (uint8_t)v4;
eoam_mac[4] = (uint8_t)v5;
eoam_mac[5] = (uint8_t)v6;
}
else
printk("%s: illegal operation <%s>\n", __FUNCTION__, attr->attr.name);
raw_local_irq_restore(flags);
return len;
}
static ssize_t mv_cust_spec_proc_64_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
const char* name = attr->attr.name;
unsigned int v[64];
unsigned int index = 0;
unsigned long flags;
mv_cust_dscp_pbits_t dscp_map;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Read input */
for (index=0; index<64; index++) {
sscanf(buf, "%d", &v[index]);
dscp_map.pbits[index] = (uint8_t)v[index];
}
dscp_map.in_use = 1;
raw_local_irq_save(flags);
if (!strcmp(name, "dscp_map_set")) {
#ifdef CONFIG_MV_CUST_FLOW_MAP_HANDLE
mv_cust_dscp_map_set(&dscp_map);
#endif
}
else
printk("%s: illegal operation <%s>\n", __FUNCTION__, attr->attr.name);
raw_local_irq_restore(flags);
return len;
}
static DEVICE_ATTR(help, S_IRUSR, mv_cust_spec_proc_show, NULL);
static DEVICE_ATTR(debug, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_1_store);
static DEVICE_ATTR(omci_set, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_6_store);
static DEVICE_ATTR(eoam_gh_keep, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_1_store);
static DEVICE_ATTR(eoam_txq, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_1_store);
static DEVICE_ATTR(eoam_mac, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_6h_store);
static DEVICE_ATTR(eoam_write, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_1_store);
static DEVICE_ATTR(tcont_show, S_IRUSR, mv_cust_spec_proc_show, NULL);
static DEVICE_ATTR(tcont_set, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_2_store);
static DEVICE_ATTR(app_show, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_1_store);
static DEVICE_ATTR(app_flag_set, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_2_store);
static DEVICE_ATTR(app_etype_set, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_2_store);
static DEVICE_ATTR(udp_ports, S_IRUSR, mv_cust_spec_proc_show, NULL);
static DEVICE_ATTR(udp_src, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_6_store);
static DEVICE_ATTR(udp_dst, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_6_store);
static DEVICE_ATTR(flow_map, S_IRUSR, mv_cust_spec_proc_show, NULL);
static DEVICE_ATTR(flow_map_show, S_IRUSR, mv_cust_spec_proc_show, NULL);
static DEVICE_ATTR(flow_map_clear, S_IRUSR, mv_cust_spec_proc_show, NULL);
static DEVICE_ATTR(dscp_map_del, S_IRUSR, mv_cust_spec_proc_show, NULL);
static DEVICE_ATTR(flow_map_debug, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_flow_store);
static DEVICE_ATTR(flow_map_us_set,S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_flow_store);
static DEVICE_ATTR(flow_map_ds_set,S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_flow_store);
static DEVICE_ATTR(flow_map_del, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_flow_store);
static DEVICE_ATTR(tag_flow_get, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_flow_store);
static DEVICE_ATTR(untag_flow_get, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_flow_store);
static DEVICE_ATTR(dscp_map_set, S_IWUSR, mv_cust_spec_proc_show, mv_cust_spec_proc_64_store);
static struct attribute *mv_cust_spec_proc_attrs[] = {
&dev_attr_help.attr,
&dev_attr_debug.attr,
&dev_attr_omci_set.attr,
&dev_attr_eoam_gh_keep.attr,
&dev_attr_eoam_txq.attr,
&dev_attr_eoam_mac.attr,
&dev_attr_eoam_write.attr,
&dev_attr_tcont_show.attr,
&dev_attr_tcont_set.attr,
&dev_attr_app_show.attr,
&dev_attr_app_flag_set.attr,
&dev_attr_app_etype_set.attr,
&dev_attr_udp_ports.attr,
&dev_attr_udp_src.attr,
&dev_attr_udp_dst.attr,
&dev_attr_flow_map_debug.attr,
&dev_attr_flow_map_us_set.attr,
&dev_attr_flow_map_ds_set.attr,
&dev_attr_dscp_map_set.attr,
&dev_attr_flow_map_del.attr,
&dev_attr_tag_flow_get.attr,
&dev_attr_untag_flow_get.attr,
&dev_attr_flow_map.attr,
&dev_attr_flow_map_show.attr,
&dev_attr_flow_map_clear.attr,
&dev_attr_dscp_map_del.attr,
NULL
};
static struct attribute_group mv_cust_spec_proc_group = {
.name = "proto",
.attrs = mv_cust_spec_proc_attrs,
};
int mvcust_sysfs_init(void)
{
int err;
struct device *pd;
pd = bus_find_device_by_name(&platform_bus_type, NULL, "cust");
if (!pd) {
platform_device_register_simple("cust", -1, NULL, 0);
pd = bus_find_device_by_name(&platform_bus_type, NULL, "cust");
}
if (!pd) {
printk(KERN_ERR"%s: cannot find cust device\n", __FUNCTION__);
pd = &platform_bus;
}
err = sysfs_create_group(&pd->kobj, &mv_cust_spec_proc_group);
if (err) {
printk(KERN_INFO "sysfs group failed %d\n", err);
goto out;
}
printk(KERN_INFO "= CUST Module SYS FS Init ended successfully =\n");
out:
return err;
}
void mvcust_sysfs_delete(void)
{
struct device *pd;
pd = bus_find_device_by_name(&platform_bus_type, NULL, "cust");
if (!pd)
{
printk(KERN_ERR"%s: cannot find CUST device\n", __FUNCTION__);
return;
}
sysfs_remove_group(&pd->kobj, &mv_cust_spec_proc_group);
printk(KERN_INFO "= CUST Module SYS FS Remove ended successfully =\n");
}