/* ra8670.c - RealTek rtl8670 sar interface header */ #define DRV_NAME "RTL8670 SAR" #define DRV_VERSION "v0.0.2" #define DRV_RELDATE "Jun 17, 2003" #define AUTO_PVC_SEARCH #include <linux/module.h> #include <linux/kernel.h> #include <linux/skbuff.h> #include <linux/atmdev.h> #include <linux/atm.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/crc32.h> #include <linux/slab.h> #include <linux/netdevice.h> #include <asm/io.h> #include <asm/uaccess.h> // Kaohj -- for /proc/sys/sar #include <linux/sysctl.h> #include "ra8670.h" #include "ra_debug.h" #ifdef CONFIG_RTL8671 #ifdef CONFIG_UCLINUX #include "../../arch/mipsnommu/rtl8670/lx5280.h" #else #include "../../arch/mips/realtek/rtl8670/lx5280.h" #endif #endif #ifdef CONFIG_RTL8681_SAR_ARCH #include <gpio.h> #endif #ifdef CONFIG_REMOTE_ADSL_PHY struct sock *nl_sk = NULL; struct atm_vcc* get_atmvcc_by_channel(char ch_no); struct net_device* get_netdev_by_channel(char ch_no); extern int rtk_adslphy_sar2eth(struct atm_vcc *vcc, struct sk_buff* skb, char ch_no); #endif /************************************ * const variable defination *************************************/ //#define RTL_BridgeWANVLANID 7 /* WAN vid (bridged, default no vlan tag)*/ //#define RTL_WANVLANID 8 /* WAN vid (routed, default no vlan tag)*/ //#define RTL_LANVLANID 9 /* LAN vid (default no vlan tag) */ //ql--upstream traffic control //tylo, temp. marked for linux2.6 //#include "../../../user/boa/src/LINUX/options.h" #define __SWAP extern int enable_ipqos; /*linux-2.6.19*/ //int sar_irq=SAR_IRQ; int sar_irq=BSP_SAR_IRQ; //ql_xu: qos #define QOS_IPTV_TR69 2 #define QOS_RULE_EXIST 1 int qosRuleExist=0; int qosIPtv=0; static u32 cntr_rbf = 0; static char stop_rx = 0; #ifdef CONFIG_ATM_BONDING #include "ATMBonding.h" static unsigned int gasmtick=0; #endif int sar_send (struct atm_vcc *,struct sk_buff *); #ifdef CONFIG_DSL_CODESWAP int DSPInShowtime=0; #else #define DSPInShowtime 1 #endif #ifdef UPSTREAM_TRAFFIC_CTL #define BANDWIDT_1M 10*1024/8 //KBps unsigned char ucTcEbl=0; unsigned int uMaxTraffic=0; unsigned int uTc1Data; unsigned int LB_MIN=15000; unsigned int LB_THD=20000; unsigned int LB_SEC=30000; unsigned int LB_MAX=95000; unsigned int LB_len=100000; #endif #define SAR_RX_FORMATION // adaptive RX descriptor sharing among PVCs #define ZTE_531B_TEST 1 #ifdef AUTO_PVC_SEARCH #include <linux/proc_fs.h> #define PROCFS_MAX_SIZE 32 #define PROCFS_NAME "AUTO_PVC_SEARCH" #define MAX_PVC_SEARCH_PAIRS 16 //supports most 16 pairs static struct proc_dir_entry *APS_Proc_File; static char procfs_buffer[PROCFS_MAX_SIZE] = {'0', ',', '0'}; int auto_search_start=0; int found_pvc=0; //default is set to 1 as disable auto-pvc-search uint16 detect_vpi; uint16 detect_vci; uint16 detect_framing; // Mason Yu. 20130304 typedef enum _PacketType { PPPOED = 1, PPPOA_LCP = 2, } PacketType; static int autohunt_pkt_type = PPPOED; //deprecated after applying maximum PCR limitation mechanism #ifdef SW_QOS_STARV_PREVENTION //#define STAI_DEBUG #endif #ifdef STAI_DEBUG sar_private *sar_cp; #endif // Added by Mason Yu for autohunt // ARP request(192.168.8.1) char test_packet[]={ 0xaa, 0xaa, 0x03, 0x00, 0x80, 0xc2, 0x00, 0x07, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xe0, 0x4c, 0xdd, 0x23, 0x15, 0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x00, 0xe0, 0x4c, 0xdd, 0x23, 0x15, 0xc0, 0xa8, 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // DHCP Discovery char test_packet2[]={ 0xaa, 0xaa, 0x03, 0x00, 0x80, 0xc2, 0x00, 0x07, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xe0, 0x4c, 0xdd, 0x23, 0x15, 0x08, 0x00, 0x45, 0x00, 0x01, 0x48, 0xf8, 0xbe, 0x00, 0x00, 0x80, 0x11, 0x40, 0xe7, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x44, 0x00, 0x43, 0x01, 0x34, 0x78, 0xb3, 0x01, 0x01, 0x06, 0x00, 0x43, 0x20, 0xf7, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x4c, 0xdd, 0x23, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x01, 0xfb, 0x01, 0x01, 0x3d, 0x07, 0x01, 0x00, 0xe0, 0x4c, 0xdd, 0x23, 0x15, 0x32, 0x04, 0xc0, 0xa8, 0x01, 0x05, 0x0c, 0x09, 0x72, 0x74, 0x70, 0x64, 0x49, 0x33, 0x33, 0x36, 0x35, 0x3c, 0x08, 0x4d, 0x53, 0x46, 0x54, 0x20, 0x35, 0x2e, 0x30, 0x37, 0x0a, 0x01, 0x0f, 0x03, 0x06, 0x2c, 0x2e, 0x2f, 0x1f, 0x21, 0x2b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }; // Mason Yu. 20130304 // PPPoED Active Discovery Initiation on LLC char PPPoED[]={ 0xaa, 0xaa, 0x03, 0x00, 0x80, 0xc2, 0x00, 0x07, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xe0, 0x4c, 0x04, 0x05, 0x07, 0x88, 0x63, 0x11, 0x09, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x10, 0x00, 0xe0, 0x4c, 0x04, 0x05, 0x06, 0x70, 0x70, 0x70, 0x6f, 0x65, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00 }; // Mason Yu. 20130304 // PPPoA(LCP) on LLC #if 0 char PPPoA_LCP[]={ 0xaa, 0xaa, 0x03, 0x00, 0x80, 0xc2, 0x00, 0x07, 0x00, 0x00, 0xc0, 0x21, 0x01, 0x01, 0x00, 0x0a, 0x05, 0x06, 0x6b, 0x8b, 0x45, 0x70 }; #endif // Mason Yu. 20130304 // PPPoA(LCP) on VCMux char PPPoA_LCP[]={ 0xc0, 0x21, 0x01, 0x01, 0x00, 0x0a, 0x05, 0x06, 0x6b, 0x8b, 0x45, 0x70 }; struct VPIVCI{ int vpi; int vci; }; //PVC table struct VPIVCI Possible_PVC[MAX_PVC_SEARCH_PAIRS]; // PVC table counter int tbl_counter=0; static void sar_kfree_skb(struct sk_buff *skb) { struct atm_vcc *vcc = ATM_SKB(skb)->vcc; if (vcc && vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); } #if defined(CONFIG_RTL8681_SAR_ARCH) || defined(CONFIG_RTL8685_SAR_ARCH) /************************************ enable_mode : 0 => ATM mode 1 => PTM mode enable_phy_role: 0 => master 1 => slave 2 => slave 3 => slave ************************************/ #ifdef CONFIG_RTL8685_FPGA unsigned int enable_mode=0, enable_phy_role=0; #else extern unsigned int enable_mode, enable_phy_role; #endif #endif /* * Detect traffic for LINK(ACT) LED blinking (gpio.c) */ unsigned int latestTraffic=0,AtmTraffic=0; #ifdef CONFIG_PORT_MIRROR int sar_mirror_flag = 0; #endif /* * Get VPI from PVC table */ int getActiveVPINum(int count){ return Possible_PVC[count].vpi; } /* * Get VCI from PVC table */ int getActiveVCINum(int count){ return Possible_PVC[count].vci; } /* * Check if PVC exists in flash PVC table */ BOOL isPVCActiveExist(uint8 vpi, uint16 vci) { int i; for(i=0;i< tbl_counter;i++) { if( (Possible_PVC[i].vpi == vpi) && (Possible_PVC[i].vci == vci) ) return TRUE; } return FALSE; } // Added by Mason Yu for autohunt #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif int autohunt(struct atm_vcc *vcc, char *packet, int len) { //sar_private *cp = sar_dev; int count2=0; #if 0 // Send to default vc0 for(count2=0;count2<tbl_counter;count2++){ struct sk_buff test_skb, *testskb; int vci, vpi, loop; sar_atm_vcc *vcc_dev = RTATM_VCC(vcc); vpi = getActiveVPINum(count2); vci = getActiveVCINum(count2); if ((vpi==-1)&&(vci==-1)) continue; SetVpiVci(cp,vpi,vci,vcc_dev->ch_no); testskb = dev_alloc_skb( SAR_TX_Buffer_Size ); memset(testskb, 0, sizeof(struct sk_buff)); testskb->data=packet; testskb->len=len; mdelay(20); sar_send(vcc,testskb); mdelay(100); //for (loop = 0; loop <= (150000000/(1000*3)); loop++) { // delay 1ms // ; //} } #else // Send to outband channel for(count2=0;count2<tbl_counter;count2++){ struct sk_buff *testskb; int vci, vpi; unsigned char *tail; //sar_atm_vcc *vcc_dev = RTATM_VCC(vcc); vpi = getActiveVPINum(count2); vci = getActiveVCINum(count2); if ((vpi==-1)&&(vci==-1)) continue; testskb = dev_alloc_skb( SAR_TX_Buffer_Size ); tail=testskb->data; skb_put(testskb, len); memcpy(tail, packet, len); mdelay(20); //printk("Send to outband\n"); OutBandAAL5Tx(vpi, vci, testskb); mdelay(100); } #endif return 0; } #ifdef STAI_DEBUG static struct proc_dir_entry *ch_qos_info_proc; static int ch_qos_info_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len; struct ch_qos_type_info * ch_qos_info; ch_qos_info = sar_cp->starv; len = sprintf(page, "QoS Type Information\n"); len += sprintf(page+len, "-----------------------------------\n"); len += sprintf(page+len, "UBR \t count: %d mask: 0x%x\n", ch_qos_info[0].cnt, ch_qos_info[0].mask); len += sprintf(page+len, "CBR \t count: %d mask: 0x%x\n", ch_qos_info[1].cnt, ch_qos_info[1].mask); len += sprintf(page+len, "nrtVBR \t count: %d mask: 0x%x\n", ch_qos_info[2].cnt, ch_qos_info[2].mask); len += sprintf(page+len, "rtVBR \t count: %d mask: 0x%x\n", ch_qos_info[3].cnt, ch_qos_info[3].mask); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len>count) len = count; if (len<0) len = 0; return len; } static int ch_qos_info_proc_write(struct file *file, const char *buffer, unsigned long count, void *data) { return count; } #endif #if 0 //new procfs read // called then the /proc/AUTO_PVC_SEARCH is read int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data) { int procfs_buffer_size; if (offset > 0) { procfs_buffer_size = 0; } else { procfs_buffer_size = strlen(procfs_buffer); /* fill the buffer, return the buffer size */ memcpy(buffer, procfs_buffer, procfs_buffer_size); } //printk(KERN_INFO "%s\n", procfs_buffer); return procfs_buffer_size; } #else static int proc_aps_read(struct seq_file *seq, void *offset) { seq_printf(seq, procfs_buffer); return 0; } #endif void startPVCSearch(void); /* * called then the /proc/AUTO_PVC_SEARCH is wrote * 1 : enable SAR driver auto-pvc-search and attach PVC table * 0 : disable auto-pvc-search */ #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif int procfile_write(struct file *file, const char *buffer, unsigned long count, void *data) { sar_private *cp = sar_dev; struct atm_vcc *vcc; UCHAR proc_buffer[MAX_PVC_SEARCH_PAIRS*12], tmp[12]; int ok,vpi,vci, i,j; //int count2; vcc = cp->vcc[0].dev_data; /* write data to the buffer */ memset(proc_buffer, 0, sizeof(proc_buffer)); if ( copy_from_user(proc_buffer, buffer, count) ) { return -EFAULT; } // printk(KERN_INFO "\nprocfile_write received string %s(count %d) \n", proc_buffer, count); /* * Disable SAR driver auto-pvc-search if startup write '0' to /proc/auto_pvc_search * Parsing the PVC table pair received from user space */ if(proc_buffer[0] == '1') { tbl_counter=0;//reset for(i=1;i<count;i++) { memset(tmp,0,sizeof(tmp)); if(proc_buffer[i] == '(') { for(j=0;j<5;j++){ tmp[j] = proc_buffer[i+1+j]; if(proc_buffer[i+j+2] == ')') break; } sscanf(tmp, "%d %d ", &vpi, &vci); // printk("procfile_write : received pair %d (%d %d)\n", tbl_counter,vpi, vci); Possible_PVC[tbl_counter].vpi = vpi; Possible_PVC[tbl_counter++].vci = vci; } } auto_search_start=1; // Start SAR driver PVC search startPVCSearch(); found_pvc=0; // Added by Mason Yu. for autoHunt // Mason Yu. 20130304 //autohunt(vcc, test_packet2, sizeof(test_packet2)); if ( autohunt_pkt_type == PPPOED) { autohunt(vcc, PPPoED, sizeof(PPPoED)); printk("Send PPPOED packet\n"); autohunt_pkt_type = PPPOA_LCP; } else if ( autohunt_pkt_type == PPPOA_LCP){ autohunt(vcc, PPPoA_LCP, sizeof(PPPoA_LCP)); printk("Send PPPOA_LCP packet\n"); autohunt_pkt_type = PPPOED; } } else { // printk("procfile_write: disable SAR driver auto-pvc-search (%d,%d) auto_search_start %d found_pvc %d\n", vcc->vpi,vcc->vci, auto_search_start, found_pvc); found_pvc = 1; if( auto_search_start){ sscanf(proc_buffer, "%d %d,%d", &ok,&vpi,&vci); // printk("********** procfile_write: setting sar_dev (%d, %d) **********\n", vpi,vci); #ifdef CONFIG_RTL8672 Enable_Drop_NonOAM(sar_dev,OAM_CH_NO+1); #else Enable_Drop_NonOAM(sar_dev,OAM_CH_NO); #endif // Mason Yu. Recieve packet from OAM ch1(not cho) for AutoHunt #ifdef CONFIG_RTL8672 Disable_rx_ch(cp, OAM_CH_NO+1); #endif detect_vpi = vpi; detect_vci = vci; // detect_framing =0; //fixme auto_search_start=0; } } return count; } #endif #define DEV_LABEL "ratm" //#ifdef CONFIG_EXT_SWITCH extern int enable_ipqos; sar_private *sar_dev; struct tasklet_struct *sar_rx_tasklets=NULL; extern struct net_device *eth_net_dev; #ifdef FAST_ROUTE_Test //tylo, for linux 2.6 porting extern int fast_route_mode; int fast_frame_up=1; typedef struct _ch_val { unsigned long counter; //counts the tiny (<256bytes) pkt of this CH unsigned long start_stamp; //records the first tiny pkt of this CH arrivaled time int tx_inuse_counter; //for store the vcc->tx_inuse value before change to fast_route_mode } ch_val; ch_val ch_counter[Enable_VC_CNT]; #define MAX_MAC_ADDR 8 typedef struct _mac_table_items { unsigned int index; unsigned int enable; uint8 mac[MAX_MAC_ADDR][6]; } mac_table_items; mac_table_items fast_route_ch_no[Enable_VC_CNT]; #endif //for Auto PVC-Search unsigned int tr069_pid = 0; unsigned int boa_pid=0; //Records startup process ID #if defined(CONFIG_REMOTE_ADSL_PHY) struct atm_vcc *get_atmvcc_by_channel(char ch_no) { sar_private *cp = sar_dev; return cp->vcc[(int)ch_no].dev_data; } #endif #ifdef AUTO_PVC_SEARCH unsigned int sntp_pid=0; //Records sntp process ID /* * Found PVC * Sets the correct PVC and enables CH 0 rx and dropping nonoam cell. * Notify startup process we found PVC and recreate the connection. */ extern long sys_kill(int pid, int sig); //1__SWAP void foundVC(uint8 vpi,uint16 vci,int framing, int rfc) { sar_private *cp = sar_dev; found_pvc = 1; //Enable_rx_ch(sar_dev,0); #ifdef CONFIG_RTL8672 Enable_Drop_NonOAM(sar_dev,OAM_CH_NO+1); #else Enable_Drop_NonOAM(sar_dev,OAM_CH_NO); #endif printk("%s: (vpi,vci,framing,rfc) = (%d,%d,%d,%d)\n", __func__, vpi, vci, framing, rfc); Disable_rx_ch(cp, OAM_CH_NO+1); detect_vpi = vpi; detect_vci = vci; detect_framing = framing; memset(procfs_buffer, 0, PROCFS_MAX_SIZE); sprintf(procfs_buffer, "%d,%d,%d,%d", vpi,vci,framing,rfc); if(boa_pid) { printk("%s: kill SIGUSR2 signal to process boa (%d)\n", __func__, boa_pid); sys_kill(boa_pid, SIGUSR2); //raise sigusr2 to process boa } else { printk("%s: startup process is gone??\n", __func__); } } /* * Received none-OAM cell * Check the PVC of none-OAM cell and protocol */ __SWAP void search_autohunt(sar_private *cp) { int8 j=0; RV_STS_DESC *RVDesc=NULL; unsigned char *outband_cell; uint8 rx_vpi; uint16 rx_vci; int framing = LLC_SNAP, rfc_mode = RFC1483_BRIDGED; j=cp->vcc[OAM_CH_NO+1].RV.desc_pr; // Mason Yu. Recieve packet from OAM ch1(not cho) for AutoHunt #ifdef CONFIG_RTL8672 if(!(cp->RODesc[j+ SAR_RX_RING_SIZE].STS&OWN)) #else if(!(cp->RODesc[j].STS&OWN)) #endif { // Mason Yu. Recieve packet from OAM ch1(not cho) for AutoHunt #ifdef CONFIG_RTL8672 RVDesc=(RV_STS_DESC *)&cp->RODesc[j+ SAR_RX_RING_SIZE]; #else RVDesc=(RV_STS_DESC *)&cp->RODesc[j]; #endif outband_cell=(unsigned char *)RVDesc->START_ADDR; rx_vpi=(uint8)(outband_cell[0]<<4|outband_cell[1]>>4); rx_vci=(uint16)(outband_cell[1]<<12|outband_cell[2]<<4|outband_cell[3]>>4); printk("%s: receiving %d/%d\n", __FUNCTION__, rx_vpi, rx_vci); if (isPVCActiveExist(rx_vpi, rx_vci)) { //pvc match, check packet type #if 0 int i; for(i=0;i<0x30;i++){ if(i%0x10==0) printk("\n"); printk("%.02x ",outband_cell[i]); } printk("\n\n"); #endif if( (outband_cell[4]==0xaa) && (outband_cell[5]==0xaa) && (outband_cell[6]==0x03)) { framing = LLC_SNAP; if((outband_cell[7]==0x00) && (outband_cell[8]==0x80) && (outband_cell[9]==0xc2)) { rfc_mode = RFC1483_BRIDGED; printk("%s(%d) llc bridged\n", __FUNCTION__, __LINE__); } else if ((outband_cell[7]==0x00) && (outband_cell[8]==0x00) && (outband_cell[9]==0x00)) { rfc_mode = RFC1483_ROUTED; printk("%s(%d) llc routed\n", __FUNCTION__, __LINE__); } else { rfc_mode = RFC1483_BRIDGED; printk("%s(%d) llc unknown, treated as bridged\n", __FUNCTION__, __LINE__); } } else if( (outband_cell[4]==0xfe) && (outband_cell[5]==0xfe) && (outband_cell[6]==0x03) && (outband_cell[7]==0xcf) && (outband_cell[8]==0xc0 && (outband_cell[9]==0x21))) { framing = LLC_SNAP; rfc_mode = RFC2364; // PPPoA printk("%s(%d) llc PPPoA\n", __FUNCTION__, __LINE__); } else { framing = VC_MUX; if( (outband_cell[4]==0x00) && (outband_cell[5]==0x00)) { rfc_mode = RFC1483_BRIDGED; printk("%s(%d) vcmux bridged\n", __FUNCTION__, __LINE__); } else if ((outband_cell[4]==0xc0) && (outband_cell[5]==0x21)) { rfc_mode = RFC2364; // PPPoA printk("%s(%d) vcmux PPPoA\n", __FUNCTION__, __LINE__); } else { rfc_mode = RFC1483_ROUTED; printk("%s(%d) vcmux routed\n", __FUNCTION__, __LINE__); } } foundVC(rx_vpi, rx_vci,framing, rfc_mode);//VCMuxHdr802_3 }// is pvc active exist RVDesc=NULL; } //->RODesc[j].STS&OWN) } #endif //UCHAR SarMacAddr[6]={0x00, 0x00, 0x00, 0x04, 0x05, 0x06}; UCHAR LLCHdr802_3[10] = {0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00}; UCHAR VCMuxHdr802_3[2] = {0x00, 0x00}; UCHAR LLCHdrRoutedIP[8] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00}; UCHAR VCMuxHdrRoutedIP[1] = {0x00}; UCHAR ARP_1577[8] = {0xAA,0xAA,0x03,0x00,0x00,0x00,0x08,0x06}; UCHAR DATA_1577[8] = {0xAA,0xAA,0x03,0x00,0x00,0x00,0x08,0x00}; UCHAR *FrameHeader_1483[4]={ LLCHdr802_3, /* RFC1483_BR_LLC, LLC/SNAP for 802.3 */ VCMuxHdr802_3, /* RFC1483_BR_VCMux, VC Mux for 802.3 */ LLCHdrRoutedIP, /* RFC1483_RT_LLC, LLC/SNAP for routed ip*/ VCMuxHdrRoutedIP /* RFC1483_RT_VCMux, VC Mux for routed ip should be NULL encap */ }; UCHAR *FrameHeader_1577[2]={ ARP_1577, /* for Arp Packet */ DATA_1577 /* for Data Packet */ }; int8 FrameHeaderSize_1483[4]={0x0A, 0x02, 0x08, 0x00}; int8 FrameHeaderSize_1577[2]={0x08, 0x08}; #ifdef CONFIG_PORT_MIRROR int8 FrameHeaderSize_2364[2]={4, 0}; // {LLC, VC-MUX} UCHAR Fake_MAC_addr_header[14] = {0x00,0x06,0x68,0x89,0x90,0x06,0x00,0x66,0x88,0x99,0x00,0x66,0xFF,0xFF}; UCHAR Fake_PPPoE_header[6] = {0x11,0x00,0x56,0x78,0xFF,0xFF}; #define MAC_PROTOCOL_POS 12 #define PPPOE_LENGTH_POS 4 #define FILL_MAC_ADDR 0x01 #define FILL_PPPOE_HEADER 0x02 #endif //1/1/06' hrchen, desc # of a PVC is depended on total PVC numbers int total_pvc_number=0, per_vc_desc_number=0; //1/13/06' hrchen, for desc num re-assign static int current_desc_number[Enable_VC_CNT]; //record current desc # of a PVC #ifdef SAR_RX_FORMATION static struct sk_buff *free_rx_skb_list[SAR_MAX_Process_DESC]; //free skb list static int free_rx_skb_producer=0; //location to put free skb static int free_rx_skb_consumer=SAR_MAX_Process_DESC-1; //location to get free skb static int busy_channel[Enable_VC_CNT]; static int do_formation; #endif // of SAR_RX_FORMATION // for debug int debug_obaal5=0; int debug_obcell=0; int debug_num2print=100; /* These identify the driver base version and may not be removed. */ //static char version[] __devinitdata = // KERN_INFO DRV_NAME " sar driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; MODULE_AUTHOR("Jonah Chen <jonah@realtek.com.tw>"); MODULE_DESCRIPTION("RealTek RTL-8670 series SAR driver"); MODULE_LICENSE("GPL"); /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). The RTL chips use a 64 element hash table based on the Ethernet CRC. */ static int multicast_filter_limit = 32; /* bitmapped message enable number */ static int debug = -1; module_param(debug, int, 0); MODULE_PARM_DESC (debug, "sar bitmapped message enable number"); /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). The RTL chips use a 64 element hash table based on the Ethernet CRC. */ module_param(multicast_filter_limit, int, 0); MODULE_PARM_DESC (multicast_filter_limit, "8139cp maximum number of filtered multicast addresses"); #define PFX DRV_NAME ": " extern void enable_lx4180_irq(int irq); extern void disable_lx4180_irq(int irq); //static void sar_tx (sar_private *cp); //static void sar_clean_rings (sar_private *cp); static void sar_close (struct atm_vcc *vcc); extern void FreeVcBuff(sar_private *cp, int8 ch_no); void set_atm_data_mode(int mode); // Kaohj -- map vc index to channel number int index_vc2ch(int vc_idx); #ifdef ATM_OAM void InitOAM(unsigned short Vpi, unsigned short Vci); #endif #ifdef CONFIG_PORT_MIRROR extern void nic_tx_mirror(struct sk_buff *skb); #endif static int sar_to_qos(int type) { switch(type) { case ATM_NONE: case ATM_UBR: return QoS_UBR; case ATM_CBR: return QoS_CBR; case ATM_VBR: return QoS_nrtVBR; default: return QoS_rtVBR; } } #ifdef CONFIG_PORT_MIRROR /* non-reentrant */ static void sar_port_mirror(sar_private *cp, int ch_no, struct sk_buff *skb, int dir) { struct sk_buff *skb_mirror; //struct net_device *net_dev = (struct net_device *)atm_vcc->net_dev; int cut_len = 0, fill_flag = 0, fill_len = 0, encap_mode; unsigned char *mac_header = NULL; if ((sar_mirror_flag & dir) || (cp->vcc[ch_no].mirror_mode & dir)) { switch (cp->vcc[ch_no].rfc) { case RFC1483_BRIDGED: /* with mac */ encap_mode = cp->vcc[ch_no].rfc * 2 + cp->vcc[ch_no].framing; cut_len = FrameHeaderSize_1483[encap_mode]; mac_header = &(skb->data[cut_len]); #if 0 if (net_dev->priv_flags & IFF_BRIDGE_PORT) { /* Bridged interface; only frames from or to this device will be mirrored */ if (dir & PORT_MIRROR_OUT) { /* check source mac */ if (0 != memcmp(mac_header + ETH_ALEN, net_dev->dev_addr, ETH_ALEN)) { /* not sent by modem */ return; } } else { /* check dst mac */ if (0 != memcmp(mac_header, net_dev->dev_addr, ETH_ALEN)) { /* not sent to modem */ return; } } } #endif break; case RFC1483_ROUTED: /* fall through */ encap_mode = cp->vcc[ch_no].rfc * 2 + cp->vcc[ch_no].framing; cut_len = FrameHeaderSize_1483[encap_mode]; fill_flag = FILL_MAC_ADDR; if (VC_MUX == cp->vcc[ch_no].framing) { /* IPoA */ *(unsigned short *)(&Fake_MAC_addr_header[MAC_PROTOCOL_POS]) = (unsigned short)(0x0800); } else { /* aligned */ memcpy(&Fake_MAC_addr_header[MAC_PROTOCOL_POS], skb->data + cut_len - 2, sizeof(unsigned short)); } break; case RFC1577: cut_len = FrameHeaderSize_1577[0]; fill_flag = FILL_MAC_ADDR; memcpy(&Fake_MAC_addr_header[MAC_PROTOCOL_POS], skb->data + cut_len - 2, sizeof(unsigned short)); break; case RFC2364: cut_len = FrameHeaderSize_2364[cp->vcc[ch_no].framing]; fill_flag = FILL_PPPOE_HEADER | FILL_MAC_ADDR; *(unsigned short *)(&Fake_MAC_addr_header[MAC_PROTOCOL_POS]) = (unsigned short)(0x8864); break; default: return; } if (fill_flag & FILL_PPPOE_HEADER) { fill_len += sizeof(Fake_PPPoE_header); } if (fill_flag & FILL_MAC_ADDR) { fill_len += sizeof(Fake_MAC_addr_header); } /* reserve enough room */ if (NULL == (skb_mirror = skb_copy_expand(skb, fill_len + skb_headroom(skb), skb_tailroom(skb), GFP_ATOMIC))) { return; } skb_pull(skb_mirror, cut_len); if (NULL != mac_header) { /* when mirroring unicast frames, we should modify the dst mac, or they may * not be transmitted by 8305, bridge things. */ if (!(skb_mirror->data[0] & 0x1)) { skb_mirror->data[2] += 1; skb_mirror->data[3] += 1; } } /* Fill header */ if (fill_flag & FILL_PPPOE_HEADER) { *(unsigned short *)(&Fake_PPPoE_header[PPPOE_LENGTH_POS]) = (unsigned short)(skb_mirror->len); skb_push(skb_mirror, sizeof(Fake_PPPoE_header)); memcpy(skb_mirror->data, Fake_PPPoE_header, sizeof(Fake_PPPoE_header)); } if (fill_flag & FILL_MAC_ADDR) { skb_push(skb_mirror, sizeof(Fake_MAC_addr_header)); memcpy(skb_mirror->data, Fake_MAC_addr_header, sizeof(Fake_MAC_addr_header)); } /* mirror packets can be received on switch ports which are not bound. */ skb_mirror->vlan_member = 0; /* mirred to monitoring device */ skb_mirror->dev = cp->vcc[ch_no].monitor_dev; nic_tx_mirror(skb_mirror); } } #endif #ifdef SAR_RX_FORMATION //1/14/06' hrchen, reduce rx desc num for a PVC /* If we can't free enough desc, it means we get "Busy case!". There are pkts burst into this pvc. This pvc will extend desc in next run. Therefore, return reduce status is not necessary. */ #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif static int reduce_rx_desc(sar_private *cp, int ch_no, int sub_num) { int i, j, jm2; RV_STS_DESC *RVDesc, *jm2RVDesc; local_irq_disable(); //disable CPU local interrupts //move to last desc, free backward from last available desc j=(cp->vcc[ch_no].RV.desc_pr+current_desc_number[ch_no]-1)&(SAR_RX_DESC_NUM-1); jm2=(cp->vcc[ch_no].RV.desc_pr+current_desc_number[ch_no]-2)&(SAR_RX_DESC_NUM-1); for (i=0;i<sub_num;i++) { jm2RVDesc=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+jm2]; if (!(((int32)jm2RVDesc->STS)&OWN)) { //skb already receive a pkt, no more to free //printk("Busy case! %d\n", i); break; } //move this rx skb to free list RVDesc=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+j]; if (cp->vcc[ch_no].rx_buf[j]==(unsigned int)NULL) printk("error"); RVDesc->STS = 0; //set owner to cpu free_rx_skb_list[free_rx_skb_producer] = (struct sk_buff *)cp->vcc[ch_no].rx_buf[j]; cp->vcc[ch_no].rx_buf[j] = (UINT32)NULL; free_rx_skb_producer++; if (free_rx_skb_producer==SAR_MAX_Process_DESC) free_rx_skb_producer=0; //touch end, move to head current_desc_number[ch_no]--; if (current_desc_number[ch_no]<=SAR_RX_DESC_LOW_LIMIT) break; //reach low limit, stop reduce j = (j-1)&(SAR_RX_DESC_NUM-1); //1 desc ahead jm2 = (jm2-1)&(SAR_RX_DESC_NUM-1); //1 desc ahead } local_irq_enable(); return 0; } //1/14/06' hrchen, extend rx desc num for a PVC //rtn: 1 ok, 0 can not extend all desc at this run static int extend_rx_desc(sar_private *cp, int ch_no, int add_num) { int i, j, rtn=1; RV_STS_DESC *RVDesc; int tmp_consumer; struct sk_buff *skb; //move to last desc, allocate foreward from last free desc j=(cp->vcc[ch_no].RV.desc_pr+current_desc_number[ch_no])&(SAR_RX_DESC_NUM-1); for (i=0;i<add_num;i++) { tmp_consumer=free_rx_skb_consumer+1; //get a skb from free list if (tmp_consumer==SAR_MAX_Process_DESC) tmp_consumer=0; //touch end, move to head if (tmp_consumer==free_rx_skb_producer) { rtn=0; break; //no free skb }; if (current_desc_number[ch_no]>=SAR_RX_DESC_HI_LIMIT) break; //reach hi limit, stop extend //get a free skb, update counter current_desc_number[ch_no]++; free_rx_skb_consumer = tmp_consumer; //set & activate this rx desc RVDesc=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+j]; skb = free_rx_skb_list[tmp_consumer]; if (skb==NULL) printk("error\n"); RVDesc->START_ADDR=(UINT32)skb->data | Uncache_Mask; RVDesc->LEN=SAR_RX_Buffer_Size; cp->vcc[ch_no].rx_buf[j]= (UINT32)skb; RVDesc->STS= ((j!=(SAR_RX_DESC_NUM-1))?OWN:(OWN|EOR)); //set owner to device j = (1 + j)&(SAR_RX_DESC_NUM-1); //1 desc ahead }; return rtn; } //rtn:1 ok, 0 can't extend all desc for a pvc at this run static int change_formation(sar_private *cp, int ch_no, int ch_rx_num, int avg_desc_num) { int rtn=1; if (ch_rx_num==0) { //reduce desc int diff_num=current_desc_number[ch_no]-SAR_RX_DESC_LOW_LIMIT; if (diff_num==0) goto ret_change_formation; else { diff_num=(diff_num>8)?8:diff_num; //slow down reduce process reduce_rx_desc(cp, ch_no, diff_num); //printk("CFR%d %d\n", ch_no, diff_num); }; } else { //extend desc int diff_num=avg_desc_num - current_desc_number[ch_no]; if (diff_num==0) goto ret_change_formation; else if (diff_num<0) { diff_num=-diff_num; diff_num=(diff_num>8)?8:diff_num; //slow down reduce process reduce_rx_desc(cp, ch_no, diff_num); //printk("CFR%d %d\n", ch_no, diff_num); } else { rtn=extend_rx_desc(cp, ch_no, diff_num); //printk("CFE%d %d %d\n", ch_no, diff_num, rtn); }; }; ret_change_formation: return rtn; } #endif // of SAR_RX_FORMATION //2__SWAP void sar_rx_error_desc(sar_private *cp, uint8 ch_no, RV_STS_DESC *RVDesc, struct sk_buff *skb, int8 *j,RV_STS_DESC *enable_RVDesc,int8 *enable_j) { //Error_Desc: cp->vcc[ch_no].stat.rx_desc_fail++; cp->vcc[ch_no].stat.rx_pkt_fail++; //RVDesc->STS &= 0x4FFF; #if 0 if(ch_no==OAM_CH_NO) RVDesc->LEN=SAR_OAM_Buffer_Size; else RVDesc->LEN=SAR_RX_Buffer_Size; /* Fill Descriptor with old skb */ RVDesc->STS= ((*j!=(SAR_RX_DESC_NUM-1))?OWN:(OWN|EOR)); //cp->vcc[ch_no].rx_buf[*j]=(UINT32)skb; *j = (1 + *j)&(SAR_RX_DESC_NUM-1); RVDesc = (*j==0)?(&cp->RVDesc[ch_no*SAR_RX_RING_SIZE]):(RVDesc+1); //k= GetRxCDOI(cp, ch_no); #else if(ch_no==OAM_CH_NO) enable_RVDesc->LEN=SAR_OAM_Buffer_Size; else enable_RVDesc->LEN=SAR_RX_Buffer_Size; enable_RVDesc->START_ADDR=(UINT32)skb->data | Uncache_Mask; enable_RVDesc->STS= ((*enable_j!=(SAR_RX_DESC_NUM-1))?OWN:(OWN|EOR)); cp->vcc[ch_no].rx_buf[*enable_j]=(UINT32)skb; cp->vcc[ch_no].rx_buf[*j]=(UINT32)NULL; *j = (1 + *j)&(SAR_RX_DESC_NUM-1); //RVDesc=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+*j]; //printk("next j:%d\n",*j); *enable_j=(1 + *enable_j)&(SAR_RX_DESC_NUM-1); //enable_RVDesc=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+*enable_j]; //RVDesc = (*j==0)?(&cp->RVDesc[ch_no*SAR_RX_RING_SIZE]):(RVDesc+1); //enable_RVDesc= (*enable_j==0)?(&cp->RVDesc[ch_no*SAR_RX_RING_SIZE]):(enable_RVDesc+1); #endif } #ifdef ZTE_531B_TEST //3__SWAP void sar_rx_err_process(sar_private *cp, uint8 ch_no, RV_STS_DESC **RVDesc, struct sk_buff *skb, int *j,RV_STS_DESC **enable_RVDesc,int *enable_j) { cp->vcc[ch_no].stat.rx_desc_fail++; cp->vcc[ch_no].stat.rx_pkt_fail++; //RVDesc->STS &= 0x4FFF; #if 0 if(ch_no==OAM_CH_NO) RVDesc->LEN=SAR_OAM_Buffer_Size; else RVDesc->LEN=SAR_RX_Buffer_Size; /* Fill Descriptor with old skb */ RVDesc->STS= ((*j!=(SAR_RX_DESC_NUM-1))?OWN:(OWN|EOR)); //cp->vcc[ch_no].rx_buf[*j]=(UINT32)skb; *j = (1 + *j)&(SAR_RX_DESC_NUM-1); RVDesc = (*j==0)?(&cp->RVDesc[ch_no*SAR_RX_RING_SIZE]):(RVDesc+1); //k= GetRxCDOI(cp, ch_no); #else if(ch_no==OAM_CH_NO) (*enable_RVDesc)->LEN=SAR_OAM_Buffer_Size; else (*enable_RVDesc)->LEN=SAR_RX_Buffer_Size; (*enable_RVDesc)->START_ADDR=(UINT32)skb->data | Uncache_Mask; (*enable_RVDesc)->STS= ((*enable_j!=(SAR_RX_DESC_NUM-1))?OWN:(OWN|EOR)); cp->vcc[ch_no].rx_buf[*enable_j]=(UINT32)skb; cp->vcc[ch_no].rx_buf[*j]=(UINT32)NULL; *j = (1 + *j)&(SAR_RX_DESC_NUM-1); (*RVDesc)=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+*j]; //printk("next j:%d\n",*j); *enable_j=(1 + *enable_j)&(SAR_RX_DESC_NUM-1); (*enable_RVDesc)=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+*enable_j]; //RVDesc = (*j==0)?(&cp->RVDesc[ch_no*SAR_RX_RING_SIZE]):(RVDesc+1); //enable_RVDesc= (*enable_j==0)?(&cp->RVDesc[ch_no*SAR_RX_RING_SIZE]):(enable_RVDesc+1); #endif //(*RVDesc)=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+*j]; //(*enable_RVDesc)=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+*enable_j]; } #endif int pvc_exist(sar_private *cp, int vpi, int vci) { int i; for (i=0;i<Enable_VC_CNT;i++) { if (cp->vcc[i].vpi==vpi){ if (cp->vcc[i].vci==vci) return 1; else { if (vci == 3) return 3; if (vci == 4) return 4; } } } return 0; } // Mason Yu. Recieve packet from OAM ch1(not cho) for AutoHunt //#ifdef CONFIG_RTL8672 // handle RO0 CH OAM Cell receiving static BOOL sar_rx_outband0 (sar_private *cp) { DRV_ENTER int8 j; RV_STS_DESC *RVDesc; uint8 ch_no; #ifdef AUTO_PVC_SEARCH unsigned char * oamData; //Check the indication field of receiving OAM cell for auto_pvc search #endif ch_no = OAM_CH_NO; j=cp->vcc[ch_no].RV.desc_pr; cp->vcc[ch_no].stat.rcv_cnt++; /* working on descriptors */ while(!(cp->RODesc[j].STS&OWN)){ unsigned int *ptr; int vpi, vci; /* Drop OAM cell now */ cp->vcc[ch_no].stat.rx_oam_count++; RVDesc = (RV_STS_DESC*)&cp->RODesc[j]; /* printk("%s: dealing RODesc[%d] (0x%08x)now!\n", __func__, j+SAR_RX_RING_SIZE*(ch_no-OAM_CH_NO),(unsigned int )RVDesc); printk("%s: \nRVDesc->STS %x LEN %x\n", __func__, RVDesc->STS, RVDesc->LEN); printk("RVDesc->START_ADDR %x\n", RVDesc->START_ADDR); */ #if 1 // ptr = (unsigned int *)RVDesc->START_ADDR; ptr = (unsigned int *)(RVDesc->START_ADDR | Uncache_Mask); vpi = (*ptr>>20)&0x000000FF; vci = (*ptr>>4)&0x0000FFFF; //cp->vcc[ch_no].stat.rx_FS_cnt++; //cp->vcc[ch_no].stat.rx_LS_cnt++; //cp->vcc[ch_no].stat.rx_desc_cnt++; #ifdef ATM_OAM { int oam_type; //status = RVDesc->STS; if(RVDesc->STS&0x0100) { //only responce what PVC you have #ifdef AUTO_PVC_SEARCH oamData = (unsigned char *)RVDesc->START_ADDR; oam_type=(RVDesc->STS&0x00C0)>>6; if((oam_type == 0)||(oam_type == 1)) { // OAM F4 cell // only reply F4 OAM LB request and PVC had been existed if(oamData[OAM_FORMAT_LB_INDICATION] & 1) { if(pvc_exist(cp, vpi,vci)) OAMRxF4Cell((unsigned char *)(RVDesc->START_ADDR| Uncache_Mask), &OAMF4_info); } else { OAMRxF4Cell((unsigned char *)(RVDesc->START_ADDR| Uncache_Mask), &OAMF4_info); } } else if((oam_type == 2)||(oam_type == 3)) { // OAM F5 cell // Only reply F5 OAM LB request and PVC had been existed if(oamData[OAM_FORMAT_LB_INDICATION] & 1) { if(pvc_exist(cp, vpi,vci)) OAMRxF5Cell((unsigned char *)(RVDesc->START_ADDR| Uncache_Mask), &OAMF5_info); } else { OAMRxF5Cell((unsigned char *)(RVDesc->START_ADDR| Uncache_Mask), &OAMF5_info); } } #else //AUTO_PVC_SEARCH if (pvc_exist(cp, vpi, vci)) { #if 1 oam_type=(RVDesc->STS&0x00C0)>>6; if((oam_type == 0)||(oam_type == 1)) { // OAM F4 cell OAMRxF4Cell((unsigned char *)(RVDesc->START_ADDR| Uncache_Mask), &OAMF4_info); } else if((oam_type == 2)||(oam_type == 3)) { // OAM F5 cell OAMRxF5Cell((unsigned char *)(RVDesc->START_ADDR| Uncache_Mask), &OAMF5_info); } #else process_aal0(cp, (unsigned char *)RVDesc->START_ADDR); #endif }; #endif //AUTO_PVC_SEARCH } } #endif #ifdef REMOTE_MANAGEMENT_ENABLE //for Remote Management channel 0/16 #ifndef RM_TEST if ((vpi==0)&&(vci==16)) { #else if ((vpi==1)&&(vci==39)) { #endif struct atm_vcc * atm_vcc = cp->vcc[ch_no-1].dev_data; OutBandAAL5Rx(atm_vcc, (unsigned char *)(RVDesc->START_ADDR| Uncache_Mask)); }; #endif /* Restore LEN and CMD field */ RVDesc->LEN=SAR_OAM_Buffer_Size; RVDesc->STS= ((j!=(SAR_RX_DESC_NUM-1))?OWN:(OWN|EOR)); #endif // #if 0 /* Next Descriptor */ //cp->vcc[ch_no].RV.desc_pr = j = (1 + j)%SAR_RX_DESC_NUM; j = (1 + j)&(SAR_RX_DESC_NUM-1); //k= GetRxCDOI(cp, ch_no); } /* end of while */ /* Restore Descriptor Index */ cp->vcc[ch_no].RV.desc_pr = j; //cp->ProcessRcv = 0; cp->vcc[ch_no].stat.rcv_ok++; return SUCCESS; } //#endif // Mason Yu. Recieve packet from OAM ch1(not cho) for AutoHunt // handle RO1 none-OAM Cell receiving static BOOL sar_rx_outband1 (sar_private *cp) { int8 j; RV_STS_DESC *RVDesc; #ifdef AUTO_PVC_SEARCH if(!found_pvc && auto_search_start) search_autohunt(cp); #endif j=cp->vcc[OAM_CH_NO+1].RV.desc_pr; while(!(cp->RODesc[j+SAR_RX_RING_SIZE].STS&OWN)){ RVDesc = (RV_STS_DESC*)&cp->RODesc[j+SAR_RX_RING_SIZE]; /* Restore LEN and CMD field */ RVDesc->LEN=SAR_OAM_Buffer_Size; RVDesc->STS= ((j!=(SAR_RX_DESC_NUM-1))?OWN:(OWN|EOR)); /* Next Descriptor */ j = (1 + j)&(SAR_RX_DESC_NUM-1); } /* Restore Descriptor Index */ cp->vcc[OAM_CH_NO+1].RV.desc_pr = j; return SUCCESS; } #ifdef FAST_ROUTE_Test void learn_mac (uint8 *buf, int ch_no) { int i; /* printk("learn_mac got called MAC=%02x%02x%02x %02x%02x%02x buf[0] & 0x01 = %02x\n", buf[0],buf[1],buf[2],buf[3],buf[4],buf[5], buf[0] & 0x01); */ // check if pkt is boardcast or multicast if( (buf[0] & 0x01) == 0x00 ) // No, it's not board/multi-cast pkt { //mac table full! restart record the mac address from index 0 if(fast_route_ch_no[ch_no].index == MAX_MAC_ADDR-1 ) fast_route_ch_no[ch_no].index = 0; // search mac table from 0 to 7 for(i=0; i < MAX_MAC_ADDR; i++) { if(!memcmp(buf, fast_route_ch_no[ch_no].mac[i], 6)) { // printk("Learning a MAC address on CH %d\n", ch_no); break; } } // add a new one in mac table[index] if(i == MAX_MAC_ADDR ) { memcpy(fast_route_ch_no[ch_no].mac[ fast_route_ch_no[ch_no].index++], buf, 6); /* printk("Added one MAC address %02x %02x %02x %02x %02x %02x CH %d index %d\n", buf[0],buf[1],buf[2],buf[3],buf[4],buf[5], ch_no, fast_route_ch_no[ch_no].index-1); */ } } } unsigned int found_counter=9; unsigned int find_mac( uint8 *buf) { unsigned int i,j, ch_no=-1; /* printk("Finding MAC address %02x %02x %02x %02x %02x %02x \n", buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]); */ if( (buf[0] & 0x01) == 0x00 ) { for(i=0; i< Enable_VC_CNT; i++) { for(j=0; j< MAX_MAC_ADDR; j++) { if(!memcmp(buf, fast_route_ch_no[i].mac[j], 6) ) { ch_no = i; if(found_counter != ch_no) { /* printk("Found MAC address %02x %02x %02x %02x %02x %02x on CH %d\n", buf[0],buf[1],buf[2],buf[3],buf[4],buf[5], ch_no); */ found_counter = ch_no; } break; } } } } if(ch_no != -1) return ch_no; /* printk("Cannot found MAC address %02x %02x %02x %02x %02x %02x, using default CH 0\n", buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]); */ return -1; //cannot find it } void print_mac_tbl(void) { int i,j; //char buf[6] = {0x00,0x00,0x00,0x00,0x00,0x00}; printk("FAST_ROUTE_Test mode %d\n", fast_route_mode); for(i=0; i< Enable_VC_CNT; i++) { printk("CH %d\nindex: %d enable %d\n", i, fast_route_ch_no[i].index, fast_route_ch_no[i].enable); for(j=0; j< MAX_MAC_ADDR; j++) { printk("%02x %02x %02x %02x %02x %02x\n", fast_route_ch_no[i].mac[j][0], fast_route_ch_no[i].mac[j][1], fast_route_ch_no[i].mac[j][2], fast_route_ch_no[i].mac[j][3], fast_route_ch_no[i].mac[j][4], fast_route_ch_no[i].mac[j][5] ); } } } extern void nic_tx(struct sk_buff *skb); #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif void sar_tx(struct sk_buff *skb, unsigned int ch_no) { struct atm_vcc * atm_vcc = sar_dev->vcc[ch_no].dev_data; // Add LLCHdr802_3 header before transmitting memcpy(skb_push(skb, 0x0a), LLCHdr802_3, 0x0a); local_irq_disable(); sar_send(atm_vcc, skb); local_irq_enable(); } #endif #ifdef ZTE_531B_TEST #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif void sar_tasklet_schedule(sar_private *cp) { tasklet_hi_schedule(&cp->tasklets); } //1__SWAP // Kaohj /* * Process received packets; Function relative to external switch. */ int sar_rx_sw(struct atm_vcc *vcc, struct sk_buff *skb) { sar_private *cp = RTATM_DEV(vcc->dev); sar_atm_vcc *vcc_dev = RTATM_VCC(vcc); int ch_no; int encap_mode; ch_no = vcc_dev->ch_no; encap_mode = cp->vcc[ch_no].rfc*2+cp->vcc[ch_no].framing; // Kaohj -- for testing; open this to add vlan tag on rx #if 0 { int i, copy_len; unsigned char tag_info[4]={0x81, 0x00, 0x00, 0x64}; copy_len = FrameHeaderSize_1483[encap_mode]+12; skb_push(skb, 4); for (i=0; i<copy_len; i++) skb->data[i] = skb->data[i+4]; memcpy(&skb->data[copy_len], tag_info, 4); } #endif // Port-Mapping: set the membership that this packet belongs to // This information should be passed to Ethernet skb->vlan_member = vcc->ifgrp.member; #ifdef CONFIG_RTL_MULTI_PVC_WAN if (*(unsigned short *)(skb->data+FrameHeaderSize_1483[encap_mode]+12) == 0x8100) { // find vlan Tag(TCI) unsigned short vtag; // find associated VLAN vtag = *(unsigned short *)(skb->data+FrameHeaderSize_1483[encap_mode]+14) ; skb->mark=vtag>>13; // assign vtag into vlan_tci skb->vlan_tci = vtag+1; // remove vlan tag //memmove(skb->data + VLAN_HLEN, skb->data, 12+FrameHeaderSize_1483[encap_mode]); //skb_pull(skb, VLAN_HLEN); //printk("sar_rx_sw: Remove vlan Tag. skb->vlan_tci=0x%x\n", skb->vlan_tci); } #else /*wt-146, ethprio*/ if(vcc->pvcvlan.vlan) { // 1483_br_llc && vlan tag if (cp->vcc[ch_no].rfc == RFC1483_BRIDGED && *(unsigned short *)(skb->data+FrameHeaderSize_1483[encap_mode]+12) == 0x8100) { unsigned short vtag; vtag = *(unsigned short *)(skb->data+FrameHeaderSize_1483[encap_mode]+14) ; /*linux-2.6.19*/ //skb->nfmark=vtag>>13; skb->mark=vtag>>13; } } #endif return 1; } void sar2nic(sar_private *cp, struct sk_buff *skb, int ch_no, int16 total_len) { struct atm_vcc * atm_vcc = cp->vcc[ch_no].dev_data; #ifdef FAST_ROUTE_Test // Kaohj // in normal path; go fast-bridge next time if in fast-bridge fast_frame_up = 0; #endif if (atm_charge (atm_vcc, skb->truesize)) { ATM_SKB(skb)->vcc = atm_vcc; skb->dev = cp->dev; cp->vcc[ch_no].stat.rx_byte_cnt += (int)total_len; //skb->tstamp = xtime; //sar_rx_sw(atm_vcc, skb); atomic_inc(&atm_vcc->stats->rx); __net_timestamp(skb); skb_pvc_debug(skb, ch_no, 0); // end of our responsability atm_vcc->push (atm_vcc, skb); } else { printk(KERN_INFO "SAR: drop due to atm_charge.ch%d(%d/%d)\n",ch_no,cp->vcc[ch_no].vpi,cp->vcc[ch_no].vci); } } #endif //for small pkt int rx_small_pkt=0; //static int maxRdaCount=15; __IRAM_SAR static int sar_rx (sar_private *cp, int ch_no) { DRV_ENTER int j,enable_j; int16 total_len; //BOOL rc= TRUE; int32 status; RV_STS_DESC *RVDesc,*enable_RVDesc; struct sk_buff *skb, *tmpskb; int rx_num=0; unsigned long flags; //static int rdaCount=0; //#ifdef CONFIG_EXT_SWITCH //int encap_mode; //#endif #ifdef FAST_ROUTE_Test static unsigned int fastBridgeEnable =0, fastBridgeStartStamp=0, fastBridgeSmallPktCount=0; #endif //FAST_ROUTE_Test spin_lock_irqsave(&cp->rxlock, flags); j=cp->vcc[ch_no].RV.desc_pr; enable_j=(j+current_desc_number[ch_no])&(SAR_RX_RING_SIZE-1); RVDesc = &cp->RVDesc[ch_no*SAR_RX_RING_SIZE+j]; enable_RVDesc= &cp->RVDesc[ch_no*SAR_RX_RING_SIZE+enable_j]; //jim add to avoid BUG() called when skb==NULL, caused by sar_closed and interrupted to process rx action... if(cp->vcc[ch_no].created == VC_NOT_CREATED){ spin_unlock_irqrestore(&cp->rxlock, flags); return 0; } if (stop_rx){ spin_unlock_irqrestore(&cp->rxlock, flags); return 0; } //cp->vcc[ch_no].stat.rcv_cnt++; /* working on descriptors */ //while(((j!=k)||(!(cp->RVDesc[ch_no*SAR_RX_RING_SIZE+j].STS&OWN)))&&(i<SAR_MAX_Process_DESC)){ while(!((status=(int32)RVDesc->STS)&OWN)){ int len_err; //if(j==63) break; //for debug /* this descriptor is still own by hardware, exit this loop */ // JONAH_DEBUG open //if(cp->RVDesc[ch_no*SAR_RX_RING_SIZE+j].STS&OWN) // break; ////patch to increase interrupt times. //if (rdaCount++ > maxRdaCount) { // Enable_IERDA(sar_dev); // rdaCount = 0; //} /* Drop OAM cell now */ /* Handle this Descriptor, get recv skb */ skb=(struct sk_buff *)cp->vcc[ch_no].rx_buf[j]; if (!skb) { printk("[%s] unable to get skb from rx_buf, j = %d\n", __func__, j); BUG(); } #if 0 if(skb==(struct sk_buff *)NULL) { /* it mustn't happen, maybe we should reboot */ goto Next_Desc; } #endif if((status&(FS|LS))==(FS|LS)){ /* One descriptor contains one complete packet */ //cp->vcc[ch_no].stat.rx_FS_cnt++; //cp->vcc[ch_no].stat.rx_LS_cnt++; //cp->vcc[ch_no].stat.rx_desc_cnt++; if(status&LENErr) { len_err = 1; total_len = RVDesc->BPC_LENGTH; } else { len_err = 0; total_len = (RVDesc->LEN&LEN_Mask); } //for small pkt if(total_len<256) rx_small_pkt++; //if (total_len > 1518){ // cp->vcc[ch_no].stat.rx_lenb_error; // goto Error_Desc; // sar_rx_error_desc(cp, ch_no, RVDesc, skb, &j); // continue; // } if(total_len <= 0){ //goto Error_Desc; #ifndef ZTE_531B_TEST sar_rx_error_desc(cp, ch_no, RVDesc, skb, &j,enable_RVDesc,&enable_j); RVDesc=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+j]; enable_RVDesc=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+enable_j]; #else sar_rx_err_process(cp, ch_no, &RVDesc, skb, &j, &enable_RVDesc,&enable_j); #endif continue; } if(status&CRC32Err){ cp->vcc[ch_no].stat.rx_crc_error++; //goto Error_Desc; #ifndef ZTE_531B_TEST sar_rx_error_desc(cp, ch_no, RVDesc, skb, &j,enable_RVDesc,&enable_j); //printk("after err:%d %x\n",j,&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+j]); RVDesc=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+j]; enable_RVDesc=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+enable_j]; #else sar_rx_err_process(cp, ch_no, &RVDesc, skb, &j, &enable_RVDesc,&enable_j); #endif continue; } #ifdef CONFIG_SAR_SHARE_PRIV_SKB_WITH_ETH tmpskb = dev_alloc_skb_priv_eth(CROSS_LAN_MBUF_LEN); #else tmpskb = dev_alloc_skb(SAR_RX_Buffer_Size); #endif //CONFIG_SAR_SHARE_PRIV_SKB_WITH_ETH //tmpskb = rtl8671_getPreAlloc(); if (unlikely(tmpskb==NULL)){ //cp->vcc[ch_no].stat.rx_buf_lack++; //mark_bh(SAR_BH); //queue_task (&cp->bh, &tq_immediate); //mark_bh (IMMEDIATE_BH); //goto Error_Desc; //sar_rx_error_desc(cp, ch_no, RVDesc, skb, &j); cp->RDAI_Reg |= 1<<ch_no; #ifndef ZTE_531B_TEST tasklet_hi_schedule(&cp->tasklets); #else sar_tasklet_schedule(cp); #endif break; } /* Handle Word Insertion */ if(status&WII){ skb_reserve(skb, 2); if (!len_err) total_len-=2; } //1/5/05' tylo, pid=0x0001, discard CRC if(cp->vcc[ch_no].rfc==RFC1483_BRIDGED && cp->vcc[ch_no].framing==LLC_SNAP && skb->data[7]==0x01) total_len-=4; //skb_reserve(skb, FrameHeaderSize_1483[encap_mode]); #if 0 #ifdef LoopBack_Test total_len=Lying_Engine(skb->data, total_len); /*exchange_mac(skb->data);*/ #endif #endif skb_put(skb, total_len); #ifdef CONFIG_PORT_MIRROR sar_port_mirror(cp, ch_no, skb, PORT_MIRROR_IN); #endif #ifdef FAST_ROUTE_Test if (fast_route_mode&&cp->vcc[ch_no].br ) { // deals with the tiny pkt (specially 64 and 128 bytes) if(skb->len < 300) { //Not specific pkt type, this is a test pkt and just bridge it if((*(unsigned short *)(skb->data+0x16))==0x0000) { fastBridgeEnable = 1; fastBridgeSmallPktCount = 0; } else { if(fastBridgeStartStamp==0) fastBridgeStartStamp = jiffies; if(fastBridgeSmallPktCount++ > 20) { if(jiffies - fastBridgeStartStamp <= 1) { fastBridgeEnable = 1; fastBridgeSmallPktCount = 0; //shlee } else { fastBridgeStartStamp = jiffies; fastBridgeSmallPktCount = 0; fastBridgeEnable =0; } } } } else { fastBridgeEnable = 0; fastBridgeStartStamp = 0; fastBridgeSmallPktCount = 0; } } //if(fastBridgeEnable) if(fastBridgeEnable && !fast_frame_up) { #ifdef CONFIG_ETHWAN extern void nic_tx2(struct sk_buff *skb, struct net_device *tdev); #else extern void nic_tx2(struct sk_buff *skb); #endif //skb->dev = eth_net_dev; //skb->pkt_type = PACKET_FASTROUTE; if (skb->data[0]==0xaa) skb_pull(skb, 10); //printk("fix me nic_tx2()!"); skb->fastbr =1; spin_unlock_irqrestore(&cp->rxlock, flags); #ifdef CONFIG_ETHWAN nic_tx2(skb, NULL); #else nic_tx2(skb); #endif spin_lock_irqsave(&cp->rxlock, flags); }else { #endif //FAST_ROUTE_Test spin_unlock_irqrestore(&cp->rxlock, flags); #if defined(CONFIG_REMOTE_ADSL_PHY) cp->vcc[ch_no].stat.rx_byte_cnt += (int)total_len; rtk_adslphy_sar2eth(cp->vcc[ch_no].dev_data, skb, ch_no); #else sar2nic(cp, skb, ch_no, total_len); #endif spin_lock_irqsave(&cp->rxlock, flags); #ifdef FAST_ROUTE_Test } #endif }else { //goto Error_Desc; #ifndef ZTE_531B_TEST sar_rx_error_desc(cp, ch_no, RVDesc, skb, &j,enable_RVDesc,&enable_j); RVDesc=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+j]; enable_RVDesc=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+enable_j]; #else sar_rx_err_process(cp, ch_no, &RVDesc, skb, &j, &enable_RVDesc,&enable_j); #endif continue; } //cp->vcc[ch_no].stat.rx_desc_ok_cnt++; rx_num++; /* mask EOR and STS, clear OWN, FS, LS */ //RVDesc->STS &= 0x4FFF; //goto Next_Desc; //Error_Desc: //Next_Desc: //jim: we should invalidate cache to sure accessing DMAed data through cache. dma_cache_wback_inv((unsigned long)tmpskb->data, SAR_RX_Buffer_Size); #if 0 /* Fill Descriptor with new skb */ RVDesc->START_ADDR=(UINT32)tmpskb->data|Uncache_Mask; /* Restore LEN and CMD field */ RVDesc->LEN=SAR_RX_Buffer_Size; RVDesc->STS= ((j!=(SAR_RX_DESC_NUM-1))?OWN:(OWN|EOR)); cp->vcc[ch_no].rx_buf[j]=(UINT32)tmpskb; #else enable_RVDesc->START_ADDR=(UINT32)tmpskb->data | Uncache_Mask; enable_RVDesc->LEN=SAR_RX_Buffer_Size; cp->vcc[ch_no].rx_buf[enable_j]=(UINT32)tmpskb; enable_RVDesc->STS= ((enable_j!=(SAR_RX_DESC_NUM-1))?OWN:(OWN|EOR)); cp->vcc[ch_no].rx_buf[j]=(UINT32)NULL; //printk("enable_j:%d %x %x\n",enable_j,enable_RVDesc->STS,tmpskb); #endif /* Next Descriptor */ //cp->vcc[ch_no].RV.desc_pr = j = (1 + j)%SAR_RX_DESC_NUM; j = (1 + j)&(SAR_RX_DESC_NUM-1); //printk("next j:%d\n",j); enable_j=(1 + enable_j)&(SAR_RX_DESC_NUM-1); RVDesc=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+j]; enable_RVDesc=&cp->RVDesc[ch_no*SAR_RX_RING_SIZE+enable_j]; //RVDesc = (j==0)?(&cp->RVDesc[ch_no*SAR_RX_RING_SIZE]):(RVDesc+1); //enable_RVDesc= (enable_j==0)?(&cp->RVDesc[ch_no*SAR_RX_RING_SIZE]):(enable_RVDesc+1); //k= GetRxCDOI(cp, ch_no); } /* end of while */ /* Restore Descriptor Index */ cp->vcc[ch_no].RV.desc_pr = j; //cp->ProcessRcv = 0; //cp->vcc[ch_no].stat.rcv_ok++; cp->vcc[ch_no].stat.rx_pkt_cnt+=rx_num; AtmTraffic += rx_num; // Rx traffic tracks spin_unlock_irqrestore(&cp->rxlock, flags); return rx_num; } int sar_rbf=0; //1__SWAP __IRAM_SYS_MIDDLE void sar_rx_bh(sar_private *cp){ int ch_no; unsigned int RDAI_Reg, RBFI_Reg; unsigned long flags; #ifdef CONFIG_ATM_BONDING unsigned int is_asmtick; #endif /*CONFIG_ATM_BONDING*/ spin_lock_irqsave(&cp->rxlock, flags); #ifdef CONFIG_ATM_BONDING is_asmtick=gasmtick; gasmtick=0; #endif /*CONFIG_ATM_BONDING*/ RDAI_Reg = cp->RDAI_Reg; RBFI_Reg = cp->RBFI_Reg; cp->RDAI_Reg = 0; cp->RBFI_Reg = 0; spin_unlock_irqrestore (&cp->rxlock, flags); #ifdef CONFIG_ATM_BONDING if((is_asmtick) && (getADSLLinkStatus())) { //printk( "%s: call ASMTimeOut()\n", __FUNCTION__ ); if ( (*((unsigned int*)(0xb8302134)) & 0x1000) == 0 ) ASMTimeOut(); } #endif /*CONFIG_ATM_BONDING*/ if (RDAI_Reg&0x10000) { //Out band channel //printk("Recieve NonOAM packet from OB ch0\n"); spin_lock_irqsave(&cp->rxlock, flags); sar_rx_outband0(cp); RDAI_Reg&=~0x10000; spin_unlock_irqrestore (&cp->rxlock, flags); }; // Mason Yu. Recieve packet from OAM ch1(not cho) for AutoHunt #ifdef CONFIG_RTL8672 if (RDAI_Reg&0x20000) { //Out band channel 1 //printk("Recieve NonOAM packet from OB ch1\n"); spin_lock_irqsave(&cp->rxlock, flags); sar_rx_outband1(cp); RDAI_Reg&=~0x20000; spin_unlock_irqrestore (&cp->rxlock, flags); }; #endif if(RDAI_Reg) { int rx_num; #ifdef SAR_RX_FORMATION int pvc_rx_busy=0; int reformat_shape=FORMATION_NO_CHANGE; //do not change formation in default #endif for(ch_no=0;ch_no<Enable_VC_CNT;ch_no++){ if(RDAI_Reg&((UINT32)0x00000001) &&cp->vcc[ch_no].created == VC_CREATED) { // avoid receiveing NULL skb after delete VC rx_num=sar_rx(cp, ch_no); #ifdef SAR_RX_FORMATION if (do_formation) { if (rx_num>1) { //rx pkt number is large enough, candidate for desc increase if (busy_channel[ch_no]==0) { //this channel is not busy last time, we have to increase desc for it reformat_shape = FORMATION_CHANGE; //printk("BE %d %d\n",ch_no,rx_num); } else { //this channel is really busy and we have increase desc for it last time, leave it alone //printk("BN %d %d\n",ch_no,rx_num); }; busy_channel[ch_no] = rx_num; pvc_rx_busy++; } else { //rx pkt number is not large enough, candidate for desc reduce if (busy_channel[ch_no]!=0) { //this channel is not busy, decrease desc for it if (rx_num>0) { //if no rx pkt, it is a dummy alert and do no change formation reformat_shape = FORMATION_CHANGE; //printk("LR0 %d %d\n",ch_no,rx_num); }; } else { //this channel is not busy, decrease desc for it //printk("LR1 %d %d\n",ch_no,rx_num); }; busy_channel[ch_no] = 0; }; } // of do_formation #endif // of SAR_RX_FORMATION cp->vcc[ch_no].RDA_cnt++; }; RDAI_Reg>>=1; }; #ifdef SAR_RX_FORMATION if (do_formation) { if ( (FORMATION_CHANGE==reformat_shape)&&(0!=pvc_rx_busy) ) { //when 0==pvc_rx_busy, it means current formation can handle slow rx traffic. no need //formation change. int busy_ch_avg_desc_num; busy_ch_avg_desc_num=(SAR_MAX_Process_DESC-SAR_RX_DESC_LOW_LIMIT*total_pvc_number)/pvc_rx_busy+SAR_RX_DESC_LOW_LIMIT; for(ch_no=0;ch_no<Enable_VC_CNT;ch_no++){ if (!cp->vcc[ch_no].created) continue; if (0==change_formation(cp, ch_no, busy_channel[ch_no], busy_ch_avg_desc_num)) { //can't allocate enough desc, leave it to next run busy_channel[ch_no] = 0; }; }; }; } // of do_formation #endif // of SAR_RX_FORMATION } /* handle RBF */ if(RBFI_Reg){ /* Check each CH */ if (RBFI_Reg&0x10000) { //Out band channel spin_lock_irqsave(&cp->rxlock, flags); sar_rx_outband0(cp); Clear_RBF(cp, OAM_CH_NO, 0); spin_unlock_irqrestore (&cp->rxlock, flags); } #ifdef CONFIG_RTL8672 if (RBFI_Reg&0x20000) { //Out band channel 1 spin_lock_irqsave(&cp->rxlock, flags); sar_rx_outband1(cp); Clear_RBF(cp, OAM_CH_NO+1, 0); spin_unlock_irqrestore (&cp->rxlock, flags); } #endif for(ch_no=0;ch_no<Enable_VC_CNT;ch_no++){ if(RBFI_Reg&((UINT32)0x00000001) &&cp->vcc[ch_no].created == VC_CREATED) { // avoid receiveing NULL skb after delete VC sar_rx(cp, ch_no); spin_lock_irqsave(&cp->rxlock, flags); Clear_RBF(cp, ch_no, 0); cp->vcc[ch_no].stat.rx_rbf_count++; spin_unlock_irqrestore (&cp->rxlock, flags); } RBFI_Reg>>=1; } //continue to handle RBF, avoid sar rx stopping!! if((cp->RBFI_Reg|=reg(SAR_RBFI_Addr))!=0) tasklet_hi_schedule(&cp->tasklets); //Re-enable RBF int Enable_IERBF(sar_dev); } //7/25/05' hrchen, SAR_IRQ will be disabled if RDU happen. Open SAR_IRQ here. //enable_lx4180_irq(cp->irq); //scout(']'); //tylo, fpga //shlee 2.6 REG32(GIMR) |= SAR_IE ; //enable_irq(sar_irq); //shlee 2.6 //Enable_IERBF(sar_dev); if(sar_rbf==1){ for(ch_no=0;ch_no<Enable_VC_CNT;ch_no++){ if (!cp->vcc[ch_no].created) continue; REG32(RV_Ctrl_Addr+0x10*ch_no) &= (~CFD); } sar_rbf=0; } //Sachem disable cell discard // REG16(0xb8000c00) = 0x5023; //Enable_IERDA(sar_dev); //spin_unlock_irqrestore (&cp->rxlock, flags); return; } static void sar_tx_complete(unsigned long data) { sar_private *cp = (sar_private *)data; int ch; cp->TDFI_Reg=reg(SAR_TDFI_Addr); for(ch=0; ch<Enable_VC_CNT+1; ch++) { if (cp->TDFI_Reg&(1<<ch)) ClearTxBuffer(cp, ch); } reg(SAR_TDFI_Addr)=cp->TDFI_Reg; } extern char use_low_rate; #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif irqreturn_t sar_interrupt (int irq, void *dev_instance) { DRV_ENTER //struct atm_dev *dev = dev_instance; sar_private *cp = RTATM_DEV((struct atm_dev *)dev_instance); INT32 ch_no; //scout('3'); //shlee 1116 mask all interrupts about SAR /* cp->CNFG_Reg = reg(SAR_CNFG_Addr); reg(SAR_CNFG_Addr)&=~(IERBF|IERDA|IERTO|IETBE|IETDF); */ //shlee 1116 cp->STS_Reg=reg(SAR_STS_Addr); /* TDF */ if (cp->STS_Reg&TDF) { tasklet_schedule(&cp->tdf_tasklets); } #ifdef CONFIG_ATM_BONDING /* ASMTICK */ if(cp->STS_Reg&ASMTICK) { gasmtick=1; tasklet_hi_schedule(&cp->tasklets); } /* SID_ERR */ if(cp->STS_Reg&SID_ERR) //alway err??? { unsigned int bond_rsts; bond_rsts=reg(SAR_BOND_RSTS); if( bond_rsts&(MISS_SID|SMALL_SID) ) { if( bond_rsts&MISS_SID ) { printk( "%s: MISS_SID\n", __FUNCTION__ ); } if( bond_rsts&SMALL_SID ) { printk( "%s: SMALL_SID\n", __FUNCTION__ ); } }else{ printk( "%s: unknown BOND_RSTS=0x%08x\n", __FUNCTION__, bond_rsts ); } reg(SAR_BOND_RSTS)=bond_rsts; printk( "%s: clear BOND_RSTS=0x%08x\n", __FUNCTION__, reg(SAR_BOND_RSTS) ); } #endif /*CONFIG_ATM_BONDING*/ /* TDF */ /* TBE */ if((cp->TBEI_Reg=reg(SAR_TBEI_Addr)!=0)){ // printk("Deal with TBEI\n"); for(ch_no=0;ch_no<(Enable_VC_CNT+1);ch_no++){ if(!(cp->TBEI_Reg&((UINT32)0x00000001<<ch_no))) continue; /* cp->vcc[ch_no].TBE_cnt++; cp->vcc[ch_no].TBE_Flag=TRUE; */ Clear_TBE(ch_no, 0); } } /* RBF */ if(cp->STS_Reg&RBF){ #if 0 //8672 //Sachem cell discard enable REG16(0xb8000c00) = 0x50a3; if(sar_rbf==0){ //enable CFD for(ch_no=0;ch_no<Enable_VC_CNT;ch_no++){ if (!cp->vcc[ch_no].created) continue; REG32(RV_Ctrl_Addr+0x10*ch_no) |= CFD; } sar_rbf=1; } #endif // printk("RBF!!\n"); cntr_rbf++; // Disable RBF int (sar_rx will re-enable it) Disable_IERBF(sar_dev); if((cp->RBFI_Reg|=reg(SAR_RBFI_Addr))){ //7/25/05' hrchen, stop SAR IRQ, re-enabled in sar_rx_bh() //disable_lx4180_irq(cp->irq); //tylo, fpga //kernel irq_dispatch will ack this irq as disabled //if(REG32(GIMR)&SAR_IE) // REG32(GIMR) &= ~SAR_IE ; /*linux-2.6.19*/ //if(REG32(BSP_GIMR)&BSP_SAR_IE) // REG32(BSP_GIMR) &= ~BSP_SAR_IE ; //mark_bh(SAR_BH); //queue_task (&cp->bh, &tq_immediate); //mark_bh (IMMEDIATE_BH); //scout('f'); tasklet_hi_schedule(&cp->tasklets); //sar_rx_bh(cp); /* handle RX buffer first */ //rc = sar_rx(cp, ch_no); //cdoi= GetRxCDOI(cp, ch_no); /* Then clear RBF */ //if(rc==TRUE) Clear_RBF(ch_no, cdoi); //else Cell_Forced_Dropped(ch_no); }; } /* RDA */ if(cp->STS_Reg&RDA) { unsigned int RDAI_Reg; if((RDAI_Reg=reg(SAR_RDAI_Addr))){ reg(SAR_RDAI_Addr) = RDAI_Reg; //write to clear RDAI reg cp->RDAI_Reg |= RDAI_Reg; //7/25/05' hrchen, stop SAR IRQ, re-enabled in sar_rx_bh() //disable_lx4180_irq(cp->irq); //tylo, fpga //kernel irq_dispatch will ack this irq as disabled //if(REG32(GIMR)&SAR_IE) // REG32(GIMR) &= ~SAR_IE ; /*linux-2.6.19*/ //if(REG32(BSP_GIMR)&BSP_SAR_IE) // REG32(BSP_GIMR) &= ~BSP_SAR_IE ; //mark_bh(SAR_BH); //queue_task (&cp->bh, &tq_immediate); //mark_bh (IMMEDIATE_BH); //scout('r'); tasklet_hi_schedule(&cp->tasklets); //sar_rx_bh(cp); }; } reg(SAR_STS_Addr) = cp->STS_Reg; //shlee 1115 clear SAR_STS //shlee 1116 resume enabled interrupts about SAR /* reg(SAR_CNFG_Addr) = cp->CNFG_Reg; */ //shlee 1116 //spin_unlock(&cp->lock); return IRQ_RETVAL(1); } //#ifdef CONFIG_EXT_SWITCH //return 0: drop pkt //2__SWAP #define QOS_1P_ENABLE (1<<8) struct sk_buff *sar_send_vlan(struct atm_vcc *vcc,sar_private *cp,int ch_no, struct sk_buff *skb) { INT8 encap_mode ; char *vlan_p, *ether_type; if (skb_cow(skb, VLAN_HLEN) < 0) return 0; //vlan tagging encap_mode = cp->vcc[ch_no].rfc*2+cp->vcc[ch_no].framing; ether_type = skb->data + FrameHeaderSize_1483[encap_mode]+12; if(*(unsigned short *)ether_type == 0x8100){ vlan_p = skb->data + FrameHeaderSize_1483[encap_mode]+12; vlan_p+=2; *(unsigned short *)vlan_p = 0; // 3 bits priority #ifdef CONFIG_NETFILTER //*(unsigned short *)vlan_p |= ((skb->nfmark&0x7)<<13); /*linux-2.6.19*/ if (skb->mark&QOS_1P_ENABLE) { // IP_QoS 802.1p remarking *(unsigned short *)vlan_p |= ((skb->mark&0x7)<<13); } else #endif { #ifdef CONFIG_RTL_MULTI_PVC_WAN *(unsigned short *)vlan_p |= (skb->vlan_tci & 0xe000); #else if(vcc->pvcvlan.vlan_prio!=0) *(unsigned short *)vlan_p |= ((vcc->pvcvlan.vlan_prio-1) &0x7); #endif } // 12 bits vid #ifdef CONFIG_RTL_MULTI_PVC_WAN *(unsigned short *)vlan_p |= (skb->vlan_tci & 0x0fff); #else *(unsigned short *)vlan_p |= (vcc->pvcvlan.vid & 0x0fff); #endif } else{ int copy_len; //printk("hsize=%d\n", FrameHeaderSize_1483[encap_mode]); // add fram_header(rfc1483)+ethernet_header and reserve vlan 4-byte copy_len = FrameHeaderSize_1483[encap_mode]+12; skb_push(skb, VLAN_HLEN); memmove(skb->data, skb->data + VLAN_HLEN, copy_len); vlan_p = skb->data + copy_len; *(unsigned short *)vlan_p = 0x8100; vlan_p+=2; *(unsigned short *)vlan_p = 0; // Kaohj -- Add E8B support #ifdef CONFIG_E8B // 3 bits priority: if bit-16 is set on skb->mark, use value in skb->mark; // otherwise use value of per pvc's if applicable. #ifdef CONFIG_NETFILTER if (skb->mark & (1<<16)) { // marked by IPQoS *(unsigned short *)vlan_p |= ((skb->mark&0x7)<<13); } else { #ifdef CONFIG_RTL_MULTI_PVC_WAN *(unsigned short *)vlan_p |= (skb->vlan_tci & 0xe000); #else if (vcc->pvcvlan.vlan_prio) *(unsigned short *)vlan_p |= (((vcc->pvcvlan.vlan_prio-1) &0x7)<<13); #endif } #endif // 12 bits vid #ifdef CONFIG_RTL_MULTI_PVC_WAN *(unsigned short *)vlan_p |= (skb->vlan_tci & 0x0fff); #else *(unsigned short *)vlan_p |= (vcc->pvcvlan.vid & 0x0fff); #endif //printk("vtag=%x\n", *(unsigned short *)vlan_p); #else // 3 bits priority #ifdef CONFIG_NETFILTER //*(unsigned short *)vlan_p |= ((skb->nfmark&0x7)<<13); /*linux-2.6.19*/ if (skb->mark&QOS_1P_ENABLE) { // IP_QoS 802.1p remarking *(unsigned short *)vlan_p |= ((skb->mark&0x7)<<13); } else #endif { #ifdef CONFIG_RTL_MULTI_PVC_WAN *(unsigned short *)vlan_p |= (skb->vlan_tci & 0xe000); #else if(vcc->pvcvlan.vlan_prio!=0) *(unsigned short *)vlan_p |= (((vcc->pvcvlan.vlan_prio-1) &0x7)<<13); #endif } // 12 bits vid #ifdef CONFIG_RTL_MULTI_PVC_WAN *(unsigned short *)vlan_p |= (skb->vlan_tci & 0x0fff); #else *(unsigned short *)vlan_p |= (vcc->pvcvlan.vid & 0x0fff); #endif //printk("%s: vtag=%x\n", *(unsigned short *)vlan_p, __FUNCTION__); #endif } return skb; } struct sk_buff *pp_sar_send_vlan(int ch_no, struct sk_buff *skb){ sar_private *cp = sar_dev; struct atm_vcc *vcc; vcc = cp->vcc[ch_no].dev_data; return sar_send_vlan(vcc,cp,ch_no,skb); } //#endif #ifdef AUTO_PVC_SEARCH /* * sar_send_auto * Clone the incoming pkt and send them to the every possible PVC */ #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif int sar_send_auto (struct atm_vcc *vcc,struct sk_buff *skb){ int count, ch_no; volatile int loop; sar_atm_vcc *vcc_dev = RTATM_VCC(vcc); sar_private *cp = RTATM_DEV(vcc->dev); struct sk_buff *tmp_skb; ch_no = vcc_dev->ch_no; loop = 0; if ((found_pvc==0) && (ch_no < 6) && auto_search_start) { // auto search on. for(count=0;count<tbl_counter;count++){ int vci, vpi; vpi = getActiveVPINum(count); vci = getActiveVCINum(count); if ((vpi==-1)&&(vci==-1)) continue; SetVpiVci(cp,vpi, vci,ch_no); tmp_skb = skb_clone(skb,GFP_ATOMIC); if(count==0) tmp_skb->truesize=skb->truesize; else tmp_skb->truesize=0; mdelay(2); sar_send(vcc, tmp_skb); for (loop = 0; loop <= (150000000/(1000*3)); loop++) { // delay 1ms ; } } dev_kfree_skb_irq(skb); return 0; } else { return sar_send(vcc, skb); } } #endif // Kaohj -- for testing; open this to remove vlan tag on tx #if 0 /* * Return skb_copy if vlan removed. * Return 0 if no changed. */ struct sk_buff *sar_send_remove_vlan(struct atm_vcc *vcc,sar_private *cp,int ch_no, struct sk_buff *skb) { INT8 encap_mode ; char *ether_type; struct sk_buff *skb_copy; int len1, len2; encap_mode = cp->vcc[ch_no].rfc*2+cp->vcc[ch_no].framing; ether_type = skb->data + FrameHeaderSize_1483[encap_mode]+12; if(*(unsigned short *)ether_type == 0x8100){ // remove vlan tag // Kaohj, copy-on-write this skb if ((skb_copy=dev_alloc_skb(SAR_TX_Buffer_Size))==NULL) return 0; len1 = FrameHeaderSize_1483[encap_mode]+12; len2 = skb->len - len1 - 4; memcpy(skb_put(skb_copy, len1), skb->data, len1); // AAL5 header + DA + SA memcpy(skb_put(skb_copy, len2), skb->data+len1+4, len2); // EtherType + IP, skip vlan return skb_copy; } return 0; } #endif extern int sendToPort0; #if defined(CONFIG_RTL8681_SAR_ARCH) || defined(CONFIG_RTL8685_SAR_ARCH) //sendToPort0: 1=fast, 0=interleaved path #define SAR_TX_PATH(x) ((x)?0:1) #else #define SAR_TX_PATH(x) (x) #endif #ifdef CONFIG_FLOW_CTRL unsigned int FCFlag; unsigned int FCEnable=0; unsigned int FCCtrl=1; unsigned int FC_low=2; unsigned int FC_high=60; #endif //CONFIG_FLOW_CTRL // Kaohj /* Packets prepared to be sent; Function relative to external switch. * Return value: * 0: Drop * 1: Continue */ int sar_send_sw(struct atm_vcc *vcc, struct sk_buff **skb) { sar_private *cp = RTATM_DEV(vcc->dev); sar_atm_vcc *vcc_dev = RTATM_VCC(vcc); int ch_no; struct sk_buff *skb_to_send; #if 0 struct sk_buff *tmpskb; #endif ch_no = vcc_dev->ch_no; skb_to_send = *skb; // Kaohj -- for testing; open this to remove vlan tag on tx #if 0 if ((tmpskb=sar_send_remove_vlan(vcc, cp, ch_no, skb_to_send))!=0) { dev_kfree_skb(skb_to_send); *skb = tmpskb; } #endif //#ifdef CONFIG_EXT_SWITCH /* * The bitmap for interface should follow this convention commonly shared * by user-space program (say, startup.c: setupEth2pvc()) * Bit-map: bit5 | bit4 | bit3 | bit2 | bit1 | bit0 * wlan | device | lan3 | lan2 | lan1 | lan0 */ #ifndef NEW_PORTMAPPING #ifdef CONFIG_RTL_819X_SWCORE if (enable_port_mapping && skb_to_send->vlan_member != 0) { // not from device if(vcc->ifgrp.flag && (vcc->ifgrp.member != skb_to_send->vlan_member)){ // printk("Drop pkt!!vcc->ifgrp.member %x skb vlan member %x\n",vcc->ifgrp.member,skb_to_send->vlan_member); return 0;; } } #endif #endif //printk("vlan=%d, vid=%d, vlan_prio=%d, vpass=%d\n", vcc->pvcvlan.vlan, vcc->pvcvlan.vid, vcc->pvcvlan.vlan_prio, vcc->pvcvlan.vlan_pass); #ifdef CONFIG_RTL_MULTI_PVC_WAN //printk("skb_to_send->vlan_tci=%d\n", skb_to_send->vlan_tci ); if ((skb_to_send->vlan_tci > 0) && (RTL_WANVLANID != skb_to_send->vlan_tci) && (RTL_LANVLANID != skb_to_send->vlan_tci) && (RTL_BridgeWANVLANID != skb_to_send->vlan_tci)) { #else if (vcc->pvcvlan.vlan) { #endif //alex check tiny packet if(skb_to_send->len > 22){ if (sar_send_vlan(vcc, cp, ch_no, skb_to_send)==0) return 0; } } //#endif return 1; } //deprecated after applying maximum PCR limitation mechanism #ifdef SW_QOS_STARV_PREVENTION static int vcc_get_drop_flag(sar_private *cp,unsigned int mask){ int ret = 1; int ch_no = 0; for(ch_no = 0; mask > 0; mask=mask >> 1, ch_no++){ if(mask&1){ if(cp->vcc[ch_no].starv_drop_flag != 1){ ret = 0; } } } return ret; } static void vcc_update_drop_flag(sar_private *cp,INT8 ch_no){ unsigned long current_pkt_send_jiffies = 0; if(cp->vcc[ch_no].last_pkt_send_jiffies== 0) { cp->vcc[ch_no].last_pkt_send_jiffies = jiffies; return; } current_pkt_send_jiffies = jiffies; if(time_after(current_pkt_send_jiffies, cp->vcc[ch_no].last_pkt_send_jiffies + 2*HZ)){ cp->vcc[ch_no].starv_drop_flag = 0; //printk("%s(%d):ch %d fake starvation\n", __func__, __LINE__, ch_no); } else { cp->vcc[ch_no].starv_drop_flag = 1; //printk("%s(%d):ch %d true starvation\n", __func__, __LINE__, ch_no); } cp->vcc[ch_no].last_pkt_send_jiffies = current_pkt_send_jiffies; return; } #endif extern void close_smux_device(char *ifname); #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif __SWAP static int _sar_send (struct atm_vcc *vcc,struct sk_buff *skb) { DRV_ENTER sar_private *cp = RTATM_DEV(vcc->dev); sar_atm_vcc *vcc_dev = RTATM_VCC(vcc); INT8 ch_no, CRC_Gen_offset ; INT16 j, avail_desc; int currCDOI; UINT16 CMD; struct sk_buff *skb_to_send; //unsigned long flags; TV_CMD_DESC *TVDesc; //BOOL insert_desc = FALSE; #ifdef UPSTREAM_TRAFFIC_CTL //ql-- upstream traffic control static unsigned int uTcStamp1=0,uTcStamp2=0; static unsigned int uTcStamp=0; static unsigned int LB=0; #define TIMER_HZ (35328/19) #define LEAKY_BUCKET 100000 #endif int tx_cell=0; struct net_device_stats *netstats; skb_to_send = skb; /* patch for TDF missing bug */ if (reg(SAR_TDFI_Addr)) tasklet_schedule(&cp->tdf_tasklets); //scout('('); // Casey, 2004/02/06, I'm not sure, if it should be added here #ifdef FAST_ROUTE_Test // if (!fast_route_mode || !fast_route_ch_no[vcc_dev->ch_no].enable) #endif //atomic_sub(skb_to_send->truesize, &vcc->tx_inuse); //atomic_sub(skb_to_send->truesize, &sk_atm(vcc)->sk_wmem_alloc); //maintain sending counter ch_no = vcc_dev->ch_no; //spin_lock_irqsave(&cp->lock, flags); //deprecated after applying maximum PCR limitation mechanism #ifdef SW_QOS_STARV_PREVENTION //conduct starvation detection when there is more than 1 ch with the same QoS type if(cp->starv[(int)cp->vcc[ch_no].QoS.Type].cnt > 1){ //calculate the packet gap for packet drop decision vcc_update_drop_flag(cp, ch_no); if((REG32(0xb830200c)&cp->starv[(int)cp->vcc[ch_no].QoS.Type].mask)&~(1<<ch_no)){ //other ch with same QoS type is detected #ifdef STAI_DEBUG cp->vcc[ch_no].stat.tx_starvation++; #endif //this detected starvation is a "real" one, drop packet if(vcc_get_drop_flag(cp, cp->starv[(int)cp->vcc[ch_no].QoS.Type].mask)){ #ifdef STAI_DEBUG cp->vcc[ch_no].stat.forceDrop++; #endif goto DropPacket; } } } #endif #ifdef REMOTE_MANAGEMENT_ENABLE if (ch_no==OAM_CH_NO) { // Mason Yu abc //printk("vcc_dev->vpi=%d vcc_dev->vci=%d\n", vcc_dev->vpi, vcc_dev->vci); vcc_dev->vpi = 0; vcc_dev->vci = 16; //for Remote Management OutBandAAL5Tx(vcc_dev->vpi, vcc_dev->vci, skb_to_send); //rtl8671_putPreAlloc(skb_to_send); //free skb //spin_unlock_irqrestore (&cp->lock, flags); DRV_LEAVE; return 0; }; #endif #ifndef CONFIG_RTL8672_ATM_QoS if ((cp->QoS_Tx_Credit)&&(!vcc_dev->creditQoSTx)) { //if (vcc_dev->QoS.Type&2) { // printk("VBR %d drop pkt\n", ch_no); //}; goto DropPacket; } #endif //#ifdef CONFIG_EXT_SWITCH if (!sar_send_sw(vcc, &skb_to_send)) goto DropPacket; //#endif #if 0 #ifdef CONFIG_RTL867X_COMBO_PORTMAPPING if (enable_port_mapping && skb_to_send->vlan_member != 0) { // not from device if(vcc->ifgrp.flag && (vcc->ifgrp.member != skb_to_send->vlan_member)){ //printk("Drop pkt!!vcc->ifgrp.member %x skb vlan member %x\n",vcc->ifgrp.member,skb_to_send->vlan_member); goto DropPacket; } } #endif #endif /* Clear transmitted descriptors */ //ClearTxBuffer(cp, ch_no); /* Now For 1483 only */ //encap_mode = cp->vcc[ch_no].rfc*2+cp->vcc[ch_no].framing; #if 0 /*if no descriptor available, clear TBE if needed */ if(((((cp->vcc[ch_no].TV.desc_pw+1)%SAR_TX_DESC_NUM)==cp->vcc[ch_no].TV.desc_pf)&& (cp->TVDesc[ch_no*SAR_TX_RING_SIZE+cp->vcc[ch_no].TV.desc_pw].CMD&OWN)!=0)){ cp->vcc[ch_no].stat.send_desc_full++; /* descriptors full*/ /* get current CDOI */ currCDOI=GetTxCDOI(cp, ch_no); /* if TBE occurs and current descriptor is own by hardware (that means last time TBE occurs, and the desriptors has been refilled), clear TBE and make this channel be scheduled again */ if ((reg(SAR_TBEI_Addr)&(0x00000001<<ch_no))&&((cp->TVDesc[ch_no*SAR_TX_RING_SIZE+currCDOI].CMD)&OWN)) Clear_TBE(ch_no, currCDOI); //printk(KERN_ERR" no descriptor available\n"); goto DropPacket; } #endif //ql-- limit upstream traffic #ifdef UPSTREAM_TRAFFIC_CTL if (ucTcEbl == 1) {//enable upstream traffic control unsigned int uRate; unsigned int uCompTime; //compensate time unsigned int uLeakyBytes; uTcStamp1 = uTcStamp2; uTcStamp2 = (*(volatile u32*)0xb9c0102c); uTcStamp2 = (uTcStamp2 >> 8) & 0xffffff; if (uTcStamp == 0) uTcStamp = jiffies; total_len = skb_to_send->len; uCompTime = jiffies - uTcStamp; uTcStamp = jiffies; if (uTcStamp1 >= uTcStamp2) { if (uCompTime >= 800) uCompTime = 800; else uCompTime = 0; uLeakyBytes = (uTcStamp1 - uTcStamp2)*uMaxTraffic/TIMER_HZ + uCompTime*uMaxTraffic*10; } else { if (uCompTime >= 800) uCompTime = 801; else uCompTime = 1; uLeakyBytes = (uTc1Data - uTcStamp2 + uTcStamp1)*uMaxTraffic/TIMER_HZ + (uCompTime-1)*uMaxTraffic*10; } LB = (LB <= uLeakyBytes)?0:(LB-uLeakyBytes); //printk("uCompTime:%d uLeakyBytes:%d uTcStamp2:%d uTcStamp1:%d uTc0Data:%d\n", uCompTime, uLeakyBytes, // uTcStamp2,uTcStamp1, uTc1Data); if (total_len + LB > LB_len/*LEAKY_BUCKET*/) { goto DropPacket; } else if (total_len + LB > LB_MAX) { if (uTcStamp2 & 0x01 == 0x01)//drop packet according to 1/2 probability goto DropPacket; } else if (total_len + LB > LB_SEC) { if (uTcStamp2 & 0x03 == 0x01)//drop packet according to 1/2 probability goto DropPacket; } else if (total_len + LB > LB_THD) { if (uTcStamp2 & 0x07 == 0x01)//drop packet according to 1/2 probability goto DropPacket; } else if (total_len + LB > LB_MIN) {//drop packet according to 1/8 probability if (uTcStamp2 & 0x0f == 0x01) goto DropPacket; } LB += total_len; } #endif /* get fragment number */ //if(skb_shinfo(skb_to_send)->nr_frags) // printk("sar_send: skb need frag!\n"); //avail_desc = (cp->vcc[ch_no].TV.desc_pf- 1 - cp->vcc[ch_no].TV.desc_pw)&(SAR_TX_DESC_NUM-1); //avail_desc = cp->vcc[ch_no].TV.desc_pf - cp->vcc[ch_no].TV.desc_pw; #ifndef CONFIG_FLOW_CTRL //ClearTxBuffer(cp, ch_no); avail_desc = (cp->vcc[ch_no].TV.desc_pf- 1 - cp->vcc[ch_no].TV.desc_pw + SAR_TX_DESC_NUM)%SAR_TX_DESC_NUM; /* if not enough descriptors, drop this packet */ if (avail_desc == 0) { /*printk(KERN_ERR " SAR Tx Fail need:%d, availble: %d,desc_pf %d,desc_pw %d\n", fragNum+1, avail_desc, cp->vcc[ch_no].TV.desc_pf, cp->vcc[ch_no].TV.desc_pw);*/ if ((cp->TVDesc[ch_no*SAR_TX_RING_SIZE+cp->vcc[ch_no].TV.desc_pf].CMD&OWN)!=0) { cp->vcc[ch_no].stat.send_desc_lack++; //printk(KERN_ERR" avail_desc %d <= fragNum %d\n", avail_desc, fragNum); goto DropPacket; }; //__cli(); ClearTxBuffer(cp, ch_no); avail_desc = (cp->vcc[ch_no].TV.desc_pf- 1 - cp->vcc[ch_no].TV.desc_pw + SAR_TX_DESC_NUM)%SAR_TX_DESC_NUM; //__sti(); //free tx desc num = SAR_TX_RING_SIZE } #else /* Clear transmitted descriptors */ //ClearTxBuffer(cp, ch_no); avail_desc = (cp->vcc[ch_no].TV.desc_pf- 1 - cp->vcc[ch_no].TV.desc_pw + SAR_TX_DESC_NUM)&(SAR_TX_DESC_NUM-1); /* if not enough descriptors, enable flow control only if IPQoS not enabled */ //#ifdef CONFIG_EXT_SWITCH if (enable_ipqos==0) { //#endif //tylo, FCEnable:check if sar is ready if(FCCtrl && FCEnable){ if (avail_desc <= FC_low) { //save_flags(flags); disable_irq(sar_irq); // printk("%s: avail_desc %d enable flow control(ori RCR %x)\n", __func__, avail_desc, REG32(0xb9800044)); FCFlag = 1; //reject packets with physical address not to me //REG32(0xb9800044)=0x0000000a; REG32(0xb9800044)=0x0000000e; //restore_flags(flags); } } //#ifdef CONFIG_EXT_SWITCH } //#endif #endif //CONFIG_FLOW_CTRL if (avail_desc <= 1 && cp->vcc[ch_no].dev!=NULL) { //printk("stop queue\n"); //#ifdef CONFIG_EXT_SWITCH if (enable_ipqos) { //#endif netif_stop_queue(cp->vcc[ch_no].dev); #if defined(CONFIG_RTL_MULTI_PVC_WAN) close_smux_device(cp->vcc[ch_no].dev->name); #endif } } //tylo if(avail_desc==0) goto DropPacket; CRC_Gen_offset=4; //total_len = skb_to_send->len; { //cxy 2017-4-1: padding for pkt len small than 64 if((skb_to_send->len<64) && (cp->vcc[ch_no].rfc==RFC1483_BRIDGED)) skb_to_send->len=64; //end of cxy 2017-4-1 //i = 0; { /* Get Current Descriptor Index */ //j= (cp->vcc[ch_no].TV.desc_pw+i)%SAR_TX_DESC_NUM; j= cp->vcc[ch_no].TV.desc_pw; /* Handle this descriptor */ TVDesc=&cp->TVDesc[ch_no*SAR_TX_RING_SIZE+j]; //CMD=0; /* if this Descriptor is OWN by SAR, skip it. */ //if(TVDesc->CMD&OWN){ // goto DropPacket; //} {/* first of the fragment */ TVDesc->START_ADDR=(u32)skb_to_send->data|Uncache_Mask; cp->vcc[ch_no].tx_buf[j]=(UINT32)skb_to_send; TVDesc->LEN=skb_to_send->len&LEN_Mask; } #if 0 { /* get next frag */ skb_frag_t *this_frag = &skb_shinfo(skb_to_send)->frags[i-1]; TVDesc->START_ADDR=(u32)this_frag->page_offset|Uncache_Mask; TVDesc->LEN=this_frag->size; cp->vcc[ch_no].tx_skb[j]=(UINT32)skb_to_send; } #endif // JONAH_DEBUG //printk(KERN_ERR"sar tx 2 %d\n", TVDesc->LEN); /* Set FS LS */ //CMD |= FS; //CMD |= LS; CMD = FS|LS |TRLREN /* Enable AAL5 Trailer*/ // #ifdef CONFIG_RTL8671 //#if 1 //temp. fix to port 1 // |0x0800 /* fix to ATM port 1*/ //#else // |cp->atmport/*use ATMPORT 1 */ //#endif //|CLP //6/9/04' hrchen, disable for Nokia D500 bug /* Set CLP */ |OWN /* set owner */ |(((uint16)cp->vcc[ch_no].TV.Ether_Offset_Value<<ETHNT_OFFSET) );//ÐNT_OFFSET_MSK); /* enable Ethernet CRC32 generation and append*/ if(SAR_TX_PATH(sendToPort0)) { CMD |= 0x0800; } if(j==(SAR_TX_DESC_NUM-1)) CMD |= EOR; //tylo, fpga dma_cache_wback_inv((unsigned long)skb_to_send->data, skb_to_send->len); /* save the CMD to Descriptor */ TVDesc->CMD=CMD;//|((j==(SAR_TX_DESC_NUM-1))?EOR:0); } //cp->vcc[ch_no].TV.desc_pw = (cp->vcc[ch_no].TV.desc_pw + 1)%SAR_TX_DESC_NUM; cp->vcc[ch_no].TV.desc_pw = (j + 1)&(SAR_TX_DESC_NUM-1); } skb_pvc_debug(skb_to_send, ch_no, 1); #ifdef CONFIG_PORT_MIRROR sar_port_mirror(cp, ch_no, skb_to_send, PORT_MIRROR_OUT); #endif /* if TBE occurs and the current descriptor is owned by hardware, re-schedule this channel */ #ifdef CONFIG_CPU_RLX4181 //dcache write back, to make memory consist with cache before DMA dma_cache_wback_inv((unsigned long)skb_to_send->data, skb_to_send->len); #endif if (reg(SAR_TBEI_Addr)&(0x00000001<<ch_no)) { //if ((cp->TVDesc[ch_no*SAR_TX_RING_SIZE+currCDOI].CMD)&OWN) currCDOI = GetTxCDOI(cp, ch_no); Clear_TBE(ch_no, currCDOI); }; tx_cell=skb_to_send->len/48; if(skb_to_send->len > (tx_cell*48)) tx_cell++; cp->vcc[ch_no].hwTxCellCount+=(int)(tx_cell*512); AtmTraffic += tx_cell; //Tx traffic tracks /* Clear transmitted descriptors AGAIN */ //ClearTxBuffer(cp, ch_no); //cp->vcc[ch_no].stat.send_cnt++; //cp->vcc[ch_no].stat.send_ok++; //scout(')'); //2/4/06' hrchen, for VBR credit adjust //adjust_ATM_QoS(vcc_dev); //decrease credit vcc_dev->creditQoSTx--; //spin_unlock_irqrestore (&cp->lock, flags); DRV_LEAVE; return 1; DropPacket: //printk(KERN_ERR"tx packet dropped, desc_num = %d\n",avail_desc); //printk("sar_send> drop %p\n", skb_to_send); sar_kfree_skb(skb_to_send); //dev_kfree_skb_irq(skb_to_send); //rtl8671_putPreAlloc(skb_to_send); cp->vcc[ch_no].stat.send_fail++; cp->vcc[ch_no].stat.tx_pkt_fail_cnt++; //printk("WARNING: should never come here!!\n"); //netif_stop_queue(dev); //scout('_'); //spin_unlock_irqrestore (&cp->lock, flags); DRV_LEAVE; // Kaohj --- count for net_device tx_dropped if (vcc_dev->dev && vcc_dev->dev->netdev_ops->ndo_get_stats) { netstats = vcc_dev->dev->netdev_ops->ndo_get_stats(vcc_dev->dev); netstats->tx_dropped++; } return 0; } /*jiunming*/ #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif extern int SARvtx(struct atm_vcc *vcc, struct sk_buff* skb, uint32 len, int port); int sar_send (struct atm_vcc *vcc,struct sk_buff *skb) { sar_private *cp = RTATM_DEV(vcc->dev); sar_atm_vcc *vcc_dev = RTATM_VCC(vcc); INT8 ch_no; int ret; unsigned long flags; DRV_ENTER spin_lock_irqsave(&cp->txlock, flags); if (getADSLLinkStatus()&&(enable_mode==0)) { ret = _sar_send( vcc, skb ); spin_unlock_irqrestore (&cp->txlock, flags); //make ret value to meet the kernel convention return (ret)? 0:1; } //atomic_sub(skb->truesize, &vcc->tx_inuse); ch_no = vcc_dev->ch_no; //printk(KERN_ERR"tx packet dropped, desc_num = %d\n",avail_desc); //printk("sar_send> drop %p\n", skb_to_send); if (ATM_SKB(skb)->vcc->pop) ATM_SKB(skb)->vcc->pop(ATM_SKB(skb)->vcc,skb); else dev_kfree_skb(skb); //dev_kfree_skb_irq(skb_to_send); //rtl8671_putPreAlloc(skb_to_send); cp->vcc[ch_no].stat.send_fail++; cp->vcc[ch_no].stat.tx_pkt_fail_cnt++; //printk("WARNING: should never come here!!\n"); //netif_stop_queue(dev); spin_unlock_irqrestore (&cp->txlock, flags); DRV_LEAVE; return 1; } //tylo, removed for linux2.6 #if 0 static void sar_set_rx_mode (struct net_device *dev) { DRV_ENTER; printk(KERN_DEBUG "sar_set_rx_mode: called.\n"); if (dev==NULL) { printk(KERN_ERR "sar_set_rx_mode: dev is NULL!\n"); return; } if (dev->flags & IFF_PROMISC) { printk(KERN_DEBUG "%s: Setting promiscuous mode.\n", dev->name); } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) { printk(KERN_DEBUG "%s: All multicast list.\n", dev->name); } DRV_LEAVE; } #endif #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif static void sar_stop_hw (sar_private *cp) { DRV_ENTER int i; struct atm_vcc *vcc; /* clear Config Register */ Disable_SAR(cp); //synchronize_irq(); /*linux-2.6.19*/ synchronize_irq(cp->irq); udelay(10); Reset_Sar(); /* set all desc point to 0, include OB channel*/ for(i=0;i<(Enable_VC_CNT+NUMBER_OF_OAM_CH);i++){ if(cp->vcc[i].created==VC_CREATED){ vcc = cp->vcc[i].dev_data; clear_bit(ATM_VF_READY,&vcc->flags); }; cp->vcc[i].TV.desc_pf = 0; cp->vcc[i].TV.desc_pc = 0; cp->vcc[i].TV.desc_pw = 0; cp->vcc[i].RV.desc_pr = 0; cp->vcc[i].RV.desc_pc = 0; cp->vcc[i].RV.desc_pa = 0; } //remove_bh(SAR_BH); //5/22/04' hrchen, SAR_BH has no use /* ??? !!! free all memory */ DRV_LEAVE; } extern void Enable_IS8672_10(sar_private *cp); extern void Enable_IS8671G_1(sar_private *cp); extern void Enable_IS8671G_0(sar_private *cp); static void sar_init_hw (sar_private *cp) { DRV_ENTER #if 0 struct SAR_IOCTL_CFG cfg; #endif //ql #ifdef UPSTREAM_TRAFFIC_CTL uTc1Data = (*(volatile u32*)0xb9c01024); uTc1Data = (uTc1Data >> 8) & 0xffffff; #endif /* ---> SAR Entire Module Related <--- */ Reset_Sar(); Init_reg(cp); /* set corresponding register address */ //SetCRCTbl(); //GenCRC10Table(); //Enable_SAR(cp); /* Enable/Disable Loopback test mode */ #ifdef LoopBack_Test /*Enable_LoopBack(); */ Disable_LoopBack(cp); Enable_Sachem_Loopback(); #else Disable_LoopBack(cp); //REG16(0xb8000c20)=0x0600; //Enable_Sachem_Utopia(); //Enable_Sachem_Loopback(); #endif // Enable_LoopBack(cp); /* Select Qos Clock from External clock */ //QCLKSEL has been removed Set_QoS_Ext(cp, 0); /* external */ cp->QoS_Test= FALSE; #if 0 /* ---> Individual Chanel Related <--- */ /* Create one VC first */ cfg.ch_no = 0; cfg.vpi = 5; cfg.vci = 35; cfg.rfc = RFC1483_BRIDGED; cfg.framing = LLC_SNAP; //cfg.loopback = FALSE; cfg.QoS.Type = QoS_UBR; cfg.QoS.PCR = 0x1DFF; cfg.QoS.SCR = 0; cfg.QoS.MBS = 128; cfg.QoS.CRD = 0; cfg.QoS.CDVT = 0; CreateVC(cp, &cfg, 1); #endif #ifdef ENA_OAM_CH AllocVcBuff(cp, OAM_CH_NO); if (cp->vcc[OAM_CH_NO].dev_data) //Remote Management Channel is created Disable_Drop_NonOAM(cp, OAM_CH_NO); else Enable_Drop_NonOAM(cp, OAM_CH_NO); Enable_rx_ch(cp, OAM_CH_NO); Enable_tx_ch(cp, OAM_CH_NO); #endif #ifdef ATM_OAM //remember to change the VPI/VCI setting OAMF5Init(0, 0, &OAMF5_info); OAMF4Init(0, 0, &OAMF4_info); #endif #ifdef CONFIG_ATM_BONDING ASMInit(); #endif /* ---> Interrupt Related <--- */ Enable_IERDA(cp); Set_RDA(cp, RDATHR, RDATimer); /* polling TBE */ Disable_IETBE(cp); //Disable_IETDF(cp); //Enable_IETBE(cp); Enable_IETDF(cp); Enable_IERBF(cp); #ifdef CONFIG_RTL8672_ATM_QoS //enable 8672 new function Enable_IS8671G_1(cp); Enable_IS8671G_0(cp); Enable_IS8672_10(cp); #endif //deprecated after applying maximum PCR limitation mechanism #ifdef SW_QOS_STARV_PREVENTION //disable HW QoS starvation prevention (new QoS function) because the issue found in December 2014 Disable_QoS_Starvation(cp); //set starvation criterion, ranges form 0x01~0xff; 0xff is more likely to be triggered than 0x01 REG32(0xb8303010) = 0xfff70000; #endif //init_bh(SAR_BH, sar_rx_bh); // initialise bottom half //INIT_LIST_HEAD(&cp->bh.list); //cp->bh.sync = 0; //cp->bh.routine = (void (*)(void *)) sar_rx_bh; //cp->bh.data = cp; Enable_QoS_Priority(cp, 0); Enable_HP_CHTx(cp, 0); #if defined(CONFIG_RTL8681_SAR_ARCH) || defined(CONFIG_RTL8685_SAR_ARCH) { int ch_no; /* Set Bonding port #0, #1*/ Enable_BOND_Link(cp, 0); Enable_BOND_Link(cp, 1); /* Set Bonding line = 0, and it means non-bonding */ Set_BOND_Line(cp,0); /* Set TX path for each channel, 0:fast path, 1:interleave */ for(ch_no=0; ch_no < (Enable_VC_CNT); ch_no++){ Set_Dual_Map(cp,ch_no,SAR_TX_PATH(sendToPort0)); } /* Set WFGQ */ Set_Bond_WFQ(cp,0,5); /* Enable dummy */ if (!IS_RL6405 && !IS_RLE0822 && !IS_6518()){ Enable_Dummy(cp); } /* Config Dummy register */ Set_Bond_Dummy(cp, 0x16a); #ifdef CONFIG_ATM_BONDING Enable_IEASMTICK(cp); Set_TSTMP(cp, 0x270f, 0x270f); #endif } #endif memset(&cp->tasklets, 0, sizeof(struct tasklet_struct)); cp->tasklets.func=(void (*)(unsigned long))sar_rx_bh; cp->tasklets.data=(unsigned long)cp; sar_rx_tasklets = &cp->tasklets; memset(&cp->tdf_tasklets, 0, sizeof(struct tasklet_struct)); cp->tdf_tasklets.func=(void (*)(unsigned long))sar_tx_complete; cp->tdf_tasklets.data=(unsigned long)cp; DRV_LEAVE; } #if 0 static int sar_refill_rx (sar_private *cp) { DRV_ENTER; #if 0 unsigned i; for (i = 0; i < SAR_RX_RING_SIZE; i++) { struct sk_buff *skb; skb = dev_alloc_skb(cp->rx_buf_sz + RX_OFFSET); if (!skb) goto err_out; skb->dev = cp->dev; #if 0 cp->rx_skb[i].mapping = pci_map_single(cp->pdev, skb->tail, cp->rx_buf_sz, PCI_DMA_FROMDEVICE); #endif cp->rx_skb[i].skb = skb; cp->rx_skb[i].frag = 0; if ((u32)skb->data &0x3) printk(KERN_DEBUG "skb->data unaligment %8x\n",(u32)skb->data); cp->rx_ring[i].addr = (u32)skb->data|Uncache_Mask; if (i == (SAR_RX_RING_SIZE - 1)) cp->rx_ring[i].opts1 = (DescOwn | RingEnd | cp->rx_buf_sz); else cp->rx_ring[i].opts1 =(DescOwn | cp->rx_buf_sz); cp->rx_ring[i].opts2 = 0; } return 0; err_out: sar_clean_rings(cp); #endif DRV_LEAVE; return -ENOMEM; } static int sar_init_rings (sar_private *cp) { DRV_ENTER; #if 0 memset(cp->tx_hqring, 0, sizeof(DMA_DESC) * SAR_TX_RING_SIZE); memset(cp->rx_ring, 0, sizeof(DMA_DESC) * SAR_RX_RING_SIZE); cp->rx_tail = 0; cp->tx_hqhead = cp->tx_hqtail = 0; #endif DRV_LEAVE; return sar_refill_rx (cp); } static int sar_alloc_rings (sar_private *cp) { DRV_ENTER; #if 0 /*cp->rx_ring = pci_alloc_consistent(cp->pdev, CP_RING_BYTES, &cp->ring_dma);*/ void* pBuf; pBuf = kmalloc(SAR_RXRING_BYTES,GFP_KERNEL); if (!pBuf) goto ErrMem; cp->rxdesc_buf = pBuf; memset(pBuf, 0, SAR_RXRING_BYTES); pBuf = (void*)( (u32)(pBuf + Desc_Align-1) & ~(Desc_Align -1) ) ; cp->rx_ring = (DMA_DESC*)((u32)(pBuf) | Uncache_Mask); pBuf= kmalloc(SAR_TXRING_BYTES, GFP_KERNEL); if (!pBuf) goto ErrMem; cp->txdesc_buf = pBuf; memset(pBuf, 0, SAR_TXRING_BYTES); pBuf = (void*)( (u32)(pBuf + Desc_Align-1) & ~(Desc_Align -1) ) ; cp->tx_hqring = (DMA_DESC*)((u32)(pBuf) | Uncache_Mask); return sar_init_rings(cp); ErrMem: if (cp->rxdesc_buf) kfree(cp->rxdesc_buf); if (cp->txdesc_buf) kfree(cp->txdesc_buf); #endif DRV_LEAVE; return -ENOMEM; } static void sar_clean_rings (sar_private *cp) { DRV_ENTER; #if 0 unsigned i; for (i = 0; i < SAR_RX_RING_SIZE; i++) { if (cp->rx_skb[i].skb) { dev_kfree_skb(cp->rx_skb[i].skb); } } for (i = 0; i < SAR_TX_RING_SIZE; i++) { if (cp->tx_skb[i].skb) { struct sk_buff *skb = cp->tx_skb[i].skb; dev_kfree_skb(skb); } } memset(&cp->rx_skb, 0, sizeof(struct ring_info) * SAR_RX_RING_SIZE); memset(&cp->tx_skb, 0, sizeof(struct ring_info) * SAR_TX_RING_SIZE); #endif DRV_LEAVE; } static void sar_free_rings (sar_private *cp) { DRV_ENTER; #if 0 sar_clean_rings(cp); /*pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma);*/ kfree(cp->rxdesc_buf); kfree(cp->txdesc_buf); cp->rx_ring = NULL; cp->tx_hqring = NULL; #endif DRV_LEAVE; } #endif static int sar_start (struct atm_dev *dev) { DRV_ENTER sar_private *cp = RTATM_DEV(dev); int rc; int i; #ifdef STAI_DEBUG sar_cp = cp; #endif Alloc_desc(cp); /* alloocate memory for descriptors */ //rtl8671_initPreAlloc(); cp->atmport = ATMPORT_SLOW; //5/23/04' hrchen, default to fast path, for auto path switch sar_init_hw(cp); #ifdef FAST_ROUTE_Test // FAST_ROUTE_Test variables initialization for(i=0;i<Enable_VC_CNT; i++) { ch_counter[i].counter = 0; ch_counter[i].start_stamp = 0; fast_route_ch_no[i].index = 0; fast_route_ch_no[i].enable = 0; memset(fast_route_ch_no[i].mac[i], 0, 6); } #endif /* !!! irq 3 is used at this point due to rupert's ISR dispatch method */ cp->irq = sar_irq; //rc = request_irq(cp->irq, sar_interrupt, SA_INTERRUPT, dev->type, dev); /*linux-2.6.19*/ rc = request_irq(cp->irq, sar_interrupt, IRQF_DISABLED, dev->type, dev); if (rc) goto err_out_hw; dev->ci_range.vpi_bits = 8; dev->ci_range.vci_bits = 16; //request_irq will enable requested irq //REG32(GIMR) |= SAR_IE ; DRV_LEAVE; return 0; err_out_hw: sar_stop_hw(cp); /* free all buffers */ //5/22/04' hrchen //free pkt bfr for (i=0;i<Enable_VC_CNT;i++) { sar_close(cp->vcc[i].dev_data); }; FreeVcBuff(cp, OAM_CH_NO); Free_desc(cp); DRV_LEAVE; return rc; } void SarRecalPerVCNumber(sar_private *cp, int off) { int i, cnt; //extern int current_desc_number[Enable_VC_CNT]; //extern int do_formation; cnt = 0; for (i=0; i<Enable_VC_CNT; i++) { if (cp->vcc[i].created) cnt++; } printk("%s(%d): cnt=%d, off=%d\n",__func__,__LINE__,cnt,off); if ((cnt + off) > Enable_VC_CNT) return; total_pvc_number = cnt + off; if (total_pvc_number > 0) { per_vc_desc_number = SAR_RX_NUM/total_pvc_number; if (per_vc_desc_number>SAR_RX_DESC_HI_LIMIT) per_vc_desc_number = SAR_RX_DESC_HI_LIMIT; } #ifdef SAR_RX_FORMATION if (total_pvc_number <= 2) // do rx formation if pvc_number > 2 do_formation = 0; else do_formation = 1; printk("Change%d: total=%d pervc=%d dofmt=%d\n", off, total_pvc_number, per_vc_desc_number, do_formation); #endif } #if 0 #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif static int sar_open (struct atm_vcc *vcc, short vpi, int vci) { sar_private *cp = RTATM_DEV(vcc->dev); struct SAR_IOCTL_CFG cfg; int error=0; if (vci == ATM_VPI_UNSPEC || vpi == ATM_VCI_UNSPEC) return -EINVAL; if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) RTATM_VCC(vcc) = NULL; printk("fixme atm_find_ci in sar_open!\n"); //error = atm_find_ci(vcc,&vpi,&vci); if (error) return error; vcc->vpi = vpi; vcc->vci = vci; if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) set_bit(ATM_VF_ADDR,&vcc->flags); if (vcc->qos.aal != ATM_AAL5) return -EINVAL; /* @@@ AAL0 */ printk(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi, vcc->vci); if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { #ifdef REMOTE_MANAGEMENT_ENABLE if ((vpi==0)&&(vci==16)) { //Remote Management Channel vcc->dev_data = &cp->vcc[OAM_CH_NO]; cp->vcc[OAM_CH_NO].dev_data = vcc; cp->vcc[OAM_CH_NO].ch_no = OAM_CH_NO; cp->vcc[OAM_CH_NO].vpi = vpi; cp->vcc[OAM_CH_NO].vci = vci; } else { //normal PVC channel #endif int i; /* find a free channel */ for(i=0; i<(Enable_VC_CNT+1); i++) if(cp->vcc[i].created == VC_NOT_CREATED) break; if(i!=(Enable_VC_CNT+1)) cfg.ch_no = i; else return -1; vcc->dev_data = &cp->vcc[i]; cp->vcc[i].dev_data = vcc; /* Create one VC first */ cfg.vpi = vpi; cfg.vci = vci; /* default setting */ cfg.rfc = RFC1483_BRIDGED; cfg.framing = LLC_SNAP; //cfg.loopback = FALSE; cp->vcc[i].br=0; //default direct bridge disabled cfg.QoS.Type = sar_to_qos(vcc->qos.txtp.traffic_class); if(vcc->qos.txtp.pcr) cfg.QoS.PCR = vcc->qos.txtp.pcr; else cfg.QoS.PCR = 0x1DFF; if(vcc->qos.txtp.scr) cfg.QoS.SCR = vcc->qos.txtp.scr; else cfg.QoS.SCR = 0; if(vcc->qos.txtp.mbs) cfg.QoS.MBS = vcc->qos.txtp.mbs; else cfg.QoS.MBS = 128; cfg.QoS.CRD = 0; cfg.QoS.CDVT = 0; CreateVC(cp, &cfg, 1); set_atm_data_mode(1); #ifdef REMOTE_MANAGEMENT_ENABLE }; #endif } set_bit(ATM_VF_READY,&vcc->flags); return 0; } #else #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif #if defined(CONFIG_XDSL_CTRL_PHY_IS_DSL) int sar_open (struct atm_vcc *vcc) #else static int sar_open (struct atm_vcc *vcc) #endif { sar_private *cp = RTATM_DEV(vcc->dev); struct SAR_IOCTL_CFG cfg; short vpi; int vci; int error=0; vpi = vcc->vpi; vci = vcc->vci; if (vci == ATM_VPI_UNSPEC || vpi == ATM_VCI_UNSPEC) return -EINVAL; if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) //RTATM_VCC(vcc) = NULL; (vcc)->dev_data = NULL; printk("fixme atm_find_ci in sar_open!\n"); //error = atm_find_ci(vcc,&vpi,&vci); if (error) return error; vcc->vpi = vpi; vcc->vci = vci; if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) set_bit(ATM_VF_ADDR,&vcc->flags); if (vcc->qos.aal != ATM_AAL5) return -EINVAL; /* @@@ AAL0 */ #if !defined(CONFIG_XDSL_CTRL_PHY_IS_DSL) printk(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi, vcc->vci); #endif if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { #ifdef REMOTE_MANAGEMENT_ENABLE if ((vpi==0)&&(vci==16)) { //Remote Management Channel vcc->dev_data = &cp->vcc[OAM_CH_NO]; cp->vcc[OAM_CH_NO].dev_data = vcc; cp->vcc[OAM_CH_NO].ch_no = OAM_CH_NO; cp->vcc[OAM_CH_NO].vpi = vpi; cp->vcc[OAM_CH_NO].vci = vci; } else { //normal PVC channel #endif int i; #if defined(CONFIG_XDSL_CTRL_PHY_IS_DSL) if (vcc->itf >= 0){ cfg.ch_no = vcc->itf; i = cfg.ch_no; } else return -1; #else /* find a free channel */ for(i=0; i<(Enable_VC_CNT+1); i++) if(cp->vcc[i].created == VC_NOT_CREATED) break; if(i!=(Enable_VC_CNT+1)) cfg.ch_no = i; else return -1; #endif vcc->dev_data = &cp->vcc[i]; cp->vcc[i].dev_data = vcc; /* Create one VC first */ cfg.vpi = vpi; cfg.vci = vci; /* default setting */ cfg.rfc = RFC1483_BRIDGED; cfg.framing = LLC_SNAP; //cfg.loopback = FALSE; cp->vcc[i].br=0; //default direct bridge disabled cfg.QoS.Type = sar_to_qos(vcc->qos.txtp.traffic_class); if(vcc->qos.txtp.pcr) cfg.QoS.PCR = vcc->qos.txtp.pcr; else cfg.QoS.PCR = 0x1DFF; if(vcc->qos.txtp.scr) cfg.QoS.SCR = vcc->qos.txtp.scr; else cfg.QoS.SCR = 0; if(vcc->qos.txtp.mbs) cfg.QoS.MBS = vcc->qos.txtp.mbs; else cfg.QoS.MBS = 128; cfg.QoS.CRD = 0; cfg.QoS.CDVT = 0; SarRecalPerVCNumber(cp, 1); CreateVC(cp, &cfg, 1); set_atm_data_mode(1); #ifdef REMOTE_MANAGEMENT_ENABLE }; #endif } set_bit(ATM_VF_READY,&vcc->flags); return 0; } #endif //#if 0 #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif static void _sar_close (struct atm_vcc *vcc) { sar_private *cp = RTATM_DEV(vcc->dev); sar_atm_vcc *vcc_dev = RTATM_VCC(vcc); struct SAR_IOCTL_CFG cfg; DRV_ENTER; if (!vcc_dev) return; clear_bit(ATM_VF_READY,&vcc->flags); //disable_lx4180_irq(3); //disable SAR IRQ before free buffer cfg.ch_no = vcc_dev->ch_no; cfg.vpi = vcc->vpi; cfg.vci = vcc->vci; DeleteVC(cp, &cfg); clear_bit(ATM_VF_ADDR,&vcc->flags); DRV_LEAVE; printk("sar_close\n"); return; } #if defined(CONFIG_XDSL_CTRL_PHY_IS_DSL) void sar_close (struct atm_vcc *vcc) { #else static void sar_close (struct atm_vcc *vcc) { #endif sar_private *cp = RTATM_DEV(vcc->dev); printk("%s(%d)\n",__func__,__LINE__); _sar_close(vcc); SarRecalPerVCNumber(cp, 0); set_atm_data_mode(1); } extern int StartAtmOAMLoopBack(ATMOAMLBReq *pATMOAMLBReq); extern int SetAtmOAMCpid(ATMOAMLBID *pATMOAMLBID); extern int StopAtmOAMLoopBack(ATMOAMLBReq *pATMOAMLBReq); extern int GetAtmOAMLoopBackStatus(ATMOAMLBState *pATMOAMLBState); extern int GetAtmOAMLoopBackStatusFE(ATMOAMLBRXState *pATMOAMLBRXState); extern void OAMF5ContiLbTest(ATMOAMLBReq *pucPtr); extern void OAMF5StopLbTest(void); extern int test_memory_allocate; char pvc_mode[16]; char pvc_encap[16]; #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif int sar_ioctl (struct atm_dev *dev,unsigned int cmd,void *arg) { DRV_ENTER sar_private *cp; char *data = (char *)arg; int8 ch_no; // BOOL rc = FALSE; // int i; int iVal; if (dev==NULL) { printk("sar_ioctl: dev is NULL!\n"); return -1;} cp = RTATM_DEV(dev); if (cp==NULL) { printk("sar_ioctl: cp is NULL!\n"); return -2;} // printk(KERN_DEBUG "sar_ioctl: called. cmd=0x%x, arg=%s\n", cmd, (char*)arg); switch (cmd) { case ATM_SAR_GETSTAT: { //printk(KERN_DEBUG "sar_ioctl: SAR_GET_STATS called.\n"); struct SAR_IOCTL_CFG *get_cfg = (struct SAR_IOCTL_CFG *)data; ch_no = get_cfg->ch_no; if(ch_no < Enable_VC_CNT && ch_no >= 0 && cp->vcc[ch_no].created == VC_CREATED) { //printk("\n\nRV.desc_pr=%02x, RV.desc_pc=%02x, RV.desc_pa=%02x\n", cp->vcc[ch_no].RV.desc_pr, cp->vcc[ch_no].RV.desc_pc, cp->vcc[ch_no].RV.desc_pa); //printk("TV.desc_pf=%02x, TV.desc_pc=%02x, TV.desc_pw=%02x\n\n", cp->vcc[ch_no].TV.desc_pf, cp->vcc[ch_no].TV.desc_pc, cp->vcc[ch_no].TV.desc_pw); } if (copy_to_user(&(get_cfg->vpi), &(cp->vcc[ch_no].vpi), sizeof(char))) return -EFAULT; if (copy_to_user(&(get_cfg->vci), &(cp->vcc[ch_no].vci), sizeof(short))) return -EFAULT; if (copy_to_user(&(get_cfg->rfc), &(cp->vcc[ch_no].rfc), sizeof(int))) return -EFAULT; if (copy_to_user(&(get_cfg->created), &(cp->vcc[ch_no].created), sizeof(int))) return -EFAULT; if (copy_to_user(&(get_cfg->stat), &(cp->vcc[ch_no].stat), sizeof(ch_stat))) return -EFAULT; //printk(KERN_DEBUG "sar_ioctl: SAR_GET_STATS done.\n"); break; } #ifdef UPSTREAM_TRAFFIC_CTL //ql case SAR_SET_TRAFFIC_CTL: { if (copy_from_user(&uMaxTraffic, data, sizeof(int))) return -EFAULT;/*//for test if (copy_from_user(&LB_len, data+4, sizeof(int))) return -EFAULT; if (copy_from_user(&LB_MAX, data+4, sizeof(int))) return -EFAULT; if (copy_from_user(&LB_SEC, data+4, sizeof(int))) return -EFAULT; if (copy_from_user(&LB_THD, data+4, sizeof(int))) return -EFAULT; if (copy_from_user(&LB_MIN, data+4, sizeof(int))) return -EFAULT;*/ if (uMaxTraffic > BANDWIDT_1M) { printk("sar_ioctl: SAR_SET_TRAFFIC_CTL not allowed (0x%x)\n", uMaxTraffic); return -EFAULT; }; if (uMaxTraffic > 0) ucTcEbl = 1; else //uMaxTraffic==0 ucTcEbl = 0; uMaxTraffic = uMaxTraffic*1024/1000; break; } #endif #ifdef CONFIG_RTL8672 case SAR_SET_SARHDR: { uint32 mode,vpi,vci,i, ch_no=0xff; printk(KERN_DEBUG "sar_ioctl: SAR_SET_SARHDR called.\n"); if (copy_from_user(&mode, data, sizeof(int))) return -EFAULT; if(mode>0) { if (copy_from_user(&vpi, data+4, sizeof(int))) return -EFAULT; if (copy_from_user(&vci, data+8, sizeof(int))) return -EFAULT; printk(KERN_DEBUG "vpi=%d, vci = %d\n", vpi,vci); for (i=0; i<Enable_VC_CNT; i++) { if (cp->vcc[i].vpi ==(short) vpi && cp->vcc[i].vci == vci) ch_no = (uint32)cp->vcc[i].ch_no; } if(ch_no==0xff){ printk(KERN_DEBUG "Cannot find PVC (%d, %d) corresponding channle number!\n", vpi,vci); break; } switch(mode){ case 1: //MER Set_SARhdr(cp, ch_no, MER_mode); //MER mode printk(KERN_DEBUG "Set CH %d MER mode on CKS register\n", ch_no); pvc_mode[ch_no]=MER_mode; break; case 2: //PPPoE Set_SARhdr(cp, ch_no, PPPoE_mode); //PPPoE mode printk(KERN_DEBUG "Set CH %d PPPoE mode on CKS register\n", ch_no); pvc_mode[ch_no]=PPPoE_mode; break; case 3: //PPPoA Set_SARhdr(cp, ch_no, PPPoA_mode); //PPPoA mode printk(KERN_DEBUG "Set CH %d PPPoA mode on CKS register\n", ch_no); pvc_mode[ch_no]=PPPoA_mode; break; case 4: //1483 Routed Set_SARhdr(cp, ch_no, Routed_mode); //Routed mode printk(KERN_DEBUG "Set CH %d Routed mode on CKS register\n", ch_no); pvc_mode[ch_no]=Routed_mode; break; default: printk(KERN_DEBUG "sar_iotcl: Unknown or bridged encapsulate mode\n"); } } printk(KERN_DEBUG "sar_ioctl: SAR_SET_SARHDR done.\n"); break; } case SAR_SET_PKTA: { //no more packet processor //pp_set_vc_type(total_pvc_number); break; } #endif #if 1 case SAR_SET_BRIDGE_MODE: { //Merge Kao's fix from 2.4.x int ch_no; printk(KERN_DEBUG "sar_ioctl: SAR_SET_BRIDGE_MODE called.\n"); if (copy_from_user(&ch_no, data, sizeof(int))) return -EFAULT; ch_no = index_vc2ch(ch_no); if (ch_no >= 0) { cp->vcc[ch_no].br=1; #ifdef CONFIG_RTL8672 Set_SARhdr(cp, ch_no, Bridged_mode); pvc_mode[ch_no]=Bridged_mode; #endif //CONFIG_RTL8672 } else printk("sar_ioctl(SAR_SET_BRIDGE_MODE): channel not found!\n"); // printk("Enable CH %d direct bridge mode\n", ch_no); printk(KERN_DEBUG "sar_ioctl: SAR_SET_BRIDGE_MODE done.\n"); break; } #endif case QOS_ENABLE_IMQ: { int tmp; if (copy_from_user(&tmp, data, sizeof(int))) return -EFAULT; printk("set qos state:%d\n", tmp); if (tmp & QOS_IPTV_TR69) qosIPtv = 1; else qosIPtv = 0; if (tmp & QOS_RULE_EXIST) qosRuleExist = 1; else qosRuleExist = 0; break; } case PVC_QOS_TYPE: { struct SAR_IOCTL_CFG cfg; int idx; char ifname[6]; printk(KERN_DEBUG "sar_ioctl: PVC_QOS_TYPE called.\n"); if (copy_from_user(&cfg, (struct SAR_IOCTL_CFG *)data, sizeof(struct SAR_IOCTL_CFG))) return -EFAULT; ch_no = cfg.ch_no; snprintf(ifname, 6, "vc%d", ch_no); ch_no = 0; for (idx = 0; idx < Enable_VC_CNT; idx++) { if (cp->vcc[idx].dev && !strcmp(ifname, cp->vcc[idx].dev->name)) { ch_no = idx; break; } } //////// printk("set channel %d qos to %d\n", ch_no, cfg.QoS.Type); SetQoS(cp, ch_no, cfg.QoS.Type); if (cfg.QoS.Type==QoS_nrtVBR || cfg.QoS.Type==QoS_rtVBR) { SetPCR(cp, ch_no, cfg.QoS.PCR); SetSCR(cp, ch_no, cfg.QoS.SCR); SetMBS(cp, ch_no, cfg.QoS.MBS); } else if (cfg.QoS.Type==QoS_CBR) { SetPCR(cp, ch_no, cfg.QoS.PCR); } else { SetPCR(cp, ch_no, cfg.QoS.PCR); } break; } case SAR_ENABLE: { printk(KERN_DEBUG "sar_ioctl: SAR_ENABLE called.\n"); //set_atm_data_mode(1); Enable_SAR(cp); printk(KERN_DEBUG "sar_ioctl: SAR_ENABLE done.\n"); break; } case SAR_DISABLE: { printk(KERN_DEBUG "sar_ioctl: SAR_DISABLE called.\n"); Disable_SAR(cp); printk(KERN_DEBUG "sar_ioctl: SAR_DISABLE done.\n"); break; } case ATM_SAR_GETCONFIG: //case SAR_GET_CONFIG: { struct SAR_IOCTL_CFG *get_cfg = (struct SAR_IOCTL_CFG *)data; struct atm_vcc *vcc; printk(KERN_DEBUG "sar_ioctl: SAR_GET_CONFIG called.\n"); ch_no = get_cfg->ch_no; get_cfg->ch_no=ch_no; get_cfg->vpi = cp->vcc[ch_no].vpi; get_cfg->vci = cp->vcc[ch_no].vci; get_cfg->rfc = cp->vcc[ch_no].rfc; get_cfg->framing = cp->vcc[ch_no].framing; get_cfg->created = cp->vcc[ch_no].created; //get_cfg->loopback = cp->vcc[ch_no].loopback; vcc = cp->vcc[ch_no].dev_data; get_cfg->QoS.Type = sar_to_qos(vcc->qos.txtp.traffic_class); if(vcc->qos.txtp.pcr) get_cfg->QoS.PCR = vcc->qos.txtp.pcr; else get_cfg->QoS.PCR = 0x1DFF; if(vcc->qos.txtp.scr) get_cfg->QoS.SCR = vcc->qos.txtp.scr; else get_cfg->QoS.SCR = 0; if(vcc->qos.txtp.mbs) get_cfg->QoS.MBS = vcc->qos.txtp.mbs; else get_cfg->QoS.MBS = 128; get_cfg->QoS.CRD = 0; get_cfg->QoS.CDVT = 0; //memcpy(&get_cfg->QoS, &cp->vcc[ch_no].QoS, sizeof(Traffic_Manage)); memcpy(&get_cfg->stat, &cp->vcc[ch_no].stat, sizeof(ch_stat)); printk(KERN_DEBUG "sar_ioctl: RLCM_GET_CONFIG done.\n"); break; } case SAR_SET_CONFIG: { struct SAR_IOCTL_CFG cfg; printk(KERN_DEBUG "sar_ioctl: SAR_SET_CONFIG called.\n"); if (copy_from_user(&cfg, (struct SAR_IOCTL_CFG *)data, sizeof(struct SAR_IOCTL_CFG))) return -EFAULT; ch_no = cfg.ch_no; if(cp->vcc[ch_no].created !=FALSE) return -EFAULT; CreateVC(cp, &cfg, 0); printk(KERN_DEBUG "sar_ioctl: SAR_SET_CONFIG done.\n"); break; } case SAR_SET_ENCAPS: { struct SAR_IOCTL_CFG *cfg; int i; //if (copy_from_user(&cfg, (struct SAR_IOCTL_CFG *)data, sizeof(struct SAR_IOCTL_CFG))) // return -EFAULT; cfg = (struct SAR_IOCTL_CFG *)data; if (!cfg) return -EFAULT; // find the channel number for (i=0; i<Enable_VC_CNT; i++) { if (cp->vcc[i].vpi == cfg->vpi && cp->vcc[i].vci == cfg->vci) break; } if (i == Enable_VC_CNT) { printk(KERN_DEBUG "sar_ioctl: set encapsulation failed!\n"); return -EFAULT; } ch_no = i; cp->vcc[ch_no].rfc = cfg->rfc; cp->vcc[ch_no].framing = cfg->framing; // andrew, VC is created before encap is set? need to review!! 2007/11/08 if(RFC2364 == cfg->rfc) { Enable_Word_Insert(cp, ch_no); Write_IP_Parser(cp, ch_no, 1, 0); // enable eth parse, 0 offset } /* Set L2Encap in RV[x]_CKS for checking RX packet correctness */ if(cp->vcc[ch_no].framing == LLC_SNAP) Set_L2Encap(cp, ch_no, L2Encap_LLC); else Set_L2Encap(cp, ch_no, L2Encap_VCM); //#ifdef CONFIG_RTL867X_PACKET_PROCESSOR //set SAR interface encap. here if(cp->vcc[ch_no].framing == LLC_SNAP) pvc_encap[ch_no]=L2Encap_LLC; else pvc_encap[ch_no]=L2Encap_VCM; //#endif break; } #ifdef ATM_OAM case ATM_OAM_SET_ID: { ATMOAMLBID pATMOAMLBID; int i; /*jiunming*/ if( !DSPInShowtime ) { printk( "Not Enter Showtime!(line:%d)\n", __LINE__ ); return -EFAULT; } if (copy_from_user(&pATMOAMLBID, (ATMOAMLBID *)data, sizeof(ATMOAMLBID))) return -EFAULT; printk("SAR_ATM_OAM_SET_ID: Vpi = %d, Vci = %d, ", (int)pATMOAMLBID.vpi, (int)pATMOAMLBID.vci); printk("ID = "); for (i = 0; i < OAM_LB_SRCID_SIZE; i++) printk("%.02x", pATMOAMLBID.LocID[i]); printk("\n"); if(SetAtmOAMCpid(&pATMOAMLBID) == 0) { return -EFAULT; } break; } case ATM_OAM_LB_START: { ATMOAMLBReq pucPtr; //unsigned char i; /*jiunming*/ if( !DSPInShowtime ) { printk( "Not Enter Showtime!(line:%d)\n", __LINE__ ); return -EFAULT; } if (copy_from_user(&pucPtr, (ATMOAMLBReq *)data, sizeof(ATMOAMLBReq))) return -EFAULT; printk("SAR_ATM_OAM_START: Vpi = %d, Vci = %d\n", (int)pucPtr.vpi, (int)pucPtr.vci); if(StartAtmOAMLoopBack(&pucPtr) == 0) { return -EFAULT; } else { put_user(pucPtr.Tag, &((ATMOAMLBReq *)data)->Tag); printk("SAR_ATM_OAM_START: Tag is %d\n", (int)pucPtr.Tag); } break; } case ATM_OAM_LB_STOP: { ATMOAMLBReq pucPtr; /*jiunming*/ if( !DSPInShowtime ) { printk( "Not Enter Showtime!(line:%d)\n", __LINE__ ); return -EFAULT; } if (copy_from_user(&pucPtr, (ATMOAMLBReq *)data, sizeof(ATMOAMLBReq))) return -EFAULT; if(StopAtmOAMLoopBack(&pucPtr) == 0) { return -EFAULT; } else { printk("SAR_ATM_OAM_STOP: Tag is %d\n", (int)pucPtr.Tag); } break; } case ATM_OAM_LB_STATUS: { //OAMF5_LB_INFO *pLBInfo; //OAMF5_LBRX_INFO *pLBRXInfo; ATMOAMLBState pucPtr; //unsigned char i, j; /*jiunming*/ if( !DSPInShowtime ) { printk( "Not Enter Showtime!(line:%d)\n", __LINE__ ); return -EFAULT; } if (copy_from_user(&pucPtr, (ATMOAMLBState *)data, sizeof(ATMOAMLBState))) return -EFAULT; //printk("SAR_ATM_OAM_STATUS: Vpi = %d, Vci = %d\n",(int)pucPtr.vpi, (int)pucPtr.vci); if(GetAtmOAMLoopBackStatus(&pucPtr) == 0) { printk("SAR_ATM_OAM_STATUS: Tag %d NOT found!\n", (int)pucPtr.Tag); return -EFAULT; } else { //int i, j; /* printk("SAR_ATM_OAM_STATUS: Tag %d\n", (int)pucPtr.Tag); for(i=0;i<6;i++) { if(pucPtr.status[i] == FAULT_LB_WAITING) { printk("status Waiting\n"); } else if(pucPtr.status[i] == FAULT_LB_STOP) { printk("status Stop, count %u, rtt %u, LLID ", (int)pucPtr.count[i], (int)pucPtr.rtt[i]); for (j = 0; j < OAM_LB_LLID_SIZE; j++) printk("%.02x", pucPtr.LocID[i][j]); printk("\n"); } } */ copy_to_user(data, &pucPtr, sizeof(ATMOAMLBState)); } break; } case ATM_OAM_STATUS_FE: { ATMOAMLBRXState pucPtr; /*jiunming*/ if( !DSPInShowtime ) { printk( "Not Enter Showtime!(line:%d)\n", __LINE__ ); return -EFAULT; } if (copy_from_user(&pucPtr, (ATMOAMLBRXState *)data, sizeof(ATMOAMLBRXState))) return -EFAULT; if(GetAtmOAMLoopBackStatusFE(&pucPtr) == 0) { printk("SAR_ATM_OAM_STATUS_FE: NOT found!\n"); return -EFAULT; } else { //int i, j; printk("SAR_ATM_OAM_STATUS_FE: \n"); copy_to_user(data, &pucPtr, sizeof(ATMOAMLBRXState)); } break; } case SAR_ATM_OAM_RPT_LB: { ATMOAMLBReq pucPtr; //unsigned char i; /*jiunming*/ if( !DSPInShowtime ) { printk( "Not Enter Showtime!(line:%d)\n", __LINE__ ); return -EFAULT; } if (copy_from_user(&pucPtr, (ATMOAMLBReq *)data, sizeof(ATMOAMLBReq))) return -EFAULT; printk("SAR_ATM_OAM_START: Vpi = %d, Vci = %d\n", (int)pucPtr.vpi, (int)pucPtr.vci); OAMF5ContiLbTest(&pucPtr); break; } case SAR_ATM_OAM_STOP_LB: { /*jiunming*/ if( !DSPInShowtime ) { printk( "Not Enter Showtime!(line:%d)\n", __LINE__ ); return -EFAULT; } OAMF5StopLbTest(); break; } #endif case SAR_CREATE_VC: { struct SAR_IOCTL_CFG cfg; printk(KERN_DEBUG "sar_ioctl: SAR_CREATE_VC called.\n"); if (copy_from_user(&cfg, (struct SAR_IOCTL_CFG *)data, sizeof(struct SAR_IOCTL_CFG))) return -EFAULT; CreateVC(cp, &cfg, 1); printk(KERN_DEBUG "sar_ioctl: SAR_CREATE_VC done.\n"); break; } case SAR_DELETE_VC: { struct SAR_IOCTL_CFG cfg; printk(KERN_DEBUG "sar_ioctl: SAR_DELETE_VC called.\n"); if (copy_from_user(&cfg, (struct SAR_IOCTL_CFG *)data, sizeof(struct SAR_IOCTL_CFG))) return -EFAULT; ch_no = cfg.ch_no; if(cp->vcc[ch_no].created !=VC_CREATED) return -EFAULT; DeleteVC(cp, &cfg); //cfg.created = FALSE; printk(KERN_DEBUG "sar_ioctl: SAR_DELETE_VC done.\n"); break; } case SAR_SETMAC: { struct SAR_IOCTL_CFG cfg; printk(KERN_DEBUG "sar_ioctl: SAR_SETMAC called.\n"); if (copy_from_user(&cfg, (struct SAR_IOCTL_CFG *)data, sizeof(struct SAR_IOCTL_CFG))) return -EFAULT; ch_no=cfg.ch_no; memcpy(cp->vcc[ch_no].MAC, cfg.MAC, 6); //for(i=0;i<6;i++) // "%02X ", cp->vcc[ch_no].MAC[i]); cp->QoS_Test=TRUE; printk(KERN_DEBUG "sar_ioctl: SAR_SETMAC done.\n"); break; } case SAR_ENABLE_UTOPIA: { printk(KERN_DEBUG "sar_ioctl: SAR_ENABLE_UTOPIA called.\n"); // REG16(0xB8000c44)= (uint16)0xBE03; printk(KERN_DEBUG "sar_ioctl: SAR_ENABLE_UTOPIA done.\n"); break; } case SAR_UTOPIA_FAST: { printk(KERN_DEBUG "sar_ioctl: SAR_UTOPIA_FAST called.\n"); cp->atmport = ATMPORT_FAST; //flush_tx_desc(cp); printk(KERN_DEBUG "sar_ioctl: SAR_UTOPIA_FAST done.\n"); break; } case SAR_UTOPIA_SLOW: { printk(KERN_DEBUG "sar_ioctl: SAR_UTOPIA_SLOW called.\n"); cp->atmport = ATMPORT_SLOW; //flush_tx_desc(cp); printk(KERN_DEBUG "sar_ioctl: SAR_UTOPIA_SLOW done.\n"); break; } case SAR_EnableLOOPBACK: { printk("Enable SAR Loopback\n"); Enable_LoopBack(cp); break; } case SAR_DisableLOOPBACK: { printk("Disable SAR Loopback\n"); Disable_LoopBack(cp); break; } //12/30/05' hrchen, for PVC desc number setting case SAR_SET_PVC_NUMBER: { printk("SetPVCNumber is obsoleted\n"); #if 0 int i; if (copy_from_user(&total_pvc_number, data, sizeof(int))) return -EFAULT; /*if ((total_pvc_number>=1)&&(total_pvc_number<=8)) { per_vc_desc_number = ((SAR_RX_NUM / total_pvc_number )+3)&0xFFFFFFFC; if (per_vc_desc_number>SAR_RX_DESC_HI_LIMIT) per_vc_desc_number=SAR_RX_DESC_HI_LIMIT; } else per_vc_desc_number = 8; */ if ((total_pvc_number<1)||(total_pvc_number>Enable_VC_CNT)) { printk(KERN_DEBUG "sar_ioctl: SAR_SET_PVC_NUMBER not allowed (0x%x)\n", total_pvc_number); return -EFAULT; }; per_vc_desc_number = SAR_RX_NUM/total_pvc_number; if (per_vc_desc_number>SAR_RX_DESC_HI_LIMIT) per_vc_desc_number = SAR_RX_DESC_HI_LIMIT; for (i=0;i<total_pvc_number;i++) current_desc_number[i] = per_vc_desc_number; printk("PVC Number = %d. Set Desc number per VC = %d\n", total_pvc_number, per_vc_desc_number); #ifdef SAR_RX_FORMATION if (total_pvc_number <= 2) // do rx formation if pvc_number > 2 do_formation = 0; else do_formation = 1; #endif // of SAR_RX_FORMATION #endif break; } //1/13/06' hrchen, for memory read case SAR_READ_MEM: { unsigned int *address, len; if (copy_from_user(&address, data, sizeof(int))) return -EFAULT; if (copy_from_user(&len, data+4, sizeof(int))) return -EFAULT; data += 8; //skip 8 bytes address/len //tylo, for packet processor debug printk("Read Address 0x%08x len 0x%08x\n", (unsigned int)address, len); if (copy_to_user(data, address, len)) return -EFAULT; break; } //1/13/06' hrchen, for memory write 4 bytes case SAR_WRITE_MEM: { unsigned int *address, value; if (copy_from_user(&address, data, sizeof(int))) return -EFAULT; if (copy_from_user(&value, data+4, sizeof(int))) return -EFAULT; printk("Write Address 0x%08x Value 0x%08x\n", (unsigned int)address, value); *((unsigned int*)address) = value; break; } //#ifdef AUTO_PVC_SEARCH case SENT_BOA_PID: { if(copy_from_user(&boa_pid, data, sizeof(int))) return -EFAULT; break; } //#endif case SENT_TR069_PID: { if(copy_from_user(&tr069_pid, data, sizeof(int))) return -EFAULT; printk("Got PID %d from TR069 \n", tr069_pid); break; } case SENT_SNTP_PID: { if(copy_from_user(&sntp_pid, data, sizeof(int))) return -EFAULT; break; } #if 0 case SENT_TERM_REQ: { // printk("send PPP term-req\n"); // sendTERM(); break; } #endif // for debug case SAR_DEBUG_PVC_ENABLE: { if (copy_from_user(&dbg_cfg, (struct SAR_IOCTL_DEBUG *)data, sizeof(struct SAR_IOCTL_DEBUG))) return -EFAULT; break; } case SAR_DEBUG_OBAAL5_ENABLE: { if (copy_from_user(&debug_obaal5, data, sizeof(int))) return -EFAULT; break; } case SAR_DEBUG_OBCELL_ENABLE: { if (copy_from_user(&debug_obcell, data, sizeof(int))) return -EFAULT; break; } case SAR_DEBUG_NUM2PRINT: { if (copy_from_user(&debug_num2print, data, sizeof(int))) return -EFAULT; break; } case SAR_DEBUG_STATUS: { int _avail_desc, k; TV_CMD_DESC *TVDesc; printk("size = %d\npvc = %d\nobaal5 = %d\nobcell = %d\n", debug_num2print, dbg_cfg.enable, debug_obaal5, debug_obcell); #ifdef CONFIG_FLOW_CTRL printk("RCR = 0x%08x, FCFlag = %d\n", *(int *)(0xb9800044), FCFlag); printk("FCCtrl=%d, FC_low=%d, FC_high=%d\n", FCCtrl, FC_low, FC_high); #endif for(ch_no=0;ch_no<Enable_VC_CNT ;ch_no++){ if(cp->vcc[ch_no].created!=VC_CREATED) continue; _avail_desc = (cp->vcc[ch_no].TV.desc_pf- 1 - cp->vcc[ch_no].TV.desc_pw + SAR_TX_DESC_NUM)%SAR_TX_DESC_NUM; printk("[%02d] avail_desc = %d\n\t", ch_no, _avail_desc); TVDesc=&cp->TVDesc[ch_no*SAR_TX_RING_SIZE]; for (k=0; k<SAR_TX_DESC_NUM; k++) { printk("%1d", (TVDesc->CMD&OWN)? 1:0); TVDesc++; } printk("\n"); } break; } #ifdef CONFIG_PORT_MIRROR case SAR_PORT_MIRROR: { int vpi, vci, flag; char monitor_ifname[32]; struct net_device *todev = NULL; /* sarctl(32 octects): int(vpi), int(vci), int(flag), str(itf_name) */ if (copy_from_user(&vpi, data, sizeof(int))) return -EFAULT; if (copy_from_user(&vci, data+4, sizeof(int))) return -EFAULT; if (copy_from_user(&flag, data+8, sizeof(int))) return -EFAULT; if (copy_from_user(monitor_ifname, data+12, 20)) return -EFAULT; ch_no = 0; if ((0 == vpi) && (0 == vci)) { sar_mirror_flag = flag; } else { /* search vpi vci */ for (; ch_no < Enable_VC_CNT; ch_no++) { if (VC_CREATED != cp->vcc[ch_no].created) { continue; } if (vpi == -1) { /* show mirror status */ printk("(%d/%d): flag=%d, todev=%s\n", cp->vcc[ch_no].vpi, cp->vcc[ch_no].vci, cp->vcc[ch_no].mirror_mode, cp->vcc[ch_no].monitor_dev?cp->vcc[ch_no].monitor_dev->name:"dft"); } else if ((cp->vcc[ch_no].vpi == vpi) && (cp->vcc[ch_no].vci == vci)) { cp->vcc[ch_no].mirror_mode = flag; todev = 0; if (monitor_ifname[0]) { todev = dev_get_by_name(&init_net, monitor_ifname); if(!todev) { printk("error monitoring device!\n"); return -EFAULT; } } // assign monitoring lan interface if (cp->vcc[ch_no].monitor_dev != NULL) dev_put(cp->vcc[ch_no].monitor_dev); cp->vcc[ch_no].monitor_dev = todev; break; } } } if (vpi != -1 && Enable_VC_CNT == ch_no) { return -EFAULT; } break; } #endif case SAR_UPGRADE_FW: { break; } case SAR_RESET_STATS: { if(copy_from_user(&iVal, arg, sizeof(int))) return -EFAULT; if (iVal == -1) { // all for (iVal=0; iVal<Enable_VC_CNT; iVal++) { memset(&cp->vcc[iVal].stat, 0, sizeof(ch_stat)); } } else if (iVal>=0 && iVal <= Enable_VC_CNT) { memset(&cp->vcc[iVal].stat, 0, sizeof(ch_stat)); } else return -EOPNOTSUPP; break; } default: printk("Command error or not supported\n"); //printk(KERN_DEBUG "sar_ioctl: not support ioctl command (0x%x)\n", cmd); return -EOPNOTSUPP; } DRV_LEAVE; return 0; } /* for auto switch data mode, FAST mode is 1, INTERLEAVED mode is 2 hrchen 5/22/04' */ static void sar_restart_hw (sar_private *cp) { /* ---> SAR Entire Module Related <--- */ Reset_Sar(); Init_reg(cp); /* set corresponding register address */ //SetCRCTbl(); //GenCRC10Table(); //Enable_SAR(cp); /* Enable/Disable Loopback test mode */ #ifdef LoopBack_Test /*Enable_LoopBack(); */ Disable_LoopBack(cp); Enable_Sachem_Loopback(); #else Disable_LoopBack(cp); //REG16(0xb8000c20)=0x0600; //Enable_Sachem_Utopia(); //Enable_Sachem_Loopback(); #endif // Enable_LoopBack(cp); /* Select Qos Clock from External clock */ // QCLKSEL has been removed Set_QoS_Ext(cp, 0); /* external */ cp->QoS_Test= FALSE; #ifdef ENA_OAM_CH //AllocVcBuff(cp, OAM_CH_NO); //if (cp->vcc[OAM_CH_NO].dev_data) //Remote Management Channel is created // Disable_Drop_NonOAM(cp, OAM_CH_NO); //else // Enable_Drop_NonOAM(cp, OAM_CH_NO); //Enable_rx_ch(cp, OAM_CH_NO); //Enable_tx_ch(cp, OAM_CH_NO); #endif #ifdef ATM_OAM //remember to change the VPI/VCI setting OAMF5Init(0, 0, &OAMF5_info); OAMF4Init(0, 0, &OAMF4_info); #endif #ifdef CONFIG_ATM_BONDING ASMInit(); #endif /* ---> Interrupt Related <--- */ Enable_IERDA(cp); Set_RDA(cp, RDATHR, RDATimer); /* polling TBE */ Disable_IETBE(cp); //Disable_IETDF(cp); //Enable_IETBE(cp); Enable_IETDF(cp); Enable_IERBF(cp); #ifdef CONFIG_RTL8672_ATM_QoS //enable 8672 new function Enable_IS8671G_1(cp); Enable_IS8671G_0(cp); Enable_IS8672_10(cp); /* * Disable QoS Starvtaion bit for maximum PCR limitation mechanism * This mechanism is added to solve the imprecise PCR issue that * was found in Dec. 2014. */ //Enable_QoS_Starvation(cp); Disable_QoS_Starvation(cp); #endif //deprecated after applying maximum PCR limitation mechanism #ifdef SW_QOS_STARV_PREVENTION Disable_QoS_Starvation(cp); REG32(0xb8303010) = 0xfff70000; #endif Enable_QoS_Priority(cp, 0); Enable_HP_CHTx(cp, 0); #if defined(CONFIG_RTL8681_SAR_ARCH) || defined(CONFIG_RTL8685_SAR_ARCH) { int ch_no; /* Set Bonding port #0, #1*/ Enable_BOND_Link(cp, 0); Enable_BOND_Link(cp, 1); /* Set Bonding line = 0, and it means non-bonding */ Set_BOND_Line(cp,0); /* Set TX path for each channel, 0:fast path, 1:interleave */ for(ch_no=0; ch_no < (Enable_VC_CNT); ch_no++){ Set_Dual_Map(cp,ch_no, SAR_TX_PATH(sendToPort0)); } /* Set WFGQ */ Set_Bond_WFQ(cp,0,5); /* Enable dummy */ if (!IS_RL6405 && !IS_RLE0822 && !IS_6518()){ Enable_Dummy(cp); } /* Config Dummy register */ Set_Bond_Dummy(cp, 0x16a); #ifdef CONFIG_ATM_BONDING Enable_IEASMTICK(cp); Set_TSTMP(cp, 0x270f, 0x270f); #endif } #endif } #ifdef SAR_RX_FORMATION //free skb buffer in free list #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif void free_rx_free_list(void) { struct sk_buff *skb; free_next_rx_free_list: free_rx_skb_consumer++; if (free_rx_skb_consumer==SAR_MAX_Process_DESC) free_rx_skb_consumer=0; //touch end, move to head if (free_rx_skb_producer==free_rx_skb_consumer) goto stop_free; //no mroe skb in free list skb = free_rx_skb_list[free_rx_skb_consumer]; if(skb!=(struct sk_buff *)NULL) dev_kfree_skb(skb); goto free_next_rx_free_list; stop_free: free_rx_skb_producer=0; free_rx_skb_consumer=SAR_MAX_Process_DESC-1; } #endif // of SAR_RX_FORMATION #ifdef AUTO_PVC_SEARCH void searchPVC(void){ int i; //set temp vpi/vci SetVpiVci(sar_dev,0,0,0); //Disable_rx_ch(sar_dev,0); for (i = 0; i<Enable_VC_CNT; i++) Disable_rx_ch(sar_dev,i); } void startPVCSearch(void) { #ifdef CONFIG_RTL8672 // Mason Yu. Recieve packet from OAM ch1(not cho) for AutoHunt sar_private *cp = sar_dev; #endif //search possible VC //REG16(GIMR)&=(~SAR_IM); // search_flag=0; #ifdef CONFIG_RTL8672 Disable_Drop_NonOAM(sar_dev,OAM_CH_NO+1); #else Disable_Drop_NonOAM(sar_dev,OAM_CH_NO); #endif //REG16(GIMR)|=SAR_IM; // Mason Yu. Recieve packet from OAM ch1(not cho) for AutoHunt #ifdef CONFIG_RTL8672 Enable_rx_ch(cp, OAM_CH_NO+1); #endif } #endif //#include "../../net/atm/br2684.c" extern char PrioChannelNum[5]; //tylo, temp. marked for linux2.6 porting //extern BOOL GetLinkSpeed(char *Rate); T_LinkSpeed LINE_rate; char checkRateEnable=0; #ifdef CONFIG_RTL8685_SAR_TPS_RESET extern void ShowtimeTpsReset(void); extern void ShowtimeTpsSet(void); #endif /*CONFIG_RTL8685_SAR_TPS_RESET*/ #ifdef CONFIG_RTL867X_KERNEL_MIPS16_DRIVERS_ATM __NOMIPS16 #endif void set_atm_data_mode(int mode) { #if 1 int io_cmd=0; int i; sar_private *cp = sar_dev; sar_atm_vcc *bakup_vcc[Enable_VC_CNT]; struct SAR_IOCTL_CFG cfg; struct atm_vcc *vcc; struct atm_vcc * tmp_atm_vcc; unsigned long flags; stop_rx = 1; synchronize_net(); // spin_lock_irqsave(&cp->ctllock, flags); checkRateEnable=1; if (mode==1) io_cmd = SAR_UTOPIA_FAST; else if (mode==2) io_cmd = SAR_UTOPIA_SLOW; for(i=0;i<5;i++){ PrioChannelNum[i]=0; } #ifdef CONFIG_RTL8685_SAR_TPS_RESET if(getADSLLinkStatus()&&(enable_mode==0)) ShowtimeTpsReset(); #endif /*CONFIG_RTL8685_SAR_TPS_RESET*/ if (io_cmd!=0) { //stop & reset VC structure //disable_lx4180_irq(cp->irq); //tasklet_disable(&cp->tasklets); sar_stop_hw(cp); //close VC for (i=0;i<Enable_VC_CNT;i++) { if(cp->vcc[i].created==VC_CREATED){ //backup vcc bakup_vcc[i] = kmalloc(sizeof(sar_atm_vcc), GFP_ATOMIC); memcpy(bakup_vcc[i], &cp->vcc[i], sizeof(sar_atm_vcc)); memset(bakup_vcc[i]->rx_buf, 0, sizeof(bakup_vcc[i]->rx_buf)); memset(bakup_vcc[i]->tx_buf, 0, sizeof(bakup_vcc[i]->tx_buf)); vcc = cp->vcc[i].dev_data; _sar_close(cp->vcc[i].dev_data); } else { bakup_vcc[i]=NULL; }; }; Disable_rx_ch(cp, OAM_CH_NO); Disable_tx_ch(cp, OAM_CH_NO); FreeVcBuff(cp, OAM_CH_NO); #ifdef SAR_RX_FORMATION //for rx desc re-assign reset free_rx_free_list(); #endif // of SAR_RX_FORMATION //reset current_desc_number, per_vc_desc_number is set in ioctl(SAR_SET_PVC_NUMBER) for (i=0;i<Enable_VC_CNT;i++) { current_desc_number[i] = per_vc_desc_number; } //set data mode if (mode==1) cp->atmport = ATMPORT_FAST; else cp->atmport = ATMPORT_SLOW; //restart SAR sar_restart_hw(cp); //open PVC for (i=0;i<Enable_VC_CNT;i++) { if (bakup_vcc[i]==NULL) continue; if (bakup_vcc[i]->created==VC_CREATED){ //restore vcc memcpy(&cp->vcc[i], bakup_vcc[i], sizeof(sar_atm_vcc)); vcc = cp->vcc[i].dev_data; cfg.ch_no = i; /* Create one VC first */ cfg.vpi = cp->vcc[i].vpi; cfg.vci = cp->vcc[i].vci; /* default setting */ cfg.rfc = cp->vcc[i].rfc; cfg.framing = cp->vcc[i].framing; cfg.QoS.Type = sar_to_qos(vcc->qos.txtp.traffic_class); if(vcc->qos.txtp.pcr) cfg.QoS.PCR = vcc->qos.txtp.pcr; else cfg.QoS.PCR = 0x1DFF; if(vcc->qos.txtp.scr) cfg.QoS.SCR = vcc->qos.txtp.scr; else cfg.QoS.SCR = 0; if(vcc->qos.txtp.mbs) cfg.QoS.MBS = vcc->qos.txtp.mbs; else cfg.QoS.MBS = 128; cfg.QoS.CRD = 0; cfg.QoS.CDVT = 0; cp->vcc[i].created = VC_NOT_CREATED; CreateVC(cp, &cfg, 0); //get net_device tmp_atm_vcc=(struct atm_vcc *)cp->vcc[i].dev_data; cp->vcc[i].dev = (struct net_device *)tmp_atm_vcc->net_dev; //check if this interface is bridged #if 0 if (cp->vcc[i].dev) { if(cp->vcc[i].dev->br_port) cp->vcc[i].br=1; else{ cp->vcc[i].br=0; } } #endif //printk("net_device: %x\n", (unsigned long)cp->vcc[i].dev); if (cp->vcc[i].dev) netif_wake_queue(cp->vcc[i].dev); set_bit(ATM_VF_READY, &vcc->flags); }; kfree(bakup_vcc[i]); }; for (i=0;i<Enable_VC_CNT;i++) { if (cp->vcc[i].created!=VC_CREATED) continue; Enable_rx_ch(cp, i); Enable_tx_ch(cp, i); } AllocVcBuff(cp, OAM_CH_NO); if (cp->vcc[OAM_CH_NO].dev_data) //Remote Management Channel is created Disable_Drop_NonOAM(cp, OAM_CH_NO); else Enable_Drop_NonOAM(cp, OAM_CH_NO); Enable_rx_ch(cp, OAM_CH_NO); Enable_tx_ch(cp, OAM_CH_NO); //tasklet_enable(&cp->tasklets); //enable_lx4180_irq(cp->irq); //REG16(GIMR) |= SAR_IM ; } #ifdef CONFIG_RTL8685_SAR_PATCH_ONOFF if(getADSLLinkStatus()&&(enable_mode==0)) Enable_SAR(cp); #else //CONFIG_RTL8685_SAR_PATCH_ONOFF if(getADSLLinkStatus()) Enable_SAR(cp); #endif /*CONFIG_RTL8685_SAR_PATCH_ONOFF*/ #ifdef CONFIG_RTL8685_SAR_TPS_RESET if(getADSLLinkStatus()&&(enable_mode==0)) ShowtimeTpsSet(); #endif /*CONFIG_RTL8685_SAR_TPS_RESET*/ //GetLinkSpeed(&LINE_rate); #ifdef AUTO_PVC_SEARCH found_pvc=1; //set as found already, wait for startup to inform driver pvc-search #endif //AUTO_PVC_SEARCH if(sntp_pid) { //printk("signal SIGUSR1 to process vsntp (%d)\n", sntp_pid); extern long sys_kill(int pid, int sig); sys_kill(sntp_pid, SIGUSR1); //raise sigusr1 to process vsntp } #endif #if defined(CONFIG_RTL8681_SAR_ARCH) || defined(CONFIG_RTL8685_SAR_ARCH) /* Flush ATM TX cell fifo in DSP lib already */ #else printk("applying workaround..."); REG16(0xb8600c42) = 0x0003; REG16(0xb8600c42) = 0x0000; printk("done\n"); #endif spin_unlock_irqrestore(&cp->ctllock, flags); stop_rx = 0; } int sar_getsockopt(struct atm_vcc *vcc, int level, int optname, void *optval, int optlen) { return -EINVAL; } int sar_setsockopt(struct atm_vcc *vcc, int level, int optname, void *optval, unsigned int optlen) { return -EINVAL; } void sar_phy_put(struct atm_dev *dev,unsigned char value, unsigned long addr) { } unsigned char sar_phy_get(struct atm_dev *dev,unsigned long addr) { return -EINVAL; } void sar_feedback(struct atm_vcc *vcc, struct sk_buff *skb, unsigned long start, unsigned long dest, int len) { } int sar_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flags) { sar_private *cp; sar_atm_vcc *vcc_dev; int ch_no; /* if it set before vcc open, it's ok to return no error */ cp = RTATM_DEV(vcc->dev); if(!cp) return 0; vcc_dev = RTATM_VCC(vcc); if(!vcc_dev) return 0; ch_no = vcc_dev->ch_no; SetQoS(cp, ch_no, sar_to_qos(vcc->qos.txtp.traffic_class)); SetPCR(cp, ch_no, vcc->qos.txtp.pcr); SetSCR(cp, ch_no, vcc->qos.txtp.scr); SetMBS(cp, ch_no, vcc->qos.txtp.mbs); return 0; } #ifdef CONFIG_RTL8681_SAR_ARCH void sar_set_gpio(void) { // DSP lib select the ptm/atm mode, and don't selet mode here //REG32(BSP_IP_SEL) |= (BSP_EN_SAR | BSP_EN_SACHEM); gpioClear(GPIO_A_2); gpioConfig(GPIO_A_2,GPIO_FUNC_OUTPUT); gpioClear(GPIO_A_3); gpioConfig(GPIO_A_3,GPIO_FUNC_OUTPUT); gpioClear(GPIO_A_4); gpioConfig(GPIO_A_4,GPIO_FUNC_OUTPUT); gpioClear(GPIO_A_5); gpioConfig(GPIO_A_5,GPIO_FUNC_OUTPUT); gpioClear(GPIO_A_6); gpioConfig(GPIO_A_6,GPIO_FUNC_OUTPUT); gpioClear(GPIO_B_1); gpioConfig(GPIO_B_1,GPIO_FUNC_OUTPUT); } #endif ///////////////////////////////OAM related #ifdef ATM_OAM __SWAP //int OAMFSendACell(unsigned char *pCell, int flagOAM) static int ATMSendACell(unsigned char *pCell, int flagOAM, unsigned char flagASM, unsigned char intrlv, unsigned char atmport ) { sar_private *cp = sar_dev; INT16 j=0, fragNum=1; int currCDOI; UINT16 CMD=0; TV_CMD_DESC *TVDesc; //END_TX_SEM_TAKE (&sar_end->end, WAIT_FOREVER); cp->vcc[OAM_CH_NO].stat.send_cnt++; /* Clear transmitted descriptors */ ClearTxBuffer(cp, OAM_CH_NO); { static int oam_tx_counter = 0; oam_tx_counter++; if(oam_tx_counter%10000 == 1) printk("OAM tx %d\n",oam_tx_counter); } #ifdef Do_Make /*if no descriptor available, clear TBE if needed */ if(((((cp->vcc[OAM_CH_NO].TV.desc_pw+1)%SAR_TX_DESC_NUM)==cp->vcc[ch_no].TV.desc_pf)&& (cp->TODesc[cp->vcc[OAM_CH_NO].TV.desc_pw].CMD&OWN)!=0)){ cp->vcc[OAM_CH_NO].stat.send_desc_full++; /* descriptors full*/ /* get current CDOI */ currCDOI=GetTxCDOI(cp,OAM_CH_NO); /* if TBE occurs and current descriptor is own by hardware (that means last time TBE occurs, and the desriptors has been refilled), clear TBE and make this channel be scheduled again */ if ((reg(SAR_TBEI_Addr)&(0x00000001<<OAM_CH_NO))&&((cp->TODesc[currCDOI].CMD)&OWN)) Clear_TBE(OAM_CH_NO, currCDOI); goto DropPacket; } /* if not enough descriptors, drop this packet */ avail_desc = (cp->vcc[OAM_CH_NO].TV.desc_pf- 1 - cp->vcc[OAM_CH_NO].TV.desc_pw + SAR_TX_DESC_NUM)%SAR_TX_DESC_NUM; if (avail_desc <= fragNum) { cp->vcc[OAM_CH_NO].stat.send_desc_lack++; goto DropPacket; } #endif /* Fix the unstable OAM ping -shlee */ dma_cache_wback_inv((unsigned long)pCell, 52); /* Get Current Descriptor Index */ j= cp->vcc[OAM_CH_NO].TV.desc_pw; /* if this Descriptor is OWN by SAR*/ if(cp->TODesc[j].CMD&OWN){ goto Drop_OAM_Cell; } /* Handle this descriptor */ TVDesc=(TV_CMD_DESC *)(&cp->TODesc[j]); CMD=0; cell_debug(pCell, debug_obcell, 1); /* fill 1483 header if first descriptor*/ TVDesc->START_ADDR = (uint32)pCell|Uncache_Mask; TVDesc->LEN = 52; cp->vcc[OAM_CH_NO].tx_buf[j]=(UINT32)pCell; /* Set FS LS */ CMD |= (FS|LS); #if defined(CONFIG_RTL8681_SAR_ARCH) || defined(CONFIG_RTL8685_SAR_ARCH) if(flagASM) { CMD = CMD | OWN | (intrlv? INTRLV:0) | CRC10EN | isASM | ( ((unsigned short)(atmport&0x1f))<<4 ) ; }else{ CMD = CMD | (intrlv? INTRLV:0) |(flagOAM?CRC10EN:0) /* Enable CRC10 Generate if OAM cell*/ |OWN /* set owner */ | ( ((unsigned short)(atmport&0x1f))<<4 ); } #else CMD = CMD |(flagOAM?CRC10EN:0) /* Enable CRC10 Generate if OAM cell*/ #ifndef CONFIG_RTL8672 |cp->atmport/*use ATMPORT 1 */ #endif |OWN; /* set owner */ if(SAR_TX_PATH(sendToPort0)){ //atmport 1 CMD |= 0x0800; } #endif if(j==(SAR_TX_DESC_NUM-1)) CMD |= EOR; /* save the CMD to Descriptor */ TVDesc->CMD=CMD; cp->vcc[OAM_CH_NO].TV.desc_pw = (cp->vcc[OAM_CH_NO].TV.desc_pw + 1)%SAR_TX_DESC_NUM; currCDOI = GetTxCDOI(cp, OAM_CH_NO); /* if TBE occurs and the current descriptor is owned by hardware, re-schedule this channel */ if (reg(SAR_TBEI_Addr)&(0x00000001<<HW_OAM_CH_NO)) { //if ((reg(SAR_TBEI_Addr)&(0x00000001<<HW_OAM_CH_NO))&&((cp->TVDesc[OAM_CH_NO*SAR_TX_RING_SIZE+currCDOI].CMD)&OWN)) { Clear_TBE(OAM_CH_NO, currCDOI); }; /* Clear transmitted descriptors AGAIN */ //ClearTxBuffer(cp, OAM_CH_NO); cp->vcc[OAM_CH_NO].stat.send_ok++; cp->vcc[OAM_CH_NO].stat.tx_byte_cnt += 53; // END_TX_SEM_GIVE (&sar_end->end); return 1; Drop_OAM_Cell: //printk(" tx OAM Cell dropped, available descriptors = %d\n",avail_desc); cp->vcc[OAM_CH_NO].stat.send_fail++; cp->vcc[OAM_CH_NO].stat.tx_pkt_fail_cnt+=fragNum; kfree(pCell); //5/25/04' hrchen, fix pCell not free bug //END_TX_SEM_GIVE (&sar_end->end); return 0; } int OAMFSendACell(unsigned char *pCell, int flagOAM) { sar_private *cp = sar_dev; #if (defined(CONFIG_RTL8681_SAR_ARCH) || defined(CONFIG_RTL8685_SAR_ARCH)) && defined(CONFIG_ATM_BONDING) if( getADSLLinkStatus() &&(enable_mode==0) ){ if (ActivePortOAM() != -1){ return ATMSendACell( pCell, flagOAM, 0, SAR_TX_PATH(sendToPort0), ActivePortOAM() ); } } #elif defined(CONFIG_RTL8681_SAR_ARCH) || defined(CONFIG_RTL8685_SAR_ARCH) if( getADSLLinkStatus() &&(enable_mode==0) ){ return ATMSendACell( pCell, flagOAM, 0, SAR_TX_PATH(sendToPort0), 0 ); } #else if(getADSLLinkStatus()) return ATMSendACell( pCell, flagOAM, 0, 0, 0 ); #endif printk("No active port for OAM!\n"); //Drop_ASM_Cell: cp->vcc[OAM_CH_NO].stat.send_fail++; cp->vcc[OAM_CH_NO].stat.tx_pkt_fail_cnt+=1; kfree(pCell); return 0; } #ifdef CONFIG_ATM_BONDING static int ASMSendACell(unsigned char *pCell, unsigned char intrlv, unsigned char atmport) { sar_private *cp = sar_dev; if( getADSLLinkStatus() &&(enable_mode==0) ) return ATMSendACell( pCell, 0, 1, intrlv, atmport ); //Drop_ASM_Cell: cp->vcc[OAM_CH_NO].stat.send_fail++; cp->vcc[OAM_CH_NO].stat.tx_pkt_fail_cnt+=1; kfree(pCell); return 0; } int ASMTxHandler(unsigned char *p, unsigned char intrlv, unsigned char atmport) { unsigned char *pCell; if(p==NULL) return 0; pCell=kmalloc(OAM_CELL_SIZE, GFP_ATOMIC); if (pCell==NULL) { printk( "%s: No buffer for ASM cell!!!\n", __FUNCTION__ ); return 0; } memcpy( pCell, p, OAM_CELL_SIZE); if(ASMSendACell(pCell, intrlv, atmport)==0) { printk( "%s: call ASMSendACell() failed!\n", __FUNCTION__ ); return 0; }; return 1; } #endif /*CONFIG_ATM_BONDING*/ /*void OAMFReceiveCell(unsigned int type, unsigned char *pCell){ unsigned char *pcell2; pcell2 = (unsigned char *)malloc(SAR_OAM_Buffer_Size); memcpy(pcell2, pCell, SAR_OAM_Buffer_Size); OAMFSendACell(pcell2, 1); return; }*/ #if 0 typedef struct { unsigned gfc:4; /* Generic Flow Control; */ unsigned vpi:8; /* Virtual Path Identifier */ unsigned vci:16; /* Virtual Channel Identifier */ unsigned pti:3; /* Payload type Identifier */ unsigned clp:1; /* Cell Loss Priority */ unsigned oam:4; unsigned fun:4; } Cell_header; // AAL0 channel used typedef struct { unsigned long hdr0; unsigned char hdr1; unsigned char loopbk; unsigned long ctag; unsigned char lbk_loc_id[16]; unsigned char lbk_src_id[16]; unsigned char unused[8]; } lbk_spec_field; #define get_gfc(x) (x->hdr0>>28) #define get_vpi(x) (x->hdr0>>20)&0xFF #define get_vci(x) (x->hdr0>>4)&0xFFFF #define get_pti(x) (x->hdr0>>1)&0x07 #define get_clp(x) (x->hdr0&0x01) #define get_oam(x) (x->hdr1>>4) #define get_fun(x) (x->hdr1&0x0f) void process_aal0(sar_private *cp, unsigned char *mp) { lbk_spec_field *pCell; int i,vc; pCell = (lbk_spec_field*)mp; if ( get_vci(pCell) == 3 || get_vci(pCell) == 4) { /* F4 end-to-end and s-to-s cell */ if( (get_oam(pCell)==1) && (get_fun(pCell)==8) ) { /* loopback type */ if (get_vci(pCell) == 3) printk("Rx F4 SEG LB cell\n"); else printk("Rx F4 ETE LB cell\n"); /* check if VPI is exist */ /* process loopback function field */ if(pCell->loopbk) { /* the cell should be loopback */ /* LoopBack identifier decrement 1 */ pCell->loopbk = 0; } else { /* the cell is a loopback response */ /* try to pass to ATM socket */ return; } } else if((get_oam(pCell)==1) && (get_fun(pCell)==0)) { /* AIS received */ if (get_vci(pCell) == 3) printk("Rx F4 SEG AIS cell\n"); else printk("Rx F4 ETE AIS cell\n"); /* Func type set RDI */ get_fun(pCell)=0x1; /* generate RDI payload */ for(i=5;i<(5+17);i++) mp[i]=0x6A; // RDI default value mp[i]=0x00; } else { printk("Unprocessed raw cell, discard\n"); return; } } else if( get_pti(pCell) == 4 || get_pti(pCell) == 5) { /* F5 end-to-end and s-to-s cell */ if( (get_oam(pCell)==1) && (get_fun(pCell)==8) ) { /* LoopBack type */ if (get_pti(pCell) == 4) printk("Rx F5 SEG LB cell\n"); else printk("Rx F5 ETE LB cell\n"); /* search active vccs */ /* process loopback function field */ if(pCell->loopbk) { /* the cell should be loopback */ /* LoopBack identifier decrement 1 */ pCell->loopbk = 0; } else { /* the cell is a loopback response */ /* try to pass to ATM socket */ return; } } else if((get_oem(pCell)==1) && (get_fun(pCell)==0)) { /* AIS received */ if (get_pti(pCell) == 4) printf("Rx F5 SEG AIS cell\n"); else printf("Rx F5 ETE AIS cell\n"); /* search active vccs */ /* Func type set RDI */ get_fun(pCell) = 0x1; /* generate RDI payload */ for(i=5;i<(5+17);i++) mp[i]=0x6A; // RDI default value mp[i]=0x00; } else { printk("Unprocessed raw cell, discard\n"); return; } } else { printk("Unprocessed raw cell, discard\n"); return; } /* response OAM cell */ { unsigned char *pRCell = (unsigned char *) kmalloc(OAM_CELL_SIZE); if(pRCell == NULL) return; memcpy(pRCell, mp, OAM_CELL_SIZE); OAMFSendACell(pRCell, 1); kfree(pRCell); } } #endif #endif static const struct atmdev_ops ops = { .owner = THIS_MODULE, .open = sar_open, .close = sar_close, .ioctl = sar_ioctl, .getsockopt = sar_getsockopt, .setsockopt = sar_setsockopt, .send = sar_send, .phy_put = sar_phy_put, .phy_get = sar_phy_get, .change_qos = sar_change_qos, }; #ifdef REMOTE_MANAGEMENT_ENABLE extern void init_crc32_table(void); #endif // Kaohj -- /proc/sys/sar static struct ctl_table_header *sar_table_header; extern int netdev_backlog_drop; // net/core/dev.c static struct ctl_table sar_table[]= { #ifdef CONFIG_FLOW_CTRL {.procname = "flow_ctrl", .data = &FCCtrl, .maxlen = sizeof(FCCtrl), .mode = 0644, .proc_handler = &proc_dointvec }, {.procname = "fc_low", .data = &FC_low, .maxlen = sizeof(FC_low), .mode = 0644, .proc_handler = &proc_dointvec }, {.procname = "fc_high", .data = &FC_high, .maxlen = sizeof(FC_high), .mode = 0644, .proc_handler = &proc_dointvec }, #endif #ifdef FAST_ROUTE_Test {.procname = "direct_bridge", .data = &fast_route_mode, .maxlen = sizeof(fast_route_mode), .mode = 0644, .proc_handler = &proc_dointvec }, #endif #if 0 {.procname = "rx0", .data = ¤t_desc_number[0], .maxlen = sizeof(current_desc_number[0]), .mode = 0644, .proc_handler = &proc_dointvec }, {.procname = "rx1", .data = ¤t_desc_number[1], .maxlen = sizeof(current_desc_number[1]), .mode = 0644, .proc_handler = &proc_dointvec }, #endif #ifdef SAR_RX_FORMATION {.procname = "rx_formation", .data = &do_formation, .maxlen = sizeof(do_formation), .mode = 0644, .proc_handler = &proc_dointvec }, #endif // of SAR_RX_FORMATION {.procname = "netdev_backlog_drop", .data = &netdev_backlog_drop, .maxlen = sizeof(netdev_backlog_drop), .mode = 0644, .proc_handler = &proc_dointvec }, {} }; static struct ctl_table sar_root_table[]= { {.procname = "sar", .mode = 0555, .child = sar_table }, {} }; #if 0 #define DEBUG_RX_CH_NUM 8 #define DEBUG_TX_CH_NUM 8 static void print_rx_desc(int ch) { int i; u32 *p; sar_atm_vcc *vcc; vcc = &sar_dev->vcc[ch]; printk("[CH=%d %2d/%2d] FDP=%x [%3d,%3d,%3d]\n", ch, vcc->vpi, vcc->vci, (u32)(vcc->RV_Desc), vcc->RV.desc_pr, vcc->RV.desc_pc, vcc->RV.desc_pa); for (i=0; i<SAR_RX_DESC_NUM; i++) { p = (u32 *) &(vcc->RV_Desc[i]); printk("[%03d] %08x %08x %08x %08x %08x [%08x]\n", i, p[0], p[1], p[2], p[3], p[4], vcc->rx_buf[i]); } } static void print_tx_desc(int ch) { int i; u32 *p; sar_atm_vcc *vcc; vcc = &sar_dev->vcc[ch]; printk("[CH=%d %2d/%2d] FDP=%x [%3d,%3d,%3d]\n", ch, vcc->vpi, vcc->vci, (u32)(vcc->TV_Desc), vcc->TV.desc_pf, vcc->TV.desc_pc, vcc->TV.desc_pw); for (i=0; i<SAR_TX_DESC_NUM; i++) { p = (u32 *) &(vcc->TV_Desc[i]); printk("[%03d] %08x %08x %08x %08x [%08x]\n", i, p[0], p[1], p[2], p[3], vcc->tx_buf[i]); } } static int sar_tx_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int ch; for (ch=0; ch<DEBUG_TX_CH_NUM; ch++) { print_tx_desc(ch); } return 0; } static int sar_tx_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { char str[8]; int ch = -1; if (copy_from_user(str, buffer, sizeof(str))) { return -EFAULT; } sscanf(str, "%d", &ch); if ((ch >= 0) && (ch < DEBUG_TX_CH_NUM)) print_tx_desc(ch); return count; } static int sar_rx_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int ch; for (ch=0; ch<DEBUG_RX_CH_NUM; ch++) { print_rx_desc(ch); } return 0; } static int sar_rx_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { char str[8]; int ch = -1; if (copy_from_user(str, buffer, sizeof(str))) { return -EFAULT; } sscanf(str, "%d", &ch); if ((ch >= 0) && (ch < DEBUG_RX_CH_NUM)) print_rx_desc(ch); return count; } static int sar_info_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int ch; printk("Total:%d PerVC: %d RBF: %u\n", total_pvc_number, per_vc_desc_number, cntr_rbf); for (ch=0; ch<Enable_VC_CNT; ch++) { printk("[%2d]%4d ", ch, current_desc_number[ch]); if ((ch&3)==3) printk("\n"); } printk("\n"); return 0; } #endif static int atm_start_xmit(struct sk_buff *skb, struct net_device *dev) { dev_kfree_skb(skb); return 0; } static const struct net_device_ops atm_netdev_ops = { .ndo_start_xmit = atm_start_xmit, }; static const struct ethtool_ops atm_ethtool_ops = { .get_link = ethtool_op_get_link, }; static void atm_setup(struct net_device *netdev) { netdev->netdev_ops = &atm_netdev_ops; netdev->ethtool_ops = &atm_ethtool_ops; return; } static ssize_t write_proc_aps(struct file *file, const char __user * userbuf, size_t count, loff_t * off) { return procfile_write(file, userbuf, count, NULL); } static int read_proc_open_aps(struct inode *inode, struct file *file) { return(single_open(file, proc_aps_read, NULL)); } static struct file_operations fops_proc_aps = { .open = read_proc_open_aps, .read = seq_read, .llseek = seq_lseek, .release = single_release, .write = write_proc_aps, }; #ifdef CONFIG_SMP extern spinlock_t oamf5_lock; #endif #if defined(CONFIG_DSL_ON_SLAVE) int rtl8670_atm_init (void) #else int __init rtl8670_atm_init (void) #endif { struct atm_dev *dev; struct net_device *netdev; sar_private *cp; int err = 0; REG32(BSP_IP_SEL) |= (BSP_EN_SAR | BSP_EN_SACHEM); mdelay(5); // Add atm0 for dsl link status netdev = alloc_netdev(200, "atm%d", NET_NAME_UNKNOWN, atm_setup); if (netdev) { register_netdev(netdev); netif_carrier_off(netdev); } cp = (sar_private *) kzalloc(sizeof(sar_private), GFP_KERNEL); if (!cp) { printk(KERN_ERR DEV_LABEL ": kzalloc() failed\n"); err = -ENOMEM; goto out; } sar_dev = cp; dev = atm_dev_register(DEV_LABEL, NULL, &ops, -1, NULL); if (!dev) { printk(KERN_ERR DEV_LABEL ": atm_dev_register() failed\n"); err = -ENODEV; goto out_kfree; } dev->dev_data = cp; cp->dev = dev; // init ATM signal dev->signal = ATM_PHY_SIG_LOST; //init lock spin_lock_init(&cp->txlock); spin_lock_init(&cp->rxlock); spin_lock_init(&cp->ctllock); #ifdef CONFIG_SMP spin_lock_init(&oamf5_lock); #endif if(sar_start(dev)) { printk(KERN_ERR DEV_LABEL ": sar_start failed\n"); err = -ENODEV; goto out_unregister; } printk (KERN_INFO "%s: %s %s (%s)\n", dev->type, DRV_NAME, DRV_VERSION, DRV_RELDATE); #ifdef CONFIG_RTL8681_SAR_ARCH sar_set_gpio(); #endif #ifdef AUTO_PVC_SEARCH APS_Proc_File = proc_create_data(PROCFS_NAME,0644,NULL,&fops_proc_aps,NULL); if (APS_Proc_File == NULL) { printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", PROCFS_NAME); err = -ENOMEM; goto out_unregister; } printk(KERN_INFO "/proc/%s created\n", PROCFS_NAME); #endif #ifdef CONFIG_REMOTE_ADSL_PHY {/*For Remote ADSL netlink event*/ struct netlink_kernel_cfg cfg = { .input = receive_netlinkMsg, }; nl_sk = netlink_kernel_create(&init_net, NETLINK_RTK_REMOTE_ADSL_EVENT, &cfg); } #endif // Kaohj -- /proc/sys/sar //sar_table_header = register_sysctl_table(sar_root_table, 0); /*linux-2.6.19*/ sar_table_header = register_sysctl_table(sar_root_table); out: return err; out_unregister: atm_dev_deregister(dev); out_kfree: kfree(cp); goto out; } static void __exit sar_exit (void) { atm_dev_deregister(sar_dev->dev); kfree(sar_dev); } /* * Traffic tracker called by gpio.c for Link LED blinking */ int IsTrafficOnAtm(void) { if(latestTraffic != AtmTraffic){ latestTraffic = AtmTraffic; return 1; } else { latestTraffic = AtmTraffic = 0; return 0; } } // Kaohj /* * Return value: * -1: fail * 0 ~ Enable_VC_CNT-1 : ok */ int index_vc2ch(int vc_idx) { sar_private *cp = sar_dev; int ch_no; int idx; char ifname[] = "vc0"; ifname[2] += vc_idx; ch_no = -1; for (idx = 0; idx < Enable_VC_CNT; idx++) { if (cp->vcc[idx].dev && !strcmp(ifname, cp->vcc[idx].dev->name)) { ch_no = idx; break; } } return ch_no; } /* * Return value: * -1: fail * 0 ~ Enable_VC_CNT-1 : ok */ int index_dev2ch(struct net_device* dev) { sar_private *cp = sar_dev; int ch_no; int idx; ch_no = -1; for (idx = 0; idx < Enable_VC_CNT; idx++) { if (cp->vcc[idx].dev == dev) { ch_no = idx; break; } } return ch_no; } void vc_ch_remapping(unsigned *member) { int ch_no; int j; unsigned tmp_mbr = 0, msk = 0x10000, mbr = *member; // | resvd | vc7 vc6 vc5 vc4 | vc3 vc2 vc1 vc0 | vap3 | vap2 vap1 vap0 wlan0 | resvd | LAN4 LAN3 LAN2 LAN1 if( (mbr & 0xFF0000) == 0 ) // Skip it if this vlan group doesn't contain any vc channels. return; tmp_mbr = mbr & 0xff00ffff; // mask vc bits // remap vc bits for( j = 0; j < 8; j++ ) { if( mbr & (msk << j) ) { // vcj ch_no = index_vc2ch(j); if( ch_no >= 0 ) tmp_mbr |= msk << ch_no; } } *member = tmp_mbr; //printk("set %s ch_no %d to br; member = 0x%.08x; tmp_mbr = 0x%.08x\n", cp->vcc[ch_no].dev->name, ch_no, mbr, tmp_mbr); } module_init(rtl8670_atm_init); module_exit(sar_exit); #if defined(CONFIG_XDSL_CTRL_PHY_IS_DSL) EXPORT_SYMBOL(sar_send); EXPORT_SYMBOL(sar_open); EXPORT_SYMBOL(sar_close); EXPORT_SYMBOL(sar_ioctl); #endif