#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/semaphore.h> #include <linux/slab.h> #include <linux/seq_file.h> #include <asm/uaccess.h> #include <linux/proc_fs.h> #include <linux/device.h> #include <linux/spinlock.h> #include "bspchip.h" #include "ptm_regs.h" #include "ptm_rtl8685.h" #define PTM_RESET 1 #ifdef PTM_RESET #define PTM_TX_RESET 1 #if defined(CONFIG_RTL8685S) || defined(CONFIG_RTL8685SB) #define SACHEM_TX_RESET #endif /* CONFIG_RTL8685S */ #include <linux/timer.h> #include <linux/delay.h> #include <linux/sched.h> #endif /* Prototype */ static int ptm_open( struct inode *inode, struct file *filp ); static int ptm_close( struct inode *inode, struct file *filp ); static long ptm_ioctl(struct file *flip, unsigned int command, unsigned long inarg ); static void rtl8685_set_ptm_counter(void); static void ptm_init_hw (void); void ptm_start_hw (void); void ptm_stop_hw (void); #if defined(CONFIG_PTM_BONDING_MASTER) #define SLAVE_TPSTC_RX_POLLING 1 extern void RestartWan(void); extern int mdio_exeception(char flag); extern int bonding_rx_fifo_check(int line); extern void bonding_rx_fifo_reset_done(void); extern long ptm1_ioctl(struct file *flip, unsigned int command, unsigned long inarg); static int master_rx_fifo_full = 0; static int slave_rx_fifo_full = 0; static int rx_fifo_reset=1; extern char adslup, slv_adslup; extern int CheckTPScount_Flag; static char tpstc_reset=0, utopia_reset=0, bonding_rx_reset=0; static int line0rx_check=0, line1rx_check=0; #endif #if defined(CONFIG_PTM_BONDING_SLAVE) #define RX_FIFO_FULL_EXECEPTION 1 #define RX_FIFO_CHECK_EXECEPTION 2 extern void bonding_rx_fifo_reset_done(void); extern int nfbi_exeception(char flag); static int rx_fifo_reset=1; extern int CheckTPScount_Flag; #endif /* Definitions */ #define PTMBASE 0xB8400000 #define SARCHEM_BASE 0xB8A80000 #define SYSTEM_BASE 0xB8000000 #define RTL_W32(reg, value) (*(volatile u32*)(PTMBASE+reg)) = (u32)value #define RTL_W16(reg, value) (*(volatile u16*)(PTMBASE+reg)) = (u16)value #define RTL_W8(reg, value) (*(volatile u8*)(PTMBASE+reg)) = (u8)value #define RTL_R32(reg) (*(volatile u32*)(PTMBASE+reg)) #define RTL_R16(reg) (*(volatile u16*)(PTMBASE+reg)) #define RTL_R8(reg) (*(volatile u8*)(PTMBASE+reg)) /* ioctl command called by protocols (system-independent) */ #define PTM_MAGIC (('R'+'T'+'L'+'P'+'T'+'M') << 8) #define PTM_SET_DEFAULT_TABLE (PTM_MAGIC+1) #define PTM_GET_TABLE (PTM_MAGIC+2) #define PTM_READ_DATA (PTM_MAGIC+3) #define PTM_WRITE_DATA (PTM_MAGIC+4) #define PTM_SET_HW (PTM_MAGIC+5) #define PTM_GET_QMAP (PTM_MAGIC+6) #define PTM_STOP_HW (PTM_MAGIC+7) #define PTM_START_HW (PTM_MAGIC+8) #define PTM_CLEAN_WANIF (PTM_MAGIC+9) #define PTM_CLEAN_QMAP (PTM_MAGIC+10) #define PTM_SET_WANIF (PTM_MAGIC+11) #define PTM_SET_QMAP (PTM_MAGIC+12) #define PTM_SET_STAGTYPE (PTM_MAGIC+13) #define PTM_SET_DUMMYVID (PTM_MAGIC+14) #define PTM_SET_QMAPATSTAG (PTM_MAGIC+15) #define PTM_SET_MODE (PTM_MAGIC+16) #define PTM_SET_SYSTEM (PTM_MAGIC+17) #define PTM_ENABLE_TPSTC (PTM_MAGIC+18) #define PTM_DISABLE_TPSTC (PTM_MAGIC+19) #define PTM_RESET_TPSTC (PTM_MAGIC+20) #define PTM_GET_TPSTC_TX_CNT (PTM_MAGIC+21) #define PTM_GET_UTOPIA_TX_CNT (PTM_MAGIC+22) #ifndef SUCCESS #define SUCCESS 0 #endif #ifndef FAILED #define FAILED -1 #endif /* Globals. */ #define PTM_DEV_MAJOR 120 #define PTM_DEV_NAME "ptm" static struct class *ptm_class=NULL; static struct file_operations ptm_fops = { unlocked_ioctl: ptm_ioctl, open: ptm_open, release: ptm_close, }; /* IOCTL structure */ struct ptm_arg{ unsigned char cmd; union{ struct{ unsigned int cmd2; unsigned int cmd3; unsigned int cmd4; }; struct{ unsigned short a1; unsigned short a2; unsigned char a3[8]; }; unsigned char arg[12]; }; }; /* Default table */ rtl8685_WANtbl_t default_tbl[]={ {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}, 0x020, 0x125, 0x1, "ptm0",0,0,0,0}, {{0xab, 0xcd, 0xed, 0x12, 0x32, 0x57}, 0x344, 0x126, 0x1, "ptm1",0,0,0,0}, {{0x00, 0x01, 0x02, 0x03, 0x04, 0x06}, 0x020, 0x127, 0x1, "ptm2",0,0,0,0}, {{0xab, 0xcd, 0xed, 0x12, 0x32, 0x58}, 0x344, 0x128, 0x1, "ptm3",0,0,0,0}, {{0x00, 0x01, 0x02, 0x03, 0x04, 0x07}, 0x020, 0x129, 0x1, "ptm4",0,0,0,0}, {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x000, 0x000, 0x1, "ptm5",0,0,0,0}, {{0xab, 0xcd, 0xed, 0x12, 0x32, 0x05}, 0x344, 0x130, 0x0, "ptm6",0,0,0,0}, {{0x00, 0x01, 0x02, 0x03, 0x04, 0x09}, 0x020, 0x131, 0x0, "ptm7",0,0,0,0} }; /* Current table */ rtl8685_WANtbl_t *current_tbl=NULL; /*Queue mapping table */ unsigned int *qmap_tbl=NULL; /*Bonding mode selection 0: non-bonding mode 1: bonding mode */ unsigned int ptm_bonding = 0, ptm_bonding_line = 0; #if defined(CONFIG_PTM_BONDING_MASTER) spinlock_t bonding_lock; struct mutex bonding_mutex; #endif /* 0x1064 bit9*/ #define ptm_table_lock(void) \ do { \ unsigned int p; \ p=RTL_R32(Debug_Sel); \ p=p|Update_en_tx; \ RTL_W32(Debug_Sel, p); \ }while(0) #define ptm_table_unlock(void) \ do { \ unsigned int p; \ p=RTL_R32(Debug_Sel); \ p=p&(~Update_en_tx); \ RTL_W32(Debug_Sel, p); \ }while(0) void Dumpreg(unsigned long Buffer, unsigned int size){ int k; if(size%4) size=size+4-(size%4); if ((Buffer&0xF0000000)==0x80000000) Buffer |= 0xA0000000; printk("Address : Data"); for(k=0;k<(size/4);k++){ if ((k%4)==0) { printk ("\n"); printk("%08X : ",(unsigned int)Buffer+k*4); } //mdelay(100); printk("%08X ", (*(volatile unsigned int *)((unsigned int)((Buffer)+k*4)))); } printk("\n"); } int rtl8685_getWanTable(u32 idx, rtl8685_WANtbl_t *WANp) { int ptm_intf_count = PTM_MAX_INTF; if (idx >= ptm_intf_count || WANp == NULL) return FAILED; /* Accumulate counter */ current_tbl[idx].tx_pkt_cnt = RTL_R32(Entry_tx_pkt_cnt + idx*4); current_tbl[idx].rx_pkt_cnt = RTL_R32(Entry_rx_pkt_cnt + idx*4); current_tbl[idx].tx_pkt_byte = RTL_R32(Entry_tx_byte_cnt + idx*4); current_tbl[idx].rx_pkt_byte = RTL_R32(Entry_rx_byte_cnt + idx*4); memcpy(WANp, ¤t_tbl[idx], sizeof(rtl8685_WANtbl_t)); return SUCCESS; } int rtl8685_setWanTable(u32 idx, rtl8685_WANtbl_t *WANp) { int ptm_intf_count = PTM_MAX_INTF; int i; printk("idx=%u, %u, %s, %u, %u, %02x%02x%02x%02x%02x%02x\n", idx, WANp->Valid, WANp->ifname, WANp->SVlanID, WANp->CVlanID, WANp->MAC[0],WANp->MAC[1],WANp->MAC[2], WANp->MAC[3],WANp->MAC[4],WANp->MAC[5] ); if (idx >= ptm_intf_count || WANp == NULL) return FAILED; memset( ¤t_tbl[idx], 0x0, sizeof(rtl8685_WANtbl_t)) ; memcpy( ¤t_tbl[idx], WANp, sizeof(rtl8685_WANtbl_t)); ptm_table_lock(); /* Valid */ RTL_R8( EntryValid_ADDR) &= ~(1 << idx); RTL_R8( EntryValid_ADDR) |= ( current_tbl[idx].Valid << idx); /* Set MAC address */ for(i=0; i<6; i++){ RTL_R8( EntryMAC_ADDR + idx*6 + i) = current_tbl[idx].MAC[i]; } /* C-tag */ RTL_R16( CTag_ADDR + idx*2) = current_tbl[idx].CVlanID; /* S-tag */ RTL_R16( STag_ADDR + idx*2) = current_tbl[idx].SVlanID; /* Reset counter, do WriteClear */ RTL_R32( Entry_tx_byte_cnt + idx*4) = 0x0; RTL_R32( Entry_rx_byte_cnt + idx*4) = 0x0; RTL_R32( Entry_tx_pkt_cnt + idx*4) = 0x0; RTL_R32( Entry_rx_pkt_cnt + idx*4) = 0x0; ptm_table_unlock(); return SUCCESS; } void rtl8685_dumpWanTable(void) { rtl8685_WANtbl_t INTF_CTL; int i; printk("Intf Valid SVID CVID MAC \n"); for(i=0; i<PTM_MAX_INTF; i++){ rtl8685_getWanTable(i,&INTF_CTL); printk("%s %d 0x%03X 0x%03X %02X-%02X-%02X-%02X-%02X-%02X\n", INTF_CTL.ifname, INTF_CTL.Valid, INTF_CTL.SVlanID, INTF_CTL.CVlanID, INTF_CTL.MAC[0], INTF_CTL.MAC[1], INTF_CTL.MAC[2], INTF_CTL.MAC[3], INTF_CTL.MAC[4], INTF_CTL.MAC[5]); } printk("\nIntf Tx_pkt Rx_pkt Tx_byte Rx_byte\n"); for(i=0;i<PTM_MAX_INTF;i++){ rtl8685_getWanTable(i,&INTF_CTL); printk("%s 0x%08X 0x%08X 0x%08X 0x%08X\n", INTF_CTL.ifname, INTF_CTL.tx_pkt_cnt, INTF_CTL.rx_pkt_cnt, INTF_CTL.tx_pkt_byte, INTF_CTL.rx_pkt_byte); } } int rtl8685_set_QMap(u32 idx, u8 pri, u8 value) { int ptm_intf_count = PTM_MAX_INTF; unsigned int QMap_val = 0; //printk("idx=%u, pri=%u, value=0x%02x ", idx, pri, value ); if (idx >= ptm_intf_count ) return FAILED; QMap_val = (*(qmap_tbl + idx )); QMap_val &= ~( (0x7) << (pri*3)); QMap_val |= (value & 0x7) << (pri*3); //printk(", QMap_val = 0x%X\n", QMap_val); (*(qmap_tbl + idx )) = QMap_val; ptm_table_lock(); RTL_R32( QMap_ADDR + idx*4) = QMap_val; ptm_table_unlock(); return SUCCESS; } void rtl8685_dump_QMap(void) { unsigned int qval32=0; int i,j; printk("Intf PRI0 PRI1 PRI2 PRI3 PRI4 PRI5 PRI6 PRI7\n"); for(i=0;i<PTM_MAX_INTF;i++){ qval32 = RTL_R32(QMap_ADDR + i*4); printk("%d",i); for(j=0; j<PTM_PRI_NUM;j++){ printk(" %u", (qval32>>(j*3))&0x7); } printk("\n"); } } static void ptm_restore_wanitf(void) { int i; for(i=0; i<PTM_MAX_INTF; i++) { rtl8685_WANtbl_t tmpW; unsigned int tmpQ; rtl8685_getWanTable(i, &tmpW); rtl8685_setWanTable(i, &tmpW); tmpQ=qmap_tbl[i]; ptm_table_lock(); RTL_R32( QMap_ADDR + i*4) = tmpQ; ptm_table_unlock(); } } #ifdef PTM_RESET #define PTM_DELAY_TIME (5*HZ) static struct timer_list ptm_timer; static unsigned int ptm_timer_dbg=0; static unsigned int rx_tpkt_ptm0; static unsigned int rx_tpkt_ptm1; static unsigned int rx_tpkt_ptm2; static unsigned int rx_tpkt_ptm3; #ifdef PTM_TX_RESET static unsigned int tx_total_cf_p0; static unsigned int tx_total_cf_p1; #endif /*PTM_TX_RESET*/ #ifdef SACHEM_TX_RESET extern unsigned long gUStpsDataAccCnt0; unsigned long sachem_tx_data_total; static unsigned int sachem_tx_reset_try; static unsigned int sachem_tx_reset_count; static unsigned int sachem_tx_reset_done; static unsigned int sachem_tx_reset_count_overall; static unsigned long tx_data_cf_p0; int sachem_tx_reset_step=25; int sachem_tx_reset_times=6; #endif /* SACHEM_TX_RESET */ #define SARCHEM_W32(reg, value) (*(volatile u32*)(SARCHEM_BASE+reg)) = (u32)value #define SARCHEM_R32(reg) (*(volatile u32*)(SARCHEM_BASE+reg)) #define SYSTEM_W32(reg, value) (*(volatile u32*)(SYSTEM_BASE+reg)) = (u32)value #define SYSTEM_R32(reg) (*(volatile u32*)(SYSTEM_BASE+reg)) #define PTM_WAIT_SWITCH_TIME ((HZ)/5) //wait max.=200ms #define P5_DCR0 (0xbb806160) #define P5_DCR1 (P5_DCR0+4) #define P5_DCR2 (P5_DCR0+8) #define PCRP5 (0xbb804118) #define ForceLink (1<<23) static void ptm_event_init(void) { rx_tpkt_ptm0 = RTL_R32(RX_TPKT_PTM0); rx_tpkt_ptm1 = RTL_R32(RX_TPKT_PTM1); rx_tpkt_ptm2 = RTL_R32(RX_TPKT_PTM2); rx_tpkt_ptm3 = RTL_R32(RX_TPKT_PTM3); #ifdef PTM_TX_RESET tx_total_cf_p0 = RTL_R32(TX_TOTAL_CF_P0); tx_total_cf_p1 = RTL_R32(TX_TOTAL_CF_P1); #endif /*PTM_TX_RESET*/ #ifdef SACHEM_TX_RESET sachem_tx_data_total = gUStpsDataAccCnt0; sachem_tx_reset_try = 0; sachem_tx_reset_count = 0; (IS_RL6405A==1)?(sachem_tx_reset_done = 0):(sachem_tx_reset_done = 1); tx_data_cf_p0 = RTL_R32(TX_DATA_CF_P0); #endif /*SACHEM_TX_RESET*/ } static int ptm_event_detect(void) { #ifdef SACHEM_TX_RESET unsigned long sachem_tx_data_0_new; unsigned int tx_data_cf_p0_new; unsigned int IS_PTM_TRAFFIC = 0; int ret_sachem_tx=0; #endif /* SACHEM_TX_RESET */ #ifdef PTM_TX_RESET unsigned int tx_total_cf_p0_new; unsigned int tx_total_cf_p1_new; int ret_tx=0; #endif /*PTM_TX_RESET*/ unsigned int rx_tpkt_ptm0_new; unsigned int rx_tpkt_ptm1_new; unsigned int rx_tpkt_ptm2_new; unsigned int rx_tpkt_ptm3_new; int ret=0; #ifdef SACHEM_TX_RESET if(sachem_tx_reset_done) #endif /* SACHEM_TX_RESET */ { rx_tpkt_ptm0_new = RTL_R32(RX_TPKT_PTM0); rx_tpkt_ptm1_new = RTL_R32(RX_TPKT_PTM1); rx_tpkt_ptm2_new = RTL_R32(RX_TPKT_PTM2); rx_tpkt_ptm3_new = RTL_R32(RX_TPKT_PTM3); if( (rx_tpkt_ptm0_new==rx_tpkt_ptm0) && (rx_tpkt_ptm1_new==rx_tpkt_ptm1) && (rx_tpkt_ptm2_new==rx_tpkt_ptm2) && (rx_tpkt_ptm3_new==rx_tpkt_ptm3) ){ printk("[%s]: Trigger PTM Rx reset event\n",__func__); ret=1; } rx_tpkt_ptm0 = rx_tpkt_ptm0_new; rx_tpkt_ptm1 = rx_tpkt_ptm1_new; rx_tpkt_ptm2 = rx_tpkt_ptm2_new; rx_tpkt_ptm3 = rx_tpkt_ptm3_new; #ifdef PTM_TX_RESET tx_total_cf_p0_new = RTL_R32(TX_TOTAL_CF_P0); tx_total_cf_p1_new = RTL_R32(TX_TOTAL_CF_P1); if( (tx_total_cf_p0_new==tx_total_cf_p0) && (tx_total_cf_p1_new==tx_total_cf_p1) ){ printk("[%s]: Trigger PTM Tx reset event\n",__func__); ret_tx=1; } tx_total_cf_p0 = tx_total_cf_p0_new; tx_total_cf_p1 = tx_total_cf_p1_new; if(ret || ret_tx) { printk( "%s: reset_by: rx=%d, tx=%d\n", __func__, ret, ret_tx ); ret=1; } #endif /*PTM_TX_RESET*/ } #ifdef SACHEM_TX_RESET if(IS_RL6405A){ if(!sachem_tx_reset_done) { sachem_tx_data_0_new = gUStpsDataAccCnt0; sachem_tx_reset_try++; if((sachem_tx_data_0_new)>=(sachem_tx_reset_step+sachem_tx_data_total)){ ret_sachem_tx = 1; sachem_tx_reset_count++; sachem_tx_reset_count_overall++; printk("[%s]: Trigger Sachem Tx reset event\n",__func__); } printk("%s, [after=%lu, before=%lu]\n",__func__,sachem_tx_data_0_new,sachem_tx_data_total); printk("%s, [TryCounter=%u, DoCounter=%u, OverallCounter=%u]\n",__func__ ,sachem_tx_reset_try,sachem_tx_reset_count,sachem_tx_reset_count_overall); if(sachem_tx_reset_try>=(sachem_tx_reset_times+sachem_tx_reset_count)){ sachem_tx_reset_done = 1; /* Force SwCore port 5 link up */ REG32(PCRP5) |= (ForceLink); } sachem_tx_data_total = sachem_tx_data_0_new; if(ret_sachem_tx) { printk( "%s: rx=%d, tx=%d, sachem tx=%d\n", __func__, ret, ret_tx, ret_sachem_tx); ret=1; } }else{ sachem_tx_data_0_new = gUStpsDataAccCnt0; tx_data_cf_p0_new = RTL_R32(TX_DATA_CF_P0); /* Real traffic : IS_PTM_TRAFFIC = 1*/ IS_PTM_TRAFFIC = ((tx_data_cf_p0_new-tx_data_cf_p0)>10)?1:0; if(!IS_PTM_TRAFFIC){ if( (sachem_tx_data_0_new-sachem_tx_data_total)>=((tx_data_cf_p0_new-tx_data_cf_p0)+1000)){ ret_sachem_tx=1; printk("[%s,%d]: Trigger Sachem Tx reset event\n",__func__,__LINE__); printk("[%s,%d]: Sachem up counter = %d, PTM TX counter = %d\n",__func__,__LINE__, (sachem_tx_data_0_new-sachem_tx_data_total), (tx_data_cf_p0_new-tx_data_cf_p0)); } } sachem_tx_data_total = sachem_tx_data_0_new; tx_data_cf_p0 = tx_data_cf_p0_new; if(ret || ret_tx || ret_sachem_tx) { printk( "%s: rx=%d, tx=%d, sachem tx in showtime=%d\n", __func__, ret, ret_tx, ret_sachem_tx); ret=1; } } } #endif /* SACHEM_TX_RESET */ if(ptm_timer_dbg) printk("%s: return %d\n",__func__, ret); return ret; } #if defined(CONFIG_PTM_BONDING) int bonding_tpstc_rx_receive(void) { #if defined(CONFIG_PTM_BONDING_MASTER) unsigned long flags; printk("bonding master rx fifo checking..\n"); bonding_rx_fifo_check(0); #endif #if defined(CONFIG_PTM_BONDING_SLAVE) printk("bonding slave rx fifo checking..\n"); nfbi_exeception(RX_FIFO_CHECK_EXECEPTION); #endif } #endif static void ptm_SwitchPHYIfEnable(int en) { if(en) { unsigned long cur_jiffies=jiffies; unsigned long to_jiffies; to_jiffies = cur_jiffies + PTM_WAIT_SWITCH_TIME; if(ptm_timer_dbg) printk( "%s: start cur_jiffies=%08lx, to_jiffies=%08lx\n", __func__, cur_jiffies, to_jiffies ); while( cur_jiffies < to_jiffies ) { unsigned int p5_dcr0,p5_dcr1,p5_dcr2; p5_dcr0=REG32(P5_DCR0); p5_dcr1=REG32(P5_DCR1); p5_dcr2=REG32(P5_DCR2); if( (p5_dcr0==0) && (p5_dcr1==0) && (p5_dcr2==0) ) break; if(ptm_timer_dbg) printk( "%s: p5_dcr= %08x %08x %08x\n", __func__, p5_dcr0, p5_dcr1, p5_dcr2 ); cur_jiffies=jiffies; } #ifdef SACHEM_TX_RESET if(sachem_tx_reset_done) #endif { REG32(PCRP5) = REG32(PCRP5)|(ForceLink); } if(ptm_timer_dbg) printk( "%s: end cur_jiffies=%08lx, to_jiffies=%08lx\n", __func__, cur_jiffies, to_jiffies ); if(cur_jiffies>=to_jiffies) printk( "%s: wait p5_dcr timeout!\n", __func__ ); }else{ REG32(PCRP5) = REG32(PCRP5)&~(ForceLink); } printk( "%s: PCRP5=0x%08x\n",__func__, REG32(PCRP5) ); } extern void ShowtimeTpsReset(void); extern void ShowtimeTpsSet(void); static int ptm_event_process(void) { printk("%s: ptm reset\n",__func__); ptm_SwitchPHYIfEnable(0); SARCHEM_W32(0x5040, 0x1); printk("0xb8a85040 : %x \n",SARCHEM_R32(0x5040)); ptm_stop_hw(); REG32(BSP_IP_SEL) &= (~BSP_EN_PTM); printk( "PTM: disable IP %08x\n", REG32(BSP_IP_SEL) ); ShowtimeTpsReset(); REG32(BSP_IP_SEL) |= BSP_EN_PTM; printk( "PTM: enable IP %08x\n", REG32(BSP_IP_SEL) ); ptm_init_hw(); ptm_restore_wanitf(); ShowtimeTpsSet(); ptm_start_hw(); if(IS_RL6405A){ SARCHEM_W32(0x5040, 0x0); } ptm_SwitchPHYIfEnable(1); printk("%s: ptm reset done\n",__func__); return 0; } #if defined(CONFIG_PTM_BONDING_MASTER) void ptm_reset(void) { unsigned long flags; spin_lock_irqsave(&bonding_lock, flags); ptm1_ioctl(NULL, PTM_DISABLE_TPSTC, 0); SARCHEM_W32(0x5040, 0x1); ptm_stop_hw(); ShowtimeTpsReset(); ptm1_ioctl(NULL, PTM_RESET_TPSTC, 0); ShowtimeTpsSet(); ptm_start_hw(); SARCHEM_W32(0x5040, 0x0); ptm1_ioctl(NULL, PTM_ENABLE_TPSTC, 0); spin_unlock_irqrestore(&bonding_lock, flags); } int bonding_rx_fifo_reset(void) { int master_ptm_rx, slave_ptm_rx; int master_ptm_rx2, slave_ptm_rx2; int master_rx_cnt, slave_rx_cnt; if (rx_fifo_reset==0) return 0; master_ptm_rx = RTL_R32(RX_TPKT_PTM0); slave_ptm_rx = RTL_R32(RX_TPKT_PTM4); mdelay(1000); master_ptm_rx2 = RTL_R32(RX_TPKT_PTM0); slave_ptm_rx2 = RTL_R32(RX_TPKT_PTM4); master_rx_cnt = master_ptm_rx - master_ptm_rx2; slave_rx_cnt = slave_ptm_rx - slave_ptm_rx2; if ((master_rx_fifo_full && (master_rx_cnt == 0)) || (slave_rx_fifo_full && slave_rx_cnt==0)){ REG32(PCRP5) = REG32(PCRP5)&~(ForceLink); ptm_reset(); REG32(PCRP5) = REG32(PCRP5)|(ForceLink); RestartWan(); } } int bonding_rx_fifo_check(int line) { unsigned int line0_rx, line1_rx; int tpstc_rxpolling = 0; if ((utopia_reset==1 || tpstc_reset==1 || bonding_rx_reset==1) && (adslup && slv_adslup)){ if ((line==0 && line1rx_check) || (line==1 && line0rx_check)){ line0_rx = RTL_R32(RX_TPKT_PTM0); line1_rx = RTL_R32(RX_TPKT_PTM4); if ((line0_rx > 0) && (line1_rx>0)){ printk("check line0 & line1 ptm ok\n"); line0rx_check = 1; line1rx_check = 1; } else { printk("check line0 & line1 rx fifo error, do ptm reset\n"); REG32(PCRP5) = REG32(PCRP5)&~(ForceLink); ptm_reset(); REG32(PCRP5) = REG32(PCRP5)|(ForceLink); RestartWan(); tpstc_rxpolling = 1; bonding_rx_reset = 1; line0rx_check = 0; line1rx_check = 0; } } else if (line==0){ line0rx_check = 1; } else if (line==1){ line1rx_check = 1; } } else { if (line==0){ line0_rx = RTL_R32(RX_TPKT_PTM0); printk("line0 ptm rx current value: %x\n", line0_rx); if (line0_rx > 0){ printk("check line0 ptm ok\n"); } else { printk("check line0 rx fifo error, do ptm reset\n"); REG32(PCRP5) = REG32(PCRP5)&~(ForceLink); ptm_reset(); REG32(PCRP5) = REG32(PCRP5)|(ForceLink); RestartWan(); tpstc_rxpolling = 1; bonding_rx_reset = 1; } } else if (line==1){ line1_rx = RTL_R32(RX_TPKT_PTM4); printk("line1 ptm rx current value: %x\n", line1_rx); if (line1_rx > 0){ printk("check line1 ptm ok\n"); } else { printk("check line1 rx fifo error, do ptm reset\n"); REG32(PCRP5) = REG32(PCRP5)&~(ForceLink); ptm_reset(); REG32(PCRP5) = REG32(PCRP5)|(ForceLink); RestartWan(); tpstc_rxpolling = 1; bonding_rx_reset = 1; } } else { printk("bonding_rx_fifo_check: invalid line number\n"); return -1; } } if (tpstc_rxpolling){ if (adslup){ CheckTPScount_Flag = 1; } if (slv_adslup){ mdio_exeception(SLAVE_TPSTC_RX_POLLING); } } return 0; } #endif int bonding_rx_fifo_full(void) { #if defined(CONFIG_PTM_BONDING_MASTER) unsigned long flags; master_rx_fifo_full = 1; bonding_rx_fifo_reset(); master_rx_fifo_full = 0; bonding_rx_fifo_reset_done(); printk("bonding master rx fifo reset done\n"); #elif defined(CONFIG_PTM_BONDING_SLAVE) nfbi_exeception(RX_FIFO_FULL_EXECEPTION); mdelay(1500); bonding_rx_fifo_reset_done(); printk("bonding slave rx fifo reset done\n"); #endif return 0; } #if defined(CONFIG_PTM_BONDING_SLAVE) void slave_tpstc_rx_polling(void) { CheckTPScount_Flag = 1; } #endif #if defined(CONFIG_PTM_BONDING_MASTER) void slave_bonding_rx_fifo_check(void) { unsigned long flags; printk("bonding slave rx fifo checking..\n"); bonding_rx_fifo_check(1); } void slave_bonding_rx_fifo_full(void) { unsigned long flags; slave_rx_fifo_full = 1; bonding_rx_fifo_reset(); slave_rx_fifo_full = 0; printk("bonding slave rx fifo reset done\n"); } void ptm_tpstc_reset(void) { int val=0, retry, master_tpstc_txcnt, slave_tpstc_txcnt; //SwitchPHYPort5 Disable REG32(PCRP5) = REG32(PCRP5)&~(ForceLink); master_tpstc_txcnt = (*(volatile u32*)(0xb8af0040)); slave_tpstc_txcnt = ptm1_ioctl(NULL, PTM_GET_TPSTC_TX_CNT, 0); mdelay(100); for (retry=0; retry<5; retry++){ master_tpstc_txcnt = (*(volatile u32*)(0xb8af0040)); slave_tpstc_txcnt = ptm1_ioctl(NULL, PTM_GET_TPSTC_TX_CNT, 0); printk("check master tpstc tx cnt=%x\n", master_tpstc_txcnt); printk("check slave tpstc tx cnt=%x\n", slave_tpstc_txcnt); if ((master_tpstc_txcnt > 0x100) || (slave_tpstc_txcnt > 0x100)){ printk("%s: ptm reset\n",__func__); ptm_reset(); tpstc_reset = 1; printk("%s: ptm reset done\n",__func__); } else { printk("check master/slave tpstc status ok\n"); break; } mdelay(1000); printk("retry: %d\n", retry+1); } //SwitchPHYPort5 Enable REG32(PCRP5) = REG32(PCRP5)|(ForceLink); } #define MASTER 0 #define SLAVE 1 void ptm_utopia_reset(char active_line) { int val=0, retry; int master_utopia_txcnt, slave_utopia_txcnt; master_utopia_txcnt = (*(volatile u32*)(0xb8af0028)); slave_utopia_txcnt = ptm1_ioctl(NULL, PTM_GET_UTOPIA_TX_CNT, 0); mdelay(100); for (retry=0; retry<5; retry++){ printk("check utopia status\n"); if (active_line & (1<<MASTER)){ master_utopia_txcnt = (*(volatile u32*)(0xb8af0028)); printk("master linkup: check master utopia tx cnt=%x\n", master_utopia_txcnt); } if (active_line & (1<<SLAVE)){ slave_utopia_txcnt = ptm1_ioctl(NULL, PTM_GET_UTOPIA_TX_CNT, 0); printk("slave linkup: check slave utopia tx cnt=%x\n", slave_utopia_txcnt); } if (((active_line & (1<<MASTER)) && master_utopia_txcnt==0) || ((active_line & (1<<SLAVE)) && slave_utopia_txcnt==0)) { printk("%s: utopia reset\n",__func__); //SwitchPHYPort5 Disable REG32(PCRP5) = REG32(PCRP5)&~(ForceLink); ptm_reset(); REG32(PCRP5) = REG32(PCRP5)|(ForceLink); RestartWan(); utopia_reset = 1; printk("%s: utopia reset done\n",__func__); } else { printk("check utopia status ok\n"); break; } mdelay(1000); printk("retry: %d\n", retry+1); } } #endif static void ptm_timer_handle(unsigned long arg) { if(ptm_timer_dbg) printk("%s\n",__func__); #ifdef SACHEM_TX_RESET if(!sachem_tx_reset_done){ mod_timer(&ptm_timer, jiffies+(PTM_DELAY_TIME/10)); }else #endif /* SACHEM_TX_RESET */ { mod_timer(&ptm_timer, jiffies+PTM_DELAY_TIME); } if( ptm_event_detect() ) ptm_event_process(); return; } static void ptm_timer_init(void) { printk("%s\n",__func__); init_timer(&ptm_timer); ptm_timer.function = &ptm_timer_handle; #ifdef SACHEM_TX_RESET if(IS_RL6405A) ptm_timer.expires = jiffies+(PTM_DELAY_TIME/10); else #endif /* SACHEM_TX_RESET */ { ptm_timer.expires = jiffies+PTM_DELAY_TIME; } } #if defined(CONFIG_DSL_ON_SLAVE) void ptm_timer_add(void) #else static void ptm_timer_add(void) #endif { printk("%s\n",__func__); ptm_event_init(); #ifdef SACHEM_TX_RESET if(!sachem_tx_reset_done){ mod_timer(&ptm_timer, jiffies+(PTM_DELAY_TIME/10)); }else #endif /* SACHEM_TX_RESET */ { mod_timer(&ptm_timer, jiffies+PTM_DELAY_TIME); } } static void ptm_timer_exit(void) { printk("%s\n",__func__); del_timer(&ptm_timer); } #endif /*************************************************************************** * Function Name: ptm_stop_hw * Description :Disable TX and RX function * Returns : None. ***************************************************************************/ void ptm_stop_hw (void) { u8 val; val = RTL_R8( WCR); val &= ~(RXRESB | TXRESB); RTL_R8( WCR) = val; #ifdef SACHEM_TX_RESET /* Force SwCore port 5 link down */ if(IS_RL6405A){ REG32(PCRP5) &= ~(ForceLink); } #endif /* SACHEM_TX_RESET */ #ifdef PTM_RESET ptm_timer_exit(); #endif //udelay(10); } typedef struct MSGTODSL { int message; int* intVal; } msgToDsl; extern __attribute__ ((mips16)) void UserGetDslData(msgToDsl *pData); extern __attribute__ ((mips16)) int GetLinkSpeed(char* pData); extern int rtl8651_setAsicQueueRate( int port, int queueid, unsigned int pprTime, unsigned int aprBurstSize, unsigned int apr ); int ratelimit_ratio =96; int ratelimit_ratio_not30a = 91; int ratelimit_state=1; static void set_port5_engress_ratelimit(void) { #ifdef CONFIG_RTL8685 int i=0; unsigned long dslNetDataRate[2]; unsigned long dsl_tx_rate; msgToDsl msgToDsl0; unsigned int profileName=0; unsigned int dsl_device; if(!IS_RTL8685C()) { if(ratelimit_state==-1)//stop { return; }else if(ratelimit_state==0)//disable { for(i=0;i<8;i++) rtl8651_setAsicQueueRate(5, i, 7, 0xff, 0x3fff); return; }//else enable msgToDsl0.intVal= kmalloc( sizeof(int), GFP_KERNEL); if(msgToDsl0.intVal==NULL) { kfree(msgToDsl0.intVal); return; } memset(msgToDsl0.intVal, 0, sizeof(int)); msgToDsl0.message=1;//GetVdslProfile=1 UserGetDslData(&msgToDsl0); profileName=msgToDsl0.intVal[0]; msgToDsl0.message=53;//GetDeviceType=53, 0:VTUO, 1:VTUR msgToDsl0.intVal[0]=1;//default VTUR if failed UserGetDslData(&msgToDsl0); dsl_device=msgToDsl0.intVal[0]; kfree(msgToDsl0.intVal); GetLinkSpeed((char*) dslNetDataRate); if(dsl_device) //VTUR dsl_tx_rate=dslNetDataRate[0];//upstream rate else //VTUO dsl_tx_rate=dslNetDataRate[1];//downstream rate //printk( "%s: got dsl_tx_rate=%lu\n", __FUNCTION__, dsl_tx_rate ); if(profileName==0x80)//30a { for(i=0;i<8;i++) rtl8651_setAsicQueueRate(5, i, 0, 1, (unsigned int)(dsl_tx_rate*ratelimit_ratio/25600)); } else { for(i=0;i<8;i++) rtl8651_setAsicQueueRate(5, i, 1, 1, (unsigned int)(dsl_tx_rate*ratelimit_ratio_not30a/25600)); } } #endif /* CONFIG_RTL8685 */ } /*************************************************************************** * Function Name: ptm_start_hw * Description :Enable TX and RX function * Returns : None. ***************************************************************************/ void ptm_start_hw (void) { u8 val; val = RTL_R8( WCR); /* Set as stand alone mode */ val |= (RXRESB|TXRESB); RTL_R8( WCR) = val; #ifdef SACHEM_TX_RESET /* Force SwCore port 5 link down in default */ if(IS_RL6405A) { u32 val_port5; val_port5 = REG32(PCRP5); val_port5 &= ~(ForceLink); REG32(PCRP5) = val_port5; } #endif /* SACHEM_TX_RESET */ set_port5_engress_ratelimit(); /* Clear PTM HW counters */ rtl8685_set_ptm_counter(); #ifdef PTM_RESET if(!ptm_bonding) ptm_timer_add(); #endif } void ptm_set_mode (u8 mode) { u8 c; c=RTL_R8(WCR); c &= ~(Mode_Sel_Mask); c = c | mode; RTL_R8(WCR)=c; } /*************************************************************************** * Function Name: ptm_init_hw * Description :Set HW registers procedures * Returns : None. ***************************************************************************/ static void ptm_init_hw (void) { int i; /* Stop PTM HW first */ ptm_stop_hw(); /* Reset PTM module */ RTL_W8(SRestReg, srstn); /* Set rate limit */ // no rx rate limit RTL_W16( TTRL, 0xff03); //RTL_W16( TTRL, 0x6400); /* Set S-tag type*/ RTL_W16(Stag_type_val, 0x88a8); /* Set dummy VID*/ RTL_W16(Dummy_vid, 0xfff); /* Set PCR to zero before using */ RTL_W32(PCR, 0x0); /* Bonding setting */ if(ptm_bonding==0){ /* Non-bonding mode */ RTL_W32(BD_SLV_NUM, (1<<1)); RTL_W32(PCR, (TY_SYNC_F0 |TY_SYNC_S0 )); /* Cell avaliable in PTM */ if(IS_RL6405 || IS_RLE0797){ RTL_W32( PCR, (RTL_R32(PCR)|(rxutp_clav_en)) /*| (txutp_clav_en)*/); } else if(IS_RLE0822 || IS_6518()){ #if !defined(CONFIG_PTM_BONDING_MASTER) RTL_W32( PCR, (RTL_R32(PCR) | (rxutp_clav_en) | (txutp_clav_en) | (rxutp_clav_ext_en) | (txutp_clav_ext_en)) ); #endif } }else{ /* UTP QoS */ RTL_W32( UTP_APR32_F, 0x000e000e); RTL_W32( UTP_APR10_F, 0x7ffc7ffc); RTL_W32( UTP_APR32_S, 0x000e000e); RTL_W32( UTP_APR10_S, 0x7ffc7ffc); RTL_W32( UTP_APR_ALL, 0x7ffc7ffc); RTL_W32( UTP_WEIGHT_F, 0x01010101); RTL_W32( UTP_WEIGHT_S, 0x01010101); RTL_W32( UTP_QOS_MIS, 0x00983300); /* Bonding mode */ RTL_W32(BD_SLV_NUM, (ptm_bonding_line << 1)); /* line number */ RTL_W32(BOND_FRAG_LF, 0x000001f8); RTL_W32(BD_TIMEOUT, 0x00000100); for(i=0;i<ptm_bonding_line;i++){ RTL_W32( PCR, RTL_R32(PCR)|(TY_SYNC_F0 <<i)| (TY_SYNC_S0 <<i)); } /* Move ptm tx/rx utp avaiable bit setting to AdslLinkUp() */ } #ifdef CONFIG_PTM_HDLC RTL_W32( PCR, RTL_R32(PCR)|TC_SYNC_LC); #else /*8681: 64/65 mode turns on short packet mode! BUG!!! */ //RTL_W32( PCR, RTL_R32(PCR)|TC_SYNC_LC|EFM64BSP); //8685: don't turn on short packets by default RTL_W32( PCR, RTL_R32(PCR)|TC_SYNC_LC); #endif /* Clear PTM HW counters */ rtl8685_set_ptm_counter(); ptm_set_mode(Mode2_Sel); if (!IS_RLE0822 && !IS_6518()) { RTL_W32( Debug_Sel, RTL_R32(Debug_Sel)| (Enable_LS_flow|Enable_LF_flow) ); } /* Move ptm_start_hw() to AdslLinkUp()*/ } static int hw_reg_read(struct seq_file *seq, void *offset) { unsigned char c; seq_printf(seq, "PTMBASE = 0x%08X\n", PTMBASE); c=RTL_R8(WCR); seq_printf(seq, "WCR = 0x%02X\n", c); seq_printf(seq, " mode:%u\n", (c&Mode_Sel_Mask)?1:0 ); seq_printf(seq, " qmap_at_stag: tx=%u, rx=%u\n", (c&Qmap_at_stag_tx)?1:0, (c&Qmap_at_stag_rx)?1:0 ); seq_printf(seq, " enable: tx=%u, rx=%u\n", (c&TXRESB)?1:0, (c&RXRESB)?1:0 ); seq_printf(seq, "TMII Rate Limit = 0x%04X\n", RTL_R16(TTRL)); seq_printf(seq, "S-tag type = 0x%04X\n", RTL_R16(Stag_type_val)); seq_printf(seq, "Dummy vid = 0x%03X\n", RTL_R16(Dummy_vid)); seq_printf(seq, "PCR = 0x%08X\n", RTL_R32(PCR)); seq_printf(seq, "Debug_Sel = 0x%08X\n", RTL_R32(Debug_Sel)); //if(ptm_bonding==1) { seq_printf(seq, "\nPTM bonding registers:\n"); seq_printf(seq, "BOND_FRAG_LF = 0x%08X\n",RTL_R32(BOND_FRAG_LF)); seq_printf(seq, "BD_SLV_NUM = 0x%08X\n",RTL_R32(BD_SLV_NUM)); seq_printf(seq, "BD_TIMEOUT = 0x%08X\n",RTL_R32(BD_TIMEOUT)); } return 0; } static int hw_qos_read(struct seq_file *seq, void *data) { seq_printf(seq, "\nUTP QoS registers:\n"); seq_printf(seq, "UTP_APR32_F = 0x%08x UTP_APR32_S = 0x%08x\n",RTL_R32(UTP_APR32_F),RTL_R32(UTP_APR32_S)); seq_printf(seq, "UTP_APR10_F = 0x%08x UTP_APR10_S = 0x%08x\n",RTL_R32(UTP_APR10_F),RTL_R32(UTP_APR10_S)); seq_printf(seq, "UTP_APR_ALL = 0x%08x\n",RTL_R32(UTP_APR_ALL)); seq_printf(seq, "UTP_WEIGHT_F= 0x%08x UTP_WEIGHT_S= 0x%08x\n",RTL_R32(UTP_WEIGHT_F),RTL_R32(UTP_WEIGHT_S)); seq_printf(seq, "UTP_QOS_MIS = 0x%08x\n",RTL_R32(UTP_QOS_MIS)); seq_printf(seq, "\n"); seq_printf(seq, "UTP_F0_ACC_INTERVAL = 0x%08x UTP_S0_ACC_INTERVAL = 0x%08x\n",RTL_R32(UTP_F0_ACC_INTERVAL),RTL_R32(UTP_S0_ACC_INTERVAL)); seq_printf(seq, "UTP_F1_ACC_INTERVAL = 0x%08x UTP_S1_ACC_INTERVAL = 0x%08x\n",RTL_R32(UTP_F1_ACC_INTERVAL),RTL_R32(UTP_S1_ACC_INTERVAL)); seq_printf(seq, "UTP_F2_ACC_INTERVAL = 0x%08x UTP_S2_ACC_INTERVAL = 0x%08x\n",RTL_R32(UTP_F2_ACC_INTERVAL),RTL_R32(UTP_S2_ACC_INTERVAL)); seq_printf(seq, "UTP_F3_ACC_INTERVAL = 0x%08x UTP_S3_ACC_INTERVAL = 0x%08x\n",RTL_R32(UTP_F3_ACC_INTERVAL),RTL_R32(UTP_S3_ACC_INTERVAL)); seq_printf(seq, "\n"); seq_printf(seq, "UTP_F0_ACC = 0x%08x UTP_S0_ACC = 0x%08x\n",RTL_R32(UTP_F0_ACC),RTL_R32(UTP_S0_ACC)); seq_printf(seq, "UTP_F1_ACC = 0x%08x UTP_S1_ACC = 0x%08x\n",RTL_R32(UTP_F1_ACC),RTL_R32(UTP_S1_ACC)); seq_printf(seq, "UTP_F2_ACC = 0x%08x UTP_S2_ACC = 0x%08x\n",RTL_R32(UTP_F2_ACC),RTL_R32(UTP_S2_ACC)); seq_printf(seq, "UTP_F3_ACC = 0x%08x UTP_S3_ACC = 0x%08x\n",RTL_R32(UTP_F3_ACC),RTL_R32(UTP_S3_ACC)); seq_printf(seq, "\n"); return 0; } static int hw_wanif_read(struct seq_file *seq, void *offset) { int len = 0; rtl8685_dumpWanTable(); return len; } static int hw_qmap_read(struct seq_file *seq, void *offset) { int len = 0; rtl8685_dump_QMap(); return len; } static int hw_counter_read(struct seq_file *seq, void *offset) { int len = 0; seq_printf(seq, "TC counter (offset 0x01CC-01DC)\n"); seq_printf(seq, "TCTX_PKT =0x%08x TCRX_PKT =0x%08x\n",RTL_R32(TCTX_PKT),RTL_R32(TCRX_PKT)); seq_printf(seq, "TCRX_GPKT =0x%08x TCRX_BPKT =0x%08x\n",RTL_R32(TCRX_GPKT),RTL_R32(TCRX_BPKT)); seq_printf(seq, "TCRX_IPKT =0x%08x \n",RTL_R32(TCRX_IPKT)); seq_printf(seq, "\nTX PTMx Codeword/Frame counter (offset 0x0220-023C)\n"); seq_printf(seq, "TX_PTM0 =0x%08x TX_PTM1 =0x%08x\n",RTL_R32(TX_TOTAL_CF_P0),RTL_R32(TX_TOTAL_CF_P1)); seq_printf(seq, "TX_PTM2 =0x%08x TX_PTM3 =0x%08x\n",RTL_R32(TX_TOTAL_CF_P2),RTL_R32(TX_TOTAL_CF_P3)); seq_printf(seq, "TX_PTM4 =0x%08x TX_PTM5 =0x%08x\n",RTL_R32(TX_TOTAL_CF_P4),RTL_R32(TX_TOTAL_CF_P5)); seq_printf(seq, "TX_PTM6 =0x%08x TX_PTM7 =0x%08x\n",RTL_R32(TX_TOTAL_CF_P6),RTL_R32(TX_TOTAL_CF_P7)); seq_printf(seq, "\nTX PTMx Data Codeword/Frame counter (offset 0x0240-025C)\n"); seq_printf(seq, "TX_DATA_PTM0 =0x%08x TX_DATA_PTM1 =0x%08x\n",RTL_R32(TX_DATA_CF_P0),RTL_R32(TX_DATA_CF_P1)); seq_printf(seq, "TX_DATA_PTM2 =0x%08x TX_DATA_PTM3 =0x%08x\n",RTL_R32(TX_DATA_CF_P2),RTL_R32(TX_DATA_CF_P3)); seq_printf(seq, "TX_DATA_PTM4 =0x%08x TX_DATA_PTM5 =0x%08x\n",RTL_R32(TX_DATA_CF_P4),RTL_R32(TX_DATA_CF_P5)); seq_printf(seq, "TX_DATA_PTM6 =0x%08x TX_DATA_PTM7 =0x%08x\n",RTL_R32(TX_DATA_CF_P6),RTL_R32(TX_DATA_CF_P7)); seq_printf(seq, "\nRX non-short packet counter (offset 0x0260-026c)\n"); seq_printf(seq, "H_F =0x%08x H_S =0x%08x\n",RTL_R32(RX_HF_TPKT),RTL_R32(RX_HS_TPKT)); seq_printf(seq, "L_F =0x%08x L_S =0x%08x\n",RTL_R32(RX_LF_TPKT),RTL_R32(RX_LS_TPKT)); seq_printf(seq, "\nRX short packet counter (offset 0x0270-027c)\n"); seq_printf(seq, "H_F =0x%08x H_S =0x%08x\n",RTL_R32(RX_HF_TPKT_SHT),RTL_R32(RX_HS_TPKT_SHT)); seq_printf(seq, "L_F =0x%08x L_S =0x%08x\n",RTL_R32(RX_LF_TPKT_SHT),RTL_R32(RX_LS_TPKT_SHT)); seq_printf(seq, "\nRX CRC16 error packet counter (offset 0x0280-028c)\n"); seq_printf(seq, "H_F =0x%08x H_S =0x%08x\n",RTL_R32(RX_CRC_ERR_HF),RTL_R32(RX_CRC_ERR_HS)); seq_printf(seq, "L_F =0x%08x L_S =0x%08x\n",RTL_R32(RX_CRC_ERR_LF),RTL_R32(RX_CRC_ERR_LS)); seq_printf(seq, "\nRX CRC16 error short packet counter (offset 0x0290-029c)\n"); seq_printf(seq, "H_F =0x%08x H_S =0x%08x\n",RTL_R32(RX_CRC_ERR_HF_SHT),RTL_R32(RX_CRC_ERR_HS_SHT)); seq_printf(seq, "L_F =0x%08x L_S =0x%08x\n",RTL_R32(RX_CRC_ERR_LF_SHT),RTL_R32(RX_CRC_ERR_LS_SHT)); seq_printf(seq, "\nRX HDLC invlaid frame counter (offset 0x02a0-02a4)\n"); seq_printf(seq, "Fast =0x%08x Slow =0x%08x\n",RTL_R32(HDLC_INVLD_F),RTL_R32(HDLC_INVLD_S)); seq_printf(seq, "\nRX coding err counter (offset 0x02a8-02ac)\n"); seq_printf(seq, "Fast =0x%08x Slow =0x%08x\n",RTL_R32(TC_CODING_ERR_F),RTL_R32(TC_CODING_ERR_S)); seq_printf(seq, "\nRX data codeword counter (offset 0x02b0-02b4)\n"); seq_printf(seq, "Fast =0x%08x Slow =0x%08x\n",RTL_R32(RX_DPKT_PTM0),RTL_R32(RX_DPKT_PTM2)); seq_printf(seq, "\nRX line0 codeword counter (offset 0x02b8-02c4)\n"); seq_printf(seq, "FL =0x%08x FH =0x%08x\n",RTL_R32(RX_TPKT_PTM0),RTL_R32(RX_TPKT_PTM1)); seq_printf(seq, "SL =0x%08x SH =0x%08x\n",RTL_R32(RX_TPKT_PTM2),RTL_R32(RX_TPKT_PTM3)); if(ptm_bonding){ seq_printf(seq, "\nRX line1 codeword counter (offset 0x02c8-02d4)\n"); seq_printf(seq, "FL =0x%08x FH =0x%08x\n",RTL_R32(RX_TPKT_PTM4),RTL_R32(RX_TPKT_PTM5)); seq_printf(seq, "SL =0x%08x SH =0x%08x\n",RTL_R32(RX_TPKT_PTM6),RTL_R32(RX_TPKT_PTM7)); seq_printf(seq, "\nRX line2 codeword counter (offset 0x02d8-02e4)\n"); seq_printf(seq, "FL =0x%08x FH =0x%08x\n",RTL_R32(RX_TPKT_PTM8),RTL_R32(RX_TPKT_PTM9)); seq_printf(seq, "SL =0x%08x SH =0x%08x\n",RTL_R32(RX_TPKT_PTM10),RTL_R32(RX_TPKT_PTM11)); seq_printf(seq, "\nRX line3 codeword counter (offset 0x02e8-02f4)\n"); seq_printf(seq, "FL =0x%08x FH =0x%08x\n",RTL_R32(RX_TPKT_PTM12),RTL_R32(RX_TPKT_PTM13)); seq_printf(seq, "SL =0x%08x SH =0x%08x\n",RTL_R32(RX_TPKT_PTM14),RTL_R32(RX_TPKT_PTM15)); } return len; } static void rtl8685_set_ptm_counter(void) { int i; /* Set pkt counter */ for(i=0; i<5; i++){ RTL_W32(TCTX_PKT+i*4, 0); } /* TX PTMx Codeword/Frame */ for(i=0;i<8;i++){ RTL_W32(TX_TOTAL_CF_P0+i*4,0); } /* TX PTMx Data Codeword/Frame */ for(i=0;i<8;i++){ RTL_W32(TX_DATA_CF_P0+i*4,0); } for(i=0;i<4;i++){ /* RX non-short packet counter */ RTL_W32(RX_HF_TPKT+i*4,0); /* RX short packet counter */ RTL_W32(RX_HF_TPKT_SHT+i*4,0); /* RX CRC16 error packet counter */ RTL_W32(RX_CRC_ERR_HF+i*4,0); /* RX CRC16 error short packet counter */ RTL_W32(RX_CRC_ERR_HF_SHT+i*4,0); /* RX line 0*/ RTL_W32(RX_TPKT_PTM0+i*4,0); /* RX line 1*/ RTL_W32(RX_TPKT_PTM4+i*4,0); /* RX line 2*/ RTL_W32(RX_TPKT_PTM8+i*4,0); /* RX line 3*/ RTL_W32(RX_TPKT_PTM12+i*4,0); } for(i=0;i<2;i++){ /* RX HDLC invlaid frame counter */ RTL_W32(HDLC_INVLD_F+i*4,0); /* RX coding err counter */ RTL_W32(TC_CODING_ERR_F+i*4,0); /* RX data codeword counter */ RTL_W32(RX_DPKT_PTM0+i*4,0); } /* RX codeword counter */ for(i=0;i<16;i++){ RTL_W32(RX_TPKT_PTM0+i*4,0); } /* WAN Interface counter */ for(i=0;i<8;i++){ RTL_W32(Entry_tx_pkt_cnt + i*4, 0); RTL_W32(Entry_rx_pkt_cnt + i*4, 0); RTL_W32(Entry_tx_byte_cnt + i*4, 0); RTL_W32(Entry_rx_byte_cnt + i*4, 0); } return; } #ifdef SACHEM_TX_RESET static int hw_sachem_threshold_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; printk("IC Version: %s\n",(IS_RL6405)?"RL6405":"Not RL6405"); if(IS_RL6405){ printk("Sub Version: %s\n",(IS_RL6405A)?"A":"B"); } printk("Sachem reset status: %s\n",(sachem_tx_reset_done)?"Done":"Undergoing"); printk("[Sachem TX Threshold] Step = %d\n",sachem_tx_reset_step); printk("[Sachem TX Threshold] Times = %d\n",sachem_tx_reset_times); return len; } static int hw_sachem_threshold_wirte( struct file *filp, const char *buff,unsigned long len, void *data ) { char tmpbuf[512]; char *strptr; char *cmdptr; if (buff && !copy_from_user(tmpbuf, buff, len)) { tmpbuf[len]=0; strptr=tmpbuf; if(strlen(strptr)==0) goto errout; cmdptr = strsep(&strptr," "); if(cmdptr==NULL) goto errout; if(strncmp(cmdptr, "step",4) == 0) { if(strptr==NULL) goto errout; cmdptr = strsep(&strptr," "); if(cmdptr==NULL) goto errout; sachem_tx_reset_step=simple_strtol(cmdptr, NULL, 0); printk("[%s] sachem_tx_reset_step = %d\n",__func__,sachem_tx_reset_step); } else if(strncmp(cmdptr, "times",4) == 0) { if(strptr==NULL) goto errout; cmdptr = strsep(&strptr," "); if(cmdptr==NULL) goto errout; sachem_tx_reset_times=simple_strtol(cmdptr, NULL, 0); printk("[%s] sachem_tx_reset_times = %d\n",__func__,sachem_tx_reset_times); } } return len; errout: printk("error input\n"); return len; } #endif /* SACHEM_TX_RESET */ static int hw_port5_tx_limitrate_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; printk("ratelimite scale : %d\n",ratelimit_ratio); printk("ratelimite scale not30a : %d\n",ratelimit_ratio_not30a); printk("ratelimite state : "); if(ratelimit_state==-1) printk("stop\n"); else if(ratelimit_state==0) printk("disable\n"); else printk("enable\n"); #ifdef CONFIG_RTL8685 printk("RTL8685C chip = %d\n", IS_RTL8685C() ); #endif /* CONFIG_RTL8685 */ return len; } static int hw_port5_tx_limitrate_wirte( struct file *filp, const char *buff,unsigned long len, void *data ) { char tmpbuf[512]; char *strptr; char *cmdptr; if (buff && !copy_from_user(tmpbuf, buff, len)) { tmpbuf[len]=0; strptr=tmpbuf; if(strlen(strptr)==0) goto errout; cmdptr = strsep(&strptr," "); if(cmdptr==NULL) goto errout; if(strncmp(cmdptr, "disable",7) == 0) { ratelimit_state=0; }else if(strncmp(cmdptr, "enable",6) == 0) { ratelimit_state=1; }else if(strncmp(cmdptr, "stop",4) == 0) { ratelimit_state=-1; }else if(strncmp(cmdptr, "not30a",6) == 0) { if(strptr==NULL) goto errout; cmdptr = strsep(&strptr," "); if(cmdptr==NULL) goto errout; ratelimit_ratio_not30a=simple_strtol(cmdptr, NULL, 0); }else{ ratelimit_ratio=simple_strtol(cmdptr, NULL, 0); } set_port5_engress_ratelimit(); } return len; errout: printk("error input\n"); return len; } static int hw_counter_write( struct file *filp, const char *buff,unsigned long len, void *data ) { char tmpbuf[512]; char *strptr; char *cmdptr; if (buff && !copy_from_user(tmpbuf, buff, len)) { tmpbuf[len] = '\0'; strptr=tmpbuf; if(strlen(strptr)==0) { goto errout; } cmdptr = strsep(&strptr," "); if (cmdptr==NULL) { goto errout; } #ifdef PTM_RESET if(strncmp(cmdptr, "1",1) == 0) ptm_event_process(); if(strncmp(cmdptr, "2",1) == 0) ptm_timer_dbg=0; if(strncmp(cmdptr, "3",1) == 0) ptm_timer_dbg=1; #if defined(CONFIG_PTM_BONDING_MASTER) if(strncmp(cmdptr, "4",1) == 0){ rx_fifo_reset=0; printk("bonding rx fifo reset function disable\n"); } if(strncmp(cmdptr, "5",1) == 0){ rx_fifo_reset=1; printk("bonding rx fifo reset function enable\n"); } #endif #endif /*parse command*/ if(strncmp(cmdptr, "clearall",8) == 0) { printk("Reset PTM counter to zero!!\n"); rtl8685_set_ptm_counter(); } } return len; errout: printk("error input\n"); return len; } static int read_proc_open_hwreg(struct inode *inode, struct file *file) { return(single_open(file, hw_reg_read, NULL)); } static struct file_operations fops_read_proc_hwreg = { .open = read_proc_open_hwreg, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int read_proc_open_hwqos(struct inode *inode, struct file *file) { return(single_open(file, hw_qos_read, NULL)); } static struct file_operations fops_read_proc_hwqos = { .open = read_proc_open_hwqos, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int read_proc_open_hwwanif(struct inode *inode, struct file *file) { return(single_open(file, hw_qmap_read, NULL)); } static struct file_operations fops_read_proc_hwwanif = { .open = read_proc_open_hwwanif, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int read_proc_open_hwqmap(struct inode *inode, struct file *file) { return(single_open(file, hw_wanif_read, NULL)); } static struct file_operations fops_read_proc_hwqmap = { .open = read_proc_open_hwqmap, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static ssize_t write_proc_hwcounter(struct file *file, const char __user * userbuf, size_t count, loff_t * off) { return hw_counter_write(file, userbuf, count, NULL); } static int read_proc_open_hwcounter(struct inode *inode, struct file *file) { return(single_open(file, hw_counter_read, NULL)); } static struct file_operations fops_proc_hwcounter = { .open = read_proc_open_hwcounter, .read = seq_read, .llseek = seq_lseek, .release = single_release, .write = write_proc_hwcounter, }; static ssize_t write_proc_hw_port5_tx_limitrate(struct file *file, const char __user * userbuf, size_t count, loff_t * off) { return hw_port5_tx_limitrate_wirte(file, userbuf, count, NULL); } static int read_proc_open_hw_port5_tx_limitrate(struct inode *inode, struct file *file) { return(single_open(file, hw_port5_tx_limitrate_read, NULL)); } static struct file_operations fops_proc_hw_port5_tx_limitrate = { .open = read_proc_open_hw_port5_tx_limitrate, .read = seq_read, .llseek = seq_lseek, .release = single_release, .write = write_proc_hw_port5_tx_limitrate, }; #ifdef SACHEM_TX_RESET static ssize_t hw_sachem_threshold_write_proc(struct file *file, const char __user * userbuf, size_t count, loff_t * off) { return hw_sachem_threshold_wirte(file, userbuf, count, NULL); } static int hw_sachem_threshold_open(struct inode *inode, struct file *file) { return(single_open(file, hw_sachem_threshold_read, NULL)); } static struct file_operations fops_proc_hw_sachem_threshold = { .open = hw_sachem_threshold_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, .write = hw_sachem_threshold_write_proc, }; #endif /* SACHEM_TX_RESET */ #define PTM_PROC_DIR_NAME "ptm" struct proc_dir_entry *ptm_proc_dir=NULL; static struct proc_dir_entry *hw_counter, *hw_reg ,*hw_port5_tx_limitrate; static struct proc_dir_entry *hw_qos, *hw_wanif, *hw_qmap; #ifdef SACHEM_TX_RESET static struct proc_dir_entry *hw_sachem_threshold; #endif /* SACHEM_TX_RESET */ /*************************************************************************** * Function Name: ptm_debug_proc_init * Description :Show PTM debug message * Returns : None. ***************************************************************************/ static void ptm_debug_proc_init(void){ if(ptm_proc_dir==NULL) ptm_proc_dir = proc_mkdir(PTM_PROC_DIR_NAME,NULL); if(ptm_proc_dir) { hw_reg = proc_create_data("hw_reg", 0444, ptm_proc_dir, &fops_read_proc_hwreg, NULL); if(hw_reg == NULL) { printk("can't create proc entry for hw_reg\n"); } hw_qos = proc_create_data("hw_qos", 0444, ptm_proc_dir, &fops_read_proc_hwqos, NULL); if(hw_qos == NULL) { printk("can't create proc entry for hw_qos\n"); } hw_wanif = proc_create_data("hw_wanif", 0444, ptm_proc_dir, &fops_read_proc_hwwanif, NULL); if(hw_wanif == NULL) { printk("can't create proc entry for hw_wanif\n"); } hw_qmap = proc_create_data("hw_qmap", 0444, ptm_proc_dir, &fops_read_proc_hwqmap, NULL); if(hw_qmap == NULL) { printk("can't create proc entry for hw_qmap\n"); } hw_counter = proc_create_data("hw_counter", 0644, ptm_proc_dir, &fops_proc_hwcounter, NULL); if(hw_counter == NULL) { printk("can't create proc entry for hw_counter\n"); } hw_port5_tx_limitrate = proc_create_data("hw_port5_tx_limitrate", 0644, ptm_proc_dir, &fops_proc_hw_port5_tx_limitrate, NULL); if(hw_port5_tx_limitrate == NULL) { printk("can't create proc entry for hw_port5_tx_limitrate\n"); } #ifdef SACHEM_TX_RESET hw_sachem_threshold = proc_create_data("hw_sachem_threshold", 0644, ptm_proc_dir, &fops_proc_hw_sachem_threshold, NULL); if(hw_sachem_threshold == NULL) { printk("can't create proc entry for hw_sachem_threshold\n"); } #endif /* SACHEM_TX_RESET */ } } #if defined(CONFIG_DSL_ON_SLAVE) int ipc_ptmdev_init(void) #else static int __init rtl8685_ptm_init(void) #endif { int err; struct device *dp; printk( "PTM: rtl8685_ptm_init entry\n" ); /* Enable PTM module after PLL clock has provided*/ REG32(BSP_IP_SEL) &= (~BSP_EN_PTM); REG32(BSP_IP_SEL) |= BSP_EN_PTM; printk( "PTM: disable => enable IP, %08x\n", REG32(BSP_IP_SEL) ); /* Allocate PTM current tables */ current_tbl = kzalloc(PTM_MAX_INTF*sizeof(rtl8685_WANtbl_t), GFP_KERNEL); if(current_tbl==NULL){ printk("Out of memory !!\n"); goto Err_MEM; } /* Allocate Q-Map tables */ qmap_tbl = kzalloc(PTM_MAX_INTF*sizeof(unsigned int), GFP_KERNEL); if(qmap_tbl==NULL){ printk("Out of memory !!\n"); goto Err_MEM; } //init char device, /dev/ptm err=register_chrdev( PTM_DEV_MAJOR, PTM_DEV_NAME, &ptm_fops ); if (err) { printk(KERN_ERR "failed to register ptm device (%d)\n", err); goto out_reg; } ptm_class = class_create(THIS_MODULE, PTM_DEV_NAME); if (IS_ERR(ptm_class)) { err = PTR_ERR(ptm_class); goto out_class; } dp = device_create(ptm_class, NULL, MKDEV(PTM_DEV_MAJOR, 0), NULL, PTM_DEV_NAME); if (IS_ERR(dp)) printk( "ptm: create device failed\n" ); else printk( "ptm: create device successed\n" ); ptm_debug_proc_init(); #ifdef PTM_RESET ptm_timer_init(); #endif #if defined(CONFIG_PTM_BONDING_MASTER) spin_lock_init(&bonding_lock); mutex_init(&bonding_mutex); #endif return 0; out_class: unregister_chrdev(PTM_DEV_MAJOR, PTM_DEV_NAME); out_reg: Err_MEM: if(qmap_tbl) kfree(qmap_tbl); if(current_tbl)kfree(current_tbl); return FAILED; } /*************************************************************************** * Function Name: rtl8685_ptm_exit * Description : Final function that is called when the module is unloaded. * Returns : None. ***************************************************************************/ static void __exit rtl8685_ptm_exit( void ) { printk( "PTM: rtl8685_ptm_exit entry\n" ); /* Free memory */ if(current_tbl!=NULL){ kfree(current_tbl); } if(qmap_tbl!=NULL){ kfree(qmap_tbl); } /* Remove related proc */ remove_proc_entry("hw_reg", ptm_proc_dir); remove_proc_entry("hw_qos", ptm_proc_dir); remove_proc_entry("hw_wanif", ptm_proc_dir); remove_proc_entry("hw_qmap", ptm_proc_dir); remove_proc_entry("hw_counter", ptm_proc_dir); remove_proc_entry("hw_port5_tx_limitrate", ptm_proc_dir); remove_proc_entry(PTM_PROC_DIR_NAME, NULL); //cleanup char device, /dev/ptm unregister_chrdev(PTM_DEV_MAJOR, PTM_DEV_NAME); device_destroy(ptm_class, MKDEV(PTM_DEV_MAJOR, 0)); class_destroy(ptm_class); #ifdef PTM_RESET ptm_timer_exit(); #endif } /* rtl8685_ptm_exit */ /*************************************************************************** * Function Name: ptm_open * Description : Called when an application opens this device. * Returns : 0 - success ***************************************************************************/ static int ptm_open( struct inode *inode, struct file *filp ) { //printk("PTM: %s\n",__func__); return( 0 ); } /* ptm_open */ /*************************************************************************** * Function Name: ptm_close * Description : Called when an application stops this device. * Returns : 0 - success ***************************************************************************/ static int ptm_close( struct inode *inode, struct file *filp ) { //printk("PTM: %s\n",__func__); return( 0 ); } /* ptm_close */ void set_nonbonding_board(void) { int val = 0; /* Set PCR to zero before using */ RTL_W32(PCR, 0x0); if (IS_RLE0822 || IS_6518()){ val = SYSTEM_R32(0x0100); val &= (~(1<<24)); val &= (~(1<<25)); SYSTEM_W32(0x0100, val); val = SYSTEM_R32(0x010c); val &= (~(1<<8)); SYSTEM_W32(0x010c, val); val = SYSTEM_R32(0x0114); val &= (~(1<<13)); SYSTEM_W32(0x0114, val); } /* Non-bonding mode */ RTL_W32(BD_SLV_NUM, (1<<1)); RTL_W32(PCR, (TY_SYNC_F0 |TY_SYNC_S0 )); /* Cell avaliable in PTM */ if(IS_RL6405 || IS_RLE0797){ RTL_W32( PCR, (RTL_R32(PCR)|(rxutp_clav_en)) /*| (txutp_clav_en)*/); } else if(IS_RLE0822 || IS_6518()){ RTL_W32( PCR, (RTL_R32(PCR) | (rxutp_clav_en) | (txutp_clav_en) | (rxutp_clav_ext_en) | (txutp_clav_ext_en)) ); } RTL_W32( PCR, RTL_R32(PCR)|TC_SYNC_LC); } void bonding_enable(int line_num) { //master enable if (line_num == 0) RTL_W32( PCR, (RTL_R32(PCR) | (rxutp_clav_en) | (txutp_clav_en)) ); //slave enable if (line_num == 1) RTL_W32( PCR, (RTL_R32(PCR) | (rxutp_clav_ext_en) | (txutp_clav_ext_en)) ); } void bonding_disable(int line_num) { //master disable if (line_num == 0) RTL_W32( PCR, (RTL_R32(PCR) & (~(rxutp_clav_en)) & (~(txutp_clav_en))) ); //slave disable if (line_num == 1) RTL_W32( PCR, (RTL_R32(PCR) & (~(rxutp_clav_ext_en)) & (~(txutp_clav_ext_en))) ); } void nonbonding_enable(void) { RTL_W32( PCR, (RTL_R32(PCR) | (rxutp_clav_en) | (txutp_clav_en) | (rxutp_clav_ext_en) | (txutp_clav_ext_en)) ); } void nonbonding_disable(void) { RTL_W32( PCR, (RTL_R32(PCR) & (~(rxutp_clav_en)) & (~(txutp_clav_en)) & (~(rxutp_clav_ext_en)) & (~(txutp_clav_en)) ) ); } void change_bonding_timeout(int linkup_num) { if (linkup_num == 1) RTL_W32(BD_TIMEOUT, 0x00000100); else if (linkup_num == 2) RTL_W32(BD_TIMEOUT, 0x0002ee20); return; } void set_bonding_board(void) { int i, val = 0; ptm_bonding_line = 2; /* Set PCR to zero before using */ RTL_W32(PCR, 0x0); if (IS_RLE0822 || IS_6518()){ #if defined(CONFIG_PTM_BONDING_MASTER) // enable bonding master val = SYSTEM_R32(0x0100); val |= (1<<25); val &= (~(1<<24)); SYSTEM_W32(0x0100, val); #elif defined(CONFIG_PTM_BONDING_SLAVE) // enable bonding slave val = SYSTEM_R32(0x0100); val &= (~(1<<25)); val |= (1<<24); SYSTEM_W32(0x0100, val); #endif // enable phyid_from_tpstc // the setting is needed on qa board // val = SYSTEM_R32(0x010c); // val |= (1<<8); // SYSTEM_W32(0x010c, val); // set utopia driving for bonding function val = SYSTEM_R32(0x0114); val &= (~(1<<0)); val &= (~(1<<1)); val &= (~(1<<13)); SYSTEM_W32(0x0114, val); /* UTP QoS */ RTL_W32( UTP_APR32_F, 0x000e000e); RTL_W32( UTP_APR10_F, 0x7ffc7ffc); RTL_W32( UTP_APR32_S, 0x000e000e); RTL_W32( UTP_APR10_S, 0x7ffc7ffc); RTL_W32( UTP_APR_ALL, 0x7ffc7ffc); RTL_W32( UTP_WEIGHT_F, 0x01010101); RTL_W32( UTP_WEIGHT_S, 0x01010101); RTL_W32( UTP_QOS_MIS, 0x00983300); /* Bonding mode */ RTL_W32(BD_SLV_NUM, (ptm_bonding_line << 1)); /* line number */ RTL_W32(BOND_FRAG_LF, 0x000001f8); RTL_W32(BD_TIMEOUT, 0x00000100); for(i=0;i<ptm_bonding_line;i++){ RTL_W32( PCR, RTL_R32(PCR)|(TY_SYNC_F0 <<i)| (TY_SYNC_S0 <<i)); } RTL_W32( PCR, RTL_R32(PCR) | 0x5a000000 ); } RTL_W32( PCR, RTL_R32(PCR)|TC_SYNC_LC); } /*************************************************************************** * Function Name: ptm_ioctl * Description : Main entry point for an application send issue ATM API * requests. * Returns : 0 - success or error ***************************************************************************/ static long ptm_ioctl(struct file *flip, unsigned int command, unsigned long inarg ) { int retVal = 0, i=0, j=0, val=0; char *data =(char *)inarg; unsigned char c; struct ptm_arg outarg; rtl8685_WANtbl_t INTF_CTL; copy_from_user(&outarg, data, sizeof(struct ptm_arg)); //printk("Test command, pp_cmd = %d, command = %d\n", pp_cmd, command); switch(command){ case PTM_SET_DEFAULT_TABLE: for(i=0; i<PTM_MAX_INTF;i++){ memcpy(&INTF_CTL, &default_tbl[i], sizeof(rtl8685_WANtbl_t)); rtl8685_setWanTable(i,&INTF_CTL); } break; case PTM_GET_TABLE: rtl8685_dumpWanTable(); break; case PTM_READ_DATA: printk("Read Address 0x%08x with length 0x%08x\n", (unsigned int)outarg.cmd2, outarg.cmd3); Dumpreg((unsigned long)outarg.cmd2, (unsigned int)outarg.cmd3); break; case PTM_WRITE_DATA: printk("Write Address 0x%08x Value 0x%08x\n", (unsigned int)outarg.cmd2, outarg.cmd3); *(volatile u32*)(outarg.cmd2) = outarg.cmd3; break; case PTM_SET_SYSTEM: printk("Set System for PTM Bonding Board\n"); set_bonding_board(); break; case PTM_SET_HW: if(outarg.cmd2==1) ptm_bonding=1; else ptm_bonding=0; ptm_bonding_line = outarg.cmd3; if(ptm_bonding==0){ printk("Set PTM as non-bonding mode\n"); }else{ printk("Set PTM as bonding mode with line %d\n",ptm_bonding_line); } ptm_init_hw(); break; case PTM_GET_QMAP: rtl8685_dump_QMap(); break; case PTM_STOP_HW: printk( "stop PTM HW\n" ); ptm_stop_hw(); break; case PTM_START_HW: printk( "start PTM HW\n" ); ptm_start_hw(); break; case PTM_CLEAN_WANIF: printk( "clean all wan interface\n" ); memset( &INTF_CTL, 0, sizeof(INTF_CTL) ); for(i=0; i<PTM_MAX_INTF;i++) { rtl8685_setWanTable(i,&INTF_CTL); } break; case PTM_CLEAN_QMAP: printk( "clean all queue mapping\n" ); for(i=0; i<PTM_MAX_INTF;i++) { for(j=0; j<PTM_PRI_NUM;j++) { rtl8685_set_QMap(i,j,0); } } break; case PTM_SET_WANIF: printk( "set wanif, %u %u %u %02x%02x%02x%02x%02x%02x\n", outarg.cmd, outarg.a1, outarg.a2, outarg.a3[0],outarg.a3[1], outarg.a3[2],outarg.a3[3],outarg.a3[4],outarg.a3[5]); memset( &INTF_CTL, 0, sizeof(INTF_CTL) ); INTF_CTL.Valid=1; i=outarg.cmd&0x7; sprintf(INTF_CTL.ifname, "wan_%u", i ); INTF_CTL.SVlanID=outarg.a1 & 0x0fff; INTF_CTL.CVlanID=outarg.a2 & 0x0fff; memcpy( INTF_CTL.MAC, outarg.a3, 6); rtl8685_setWanTable(i,&INTF_CTL); break; case PTM_SET_QMAP: printk( "set qmap %u %u%u%u%u%u%u%u%u\n", outarg.cmd, outarg.arg[0], outarg.arg[1], outarg.arg[2], outarg.arg[3], outarg.arg[4], outarg.arg[5], outarg.arg[6], outarg.arg[7] ); i=outarg.cmd&0x7; for(j=0; j<PTM_PRI_NUM;j++) { rtl8685_set_QMap(i,j,outarg.arg[j]&0x7); } break; case PTM_SET_STAGTYPE: printk( "set stagtype=0x%x\n", outarg.a1); RTL_R16(Stag_type_val)=outarg.a1; break; case PTM_SET_DUMMYVID: printk( "set dummyvid=0x%x\n", outarg.a1&0xfff ); RTL_R16(Dummy_vid)=outarg.a1&0xfff; break; case PTM_SET_QMAPATSTAG: printk( "set qmapatstag tx=%u rx=%u\n", outarg.a1, outarg.a2 ); c=RTL_R8(WCR); c &= ~(Qmap_at_stag_tx|Qmap_at_stag_rx); if(outarg.a1) c = c | Qmap_at_stag_tx; if(outarg.a2) c = c | Qmap_at_stag_rx; RTL_R8(WCR)=c; break; case PTM_SET_MODE: printk( "set mode %d\n", outarg.cmd); if(outarg.cmd) ptm_set_mode(Mode2_Sel); else ptm_set_mode(Mode1_Sel); break; case PTM_DISABLE_TPSTC: printk("TPSTC DISABLE\n"); SARCHEM_W32(0x5040, 0x1); break; case PTM_ENABLE_TPSTC: printk("TPSTC Enable\n"); SARCHEM_W32(0x5040, 0x0); break; case PTM_RESET_TPSTC: printk("TPSTC RESET\n"); ShowtimeTpsReset(); ShowtimeTpsSet(); break; case PTM_GET_TPSTC_TX_CNT: val = (*(volatile u32*)(0xb8af0040)); printk("Read Address: 0xb8af0040: %x\n", val); retVal = val; break; case PTM_GET_UTOPIA_TX_CNT: val = (*(volatile u32*)(0xb8af0028)); printk("Read Address: 0xb8af0028: %x\n", val); retVal = val; break; default: ;//printk("error command\n"); } return retVal; } #if !defined(CONFIG_DSL_ON_SLAVE) module_init(rtl8685_ptm_init); module_exit(rtl8685_ptm_exit); #endif