#include <linux/module.h> #include <linux/proc_fs.h> #include <linux/time.h> #include <linux/timer.h> #include <net/rtl/rtl865x_netif.h> #include "./867x_sar/ra8670.h" #define REG32(reg) (*(volatile u32*)(reg)) #define PTM_RX_BYTES (0xbb801380) #define DEFAULT_RATIO 100 #define DEFAULT_DOWNLOAD_RATIO 5 #define DEFAULT_USED_DESC_THRES 200 #define RTL865X_ACL_Mode_PTM_TCPUS_Permit 0x03 #define RTL865X_ACL_Mode_PTM_TCPUS_Trap 0x04 extern BOOL GetLinkSpeed(char *Rate); #if defined(CONFIG_TRAP_PTM_TCP_US_TRAFFIC) extern int rtl865x_acl_control_upstream_tcp_set_action(int mode); #endif static int enable_ptm_us_ctrl = 0; static int rate_ratio = DEFAULT_RATIO; static int download_ratio = DEFAULT_DOWNLOAD_RATIO; struct net_device *ptmdev = NULL; int ptm_used_desc_thres = DEFAULT_USED_DESC_THRES; int any_port = 0; static struct timer_list ptm_timer; int ptm_rx_bytes=0, ptm_rx_bytes_prev=0; static void ptm_timer_handle(unsigned long arg) { extern T_LinkSpeed LINE_rate; LINE_rate.upstreamRate = 0; LINE_rate.downstreamRate = 0; if (download_ratio > 0){ GetLinkSpeed(&LINE_rate);; if (LINE_rate.downstreamRate > 0){ ptm_rx_bytes = REG32(PTM_RX_BYTES) + (REG32(PTM_RX_BYTES+4) << 22); if (ptm_rx_bytes > 0){ // downstream throughput < download ratio/100 line rate if (((ptm_rx_bytes-ptm_rx_bytes_prev) * 8) < LINE_rate.downstreamRate * 10 * download_ratio){ enable_ptm_us_ctrl = 0; } else { enable_ptm_us_ctrl = 1; } } ptm_rx_bytes_prev = ptm_rx_bytes; } } mod_timer(&ptm_timer, jiffies + HZ); return; } static void ptm_timer_init(void) { printk("%s\n",__func__); init_timer(&ptm_timer); ptm_timer.function = &ptm_timer_handle; ptm_timer.expires = jiffies + HZ; } static void ptm_timer_add(void) { // printk("%s\n",__func__); mod_timer(&ptm_timer, jiffies + HZ); } static void ptm_timer_exit(void) { // printk("%s\n",__func__); del_timer(&ptm_timer); } void rtk_ptm_us_ctrl_decision(int isLinkup) { extern T_LinkSpeed LINE_rate; LINE_rate.upstreamRate = 0; LINE_rate.downstreamRate = 0; int r; if (isLinkup) { GetLinkSpeed(&LINE_rate); if (!LINE_rate.upstreamRate || !LINE_rate.downstreamRate) { printk("[%s](%d) ERR! Unable to get PTM line rate\n", __func__, __LINE__); return; } r = (LINE_rate.downstreamRate*100) / LINE_rate.upstreamRate; printk("[%s](%d) Line rate us:%d Kbps / ds: %d Kbps R: %d\%\n", __func__, __LINE__, LINE_rate.upstreamRate, LINE_rate.downstreamRate, r); if (r >= rate_ratio) { printk("[%s](%d) Activate PTM WAN Upstream CTRL\n", __func__, __LINE__); enable_ptm_us_ctrl = 1; #if defined(CONFIG_TRAP_PTM_TCP_US_TRAFFIC) rtl865x_acl_control_upstream_tcp_set_action(RTL865X_ACL_Mode_PTM_TCPUS_Trap); #endif } else { enable_ptm_us_ctrl = 0; #if defined(CONFIG_TRAP_PTM_TCP_US_TRAFFIC) rtl865x_acl_control_upstream_tcp_set_action(RTL865X_ACL_Mode_PTM_TCPUS_Permit); #endif } //get net dev of ptm for furthur use ptmdev = dev_get_by_name(&init_net, ALIASNAME_PTM0); ptm_timer_add(); } else { enable_ptm_us_ctrl = 0; if (ptmdev) dev_put(ptmdev); ptmdev = NULL; #if defined(CONFIG_TRAP_PTM_TCP_US_TRAFFIC) rtl865x_acl_control_upstream_tcp_set_action(RTL865X_ACL_Mode_PTM_TCPUS_Permit); #endif ptm_timer_exit(); } } EXPORT_SYMBOL(rtk_ptm_us_ctrl_decision); int rtk_ptm_us_ctrl_enabled(void) { return enable_ptm_us_ctrl; } EXPORT_SYMBOL(rtk_ptm_us_ctrl_enabled); static void show_usage(void){ printk(" e [0/1] : enable/disable PTM WAN upstream traffic control\n"); printk(" r [value] : set PTM WAN line rate ratio to [value]\%, default is %d\%\n", DEFAULT_RATIO); printk(" u [value] : set PTM WAN used desc threshold to [value], default is %d\n", DEFAULT_USED_DESC_THRES); printk(" d [value] : set PTM WAN download ratio to [value], default is %d\n", DEFAULT_DOWNLOAD_RATIO); } static int ptm_us_ctrl_write_proc(struct file * file, const char __user * userbuf, size_t count, loff_t * off) { char buf[32]; int len; int val; int enabled; struct net_device *dev; len = min(sizeof(buf), count); if (copy_from_user(buf, userbuf, len)) return -E2BIG; if (strncmp(buf, "help", 4) == 0) { show_usage(); } else if (strncmp(buf, "e ", 2) == 0) { if(1==sscanf(buf, "e %d", &enabled)){ enable_ptm_us_ctrl = enabled; printk("%s PTM WAN upstream traffic control\n", enable_ptm_us_ctrl? "Enable":"Disable"); } else{ goto ERROR_PARA; } } else if (strncmp(buf, "r ", 2) == 0) { if(1==sscanf(buf, "r %d", &val)){ rate_ratio = val; printk("set triggered PTM line rate ratio to %d\n", rate_ratio); } else{ goto ERROR_PARA; } } else if (strncmp(buf, "u ", 2) == 0) { if(1==sscanf(buf, "u %d", &val)){ ptm_used_desc_thres = val; printk("set PTM used desc threshold to %d\n", ptm_used_desc_thres); } else{ goto ERROR_PARA; } } else if (strncmp(buf, "a ", 2) == 0) { if(1==sscanf(buf, "a %d", &val)){ any_port = val; printk("set LAN port congestion check to %d\n", any_port); } else{ goto ERROR_PARA; } } else if (strncmp(buf, "d ", 2) == 0) { if(1==sscanf(buf, "d %d", &val)){ if (val>=0 && val<=100){ download_ratio = val; printk("When download rate > %d/100 line rate, enable PTM WAN upstream traffic control\n", val); } else { printk("input error, download rate: [0~100]\n"); } } else{ goto ERROR_PARA; } } else { goto ERROR_PARA; } return count; ERROR_PARA: printk("error parameter...\n"); show_usage(); return -EPERM; } static int ptm_us_ctrl_read_proc(struct seq_file *f, void *data) { seq_printf(f, "PTM WAN Upstream traffic control: %s, triggered line rate ration: %d, triggered download ratio: %d\n", enable_ptm_us_ctrl ? "Enabled" : "Disabled", rate_ratio, download_ratio); seq_printf(f, "used desc threshold: %d\n", ptm_used_desc_thres); seq_printf(f, "Lan port congestion check: %d\n\n", any_port); if (!ptmdev) seq_printf(f, "PTM dev: NULL, isRunning: unknown, isCarrierOn: unknown\n"); else seq_printf(f, "PTM dev: %s, isRunning: %d, isCarrierOn: %d\n", ptmdev->name, netif_running(ptmdev), netif_carrier_ok(ptmdev)); return 0; } static int read_proc_open_ptm_us_ctrl(struct inode *inode, struct file *file) { return(single_open(file, ptm_us_ctrl_read_proc, NULL)); } static ssize_t write_proc_ptm_us_ctrl(struct file *file, const char __user * userbuf, size_t count, loff_t * off) { return ptm_us_ctrl_write_proc(file, userbuf, count, NULL); } static struct file_operations fops_proc_ptm_us_ctrl = { .open = read_proc_open_ptm_us_ctrl, .read = seq_read, .llseek = seq_lseek, .release = single_release, .write = write_proc_ptm_us_ctrl, }; extern struct proc_dir_entry *realtek_proc; static struct proc_dir_entry *ptm_us_ctrl_proc=NULL; static int ptm_us_proc_init(void) { if (!realtek_proc) { printk("Realtek SKB Priority Assignment, create proc failed, root dir not found\n"); return -1; } ptm_us_ctrl_proc = proc_create_data("ptm_us_ctrl", 0644, realtek_proc, &fops_proc_ptm_us_ctrl, NULL); if (!ptm_us_ctrl_proc) { printk("Realtek SKB Priority Assignment, create proc failed!\n"); } return 0; } static int ptm_us_proc_clean(void) { if (realtek_proc) { remove_proc_entry(ptm_us_ctrl_proc, realtek_proc); } } static int __init rtk_ptmus_ctrl_init(void) { ptm_us_proc_init(); ptm_timer_init(); return 0; } static int __exit rtk_ptmus_ctrl_exit(void) { ptm_us_proc_clean(); return 0; } module_init(rtk_ptmus_ctrl_init); module_exit(rtk_ptmus_ctrl_exit);