/* * ---------------------------------------------------------------- * Copyright c Realtek Semiconductor Corporation, 2002 * All rights reserved. * * $Header: /usr/local/dslrepos/linux-2.6.30/drivers/net/rtl819x/rtl865xc_swNic.c,v 1.25 2013/01/24 09:52:57 knight_peng Exp $ * * Abstract: Switch core polling mode NIC driver source code. * * $Author: knight_peng $ * * $Log: rtl865xc_swNic.c,v $ * Revision 1.25 2013/01/24 09:52:57 knight_peng * fix RX_info->len in case of receive huge packet which consume more than one mbuff. * * Revision 1.24 2013/01/14 06:29:32 knight_peng * patch for huge packet that need more than one mbuf in a pkthdr * * Revision 1.23 2012/11/19 08:55:45 ikevin362 * setup tx desc. when xmit packet with vlan tag * * Revision 1.22 2012/11/15 08:57:13 ikevin362 * RTL8685 support * * Revision 1.21 2012/05/23 03:31:42 czpinging * fix compiler error * * Revision 1.20 2012/05/22 04:07:46 czpinging * refill priority in descriptor * * Revision 1.19 2012/05/21 08:47:44 czpinging * refill priority in descriptork * * Revision 1.18 2012/04/23 09:19:27 ikevin362 * skb_debug when enable dump_swNicTxRx_pkt * * Revision 1.17 2012/03/09 13:28:23 kaohj * invalidate cache before DMA * * Revision 1.16 2012/02/21 08:49:53 tylo * add debug by Kevin * * Revision 1.14 2011/12/09 08:37:56 cathy * enable debug for rx and remove trap_by_ingress_acl * * Revision 1.13 2011/11/17 07:47:26 czpinging * (Redef)8367b * * Revision 1.12 2011/11/17 03:37:34 czpinging * Add RL6000 testing function * * Revision 1.11 2011/11/16 14:09:09 czpinging * Add RL6000 testing function * * Revision 1.10 2011/11/04 10:44:09 kaohj * Fix compile error, use DELAY_REFILL_ETH_RX_BUF * * Revision 1.9 2011/07/29 14:18:35 ql * nothing change * * Revision 1.8 2011/07/25 07:01:29 ql * add debug info. * * Revision 1.7 2011/07/22 08:01:15 ikevin362 * if the pkt is only toward to extPort, reset vid to a magic number * * Revision 1.6 2011/07/11 09:04:56 cathy * avoid free the same skb in swNic_txDone * * Revision 1.5 2011/06/27 14:12:45 ikevin362 * 1. print the reason when trap to cpu 2.mark the packet which is trapped by ingress acl rule * * Revision 1.4 2011/06/20 12:07:05 tylo * fix unknown unicast rx issue * * Revision 1.3 2011/06/13 10:27:49 ikevin362 * add trap2cpu pkt debug * * Revision 1.2 2011/04/11 12:45:18 tylo * update hw nat driver from AP team * * Revision 1.11 2008/04/11 10:49:14 bo_zhao * * restore the original cache flush * * Revision 1.10 2008/04/11 10:12:38 bo_zhao * *: swap nic drive to 8186 style * * Revision 1.6 2008/02/22 05:31:52 joeylin * set one VLAN group for Bridge/WISP mode, and fix the issue: * WAN port PC can not ping br0 (192.168.1.254) in Bridge/WISP mode * * Revision 1.5 2008/02/15 09:52:46 forrest * 1. Add hardware accelerated PPTP processing. 2. Fine tune some hardware NAT to be compatible to hardware accelerated PPTP. * * Revision 1.4 2007/12/08 08:24:26 davidhsu * Adjust tx desc size. Hide error message * * Revision 1.3 2007/12/04 12:00:18 joeylin * add hardware NAT feature * * Revision 1.2 2007/11/11 02:51:24 davidhsu * Fix the bug that do not fre rx skb in rx descriptor when driver is shutdown * * Revision 1.1.1.1 2007/08/06 10:04:52 root * Initial import source to CVS * * Revision 1.11 2007/03/27 12:51:07 michaelhuang * +: add function swNic_send_portmbr for FT2 * * * * --------------------------------------------------------------- */ #include <net/rtl/rtl_types.h> #include <net/rtl/rtl_glue.h> #include <net/rtl/rtl_nic.h> #include "common/rtl_errno.h" #include "AsicDriver/asicRegs.h" #include "rtl865xc_swNic.h" #include "common/mbuf.h" #include "AsicDriver/rtl865x_asicCom.h" #include "AsicDriver/rtl865x_asicL2.h" #include <linux/skbuff.h> #include "AsicDriver/rtl865xC_hs.h" #ifdef CONFIG_RTL865X_ROMEPERF #include "romeperf.h" #endif #include <linux/netdevice.h> #ifdef CONFIG_FAST_FORWARDING #include "../brg_shortcut.h" #include <linux/netdevice.h> #include <linux/inetdevice.h> #include <linux/etherdevice.h> #endif//end of CONFIG_FAST_FORWARDING int DumpTrapCPUHs_debug = 0; int DumpTrapCPUHs_debug_LIMIT = 0; int DumpTrapCPUpkt_debug = 0; int DumpTrapCPUpkt_debug_LIMIT = 0; int DumpSwNicTxRx_debug = 0; int DumpSwNicTxRx_debug_LIMIT = 0; int DumpERBpacket_debug = 0; #if defined(CONFIG_RTL_8685S_HWNAT) char pkt_data[2048]; int DumpSwNicTxRx_debug_pkt=0; #endif extern void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size); extern void tx_done_callback(void *skb); #ifdef CONFIG_DATA_IN_IMEM extern void *allocUncachedBuffFromIMEM(uint32 len); #endif #ifdef CONFIG_RTL_ETH_PRIV_SKB_ADV extern void rtl865x_free_eth_priv_buf(struct sk_buff *skb, unsigned flag); extern unsigned char *get_buf_from_poll(void); #endif//end of CONFIG_RTL_ETH_PRIV_SKB_ADV /* RX Ring */ static uint32* rxPkthdrRing[RTL865X_SWNIC_RXRING_HW_PKTDESC]; /* Point to the starting address of RX pkt Hdr Ring */ static dma_addr_t rxPkthdrRing_addr[RTL865X_SWNIC_RXRING_HW_PKTDESC]; __DRAM_FWD static uint32 rxPkthdrRingCnt[RTL865X_SWNIC_RXRING_HW_PKTDESC]; /* Total pkt count for each Rx descriptor Ring */ __DRAM_FWD static uint32 rxPkthdrRefillThreshold[RTL865X_SWNIC_RXRING_HW_PKTDESC]; /* Ether refill threshold for each Rx descriptor Ring */ /* TX Ring */ static uint32* txPkthdrRing[RTL865X_SWNIC_TXRING_HW_PKTDESC]; /* Point to the starting address of TX pkt Hdr Ring */ static dma_addr_t txPkthdrRing_addr[RTL865X_SWNIC_TXRING_HW_PKTDESC]; #if defined(CONFIG_RTL8196C_REVISION_B) __DRAM_FWD static uint32 rtl_chip_version; static uint32* txPkthdrRing_backup[RTL865X_SWNIC_TXRING_HW_PKTDESC]; /* Point to the starting address of TX pkt Hdr Ring */ static dma_addr_t txPkthdrRing_backup_addr[RTL865X_SWNIC_TXRING_HW_PKTDESC]; #endif __DRAM_FWD static uint32 txPkthdrRingCnt[RTL865X_SWNIC_TXRING_HW_PKTDESC]; /* Total pkt count for each Tx descriptor Ring */ #define txPktHdrRingFull(idx) (((txPkthdrRingFreeIndex[idx] + 1) & (txPkthdrRingMaxIndex[idx])) == (txPkthdrRingDoneIndex[idx])) /* Mbuf */ static uint32* rxMbufRing; /* Point to the starting address of MBUF Ring */ static dma_addr_t rxMbufRing_addr; __DRAM_FWD static uint32 rxMbufRingCnt; /* Total MBUF count */ __DRAM_FWD uint32 size_of_cluster; /* descriptor ring tracing pointers */ __DRAM_FWD static int32 currRxPkthdrDescIndex[RTL865X_SWNIC_RXRING_HW_PKTDESC]; /* Rx pkthdr descriptor to be handled by CPU */ __DRAM_FWD static int32 currRxMbufDescIndex; /* Rx mbuf descriptor to be handled by CPU */ __DRAM_FWD static int32 currTxPkthdrDescIndex[RTL865X_SWNIC_TXRING_HW_PKTDESC]; /* Tx pkthdr descriptor to be handled by CPU */ __DRAM_FWD static int32 txPktDoneDescIndex[RTL865X_SWNIC_TXRING_HW_PKTDESC]; /* Rx hs table */ void dump_hstbl(void) { hsb_param_t *hsb_r, dummy_hsb_r; hsa_param_t *hsa_r, dummy_hsa_r; ipaddr_t addr; char addr_s[100]; hsb_r = &dummy_hsb_r; hsa_r = &dummy_hsa_r; memset((void*)hsb_r,0,sizeof(hsa_param_t)); memset((void*)hsa_r,0,sizeof(hsa_param_t)); rtl865xC_virtualMacGetHsb( hsb_r ); { printk("HSB("); printk("\ttype:%d",hsb_r->type); printk("\tspa:%d",hsb_r->spa); printk("\tlen:%d",hsb_r->len); printk("\tvid :%d\n",hsb_r->vid); printk("\tpppoe:%d",hsb_r->pppoeif); /* Protocol contents */ printk("\ttagif:%d\tpppoeId:%d",hsb_r->tagif,hsb_r->pppoeid); printk("\tethrtype:0x%04x\n",hsb_r->ethtype); printk("\tllc_other:%d\tsnap:%d\n",hsb_r->llcothr,hsb_r->snap); printk("\tda:%02x-%02x-%02x-%02x-%02x-%02x",hsb_r->da[0],hsb_r->da[1],hsb_r->da[2],hsb_r->da[3],hsb_r->da[4],hsb_r->da[5]); printk("\tsa:%02x-%02x-%02x-%02x-%02x-%02x\n",hsb_r->sa[0],hsb_r->sa[1],hsb_r->sa[2],hsb_r->sa[3],hsb_r->sa[4],hsb_r->sa[5]); addr = ntohl( hsb_r->sip); inet_ntoa_r(addr, addr_s); printk("\tsip:%s(hex:%08x) ",addr_s,hsb_r->sip); printk("\tsprt:%d (hex:%x)\n ",(int)hsb_r->sprt,hsb_r->sprt); addr = ntohl(hsb_r->dip); inet_ntoa_r(addr, addr_s); printk("\tdip:%s(hex:%08x) ",addr_s,hsb_r->dip);; printk("\tdprt:%d(hex:%08x)\n",hsb_r->dprt,hsb_r->dprt); printk("\tipptl:%d,",(int)hsb_r->ipptl); printk("\tipflg:%d,",hsb_r->ipfg); printk("\tiptos:%d,",hsb_r->iptos); printk("\ttcpflg:%d\n",hsb_r->tcpfg); printk("\tdirtx:%d,",hsb_r->dirtx); printk("\tprtnmat:%d",hsb_r->patmatch); printk("\tudp_nocs:%d",hsb_r->udpnocs); printk("\tttlst:0x%x\n",hsb_r->ttlst); printk("\thp:%d",hsb_r->hiprior); printk("\tl3csok:%d\tl4csok:%d\tipfragif:%d\n",hsb_r->l3csok,hsb_r->l4csok,hsb_r->ipfo0_n); printk("\textspa:%d",hsb_r->extspa); #if defined(CONFIG_RTL_8685S_HWNAT) printk("\turlmch:%d\n",hsb_r->urlmch); printk("\t ipv4_opt:%d",hsb_r->ipv4_opt); printk("\t cpuTagIf:%d",hsb_r->cpuTagIf); printk("\t v6Ext:%d\n",hsb_r->v6Ext); printk("\t v6fragmOffs:%d",hsb_r->v6fragmOffs); printk("\t v6Flag:%d",hsb_r->v6Flag); printk("\t qpri:%d\n",hsb_r->qpri); printk("\t ptpPkt:%d",hsb_r->ptpPkt); printk("\t ptpVer:%d",hsb_r->ptpVer); printk("\t ptpTyp:%d",hsb_r->ptpTyp); printk("\t ipVerFirst:%d\n",hsb_r->ipVerFirst); printk("\t Sipv6:\t%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n" ,hsb_r->v6Sip.s6_addr32[0]>>16,hsb_r->v6Sip.s6_addr32[0]&0xFFFF ,hsb_r->v6Sip.s6_addr32[1]>>16,hsb_r->v6Sip.s6_addr32[1]&0xFFFF ,hsb_r->v6Sip.s6_addr32[2]>>16,hsb_r->v6Sip.s6_addr32[2]&0xFFFF ,hsb_r->v6Sip.s6_addr32[3]>>16,hsb_r->v6Sip.s6_addr32[3]&0xFFFF); printk("\t Dipv6:\t%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n" ,hsb_r->v6Dip.s6_addr32[0]>>16,hsb_r->v6Dip.s6_addr32[0]&0xFFFF ,hsb_r->v6Dip.s6_addr32[1]>>16,hsb_r->v6Dip.s6_addr32[1]&0xFFFF ,hsb_r->v6Dip.s6_addr32[2]>>16,hsb_r->v6Dip.s6_addr32[2]&0xFFFF ,hsb_r->v6Dip.s6_addr32[3]>>16,hsb_r->v6Dip.s6_addr32[3]&0xFFFF); printk("\t v6HopLimit:%d",hsb_r->v6HopLimit); printk("\t v6TafficClass:%d",hsb_r->v6TafficClass); printk("\t v6FlowLabel:%d",hsb_r->v6FlowLabel); printk("\t v6NxtHdr:%d\n",hsb_r->v6NxtHdr); printk("\t v4PktHdr:%d",hsb_r->v4PktHdr); printk("\t v6PktHdr:%d",hsb_r->v6PktHdr); printk("\t innerIpLen:%d",hsb_r->innerIpLen); if(IS_AFTER_RL6405) { printk("\t tunnelLen:%d\n",hsb_r->tunnelLen); printk("\t l3ChecksumOfflad:%d l4ChecksumOfflad:%d innIpHeaderLen:%d \n\t swredPktFlag:%d swredPktFlag:%d", hsb_r->l3ChecksumOfflad,hsb_r->l4ChecksumOfflad,hsb_r->innIpHeaderLen,hsb_r->swredPktFlag,hsb_r->swredPktType); printk(" l3Checksum:%d l4Checksum:%d \n)\n", hsb_r->l3Checksum,hsb_r->l4Checksum); } else { printk("\t tunnelLen:%d\n)\n",hsb_r->tunnelLen); } #else /* CONFIG_RTL_8685S_HWNAT */ printk("\turlmch:%d\n)\n",hsb_r->urlmch); #endif /* CONFIG_RTL_8685S_HWNAT */ } rtl865xC_virtualMacGetHsa( hsa_r ); { printk(("HSA(")); printk("\tmac:%02x-%02x-%02x-%02x-%02x-%02x\n",hsa_r->nhmac[0],hsa_r->nhmac[1],hsa_r->nhmac[2],hsa_r->nhmac[3],hsa_r->nhmac[4],hsa_r->nhmac[5]); addr =ntohl( hsa_r->trip); inet_ntoa_r(addr, addr_s); printk("\ttrip:%s(hex:%08x)",addr_s,hsa_r->trip); printk("\tprt:%d\tipmcast:%d\n",hsa_r->port,hsa_r->ipmcastr); printk("\tl3cs:%d",hsa_r->l3csdt); printk("\tl4cs:%d",hsa_r->l4csdt); printk("\tInternal NETIF:%d",hsa_r->egif); printk("\tl2tr:%d,\n ",hsa_r->l2tr); printk("\tl34tr:%d",hsa_r->l34tr); printk("\tdirtx:%d",hsa_r->dirtxo); printk("\ttype:%d",hsa_r->typeo); printk("\tsnapo:%d",hsa_r->snapo); printk("\twhy2cpu 0x%x (%d)\n",hsa_r->why2cpu,hsa_r->why2cpu); printk("\tpppif:%d",hsa_r->pppoeifo); printk("\tpppid:%d",hsa_r->pppidx); printk("\tttl_1:0x%x",hsa_r->ttl_1if); printk("\tdpc:%d,",hsa_r->dpc); printk("\tleno:%d(0x%x)\n",hsa_r->leno,hsa_r->leno); printk("\tl3CrcOk:%d",hsa_r->l3csoko); printk("\tl4CrcOk:%d",hsa_r->l4csoko); printk("\tfrag:%d",hsa_r->frag); printk("\tlastFrag:%d\n",hsa_r->lastfrag); printk("\tsvid:0x%x",hsa_r->svid); printk("\tdvid:%d(0x%x)",hsa_r->dvid,hsa_r->dvid); printk("\tdestination interface :%d\n",hsa_r->difid); printk("\trxtag:%d",hsa_r->rxtag); printk("\tdvtag:0x%x",hsa_r->dvtag); printk("\tspa:%d",hsa_r->spao); printk("\tdpext:0x%x\thwfwrd:%d\n",hsa_r->dpext,hsa_r->hwfwrd); printk("\tspcp:%d",hsa_r->spcp); printk("\tpriority:%d",hsa_r->priority); printk("\tdp:0x%x\n",hsa_r->dp); #if defined(CONFIG_RTL_8685S_HWNAT) printk("\t mirrort:%d",hsa_r->mirrort); printk("\t v4First:%d",hsa_r->v4First); printk("\t cpuTag:%d\n",hsa_r->cpuTag); printk("\t ptpPkt:%d",hsa_r->ptpPkt); printk("\t ptpV2:%d",hsa_r->ptpV2); printk("\t ptpType:%d\n",hsa_r->ptpType); printk("\t routeModeDstPort:%d",hsa_r->routeModeDstPort); printk("\t dPri:%d",hsa_r->dPri); printk("\t ipMdf:%d\n",hsa_r->ipMdf); printk("\t Sipv6(6rd/dslite):\t%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n" ,hsa_r->sip.s6_addr32[0]>>16,hsa_r->sip.s6_addr32[0]&0xFFFF ,hsa_r->sip.s6_addr32[1]>>16,hsa_r->sip.s6_addr32[1]&0xFFFF ,hsa_r->sip.s6_addr32[2]>>16,hsa_r->sip.s6_addr32[2]&0xFFFF ,hsa_r->sip.s6_addr32[3]>>16,hsa_r->sip.s6_addr32[3]&0xFFFF); printk("\t Dipv6(6rd/dslite):\t%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n" ,hsa_r->dip.s6_addr32[0]>>16,hsa_r->dip.s6_addr32[0]&0xFFFF ,hsa_r->dip.s6_addr32[1]>>16,hsa_r->dip.s6_addr32[1]&0xFFFF ,hsa_r->dip.s6_addr32[2]>>16,hsa_r->dip.s6_addr32[2]&0xFFFF ,hsa_r->dip.s6_addr32[3]>>16,hsa_r->dip.s6_addr32[3]&0xFFFF); printk("\t ipLen:%d",hsa_r->ipLen); printk("\t v4Id:%d",hsa_r->v4Id); printk("\t v4pkt:%d",hsa_r->v4pkt); printk("\t v6pkt:%d\n",hsa_r->v6pkt); printk("\t tunnelLen:%d",hsa_r->tunnelLen); printk("\t v6Multicast:%d",hsa_r->v6Multicast); printk("\t addipPri:%d\n",hsa_r->addipPri); if(IS_AFTER_RL6405) { printk("\t l3ChecksumOfflad:%d l4ChecksumOfflad:%d innIpHeaderLen:%d \n\t swredPktFlag:%d swredPktType:%d \n" ,hsa_r->l3ChecksumOfflad,hsa_r->l4ChecksumOfflad,hsa_r->innIpHeaderLen,hsa_r->swredPktFlag,hsa_r->swredPktType); } #else /* CONFIG_RTL_8685S_HWNAT */ printk("\t fragpkt:%d",hsa_r->fragpkt); #endif /* CONFIG_RTL_8685S_HWNAT */ printk(")\n"); } return; } /* debug counters */ //__DRAM_FWD static int32 rxPktCounter; //__DRAM_FWD static int32 txPktCounter; #ifdef DELAY_REFILL_ETH_RX_BUF __DRAM_FWD static int32 rxDescReadyForHwIndex[RTL865X_SWNIC_RXRING_HW_PKTDESC]; #endif __DRAM_FWD static uint8 extPortMaskToPortNum[_RTL865XB_EXTPORTMASKS+1] = { 0, 1, 2, 0, 3, 0, 0, 0 }; #if defined(CONFIG_RTL_PROC_DEBUG)||defined(CONFIG_RTL_DEBUG_TOOL) __DRAM_FWD unsigned int rx_noBuffer_cnt; __DRAM_FWD unsigned int tx_ringFull_cnt; __DRAM_FWD unsigned int tx_drop_cnt; #endif /* locks for Tx/Rx descriptor rings */ //#define DEBUG_LOCKS 1 #define CPU_NONE -1 #ifdef DEBUG_LOCKS struct swcore_locks_counter_s { u64 cntr_wait_total; u32 cntr_wait_high; u32 cntr_lock; u32 cntr_unlock; u32 cntr_contention; }; #define DEFINE_SWCORE_LOCKS_ARRAY_VAR(name, size) \ static spinlock_t name##_locks[size]; \ static int name##_locks_owners[size]; \ DEFINE_PER_CPU(struct swcore_locks_counter_s, name##_lock_counters); #define DEFINE_SWCORE_LOCKS_ARRAY_FUNC(name, size) \ unsigned long swcore_##name##_lock(int ring) { \ unsigned long flags = 0; \ u32 t0, t1, diff; \ struct swcore_locks_counter_s *cntr = &per_cpu(name##_lock_counters, smp_processor_id()); \ if (name##_locks_owners[ring]==CPU_NONE) \ name##_locks_owners[ring] = smp_processor_id(); \ else \ cntr->cntr_contention++; \ t0 = read_c0_count(); \ spin_lock_irqsave(&name##_locks[ring], flags); \ t1 = read_c0_count(); \ diff = t1 - t0;\ cntr->cntr_wait_total += diff; \ if (unlikely(diff > cntr->cntr_wait_high)) \ cntr->cntr_wait_high = diff; \ cntr->cntr_lock++; \ return flags; \ } \ void swcore_##name##_unlock(int ring, unsigned long flags) { \ struct swcore_locks_counter_s *cntr = &per_cpu(name##_lock_counters, smp_processor_id()); \ name##_locks_owners[ring] = CPU_NONE; \ spin_unlock_irqrestore(&name##_locks[ring], flags); \ cntr->cntr_unlock++; \ } #else #define DEFINE_SWCORE_LOCKS_ARRAY_VAR(name, size) \ static spinlock_t name##_locks[size] __attribute__((__aligned__(32))); #define DEFINE_SWCORE_LOCKS_ARRAY_FUNC(name, size) \ unsigned long swcore_##name##_lock(int ring) { \ unsigned long flags = 0; \ spin_lock_irqsave(&name##_locks[ring], flags); \ return flags; \ } \ void swcore_##name##_unlock(int ring, unsigned long flags) { \ spin_unlock_irqrestore(&name##_locks[ring], flags); \ } #endif //DEBUG_LOCKS #define DECLARE_SWCORE_LOCK_ARRAY(name, size) \ DEFINE_SWCORE_LOCKS_ARRAY_VAR(name,size) \ DEFINE_SWCORE_LOCKS_ARRAY_FUNC(name, size) DECLARE_SWCORE_LOCK_ARRAY(tx,RTL865X_SWNIC_TXRING_HW_PKTDESC); DECLARE_SWCORE_LOCK_ARRAY(rx,RTL865X_SWNIC_RXRING_HW_PKTDESC); DECLARE_SWCORE_LOCK_ARRAY(buf,2); // 0 - protects eth_skbbuf_list // 1 - protects rx_skb_queue #ifdef DEBUG_LOCKS static int print_lock_counter(struct seq_file* s, struct swcore_locks_counter_s *cntrs) { return seq_printf(s, "%u/%u %u %u %llu\n", cntrs->cntr_lock, cntrs->cntr_unlock, cntrs->cntr_contention, cntrs->cntr_wait_high, cntrs->cntr_wait_total); } static int locks_read(struct seq_file* s, void* v) { int cpu; struct swcore_locks_counter_s *cntrs; seq_printf(s, "\nTxLock: \n"); for_each_possible_cpu(cpu) { cntrs = &per_cpu(tx_lock_counters, cpu); seq_printf(s, "cpu%d ",cpu); print_lock_counter(s, cntrs); } seq_printf(s, "\n"); //seq_printf(s, "Rx:"); //for (i=0;i<RTL865X_SWNIC_RXRING_HW_PKTDESC;i++) // seq_printf(s, "%u ", cntr_rx_locks[i]); seq_printf(s, "\nRxLock: \n"); for_each_possible_cpu(cpu) { cntrs = &per_cpu(rx_lock_counters, cpu); seq_printf(s, "cpu%d ",cpu); print_lock_counter(s, cntrs); } seq_printf(s, "\nBufLock: \n"); for_each_possible_cpu(cpu) { cntrs = &per_cpu(buf_lock_counters, cpu); seq_printf(s, "cpu%d ",cpu); print_lock_counter(s, cntrs); } seq_printf(s, "\n"); return 0; } static int locks_single_open(struct inode *inode, struct file *file) { return(single_open(file, locks_read, NULL)); } static ssize_t locks_single_write(struct file *filp, const char __user *buff,size_t len, loff_t *data) { return len; } static struct file_operations locks_proc_fops = { .open = locks_single_open, .write = locks_single_write, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; #endif void swcore_init_locks(void) { int i; for (i=0; i<RTL865X_SWNIC_TXRING_HW_PKTDESC;i++) { spin_lock_init(&tx_locks[i]); #ifdef DEBUG_LOCKS tx_locks_owners[i] = CPU_NONE; #endif } for (i=0; i<RTL865X_SWNIC_RXRING_HW_PKTDESC;i++) { spin_lock_init(&rx_locks[i]); #ifdef DEBUG_LOCKS rx_locks_owners[i] = CPU_NONE; #endif } for (i=0; i<2;i++) { spin_lock_init(&buf_locks[i]); } #ifdef DEBUG_LOCKS do { extern struct proc_dir_entry *rtl865x_proc_dir; proc_create_data("locks",0,rtl865x_proc_dir,&locks_proc_fops,NULL); } while (0); #endif } //__DRAM_FWD atomic_t lock_tx_tail = ATOMIC_INIT(0); #ifdef RX_NAPI __DRAM_FWD static volatile unsigned int mitigation_factor=0; //__DRAM_FWD static volatile unsigned int fast_reclaim=0; #endif static void skb_debug(const char* data) { #define NUM2PRINT 100 int i; for (i=0; i<NUM2PRINT; i++) { printk("%02X ",data[i]&0xFF); if(i%16==15) printk("\n"); else if(i%8==7) printk(" "); } printk("\n"); } #if defined(CONFIG_XDSL_NEW_HWNAT_DRIVER)&&defined(CONFIG_XDSL_ROMEDRIVER) static void skb_debug_len(const char* data,uint32 len) { int i; for (i=0; i<len; i++) { printk("%02X ",data[i]&0xFF); if(i%16==15) printk("\n"); else if(i%8==7) printk(" "); } printk("\n"); } /* WE MUST do simple parse packet for pPkthdr->ph_type/ph_vlanTagged/ph_LLCTagged/ph_pppeTagged/l3v4v6HdrFlag */ extern int32 rtk_pppoe_getIdx(int32 sessionId); void simplePacketParser(void* pData,uint32 packetLen,rtl_nicTx_info *nicTx,struct rtl_pktHdr * pPkthdr) { uint32 offset=12; uint32 protocol=0; if( *((uint16*)(((uint8*)pData)+offset)) ==htons(0x8100) ){ pPkthdr->ph_vlanTagged=1; offset+=4; } if( *((uint16*)(((uint8*)pData)+offset)) ==htons(0x8863) || *((uint16*)(((uint8*)pData)+offset)) ==htons(0x8864)){ int32 pppoeIdx=-1; pPkthdr->ph_pppeTagged=1; pppoeIdx =rtk_pppoe_getIdx( *((uint16*)(((uint8*)pData)+offset+4))); if(pppoeIdx >=0){ pPkthdr->ph_pppoeIdx=pppoeIdx; }else{ printk("error can't get pppoeid(%d) idx %s :%d\n",*((uint16*)(((uint8*)pData)+offset+4)),__func__,__LINE__); } offset+=8; } if( *((uint16*)(((uint8*)pData)+offset)) ==htons(0x0800) || *((uint16*)(((uint8*)pData)+offset)) ==htons(0x0021)){ protocol=((uint8*)pData)[offset+11]; switch(protocol){ case 0x29: //v6rd packet #if defined(CONFIG_RTL_8685S_HWNAT) if(IS_AFTER_RL6405) { pPkthdr->l3v4v6HdrFlag=v4FIRST; pPkthdr->l3v4v6HdrFlag|=v4HDR_FLAG; } #endif break; default: break; } }else if (*((uint16*)(((uint8*)pData)+offset)) ==htons(0x86dd) || *((uint16*)(((uint8*)pData)+offset)) ==htons(0x0057)){ protocol=((uint8*)pData)[offset+8]; switch(protocol){ case 4: //IP in IP ds-lite packet #if defined(CONFIG_RTL_8685S_HWNAT) if(IS_AFTER_RL6405) { pPkthdr->l3v4v6HdrFlag=v4HDR_FLAG; pPkthdr->l3v4v6HdrFlag|=v6HDR_FLAG; } break; #endif case 6: //upper level, TCP case 17: //upper level, UDP case 41: //IPv6 Header, for Tunnel case 43: //Routing Header case 60: //Destionation Options Header case 59: //No Next Header break; default: break; } } pPkthdr->ph_type=PKTHDR_ETHERNET; if(protocol==0x6){//TCP pPkthdr->ph_type=PKTHDR_TCP; }else if(protocol==0x11){//UDP pPkthdr->ph_type=PKTHDR_UDP; }else if(protocol==0x1){//ICMP pPkthdr->ph_type=PKTHDR_ICMP; }else if(protocol==0x2){ //IGMP pPkthdr->ph_type=PKTHDR_IGMP; } } void romeDriver_refillTxDesc(void* pData,uint32 packetLen,rtl_nicTx_info *nicTx,struct rtl_pktHdr * pPkthdr) { struct tx_info* ptxInfo; char* ptr_pPkthdr_debug; uint32 L234Change=0; int32 i; int32 debug_p=0; //init para ptxInfo=nicTx->ptxInfo; //FOR TX if(nicTx->ptxInfo !=NULL && nicTx->fromRomeDriver ==1){ #if 0 //for debug if(*((uint16*)(((uint8*)pData)+12+8)) == 0xc021) { debug_p=1; } #endif //need reset to a default value 0 pPkthdr->ph_pppeTagged=0; pPkthdr->ph_vlanTagged=0; pPkthdr->ph_LLCTagged=0; pPkthdr->ph_flags &=~(CSUM_IP); pPkthdr->ph_flags &=~(CSUM_TCPUDP); pPkthdr->ph_flags &=~(PKTHDR_PPPOE_AUTOADD); pPkthdr->ph_txCVlanTagAutoAdd=0; #if defined(CONFIG_RTL_8685S_HWNAT) pPkthdr->l3v4v6HdrFlag=0; #endif if(ptxInfo->opts1.bit.ipcs || ptxInfo->opts1.bit.l4cs || ptxInfo->opts2.bit.tx_vlan_action || ptxInfo->opts2.bit.tx_pppoe_action){ L234Change=TRUE; } if(L234Change){ /*parsing packet first*/ simplePacketParser(pData,packetLen,nicTx,pPkthdr); switch(ptxInfo->opts2.bit.tx_vlan_action){ case 0x2: //remove tag -> untag pPkthdr->ph_txCVlanTagAutoAdd=0; // printk("remove vlan tag -> untag\n"); break; case 0x3: //remarking (add/modify) // printk("ori pPkthdr->ph_vlanId =%d vlan=%d \n",pPkthdr->ph_vlanId,((ptxInfo->opts2.bit.vidh << 8) | (ptxInfo->opts2.bit.vidl))); pPkthdr->ph_vlanId =((ptxInfo->opts2.bit.vidh << 8) | (ptxInfo->opts2.bit.vidl)); pPkthdr->ph_txPriority =((ptxInfo->opts2.bit.prio)) ; //for 802.1p pPkthdr->_flags2._tx._tx_qid =((ptxInfo->opts2.bit.prio)) ; //for 802.1p pPkthdr->ph_txCVlanTagAutoAdd = ptxInfo->opts3.bit.tx_portmask &0x3f ; //portmask p0-p5 break; case 0x0: //no-action // printk("valn no-action\n"); if(pPkthdr->ph_vlanTagged){ //nic always do action add/remove/modify, so need modify to ori vlan pPkthdr->ph_vlanId= (((((uint8*)pData)[14])&0xf)<<8)| (((uint8*)pData)[15]); pPkthdr->ph_txPriority = (((uint8*)pData)[14]) >>5 ; } break; default: printk("default ptxInfo->opts2.bit.tx_vlan_action=%d \n ",ptxInfo->opts2.bit.tx_vlan_action); break; } switch(ptxInfo->opts2.bit.tx_pppoe_action){ case 0x2: //remove pppoe tag -> untag printk("remove pppoe tag -> untag\n"); pPkthdr->ph_flags &=~(PKTHDR_PPPOE_AUTOADD); break; case 0x3: //remarking printk("pppoe remarking to pppoeIdx=%d\n",ptxInfo->opts2.bit.tx_pppoe_idx); pPkthdr->ph_flags |=(PKTHDR_PPPOE_AUTOADD); pPkthdr->ph_pppoeIdx=ptxInfo->opts2.bit.tx_pppoe_idx; break; case 0x0: //no-action // printk("pppoe no-action pppoeIdx=%d \n",pPkthdr->ph_pppoeIdx); if(pPkthdr->ph_pppeTagged){ //should keep pppoe pPkthdr->ph_flags |=(PKTHDR_PPPOE_AUTOADD); } break; default: printk("default ptxInfo->opts2.bit.tx_vlan_action=%d \n ",ptxInfo->opts2.bit.tx_vlan_action); break; } if(ptxInfo->opts1.bit.ipcs) pPkthdr->ph_flags|=CSUM_IP; if(ptxInfo->opts1.bit.l4cs) pPkthdr->ph_flags|= CSUM_TCPUDP; } pPkthdr->ph_portlist =ptxInfo->opts3.bit.tx_portmask; //============================= unsure setting ====================================== // pPkthdr->ph_len =ptxInfo->opts1.bit.data_length ; //mask it we using skb len here // pPkthdr->ph_queueId //Bit[14:12]: the CPU Queue priority for direct Tx // pPkthdr->ph_srcExtPortNum =ptxInfo->opts3.bit.extspa; //unsure /* #define PKTHDR_ETHERNET 0 #define PKTHDR_PPTP 1 #define PKTHDR_IP 2 #define PKTHDR_ICMP 3 #define PKTHDR_IGMP 4 #define PKTHDR_TCP 5 #define PKTHDR_UDP 6 */ // printk("pPkthdr->ph_type =%d ",pPkthdr->ph_type); // pPkthdr->ph_LLCTagged // pPkthdr->ph_pppeTagged =ptxInfo->opts2.bit.tx_pppoe_action ; //unsure // pPkthdr->ph_pppoeIdx =ptxInfo->opts2.bit.tx_pppoe_idx ; //FIXME: pppoe same as vlan action // pPkthdr->ph_linkID //for wifi // pPkthdr->ph_flags //PPPoETAG/L3CS/l4CS /HW LOOKUP /* 865x Bit[7]: Reserved Bit[6]: CPU port ( no work ) Bit[5-0]: Port5-Port0 */ // pPkthdr->ph_tx_qid //============================= unsure setting ====================================== if((DumpSwNicTxRx_debug && DumpSwNicTxRx_debug_LIMIT>0)|| debug_p && ){ //debug use ptr_pPkthdr_debug = (char*)pPkthdr; printk("opts1.bit.ipcs=%d opts1.bit.l4cs=%d opts2.bit.tx_vlan_action=%d opts2.bit.tx_pppoe_action=%d \n", ptxInfo->opts1.bit.ipcs , ptxInfo->opts1.bit.l4cs , ptxInfo->opts2.bit.tx_vlan_action ,ptxInfo->opts2.bit.tx_pppoe_action); printk("TxPortmask:0x%x packetlen=%d %s %s\n",pPkthdr->ph_portlist,pPkthdr->ph_len,(pPkthdr->ph_flags&CSUM_IP)>0?"L3ChkOffload":"",(pPkthdr->ph_flags&CSUM_TCPUDP)>0?"L4ChkOffload":"" ); printk("ph_vlanTagged=%d ph_txCVlanTagAutoAdd=%x ph_vlanId=%d ph_txPriority=%d \n",pPkthdr->ph_vlanTagged,pPkthdr->ph_txCVlanTagAutoAdd,pPkthdr->ph_vlanId,pPkthdr->ph_txPriority); printk("ph_pppeTagged=%d %s ph_pppoeIdx=%d \n",pPkthdr->ph_pppeTagged,(pPkthdr->ph_flags&PKTHDR_PPPOE_AUTOADD)>0?"PPPoEAutoAdd":"DelPPPoE",pPkthdr->ph_pppoeIdx); #if defined(CONFIG_RTL_8685S_HWNAT) printk("%s %s %s \n",(pPkthdr->l3v4v6HdrFlag &v4FIRST)>0?"v4FIRST":"",(pPkthdr->l3v4v6HdrFlag &v4HDR_FLAG)>0?"v4HDR_FLAG":"",(pPkthdr->l3v4v6HdrFlag &v6HDR_FLAG)>0?"v6HDR_FLAG":""); #endif printk("(%s)--------pPkthdr-----------------\n",__func__); for(i=0;i<20;i++) printk("%02X ",ptr_pPkthdr_debug[i]&0xFF); printk("\n(%s)--------packet content -----------------\n",__func__); skb_debug_len((char*)pData,pPkthdr->ph_len); printk("\n------------------------------------------\n"); DumpSwNicTxRx_debug_LIMIT--; } } } #endif /************************************************************************* * FUNCTION * swNic_intHandler * * DESCRIPTION * This function is the handler of NIC interrupts * * INPUTS * intPending Pending interrupt sources. * * OUTPUTS * None *************************************************************************/ void swNic_intHandler(uint32 intPending) {return;} #if defined(CONFIG_DEFAULTS_KERNEL_2_6) __MIPS16 __IRAM_FWD #endif inline int32 rtl8651_rxPktPreprocess(void *pkt, unsigned int *vid) { struct rtl_pktHdr *m_pkthdr = (struct rtl_pktHdr *)pkt; uint32 srcPortNum; srcPortNum = m_pkthdr->ph_portlist&0x7; /* ph_vlanId: * RX: Destination VLAN ID(after routing). * TX: Source Destination VLAN ID select */ *vid = m_pkthdr->ph_vlanId; #if 0 if (srcPortNum >= RTL8651_CPU_PORT) { if (m_pkthdr->ph_extPortList == 0) { /* No any destination ( extension port or CPU) : ASIC's BUG */ return FAILED; }else if ((m_pkthdr->ph_extPortList & PKTHDR_EXTPORTMASK_CPU) == 0)// to extension port { /* if dest Ext port 0x1 => to dst ext port 1 => from src port 1+5=6 if dest Ext port 0x2 => to dst ext port 2 => from src port 2+5=7 if dest Ext port 0x4 => to dst ext port 3 => from src port 3+5=8 */ srcPortNum = extPortMaskToPortNum[m_pkthdr->ph_extPortList]+RTL8651_PORT_NUMBER-1; m_pkthdr->ph_portlist = srcPortNum;//now ph_portlist assign tx destinatino port mask #if defined(CONFIG_RTL_HARDWARE_NAT)&&(defined(CONFIG_RTL8192SE)||defined(CONFIG_RTL8192CD)) *vid = PKTHDR_EXTPORT_MAGIC; #endif }else//to cpu port { /* has CPU bit, pkt is original pkt from port 6~8 */ srcPortNum = m_pkthdr->ph_srcExtPortNum + RTL8651_PORT_NUMBER - 1; m_pkthdr->ph_portlist = srcPortNum; #if defined(CONFIG_RTL_HARDWARE_NAT)&&(defined(CONFIG_RTL8192SE)||defined(CONFIG_RTL8192CD)) *vid = PKTHDR_EXTPORT_MAGIC2; #endif } } else { #ifndef CONFIG_RTL_8676HWNAT /* otherwise, pkt is rcvd from PHY */ m_pkthdr->ph_srcExtPortNum = 0; if((m_pkthdr->ph_extPortList & PKTHDR_EXTPORTMASK_CPU) == 0)//to extension port or phy { /* No CPU bit, only dest ext mbr port... */ /* if dest Ext port 0x1 => to dst ext port 1 => from src port 1+5=6 if dest Ext port 0x2 => to dst ext port 2 => from src port 2+5=7 if dest Ext port 0x4 => to dst ext port 3 => from src port 3+5=8 */ if(m_pkthdr->ph_extPortList&&0!=extPortMaskToPortNum[m_pkthdr->ph_extPortList]) { /* redefine src port number */ srcPortNum = extPortMaskToPortNum[m_pkthdr->ph_extPortList] + RTL8651_PORT_NUMBER - 1; m_pkthdr->ph_portlist = srcPortNum; #if defined(CONFIG_RTL_HARDWARE_NAT)&&(defined(CONFIG_RTL8192SE)||defined(CONFIG_RTL8192CD)) *vid = PKTHDR_EXTPORT_MAGIC; #endif } } #endif } #endif //Kevin, if the pkt is only toward to extPort, reset vid to a magic number if (srcPortNum < RTL8651_CPU_PORT) { /* No CPU bit, only dest ext mbr port... */ if( !(m_pkthdr->ph_extPortList & PKTHDR_EXTPORTMASK_CPU) && (m_pkthdr->ph_extPortList & PKTHDR_EXTPORTMASK_P0)) *vid = PKTHDR_EXTPORT_MAGIC; if( !(m_pkthdr->ph_extPortList & PKTHDR_EXTPORTMASK_CPU) && (m_pkthdr->ph_extPortList & PKTHDR_EXTPORTMASK_P1)) *vid = PKTHDR_EXTPORT_MAGIC2; if( !(m_pkthdr->ph_extPortList & PKTHDR_EXTPORTMASK_CPU) && (m_pkthdr->ph_extPortList & PKTHDR_EXTPORTMASK_P2)) *vid = PKTHDR_EXTPORT_MAGIC3; return SUCCESS; } else return FAILED; } #ifdef DELAY_REFILL_ETH_RX_BUF static inline int __return_to_rxing_check(int ringIdx) { int ret; //unsigned long flags; //flags = swcore_buf_lock(1); //local_irq_save(flags); ret = ((rxPkthdrRingCnt[ringIdx]!=0) && (rxDescReadyForHwIndex[ringIdx] != currRxPkthdrDescIndex[ringIdx]))? 1:0; //swcore_buf_unlock(1,flags); //local_irq_restore(flags); return ret; } static inline int __buffer_reuse(int ringIdx) { int index1,index2,gap; //unsigned long flags; //flags = swcore_buf_lock(1); //local_irq_save(flags); index1 = rxDescReadyForHwIndex[ringIdx]; index2 = currRxPkthdrDescIndex[ringIdx]+1; gap = (index2 > index1) ? (index2 - index1) : (index2 + rxPkthdrRingCnt[ringIdx] - index1); if ((rxPkthdrRingCnt[ringIdx] - gap) < (rxPkthdrRefillThreshold[ringIdx])) { //swcore_buf_unlock(1,flags); //local_irq_restore(flags); return 1; } else { //swcore_buf_unlock(1,flags); //local_irq_restore(flags); return 0; } } static inline void set_RxPkthdrRing_OwnBit(uint32 rxRingIdx) { unsigned long flags; flags = swcore_buf_lock(1); rxPkthdrRing[rxRingIdx][rxDescReadyForHwIndex[rxRingIdx]] |= DESC_SWCORE_OWNED; if ( ++rxDescReadyForHwIndex[rxRingIdx] == rxPkthdrRingCnt[rxRingIdx] ) rxDescReadyForHwIndex[rxRingIdx] = 0; swcore_buf_unlock(1,flags); } #ifndef CONFIG_FAST_FORWARDING #if defined(CONFIG_DEFAULTS_KERNEL_2_6) __IRAM_FWD #endif static void release_pkthdr(struct sk_buff *skb, int idx) { struct rtl_pktHdr *pReadyForHw; struct rtl_mBuf *mbuf; uint32 mbufIndex; unsigned long flags; _dma_cache_wback_inv((unsigned long)skb->head, MBUF_LEN); local_irq_save(flags); pReadyForHw = (struct rtl_pktHdr *)(rxPkthdrRing[idx][rxDescReadyForHwIndex[idx]] & ~(DESC_OWNED_BIT | DESC_WRAP)); mbufIndex = ((uint32)(pReadyForHw->ph_mbuf) - (rxMbufRing[0] & ~(DESC_OWNED_BIT | DESC_WRAP))) / (sizeof(struct rtl_mBuf)); pReadyForHw->ph_mbuf->m_data = skb->data; pReadyForHw->ph_mbuf->m_extbuf = skb->data; pReadyForHw->ph_mbuf->skb = skb; //patch for huge packets which need more than one mbuf in a pktHdr //the skb in first mbuf will drop in protocol stack, the other mbufs will set ownerbit here for reuse mbuf = pReadyForHw->ph_mbuf->m_next; rxMbufRing[mbufIndex] |= DESC_SWCORE_OWNED; while(mbuf != NULL){ mbufIndex = ((uint32)mbuf - (rxMbufRing[0] & ~(DESC_OWNED_BIT | DESC_WRAP))) / (sizeof(struct rtl_mBuf)); mbuf = mbuf->m_next; rxMbufRing[mbufIndex] |= DESC_SWCORE_OWNED; } //end of patch set_RxPkthdrRing_OwnBit(idx); local_irq_restore(flags); } #else #if defined(CONFIG_DEFAULTS_KERNEL_2_6) __IRAM_FWD #endif static void release_pkthdr(unsigned char *data, int idx) { struct rtl_pktHdr *pReadyForHw; struct rtl_mBuf *mbuf; uint32 mbufIndex; unsigned long flags; //_dma_cache_wback_inv((unsigned long)skb->head, skb->truesize); _dma_cache_inv((unsigned long)data, MBUF_LEN); local_irq_save(flags); pReadyForHw = (struct rtl_pktHdr *)(rxPkthdrRing[idx][rxDescReadyForHwIndex[idx]] & ~(DESC_OWNED_BIT | DESC_WRAP)); mbufIndex = ((uint32)(pReadyForHw->ph_mbuf) - (rxMbufRing[0] & ~(DESC_OWNED_BIT | DESC_WRAP))) / (sizeof(struct rtl_mBuf)); pReadyForHw->ph_mbuf->m_data = data; pReadyForHw->ph_mbuf->m_extbuf = data; //patch for huge packets which need more than one mbuf in a pktHdr //the skb in first mbuf will drop in protocol stack, the other mbufs will set ownerbit here for reuse mbuf = pReadyForHw->ph_mbuf->m_next; rxMbufRing[mbufIndex] |= DESC_SWCORE_OWNED; while(mbuf != NULL){ mbufIndex = ((uint32)mbuf - (rxMbufRing[0] & ~(DESC_OWNED_BIT | DESC_WRAP))) / (sizeof(struct rtl_mBuf)); mbuf = mbuf->m_next; rxMbufRing[mbufIndex] |= DESC_SWCORE_OWNED; } //end of patch set_RxPkthdrRing_OwnBit(idx); local_irq_restore(flags); } #endif//end of CONFIG_FAST_FORWARDING #if defined(CONFIG_RTL_ETH_PRIV_SKB) /* return value: 1 ==> success, returned to rx pkt hdr desc return value: 0 ==> failed, no return ==> release to priv skb buf pool */ extern struct sk_buff *dev_alloc_8190_skb(unsigned char *data, int size); int return_to_rx_pkthdr_ring(unsigned char *head) { struct sk_buff *skb; int ret, i; unsigned long flags; ret=FAILED; //local_irq_save(flags); for(i = RTL865X_SWNIC_RXRING_MAX_PKTDESC -1; i >= 0; i--) { flags = swcore_rx_lock(i); if (__return_to_rxing_check(i)) { skb = dev_alloc_8190_skb(head, CROSS_LAN_MBUF_LEN); if (skb == NULL) { swcore_rx_unlock(i, flags); goto _ret1; } skb_reserve(skb, RX_OFFSET); release_pkthdr(skb, i); ret = SUCCESS; swcore_rx_unlock(i, flags); break; } swcore_rx_unlock(i, flags); } _ret1: //local_irq_restore(flags); return ret; } #endif//end of CONFIG_RTL_ETH_PRIV_SKB #ifdef CONFIG_RTL_ETH_PRIV_SKB_ADV #ifdef CONFIG_FAST_FORWARDING __IRAM_GEN int return_to_nic_rx_ring(unsigned char *data) { int ret=FAILED, i; unsigned long flags; for(i = RTL865X_SWNIC_RXRING_MAX_PKTDESC -1; i >= 0; i--) { flags = swcore_rx_lock(i); if (__return_to_rxing_check(i)) { data += NET_SKB_PAD+RX_OFFSET; release_pkthdr(data, i); ret = SUCCESS; swcore_rx_unlock(i, flags); break; } swcore_rx_unlock(i, flags); } return ret; } #else __IRAM_GEN int return_to_nic_rx_ring(struct sk_buff *skb) { int ret=FAILED, i; unsigned long flags; for(i = RTL865X_SWNIC_RXRING_MAX_PKTDESC -1; i >= 0; i--) { flags = swcore_rx_lock(i); if (__return_to_rxing_check(i)) { unsigned char *data; data = get_buf_from_poll(); if (NULL == data) { swcore_rx_unlock(i, flags); return FAILED; } init_skbhdr(skb, data, CROSS_LAN_MBUF_LEN, rtl865x_free_eth_priv_buf); release_pkthdr(skb, i); ret = SUCCESS; swcore_rx_unlock(i, flags); break; } swcore_rx_unlock(i, flags); } return ret; } #endif//end of CONFIG_FAST_FORWARDING #endif//end of CONFIG_RTL_ETH_PRIV_SKB_ADV #else //DELAY_REFILL_ETH_RX_BUF static void release_pkthdr(struct sk_buff *skb, int idx) {} #endif //DELAY_REFILL_ETH_RX_BUF /* It's the caller's responsibility to make sure "rxRingIdx" and * "currRxPktDescIdx" NOT NULL, since the callee never check * sanity of the parameters, in order to speed up. */ #if RX_ONLY_RING0 static inline int32 swNic_getRxringIdx(void) { if ((rxPkthdrRing[0][currRxPkthdrDescIndex[0]] & DESC_OWNED_BIT) == DESC_RISC_OWNED) { return SUCCESS; } return FAILED; } #else #if defined(CONFIG_DEFAULTS_KERNEL_2_6) __MIPS16 __IRAM_FWD #endif static inline int32 swNic_getRxringIdx(uint32 *rxRingIdx, uint32 *currRxPktDescIdx,uint32 policy, unsigned long *rxLockFlags) { int32 i; int32 priority; unsigned long flags; priority = policy; for(i = RTL865X_SWNIC_RXRING_MAX_PKTDESC -1; i >= priority; i--) { if(rxPkthdrRingCnt[i] == 0) continue; flags = swcore_rx_lock(i); *rxLockFlags = flags; if((rxPkthdrRing[i][currRxPkthdrDescIndex[i]] & DESC_OWNED_BIT) == DESC_RISC_OWNED) { *rxRingIdx = i; *currRxPktDescIdx = currRxPkthdrDescIndex[i]; return SUCCESS; } swcore_rx_unlock(i, flags); } return FAILED; } #endif #if defined(CONFIG_DEFAULTS_KERNEL_2_6) __IRAM_FWD #endif static int __swNic_increaseRxIdx(int rxRingIdx) { //unsigned long flags; //int32 nextIdx; //local_irq_save(flags); if ( ++currRxPkthdrDescIndex[rxRingIdx] == rxPkthdrRingCnt[rxRingIdx] ) currRxPkthdrDescIndex[rxRingIdx] = 0; #if 0 if (currRxPkthdrDescIndex[rxRingIdx]+1 == rxPkthdrRingCnt[rxRingIdx]) nextIdx = 0; else nextIdx = currRxPkthdrDescIndex[rxRingIdx]+1; #endif //local_irq_restore(flags); return SUCCESS; } #if defined(CONFIG_RTL_ETH_PRIV_SKB_DEBUG) int get_nic_txRing_buf(void) { int txCnt = 0; int i,j; struct rtl_pktHdr *pPkthdr; for(i = RTL865X_SWNIC_TXRING_MAX_PKTDESC -1; i >= 0; i--) { if(txPkthdrRingCnt[i] == 0) continue; for(j = 0; j <txPkthdrRingCnt[i]; j++) { pPkthdr = (struct rtl_pktHdr *) ((int32) txPkthdrRing[i][j]& ~(DESC_OWNED_BIT | DESC_WRAP)); if(pPkthdr->ph_mbuf->skb) { if(is_rtl865x_eth_priv_buf(((struct sk_buff *)pPkthdr->ph_mbuf->skb)->head)) txCnt++; } } } return txCnt; } int get_nic_rxRing_buf(void) { int rxCnt = 0; int i,j; struct rtl_pktHdr *pPkthdr; for(i = RTL865X_SWNIC_RXRING_MAX_PKTDESC -1; i >= 0; i--) { if(rxPkthdrRingCnt[i] == 0) continue; for(j = 0; j < rxPkthdrRingCnt[i]; j++) { { pPkthdr = (struct rtl_pktHdr *) (rxPkthdrRing[i][j] & ~(DESC_OWNED_BIT | DESC_WRAP)); if(pPkthdr->ph_mbuf->skb) { if(is_rtl865x_eth_priv_buf(((struct sk_buff *)pPkthdr->ph_mbuf->skb)->head)) rxCnt++; } } } } return rxCnt; } #endif int32 swNic_flushRxRingByPriority(int priority) { int32 i; struct rtl_pktHdr * pPkthdr; void *skb; unsigned long flags; unsigned long rxlock_flags; #if defined(CONFIG_RTL865X_WTDOG) REG32(WDTCNR) |= WDTCLR; /* reset watchdog timer */ #endif local_irq_save(flags); for(i = priority -1; i >= 0; i--) { if(rxPkthdrRingCnt[i] == 0) continue; rxlock_flags = swcore_rx_lock(i); while((rxPkthdrRing[i][currRxPkthdrDescIndex[i]] & DESC_OWNED_BIT) == DESC_RISC_OWNED) { pPkthdr = (struct rtl_pktHdr *) (rxPkthdrRing[i][currRxPkthdrDescIndex[i]] & ~(DESC_OWNED_BIT | DESC_WRAP)); skb = pPkthdr->ph_mbuf->skb; release_pkthdr(skb, i); __swNic_increaseRxIdx(i); } swcore_rx_unlock(i, rxlock_flags); } local_irq_restore(flags); REG32(CPUIISR) = (MBUF_DESC_RUNOUT_IP_ALL|PKTHDR_DESC_RUNOUT_IP_ALL); return SUCCESS; } #if defined(CONFIG_RTL_HWNAT_TESTMODEL) extern int TEST_MODEL_DONOT_DIRECT_TX; #endif /************************************************************************* * FUNCTION * swNic_receive * * DESCRIPTION * This function reads one packet from rx descriptors, and return the * previous read one to the switch core. This mechanism is based on * the assumption that packets are read only when the handling * previous read one is done. * * INPUTS * None * * OUTPUTS * None *************************************************************************/ //__MIPS16 #if defined(CONFIG_DEFAULTS_KERNEL_2_6) __IRAM_FWD #endif int32 swNic_receive(rtl_nicRx_info *info) { /*QL 20110615 start: MTU is 1522, so one mbuf is sufficient to receive a packet. * don't care the case that consecutive mbuf occupied by one packet. */ struct rtl_pktHdr * pPkthdr; #ifndef DELAY_REFILL_ETH_RX_BUF struct rtl_mBuf *mbuf; uint32 mbufIndex; #endif unsigned char *buf; void *skb=NULL; uint32 rxRingIdx=0; uint32 currRxPktDescIdx=0; int32 retval; //unsigned long flags; unsigned long rxlock_flags = 0; #if defined(CONFIG_RTL_HARDWARE_NAT) uint32 vid; #endif int i; char* ptr_pPkthdr_debug; if(DumpSwNicTxRx_debug && DumpSwNicTxRx_debug_LIMIT>0) printk("Enter %s\n",__func__); get_next: /* Check OWN bit of descriptors */ //local_irq_save(flags); #if RX_ONLY_RING0 retval = swNic_getRxringIdx(); currRxPktDescIdx=currRxPkthdrDescIndex[0]; #else retval = swNic_getRxringIdx(&rxRingIdx,&currRxPktDescIdx,info->priority, &rxlock_flags); #endif //local_irq_restore(flags); /* Check OWN bit of descriptors */ if (retval == SUCCESS ) { #if !RX_ONLY_RING0 info->priority = rxRingIdx; #endif /* Fetch pkthdr */ pPkthdr = (struct rtl_pktHdr *) (rxPkthdrRing[rxRingIdx][currRxPktDescIdx] & ~(DESC_OWNED_BIT | DESC_WRAP)); /* Increment counter */ //rxPktCounter++; /* checksum error drop it */ if (unlikely((pPkthdr->ph_flags & (CSUM_TCPUDP_OK | CSUM_IP_OK)) != (CSUM_TCPUDP_OK | CSUM_IP_OK))) { printk("%s %d checksum error.\n", __func__, __LINE__); buf = NULL; #ifdef DELAY_REFILL_ETH_RX_BUF goto release1; #else goto release; #endif } if(unlikely(DumpTrapCPUpkt_debug) && DumpTrapCPUpkt_debug_LIMIT>0) { printk("rxring_idx=%d priority:%d from port%d vid=%d reason:0x%X (",rxRingIdx,pPkthdr->ph_rxPriority,pPkthdr->ph_portlist&0x7,pPkthdr->ph_vlanId,pPkthdr->ph_reason); if(pPkthdr->ph_reason >> 9 == 0) { printk("gerneral purpose"); } else if(pPkthdr->ph_reason >> 9 == 1) { printk("trap by ingresss acl no. %d",pPkthdr->ph_reason & 0x7f); } else if(pPkthdr->ph_reason >> 9 == 2) { printk("trap by egresss acl no. %d",pPkthdr->ph_reason & 0x7f); } else if(pPkthdr->ph_reason >> 9 == 3) { printk("protocal parsing failed"); } else { printk("no reason ?? "); } printk(")\n"); DumpTrapCPUpkt_debug_LIMIT--; } if(unlikely(DumpTrapCPUHs_debug) && DumpTrapCPUHs_debug_LIMIT>0) { dump_hstbl(); DumpTrapCPUHs_debug_LIMIT--; } #if defined(CONFIG_RTL_HARDWARE_NAT) if (rtl8651_rxPktPreprocess(pPkthdr, &vid) != SUCCESS) { buf = NULL; } else { #ifdef CONFIG_FAST_FORWARDING buf = get_buf_from_poll(); #else buf = alloc_rx_buf(&skb, size_of_cluster); #endif//end of CONFIG_FAST_FORWARDING } info->vid = vid; #else /* * vid is assigned in rtl8651_rxPktPreprocess() * do not update it when CONFIG_RTL_HARDWARE_NAT is defined */ info->vid=pPkthdr->ph_vlanId; #ifdef CONFIG_FAST_FORWARDING buf = get_buf_from_poll(); #else buf = alloc_rx_buf(&skb, size_of_cluster); #endif//end of CONFIG_FAST_FORWARDING #endif//end of CONFIG_RTL_HARDWARE_NAT info->pid=pPkthdr->ph_portlist&0x7; #ifdef CONFIG_PTMWAN if(unlikely(DumpERBpacket_debug)) { unsigned char* data = ((struct sk_buff*)pPkthdr->ph_mbuf->skb)->data; if( data[14]==0xAA && data[15]==0xAA && data[16]==0x03 && data[17]==0x00 && data[18]==0x19 && data[19]==0xA7 && data[20]==0x00 && data[21]==0x03) { printk("-------- ERB packet content -----------------\n"); skb_debug(((struct sk_buff*)pPkthdr->ph_mbuf->skb)->data); printk("\n------------------------------------------\n"); } } #endif if(unlikely(DumpSwNicTxRx_debug) && DumpSwNicTxRx_debug_LIMIT>0) { ptr_pPkthdr_debug = (char*)pPkthdr; printk("(%s)info->vid : %d info->pid :%d \n",__func__,info->vid,info->pid); printk("(%s)--------pPkthdr-----------------\n",__func__); for(i=0;i<20;i++) printk("%02X ",ptr_pPkthdr_debug[i]&0xFF); printk("\n(%s)--------packet content -----------------\n",__func__); #ifdef CONFIG_FAST_FORWARDING skb_debug(pPkthdr->ph_mbuf->m_data); #else skb_debug(((struct sk_buff*)pPkthdr->ph_mbuf->skb)->data); #endif printk("\n------------------------------------------\n"); DumpSwNicTxRx_debug_LIMIT--; } #if defined(CONFIG_RTL_HWNAT_TESTMODEL) memcpy(&pkt_data ,((struct sk_buff*)pPkthdr->ph_mbuf->skb)->data ,pPkthdr->ph_mbuf->m_len); #endif if (buf) { #ifdef CONFIG_FAST_FORWARDING info->data = pPkthdr->ph_mbuf->m_data; #else info->input = pPkthdr->ph_mbuf->skb; #endif//end of CONFIG_FAST_FORWARDING //info->len = pPkthdr->ph_len - 4; //patch for huge packet which consume more than one mbuf info->len = pPkthdr->ph_mbuf->m_len - 4; #ifdef DELAY_REFILL_ETH_RX_BUF #ifdef CONFIG_FAST_FORWARDING release_pkthdr(buf, rxRingIdx); #else release_pkthdr(skb, rxRingIdx); #endif//end of CONFIG_FAST_FORWARDING #else pPkthdr->ph_mbuf->m_data = pPkthdr->ph_mbuf->m_extbuf = buf; pPkthdr->ph_mbuf->skb = skb; #endif #ifndef RX_NAPI REG32(CPUIISR) = (MBUF_DESC_RUNOUT_IP_ALL|PKTHDR_DESC_RUNOUT_IP_ALL); #endif } #ifdef DELAY_REFILL_ETH_RX_BUF else if (!__buffer_reuse(rxRingIdx)) { #ifdef CONFIG_FAST_FORWARDING info->data = pPkthdr->ph_mbuf->m_data; #else info->input = pPkthdr->ph_mbuf->skb; #endif//end of CONFIG_FAST_FORWARDING //info->len = pPkthdr->ph_len - 4; //patch for huge packet which consume more than one mbuf info->len = pPkthdr->ph_mbuf->m_len - 4; #if defined(CONFIG_RTL_ETH_PRIV_SKB_DEBUG) pPkthdr->ph_mbuf->skb = NULL; #endif #ifdef CONFIG_FAST_FORWARDING buf = (unsigned char *)info->data; #else buf = (unsigned char *)info->input; // just only for "if (buf == NULL)" below #endif//end of CONFIG_FAST_FORWARDING } else { swcore_rx_unlock(rxRingIdx, rxlock_flags); return RTL_NICRX_REPEAT; release1: skb = pPkthdr->ph_mbuf->skb; release_pkthdr(skb, rxRingIdx); skb = NULL; } #else release: //patch for huge packets which need more than one mbuf in a pktHdr //set all mbuf's ownerbit for reuse mbuf = pPkthdr->ph_mbuf; while(mbuf != NULL){ mbufIndex = ((uint32)mbuf - (rxMbufRing[0] & ~(DESC_OWNED_BIT | DESC_WRAP))) / (sizeof(struct rtl_mBuf)); mbuf = mbuf->m_next; rxMbufRing[mbufIndex] |= DESC_SWCORE_OWNED; } //end of patch rxPkthdrRing[rxRingIdx][currRxPkthdrDescIndex[rxRingIdx]] |= DESC_SWCORE_OWNED; #endif /* Increment index */ if (__swNic_increaseRxIdx(rxRingIdx)!=SUCCESS) { swcore_rx_unlock(rxRingIdx, rxlock_flags); return RTL_NICRX_REPEAT; } swcore_rx_unlock(rxRingIdx, rxlock_flags); if (buf == NULL) goto get_next; #ifdef CONFIG_FAST_FORWARDING info->input = (void *)FF_Alloc_Skb((unsigned char *)info->data, info->len); skb = info->input; /* FIXME: device addr of nas0 is fixed to 00:12:34:56:78:90, it is not the real addr of br0, so it is incorrect to * use nas0 addr for downstream briding decision. */ ((struct sk_buff *)skb)->dev = (struct net_device *)rtl865x_get_dev_by_pid(info->pid); if (compare_ether_addr(info->data, ((struct sk_buff *)skb)->dev->dev_addr)) { int dir=DIR_LAN; /*QL why I set pkt_type here? because I will use this field to check if it is a brdging packet in har_start_xmit function, * we only need invalidate and write back cache for ethernet header. */ ((struct sk_buff *)skb)->pkt_type = PACKET_OTHERHOST; if (RTL_WANPORT_MASK & (1<<info->pid)) dir = DIR_WAN; if (brgFastForwarding((struct sk_buff *)skb, dir)) return RTL_NICRX_FF; } skb_reset_mac_header((struct sk_buff *)skb); ((struct sk_buff *)skb)->protocol = ((unsigned short *)(((struct sk_buff *)skb)->data))[6]; ((struct sk_buff *)skb)->pkt_type = PACKET_HOST; skb_pull((struct sk_buff *)skb, ETH_HLEN); ((struct sk_buff *)skb)->dst = NULL; if (NET_RX_SUCCESS == rteFastForwarding((struct sk_buff *)skb)) return RTL_NICRX_FF; if (((struct sk_buff *)skb)->dst){ dst_release(((struct sk_buff *)skb)->dst); ((struct sk_buff *)skb)->dst = NULL; } skb_push((struct sk_buff *)skb, ETH_HLEN); init_skbhdr((struct sk_buff *)skb, ((struct sk_buff *)skb)->head, 0, rtl865x_free_eth_priv_buf); #endif//end of CONFIG_FAST_FORWARDING /*romedriver modify transfer here Boyce 2014-07-10*/ #if defined(CONFIG_XDSL_NEW_HWNAT_DRIVER) && defined(CONFIG_XDSL_ROMEDRIVER) bzero(&(info->RxInfo),sizeof(struct rx_info)); /* opts1 */ // info->RxInfo.opts1.bit.own = pPkthdr->; // info->RxInfo.opts1.bit.eor = pPkthdr->; // info->RxInfo.opts1.bit.fs = pPkthdr->; // info->RxInfo.opts1.bit.ls = pPkthdr->; // info->RxInfo.opts1.bit.crcerr = //8685 no crcErr field // info->RxInfo.opts1.bit.ipv4csf = !(pPkthdr->ph_flags & CSUM_IP_OK ); //8685 when set indicates checksum correct ,and 6266 reverse // info->RxInfo.opts1.bit.l4csf = !(pPkthdr->ph_flags & CSUM_TCPUDP_OK); //8685 when set indicates checksum correct ,and 6266 reverse // info->RxInfo.opts1.bit.rcdf = pPkthdr->; // info->RxInfo.opts1.bit.ipfrag = pPkthdr->; // info->RxInfo.opts1.bit.pppoetag = pPkthdr->; // info->RxInfo.opts1.bit.rwt = pPkthdr->; // info->RxInfo.opts1.bit.pkttype =pPkthdr->ph_type; // info->RxInfo.opts1.bit.l3routing = pPkthdr->; // info->RxInfo.opts1.bit.origformat = pPkthdr->; // info->RxInfo.opts1.bit.pctrl = pPkthdr->; // info->RxInfo.opts1.bit.data_length = pPkthdr->ph_len; /* addr */ // info->RxInfo.addr = /* opts2 */ // info->RxInfo.opts2.bit.cputag = // info->RxInfo.opts2.bit.ptp_in_cpu_tag_exist = // info->RxInfo.opts2.bit.svlan_tag_exist = // info->RxInfo.opts2.bit.rsvd_2 = //**xx info->RxInfo.opts2.bit.pon_stream_id = //fwdEngine use pon_stream_id,but 8685 no gpon // info->RxInfo.opts2.bit.rsvd_1 = info->RxInfo.opts2.bit.ctagva = pPkthdr->ph_vlanTagged; info->RxInfo.opts2.bit.cvlan_tag = pPkthdr->ph_vlanId & (pPkthdr->ph_txPriority << 12); /* VIDH: The high 4 bits of a 12-bit VLAN ID. VIDL: The low 8 bits of a 12-bit VLAN ID. PRIO: 3-bit 8-level priority. */ /* opts3 */ info->RxInfo.opts3.bit.src_port_num =((pPkthdr->ph_portlist)&0x7); //Bit[2-0]: source port number info->RxInfo.opts3.bit.dst_port_mask = (((pPkthdr->ph_extPortList)&0x7)<<1) | (((pPkthdr->ph_extPortList)>>3)&0x1); info->RxInfo.opts3.bit.reason = 255; /* set a useless reason to slow path*/ // info->RxInfo.opts3.bit.internal_priority // info->RxInfo.opts3.bit.ext_port_ttl_1 //**xx info->RxInfo.opts3.bit.rsvd #endif return RTL_NICRX_OK; } else { if (skb) { free_rx_buf(skb); } return RTL_NICRX_NULL; } } /************************************************************************* * FUNCTION * swNic_send * * DESCRIPTION * This function writes one packet to tx descriptors, and waits until * the packet is successfully sent. * * INPUTS * None * * OUTPUTS * None *************************************************************************/ #if 0 #ifdef CONFIG_RTL_8367B /************************************ * 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) */ #endif #endif int avail_txdscp_num(int idx) { return ((txPktDoneDescIndex[idx] - currTxPkthdrDescIndex[idx] - 1) % txPkthdrRingCnt[idx]); } static int qos_mark2prio_enable = 1; static int qos_mark2prio_count = 0; static struct qos_mark2prio_s qos_mark2prio[4]; static inline int sw_qos_count_mark2prio(void) { int i, count = 0; for (i=0; i<ARRAY_SIZE(qos_mark2prio); i++) { if (qos_mark2prio[i].en) count++; } return count; } void sw_qos_mark2prio_set_enable(int en) { en = !!en; if (qos_mark2prio_enable == en) return; qos_mark2prio_enable = en; #if 0 if (en) { REG32(MACCR1) |= (1<<3); /* CPU decides QID */ REG32(PSRP6_RW) &= ~(3 << 5); /* disable CPU Tx/Rx PAUSE */ } else { REG32(MACCR1) &= ~(1<<3); REG32(PSRP6_RW) |= (3 << 5); } #endif } void sw_qos_mark2prio_get_enable(int *en) { *en = qos_mark2prio_enable; } int sw_qos_add_mark2prio(u32 mark, u32 mask, int prio) { int i; if ((prio > 5) || (prio < 0)) return -1; for (i=0; i<ARRAY_SIZE(qos_mark2prio); i++) { if (!qos_mark2prio[i].en) break; } if (i >= ARRAY_SIZE(qos_mark2prio)) return -1; qos_mark2prio[i].en = 1; qos_mark2prio[i].mark = (mark & mask); qos_mark2prio[i].mask = mask; qos_mark2prio[i].prio = prio; qos_mark2prio_count = sw_qos_count_mark2prio(); return 0; } int sw_qos_del_mark2prio(int index) { if ((index >= ARRAY_SIZE(qos_mark2prio)) || (index < 0)) return -1; qos_mark2prio[index].en = 0; qos_mark2prio_count = sw_qos_count_mark2prio(); return 0; } int sw_qos_get_mark2prio(int index, struct qos_mark2prio_s *m) { if ((index >= ARRAY_SIZE(qos_mark2prio)) || (index < 0)) return -1; memcpy(m, &qos_mark2prio[index], sizeof(struct qos_mark2prio_s)); return 0; } //int prio2mark_debug = 0; static inline int mark_select_queue(struct sk_buff *skb, rtl_nicTx_info *txinfo) { #if defined(CONFIG_RTL8685) || defined(CONFIG_RTL8685S) || defined(CONFIG_RTL8685SB) int i; struct qos_mark2prio_s *qos; if ((!qos_mark2prio_enable) || (0==qos_mark2prio_count)) return 0; //if (unlikely(prio2mark_debug)) printk("%s(%d): skb=%p mark=%x\n",__func__,__LINE__,skb,skb->mark); for (i=0; i<ARRAY_SIZE(qos_mark2prio); i++) { qos = &qos_mark2prio[i]; if (!qos->en) continue; if ((skb->mark & qos->mask) != qos->mark) continue; if (qos->prio) txinfo->txIdx = 1; //if (unlikely(prio2mark_debug)) printk("%s(%d): skb=%p qid=%d txIdx=%d\n",__func__,__LINE__,skb,qos->prio,txinfo->txIdx); return qos->prio; } #endif return 0; } #ifdef CONFIG_RTL_HW_QOS_SUPPORT //S/W QUEUE #define RTL_IPQOS_SWQUEUE_HIGH 0 #define RTL_IPQOS_SWQUEUE_LOW 5 #define RTL_IPQOS_SWQUEUE_DEFAULT 3 extern int rtl865x_get_priority_by_swqid(int swqid); static inline void skb_set_qid(struct sk_buff *skb, struct rtl_pktHdr *hdr) { #if defined(CONFIG_RTL8685) || defined(CONFIG_RTL8685S) || defined(CONFIG_RTL8685SB) int asicPri; int swqid=RTL_IPQOS_SWQUEUE_DEFAULT; if(!qos_mark2prio_enable) { asicPri = rtl865x_get_priority_by_swqid(RTL_IPQOS_SWQUEUE_DEFAULT); if(DumpTrapCPUpkt_debug) printk("Set tx priority:%d by default.\n",asicPri); } else if(skb->priority) { switch(skb->priority) { case 8: /* Proprietary used for VOIP traffic) */ case 7: /* TC_PRIO_CONTROL(e.g. PPPoE) */ asicPri = rtl865x_get_priority_by_swqid(RTL_IPQOS_SWQUEUE_HIGH); break; default: asicPri = rtl865x_get_priority_by_swqid(RTL_IPQOS_SWQUEUE_DEFAULT); break; } if(DumpTrapCPUpkt_debug) printk("Set tx priority:%d by skb priority %d.\n",asicPri,skb->priority); } else { swqid = (skb->mark>>3)&0x7; asicPri = swqid?rtl865x_get_priority_by_swqid(swqid):rtl865x_get_priority_by_swqid(RTL_IPQOS_SWQUEUE_DEFAULT); if(DumpTrapCPUpkt_debug) printk("Set tx priority:%d by skb mark 0x%x.\n",asicPri,skb->mark); } if(asicPri == -1) asicPri = rtl865x_get_priority_by_swqid(RTL_IPQOS_SWQUEUE_DEFAULT); hdr->_flags2._tx._tx_qid = asicPri; return; #endif } #endif // of CONFIG_RTL_HW_QOS_SUPPORT static inline void mark_set_qid(struct sk_buff *skb, struct rtl_pktHdr *hdr, int prio) { #if defined(CONFIG_RTL8685) || defined(CONFIG_RTL8685S) || defined(CONFIG_RTL8685SB) hdr->_flags2._tx._tx_qid = prio; #endif } #if defined(CONFIG_DEFAULTS_KERNEL_2_6) __IRAM_FWD #endif inline int32 _swNic_send(void *skb, void * output, uint32 len,rtl_nicTx_info *nicTx) { struct rtl_pktHdr * pPkthdr; char* ptr_pPkthdr_debug; int i; int next_index, curr, avail; char txFull = 0; if(DumpSwNicTxRx_debug && DumpSwNicTxRx_debug_LIMIT>0) printk("Enter %s (nicTx->txIdx:%d)\n",__func__,nicTx->txIdx); //prio = mark_select_queue(skb, nicTx); curr = currTxPkthdrDescIndex[nicTx->txIdx]; next_index = ((curr+1)==txPkthdrRingCnt[nicTx->txIdx]) ? 0 : (curr+1); avail = avail_txdscp_num(nicTx->txIdx); if (avail<=8) { txFull = 1; if (avail <= 0) { return -1; } } currTxPkthdrDescIndex[nicTx->txIdx] = next_index; #if defined(CONFIG_XDSL_NEW_HWNAT_DRIVER) /* Pad small packets and add CRC */ if ( len < 60 ) { /*To avoid padding random content . reset padding bytes to zero Boyce 2015-08-07*/ memset( ((uint8*)output)+len ,0x00,64-len); len = 64; } else { len += 4; } #endif // Kaohj -- invalidate cache before DMA #if defined(CONFIG_RTL_8676HWNAT) && defined(CONFIG_RTL_MULTI_LAN_DEV) && defined(CONFIG_FAST_FORWARDING) /* ql: I think only ethernet header will be modified for bridge mode, so invalidate ethernet header is enough */ if ((((struct sk_buff *)skb)->src_port == IF_SWITCH) && (((struct sk_buff *)skb)->pkt_type == PACKET_OTHERHOST)) dma_cache_wback_inv((unsigned long) output, (14)/*ethernet header*/); else #endif dma_cache_wback_inv((unsigned long) output, len); /* Fetch packet header from Tx ring */ pPkthdr = (struct rtl_pktHdr *) ((int32) txPkthdrRing[nicTx->txIdx][curr] & ~(DESC_OWNED_BIT | DESC_WRAP)); ptr_pPkthdr_debug = (char*)pPkthdr; /* Pad small packets and add CRC */ #if !defined(CONFIG_XDSL_NEW_HWNAT_DRIVER) if ( len < 60 ) { len = 64; } else len += 4; #endif if((RTL_WANVLANID != nicTx->vid) && (RTL_LANVLANID != nicTx->vid) && (RTL_BridgeWANVLANID != nicTx->vid)) { pPkthdr->ph_vlanTagged = 1; pPkthdr->ph_flags2 = nicTx->portlist&0x3f; } else { pPkthdr->ph_vlanTagged = 0; pPkthdr->ph_flags2 = 0; } #if defined(CONFIG_XDSL_NEW_HWNAT_DRIVER) /*we need init other value avoid tx using previous pkthdr Boyce 2015-05-13*/ pPkthdr->ph_LLCTagged=0; pPkthdr->ph_pppeTagged=0; #if defined(CONFIG_RTL_8685S_HWNAT) pPkthdr->l3v4v6HdrFlag=0; pPkthdr->v6HdrLen=0; #endif #endif pPkthdr->ph_mbuf->m_len = len; pPkthdr->ph_mbuf->m_extsize = len; pPkthdr->ph_mbuf->skb = skb; pPkthdr->ph_len = len; pPkthdr->ph_vlanId = nicTx->vid; pPkthdr->ph_portlist = nicTx->portlist&0x3f; pPkthdr->ph_srcExtPortNum = nicTx->srcExtPort; pPkthdr->ph_flags = nicTx->flags; #if defined(CONFIG_RTL_HW_QOS_SUPPORT) pPkthdr->ph_txPriority = (((char*)output)[14]&0xFF)>>5; #endif #ifdef CONFIG_RTL_HW_QOS_SUPPORT skb_set_qid(skb,pPkthdr); #endif //printk("%s ph_vlanId=%d ph_portlist=0x%x ph_flags=0x%x\n", __func__, pPkthdr->ph_vlanId, pPkthdr->ph_portlist, pPkthdr->ph_flags); /* Set cluster pointer to buffer */ pPkthdr->ph_mbuf->m_data = (output); pPkthdr->ph_mbuf->m_extbuf = (output); /* RomeDriver's tx_info has higher priority ,for fwdEngine only (function re865x_send_with_txInfo_and_mask) */ #if defined(CONFIG_XDSL_NEW_HWNAT_DRIVER) &&defined(CONFIG_XDSL_ROMEDRIVER) romeDriver_refillTxDesc(output,len,nicTx,pPkthdr); #endif //CONFIG_XDSL_NEW_HWNAT_DRIVER #if defined(CONFIG_RTL_8685S_HWNAT) //we have hightest priority if(nicTx->replaceTxDesc){ pPkthdr->ph_type = nicTx->pktType; pPkthdr->ph_vlanTagged = nicTx->vlanTagged; pPkthdr->ph_LLCTagged = nicTx->llcTagged; pPkthdr->ph_pppeTagged = nicTx->pppeTagged; pPkthdr->ph_pppoeIdx = nicTx->pppoeIdx; pPkthdr->_flags2._tx._txCVlanTagAutoAdd = nicTx->txCVlanTagAutoAdd; pPkthdr->ph_txPriority = nicTx->_priority; pPkthdr->_flags2._tx._tx_qid = nicTx->_queueId; pPkthdr->ph_queueId = nicTx->CPUqueueId; pPkthdr->v6HdrLen = nicTx->v6HdrLen; pPkthdr->l3v4v6HdrFlag =nicTx->l3v4v6HdrFlag; } #endif if(DumpSwNicTxRx_debug && DumpSwNicTxRx_debug_LIMIT>0) { printk("(%s) pPkthdr->ph_vlanId=%d pPkthdr->ph_portlist=0x%X pPkthdr->ph_srcExtPortNum=0x%X \n",__func__ ,pPkthdr->ph_vlanId,pPkthdr->ph_portlist,pPkthdr->ph_srcExtPortNum); printk("(%s)--------pPkthdr-----------------\n",__func__); for(i=0;i<20;i++) printk("%02X ",ptr_pPkthdr_debug[i]&0xFF); printk("\n(%s)--------packet content -----------------\n",__func__); skb_debug((char*)output); printk("\n------------------------------------------\n"); DumpSwNicTxRx_debug_LIMIT--; } /* Give descriptor to switch core */ txPkthdrRing[nicTx->txIdx][curr] |= DESC_SWCORE_OWNED; #if 0 memDump((void*)output, 64, "TX"); printk("index %d address 0x%p, 0x%x 0x%p.\n", curr, &txPkthdrRing[nicTx->txIdx][curr], (*(volatile uint32 *)&txPkthdrRing[nicTx->txIdx][ret]), pPkthdr); printk("Flags 0x%x proto 0x%x portlist 0x%x vid %d extPort %d srcExtPort %d len %d.\n", pPkthdr->ph_flags, pPkthdr->ph_proto, pPkthdr->ph_portlist, pPkthdr->ph_vlanId, pPkthdr->ph_extPortList, pPkthdr->ph_srcExtPortNum, pPkthdr->ph_len); #endif #ifndef CONFIG_DESC_IN_SRAM /* fix bug: OCP memory access is slower than lx register operation*/ next_index = *(volatile unsigned int *)(&txPkthdrRing[nicTx->txIdx][curr]); #endif mb(); /* Set TXFD bit to start send */ REG32(CPUICR) |= TXFD; if (txFull) return -2; else return curr; } #if defined(CONFIG_DEFAULTS_KERNEL_2_6) __IRAM_FWD #endif inline int32 swNic_send(void *skb, void * output, uint32 len,rtl_nicTx_info *nicTx) { int ret; unsigned long flags; flags = swcore_tx_lock(nicTx->txIdx); ret = _swNic_send(skb, output, len, nicTx); swcore_tx_unlock(nicTx->txIdx, flags); return ret; } #if NUM_TX_PKTHDR_DESC>512 #define HALF_TX_PKTHDR_DESC 256 #else #define HALF_TX_PKTHDR_DESC (NUM_TX_PKTHDR_DESC/2) #endif #if defined(CONFIG_DEFAULTS_KERNEL_2_6) __IRAM_FWD #endif int32 swNic_txDone(int idx) { struct rtl_pktHdr *pPkthdr; int free_num; unsigned long flags; /* it seems swNic_txDone will never reentrance, so dont need to lock it */ //if (atomic_read(&lock_tx_tail)) // return 0; //atomic_set(&lock_tx_tail, 1); #if 0 #ifdef RX_NAPI mitigation_factor++; if ((mitigation_factor & (HALF_TX_PKTHDR_DESC-1)) && !fast_reclaim) return 0; #endif #endif //local_irq_save(flags); flags = swcore_tx_lock(idx); #if 0 #ifdef RX_NAPI fast_reclaim = 0; #endif #endif free_num = 0; { while (txPktDoneDescIndex[idx] != currTxPkthdrDescIndex[idx]) { if ( (*(volatile uint32 *)&txPkthdrRing[idx][txPktDoneDescIndex[idx]] & DESC_OWNED_BIT) == DESC_RISC_OWNED ) { #ifdef CONFIG_RTL8196C_REVISION_B if (rtl_chip_version == RTL8196C_REVISION_A) txPkthdrRing[idx][txPktDoneDescIndex[idx]] =txPkthdrRing_backup[idx][txPktDoneDescIndex[idx]] ; #endif pPkthdr = (struct rtl_pktHdr *) ((int32) txPkthdrRing[idx][txPktDoneDescIndex[idx]] & ~(DESC_OWNED_BIT | DESC_WRAP)); if (pPkthdr->ph_mbuf->skb) { tx_done_callback(pPkthdr->ph_mbuf->skb); pPkthdr->ph_mbuf->skb = NULL; } if (++txPktDoneDescIndex[idx] == txPkthdrRingCnt[idx]) txPktDoneDescIndex[idx] = 0; free_num++; } else break; } } //local_irq_restore(flags); swcore_tx_unlock(idx, flags); //atomic_set(&lock_tx_tail, 0); return free_num; } #ifdef CONFIG_RTL865X_MODEL_TEST_FT2 int32 swNic_send_portmbr(void * output, uint32 len, uint32 portmbr) { struct rtl_pktHdr * pPkthdr; uint8 pktbuf[2048]; uint8* pktbuf_alligned = (uint8*) (( (uint32) pktbuf & 0xfffffffc) | 0xa0000000); /* Copy Packet Content */ memcpy(pktbuf_alligned, output, len); ASSERT_CSP( ((int32) txPkthdrRing[0][currTxPkthdrDescIndex] & DESC_OWNED_BIT) == DESC_RISC_OWNED ); /* Fetch packet header from Tx ring */ pPkthdr = (struct rtl_pktHdr *) ((int32) txPkthdrRing[0][currTxPkthdrDescIndex] & ~(DESC_OWNED_BIT | DESC_WRAP)); /* Pad small packets and add CRC */ if ( len < 60 ) pPkthdr->ph_len = 64; else pPkthdr->ph_len = len + 4; pPkthdr->ph_mbuf->m_len = pPkthdr->ph_len; pPkthdr->ph_mbuf->m_extsize = pPkthdr->ph_len; /* Set cluster pointer to buffer */ pPkthdr->ph_mbuf->m_data = pktbuf_alligned; pPkthdr->ph_mbuf->m_extbuf = pktbuf_alligned; /* Set destination port */ pPkthdr->ph_portlist = portmbr; /* Give descriptor to switch core */ txPkthdrRing[0][currTxPkthdrDescIndex] |= DESC_SWCORE_OWNED; /* Set TXFD bit to start send */ REG32(CPUICR) |= TXFD; /* Wait until packet is successfully sent */ #if 1 while ( (*(volatile uint32 *)&txPkthdrRing[0][currTxPkthdrDescIndex] & DESC_OWNED_BIT) == DESC_SWCORE_OWNED ); #endif txPktCounter++; if ( ++currTxPkthdrDescIndex == txPkthdrRingCnt[0] ) currTxPkthdrDescIndex = 0; return 0; } #endif void swNic_freeRxBuf(void) { int idx, i; struct rtl_pktHdr * pPkthdr; for(i=RTL865X_SWNIC_RXRING_MAX_PKTDESC-1; i >= 0 ; i--) { for (idx=0; idx<rxPkthdrRingCnt[i]; idx++) { if (!((rxPkthdrRing[i][idx] & DESC_OWNED_BIT) == DESC_RISC_OWNED)) { pPkthdr = (struct rtl_pktHdr *) (rxPkthdrRing[i][idx] & ~(DESC_OWNED_BIT | DESC_WRAP)); /*if(pPkthdr == NULL || pPkthdr->ph_mbuf == NULL) * continue; */ if (pPkthdr->ph_mbuf->skb) { free_rx_buf(pPkthdr->ph_mbuf->skb); pPkthdr->ph_mbuf->skb = NULL; } pPkthdr->ph_mbuf->m_data = NULL; pPkthdr->ph_mbuf->m_extbuf = NULL; } } } } //#pragma ghs section text=default /************************************************************************* * FUNCTION * swNic_init * * DESCRIPTION * This function initializes descriptors and data structures. * * INPUTS * userNeedRxPkthdrRingCnt[RTL865X_SWNIC_RXRING_HW_PKTDESC] : * Number of Rx pkthdr descriptors of each ring. * userNeedRxMbufRingCnt : * Number of Tx mbuf descriptors. * userNeedTxPkthdrRingCnt[RTL865X_SWNIC_TXRING_HW_PKTDESC] : * Number of Tx pkthdr descriptors of each ring. * clusterSize : * Size of cluster. * * OUTPUTS * Status. *************************************************************************/ int32 swNic_init(uint32 userNeedRxPkthdrRingCnt[RTL865X_SWNIC_RXRING_HW_PKTDESC], uint32 userNeedRxMbufRingCnt, uint32 userNeedTxPkthdrRingCnt[RTL865X_SWNIC_TXRING_HW_PKTDESC], uint32 clusterSize) { uint32 i, j, k; static uint32 totalRxPkthdrRingCnt = 0, totalTxPkthdrRingCnt = 0; static struct rtl_pktHdr *pPkthdrList_start; static struct rtl_mBuf *pMbufList_start; struct rtl_pktHdr *pPkthdrList; struct rtl_mBuf *pMbufList; struct rtl_pktHdr * pPkthdr; struct rtl_mBuf * pMbuf; dma_addr_t pPkthdrList_start_addr, pMbufList_start_addr; /* init const array for rx pre-process */ extPortMaskToPortNum[0] = 0; extPortMaskToPortNum[1] = 1; extPortMaskToPortNum[2] = 2; extPortMaskToPortNum[3] = 0; extPortMaskToPortNum[4] = 3; extPortMaskToPortNum[5] = 0; extPortMaskToPortNum[6] = 0; extPortMaskToPortNum[7] = 0; rxPkthdrRefillThreshold[0] = ETH_REFILL_THRESHOLD; rxPkthdrRefillThreshold[1] = ETH_REFILL_THRESHOLD1; rxPkthdrRefillThreshold[2] = ETH_REFILL_THRESHOLD2; rxPkthdrRefillThreshold[3] = ETH_REFILL_THRESHOLD3; rxPkthdrRefillThreshold[4] = ETH_REFILL_THRESHOLD4; rxPkthdrRefillThreshold[5] = ETH_REFILL_THRESHOLD5; #if defined(CONFIG_RTL8196C_REVISION_B) rtl_chip_version = REG32(REVR); #endif if (rxMbufRing == NULL) { #ifdef CONFIG_DESC_IN_SRAM //unsigned char* s_begin = (unsigned char*)kmalloc(8*1024, GFP_KERNEL); unsigned char* s_begin = (unsigned char*)0xAF000000; unsigned int sram_off=0; s_begin = (unsigned char*)((unsigned int)s_begin | UNCACHE_MASK); //use segment 0 8K SRAM here. REG32(0xb8004000) = (((unsigned int )s_begin)&(0x1ffffffe))|1; REG32(0xb8004004) = 0x06; REG32(0xB8004008) = 0; REG32(0xb8001300) = (((unsigned int )s_begin)&(0x1ffffffe))|1; REG32(0xb8001304) = 0x06; memset((unsigned char*)s_begin, 0, 8*1024); #endif size_of_cluster = clusterSize; /* Allocate Rx descriptors of rings */ for (i = 0; i < RTL865X_SWNIC_RXRING_HW_PKTDESC; i++) { rxPkthdrRingCnt[i] = userNeedRxPkthdrRingCnt[i];//rxRingSize[] if (rxPkthdrRingCnt[i] == 0) { rxPkthdrRing[i] = NULL; continue; } #ifdef CONFIG_DESC_IN_SRAM if ((0 == i) && ((sram_off + (rxPkthdrRingCnt[i] * sizeof(uint32 *))) <= 0x2000)) { rxPkthdrRing[i] = (uint32 *)s_begin; sram_off += (rxPkthdrRingCnt[i] * sizeof(uint32 *)); } else #endif//end of CONFIG_DESC_IN_SRAM #ifdef CONFIG_DATA_IN_IMEM rxPkthdrRing[i] = (uint32 *)allocUncachedBuffFromIMEM(rxPkthdrRingCnt[i] * sizeof(uint32 *)); if (NULL == rxPkthdrRing[i]) #endif//end of CONFIG_DATA_IN_IMEM rxPkthdrRing[i] = dma_alloc_coherent(NULL, rxPkthdrRingCnt[i] * sizeof(uint32), &rxPkthdrRing_addr[i],GFP_KERNEL); ASSERT_CSP( (uint32) rxPkthdrRing[i] & 0x0fffffff ); totalRxPkthdrRingCnt += rxPkthdrRingCnt[i]; } if (totalRxPkthdrRingCnt == 0) return EINVAL; /* Allocate Tx descriptors of rings */ for (i = 0; i < RTL865X_SWNIC_TXRING_HW_PKTDESC; i++) { txPkthdrRingCnt[i] = userNeedTxPkthdrRingCnt[i];//txRingSize[] if (txPkthdrRingCnt[i] == 0) { txPkthdrRing[i] = NULL; continue; } #ifdef CONFIG_DESC_IN_SRAM if ((0 == i) && ((sram_off + (txPkthdrRingCnt[i] * sizeof(uint32 *))) <= 0x2000)) { txPkthdrRing[i] = (uint32 *)(s_begin + sram_off); sram_off += (txPkthdrRingCnt[i] * sizeof(uint32 *)); } else #endif//end of CONFIG_DESC_IN_SRAM #ifdef CONFIG_DATA_IN_IMEM txPkthdrRing[i] = (uint32 *)allocUncachedBuffFromIMEM(txPkthdrRingCnt[i] * sizeof(uint32 *)); if (NULL == txPkthdrRing[i]) #endif//end of CONFIG_DATA_IN_IMEM txPkthdrRing[i] = dma_alloc_coherent(NULL, txPkthdrRingCnt[i] * sizeof(uint32), &txPkthdrRing_addr[i], GFP_KERNEL); #ifdef CONFIG_RTL8196C_REVISION_B if (rtl_chip_version == RTL8196C_REVISION_A) { #ifdef CONFIG_DESC_IN_SRAM if ((0 == i) && ((sram_off + (txPkthdrRingCnt[i] * sizeof(uint32 *))) <= 0x2000)) { txPkthdrRing_backup[i] = (uint32 *)(s_begin + sram_off); sram_off += (txPkthdrRingCnt[i] * sizeof(uint32 *)); } else #endif//end of CONFIG_DESC_IN_SRAM #ifdef CONFIG_DATA_IN_IMEM txPkthdrRing_backup[i] = (uint32 *)allocUncachedBuffFromIMEM(txPkthdrRingCnt[i] * sizeof(uint32)); if (NULL == txPkthdrRing_backup[i]) #endif//end of CONFIG_DATA_IN_IMEM txPkthdrRing_backup[i] = dma_alloc_coherent(NULL, txPkthdrRingCnt[i] * sizeof(uint32), &txPkthdrRing_backup_addr[i], GFP_KERNEL); } #endif ASSERT_CSP( (uint32) txPkthdrRing[i] & 0x0fffffff ); totalTxPkthdrRingCnt += txPkthdrRingCnt[i]; } if (totalTxPkthdrRingCnt == 0) return EINVAL; /* Allocate MBuf descriptors of rings */ rxMbufRingCnt = userNeedRxMbufRingCnt; if (userNeedRxMbufRingCnt == 0) return EINVAL; #ifdef CONFIG_DESC_IN_SRAM if ((sram_off + (rxMbufRingCnt * sizeof(uint32*))) <= 0x2000) { rxMbufRing = (uint32 *)(s_begin + sram_off); sram_off += (rxMbufRingCnt * sizeof(uint32*)); } else #endif//end of CONFIG_DESC_IN_SRAM #ifdef CONFIG_DATA_IN_IMEM rxMbufRing = (uint32 *)allocUncachedBuffFromIMEM(rxMbufRingCnt * sizeof(uint32*)); if (NULL == rxMbufRing) #endif//end of CONFIG_DATA_IN_IMEM rxMbufRing = dma_alloc_coherent(NULL, rxMbufRingCnt * sizeof(uint32), &rxMbufRing_addr, GFP_KERNEL); ASSERT_CSP( (uint32) rxMbufRing & 0x0fffffff ); /* Allocate pkthdr */ #ifdef CONFIG_DATA_IN_IMEM pPkthdrList_start = (struct rtl_pktHdr *)allocUncachedBuffFromIMEM( (totalRxPkthdrRingCnt + totalTxPkthdrRingCnt) * sizeof(struct rtl_pktHdr)); if (NULL == pPkthdrList_start) #endif//end of CONFIG_DATA_IN_IMEM pPkthdrList_start = dma_alloc_coherent(NULL, \ (totalRxPkthdrRingCnt + totalTxPkthdrRingCnt) * sizeof(struct rtl_pktHdr), &pPkthdrList_start_addr, GFP_KERNEL); ASSERT_CSP( (uint32) pPkthdrList_start & 0x0fffffff ); /* Allocate mbufs */ #ifdef CONFIG_DATA_IN_IMEM pMbufList_start = (struct rtl_mBuf *)allocUncachedBuffFromIMEM( (rxMbufRingCnt + totalTxPkthdrRingCnt) * sizeof(struct rtl_mBuf)); if (NULL == pMbufList_start) #endif//end of CONFIG_DATA_IN_IMEM pMbufList_start = dma_alloc_coherent(NULL, \ (rxMbufRingCnt + totalTxPkthdrRingCnt) * sizeof(struct rtl_mBuf), &pMbufList_start_addr, GFP_KERNEL); ASSERT_CSP( (uint32) pMbufList_start & 0x0fffffff ); #ifdef CONFIG_DESC_IN_SRAM printk("==============>>> SRAM used 0x%x\n", sram_off); #endif//end of CONFIG_DESC_IN_SRAM } /* Initialize interrupt statistics counter */ //rxPktCounter = txPktCounter = 0; /* Initialize index of Tx pkthdr descriptor */ for (i=0;i<RTL865X_SWNIC_TXRING_HW_PKTDESC;i++) { currTxPkthdrDescIndex[i] = 0; txPktDoneDescIndex[i]=0; } pPkthdrList = pPkthdrList_start; pMbufList = pMbufList_start; /* Initialize Tx packet header descriptors */ for (i = 0; i < RTL865X_SWNIC_TXRING_HW_PKTDESC; i++) { for (j = 0; j < txPkthdrRingCnt[i]; j++) { /* Dequeue pkthdr and mbuf */ pPkthdr = pPkthdrList++; pMbuf = pMbufList++; bzero((void *) pPkthdr, sizeof(struct rtl_pktHdr)); bzero((void *) pMbuf, sizeof(struct rtl_mBuf)); pPkthdr->ph_mbuf = pMbuf; pPkthdr->ph_len = 0; pPkthdr->ph_flags = PKTHDR_USED | PKT_OUTGOING; pPkthdr->ph_type = PKTHDR_ETHERNET; pPkthdr->ph_portlist = 0; pMbuf->m_next = NULL; pMbuf->m_pkthdr = pPkthdr; pMbuf->m_flags = MBUF_USED | MBUF_EXT | MBUF_PKTHDR | MBUF_EOR; pMbuf->m_data = NULL; pMbuf->m_extbuf = NULL; pMbuf->m_extsize = 0; txPkthdrRing[i][j] = (int32) pPkthdr | DESC_RISC_OWNED; #ifdef CONFIG_RTL8196C_REVISION_B if (rtl_chip_version == RTL8196C_REVISION_A) txPkthdrRing_backup[i][j]=(int32) pPkthdr | DESC_RISC_OWNED; #endif } if(txPkthdrRingCnt[i] > 0) { /* Set wrap bit of the last descriptor */ txPkthdrRing[i][txPkthdrRingCnt[i] - 1] |= DESC_WRAP; #ifdef CONFIG_RTL8196C_REVISION_B if (rtl_chip_version == RTL8196C_REVISION_A) txPkthdrRing_backup[i][txPkthdrRingCnt[i] - 1] |= DESC_WRAP; #endif } } /* Fill Tx packet header FDP */ REG32(CPUTPDCR0) = (uint32) txPkthdrRing[0]; REG32(CPUTPDCR1) = (uint32) txPkthdrRing[1]; #ifdef CONFIG_RTL_8196D /* Fill Tx packet header FDP */ REG32(CPUTPDCR2) = (uint32) txPkthdrRing[2]; REG32(CPUTPDCR3) = (uint32) txPkthdrRing[3]; #endif /* Initialize Rx packet header descriptors */ k = 0; for (i = 0; i < RTL865X_SWNIC_RXRING_HW_PKTDESC; i++) { for (j = 0; j < rxPkthdrRingCnt[i]; j++) { /* Dequeue pkthdr and mbuf */ pPkthdr = pPkthdrList++; pMbuf = pMbufList++; bzero((void *) pPkthdr, sizeof(struct rtl_pktHdr)); bzero((void *) pMbuf, sizeof(struct rtl_mBuf)); /* Setup pkthdr and mbuf */ pPkthdr->ph_mbuf = pMbuf; pPkthdr->ph_len = 0; pPkthdr->ph_flags = PKTHDR_USED | PKT_INCOMING; pPkthdr->ph_type = PKTHDR_ETHERNET; pPkthdr->ph_portlist = 0; pMbuf->m_next = NULL; pMbuf->m_pkthdr = pPkthdr; pMbuf->m_len = 0; pMbuf->m_flags = MBUF_USED | MBUF_EXT | MBUF_PKTHDR | MBUF_EOR; pMbuf->m_extsize = size_of_cluster; #ifdef CONFIG_FAST_FORWARDING pMbuf->m_data = pMbuf->m_extbuf = get_buf_from_poll();; #else pMbuf->m_data = pMbuf->m_extbuf = alloc_rx_buf(&pPkthdr->ph_mbuf->skb, size_of_cluster); #endif//end of CONFIG_FAST_FORWARDING /* Setup descriptors */ rxPkthdrRing[i][j] = (int32) pPkthdr | DESC_SWCORE_OWNED; rxMbufRing[k++] = (int32) pMbuf | DESC_SWCORE_OWNED; } /* Initialize index of current Rx pkthdr descriptor */ currRxPkthdrDescIndex[i] = 0; /* Initialize index of current Rx Mbuf descriptor */ currRxMbufDescIndex = 0; /* Set wrap bit of the last descriptor */ if(rxPkthdrRingCnt[i] > 0) rxPkthdrRing[i][rxPkthdrRingCnt[i] - 1] |= DESC_WRAP; #ifdef DELAY_REFILL_ETH_RX_BUF rxDescReadyForHwIndex[i] = 0; #endif } rxMbufRing[rxMbufRingCnt - 1] |= DESC_WRAP; /* Fill Rx packet header FDP */ REG32(CPURPDCR0) = (uint32) rxPkthdrRing[0]; REG32(CPURPDCR1) = (uint32) rxPkthdrRing[1]; REG32(CPURPDCR2) = (uint32) rxPkthdrRing[2]; REG32(CPURPDCR3) = (uint32) rxPkthdrRing[3]; REG32(CPURPDCR4) = (uint32) rxPkthdrRing[4]; REG32(CPURPDCR5) = (uint32) rxPkthdrRing[5]; REG32(CPURMDCR0) = (uint32) rxMbufRing; return SUCCESS; } #ifdef FAT_CODE /************************************************************************* * FUNCTION * swNic_resetDescriptors * * DESCRIPTION * This function resets descriptors. * * INPUTS * None. * * OUTPUTS * None. *************************************************************************/ void swNic_resetDescriptors(void) { /* Disable Tx/Rx and reset all descriptors */ REG32(CPUICR) &= ~(TXCMD | RXCMD); return; } #endif//FAT_CODE #if defined(CONFIG_RTL_PROC_DEBUG) /* dump the rx ring info */ int32 rtl_dumpRxRing(void) { int idx, cnt; struct rtl_pktHdr * pPkthdr; for(idx=0;idx<RTL865X_SWNIC_RXRING_HW_PKTDESC;idx++) { printk("**********************************************\nRxRing%d: cnt %d\n", idx, rxPkthdrRingCnt[idx]); /* skip the null rx ring */ if (rxPkthdrRingCnt[idx]==0) continue; /* dump all the pkt header */ for(cnt=0;cnt<rxPkthdrRingCnt[idx];cnt++) { pPkthdr = (struct rtl_pktHdr *) (rxPkthdrRing[idx][cnt] & ~(DESC_OWNED_BIT | DESC_WRAP)); printk(" idx[%d]: 0x%p-->mbuf[0x%p],skb[0x%p]%s%s%s%s\n", cnt, pPkthdr, pPkthdr->ph_mbuf, pPkthdr->ph_mbuf->skb, (rxPkthdrRing[idx][cnt]&DESC_OWNED_BIT)==DESC_RISC_OWNED?" :CPU":" :SWCORE", (rxPkthdrRing[idx][cnt]&DESC_WRAP)!=0?" :WRAP":"", cnt==currRxPkthdrDescIndex[idx]?" <===currIdx":"", #ifdef DELAY_REFILL_ETH_RX_BUF cnt ==rxDescReadyForHwIndex[idx]?" <===readyForHw": #endif ""); } } return SUCCESS; } /* dump the tx ring info */ int32 rtl_dumpTxRing(void) { int idx, cnt; struct rtl_pktHdr * pPkthdr = NULL; for(idx=0;idx<RTL865X_SWNIC_TXRING_HW_PKTDESC;idx++) { printk("**********************************************\nTxRing%d: cnt %d\n", idx, txPkthdrRingCnt[idx]); /* skip the null rx ring */ if (txPkthdrRingCnt[idx]==0) continue; /* dump all the pkt header */ for(cnt=0;cnt<txPkthdrRingCnt[idx];cnt++) { #ifdef CONFIG_RTL8196C_REVISION_B if (rtl_chip_version == RTL8196C_REVISION_A) pPkthdr = (struct rtl_pktHdr *) (txPkthdrRing_backup[idx][cnt] & ~(DESC_OWNED_BIT | DESC_WRAP)); else #endif pPkthdr = (struct rtl_pktHdr *) (txPkthdrRing[idx][cnt] & ~(DESC_OWNED_BIT | DESC_WRAP)); printk(" idx[%d]: 0x%p-->mbuf[0x%p],skb[0x%p]%s%s%s%s\n", cnt, pPkthdr, pPkthdr->ph_mbuf, pPkthdr->ph_mbuf->skb, (txPkthdrRing[idx][cnt]&DESC_OWNED_BIT)==DESC_RISC_OWNED?" :CPU":" :SWCORE", (txPkthdrRing[idx][cnt]&DESC_WRAP)!=0?" :WRAP":"", cnt==currTxPkthdrDescIndex[idx]?" <===currIdx":"", cnt==txPktDoneDescIndex[idx]?" <===txDoneIdx":""); } } return SUCCESS; } /* dump the tx ring info */ int32 rtl_dumpMbufRing(void) { int idx; struct rtl_mBuf *mbuf; idx = 0; printk("**********************************************\nMbufRing:\n"); while(1) { mbuf = (struct rtl_mBuf *)(rxMbufRing[idx] & ~(DESC_OWNED_BIT | DESC_WRAP)); printk("mbuf[%d]: 0x%p: ==> pkthdr[0x%p] ==> skb[0x%p]%s%s%s\n", idx, mbuf, mbuf->m_pkthdr, mbuf->skb, (rxMbufRing[idx]&DESC_OWNED_BIT)==DESC_RISC_OWNED?" :CPU":" :SWCORE", (rxMbufRing[idx]&DESC_WRAP)==DESC_ENG_OWNED?" :WRAP":"", idx==currRxMbufDescIndex?" <===currIdx":""); if ((rxMbufRing[idx]&DESC_WRAP)!=0) break; idx++; } return SUCCESS; } #endif