⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eth8186.c

📁 瑞昱公司无线局域网芯片8186的无线多媒体扩展补丁
💻 C
📖 第 1 页 / 共 3 页
字号:
drop_frag:		if (frag_skb) {			dev_kfree_skb_irq(frag_skb);			cp->frag_skb = NULL;		}		if (last_frag) {			cp->net_stats.rx_dropped++;			cp->dropping_frag = 0;		}		return;	}	copy_skb->dev = cp->dev;	skb_reserve(copy_skb, RX_OFFSET);	skb_put(copy_skb, target_len);	if (frag_skb) {		memcpy(copy_skb->data, frag_skb->data, orig_len);		dev_kfree_skb_irq(frag_skb);	}	memcpy(copy_skb->data + orig_len, skb->data, len);	copy_skb->ip_summed = CHECKSUM_NONE;	if (last_frag) {		if (status & (RxError)) {			rtl8186_rx_err_acct(cp, rx_tail, status, len);			dev_kfree_skb_irq(copy_skb);		} else			rtl8186_rx_skb(cp, copy_skb, &cp->rx_ring[rx_tail]);		cp->frag_skb = NULL;	} else {		cp->frag_skb = copy_skb;	}}static inline unsigned int rtl8186_rx_csum_ok(u32 status){	unsigned int protocol = (status >> 16) & 0x3;	if (likely((protocol == RxProtoTCP) && (!(status & TCPFail))))		return 1;	else if ((protocol == RxProtoUDP) && (!(status & UDPFail)))		return 1;	else if ((protocol == RxProtoIP) && (!(status & IPFail)))		return 1;	return 0;}static inline void rtl8186_rx(unsigned long task_priv){	struct re_private *cp = (struct re_private *)task_priv;	unsigned rx_tail = cp->rx_tail;	unsigned rx_work = 100;	u32 status, len;	dma_addr_t mapping;	struct sk_buff *skb, *new_skb;	DMA_DESC *desc;	unsigned buflen;	while (rx_work--) {		skb = cp->rx_skb[rx_tail].skb;		if (!skb)			BUG();		desc = &cp->rx_ring[rx_tail];		status = desc->opts1;		if (status & DescOwn)			break;		// ethernet CRC-4 bytes- are padding after the payload		len = (status & 0x0fff) - 4;		mapping = cp->rx_skb[rx_tail].mapping;		if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag)) {			rtl8186_rx_frag(cp, rx_tail, skb, status, len);			goto rx_next;		}		if (status & (RxError)) {			rtl8186_rx_err_acct(cp, rx_tail, status, len);			goto rx_next;		}		if (netif_msg_rx_status(cp))			printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n",			       cp->dev->name, rx_tail, status, len);		buflen = cp->rx_buf_sz + RX_OFFSET;		new_skb = dev_alloc_skb (buflen);		if (!new_skb) {			cp->net_stats.rx_dropped++;			goto rx_next;		}		if ((u32)new_skb->data &0x3)			printk(KERN_DEBUG "new_skb->data unaligment %8x\n",(u32)new_skb->data);		/*skb_reserve(new_skb, RX_OFFSET);*/		new_skb->dev = cp->dev;		/* Handle checksum offloading for incoming packets. */		if (rtl8186_rx_csum_ok(status))			skb->ip_summed = CHECKSUM_UNNECESSARY;		else			skb->ip_summed = CHECKSUM_NONE;		skb_reserve(skb, RX_OFFSET);		skb_put(skb, len);		mapping =		cp->rx_skb[rx_tail].mapping =				(u32)new_skb->tail | UNCACHE_MASK;		rtl8186_rx_skb(cp, skb, desc);		cp->rx_skb[rx_tail].skb = new_skb;		cp->rx_ring[rx_tail].addr = virt_to_bus((void *)mapping);rx_next:		if (rx_tail == (RTL8186_RX_RING_SIZE - 1))			desc->opts1 = (DescOwn | RingEnd |						  cp->rx_buf_sz);		else			desc->opts1 = (DescOwn | cp->rx_buf_sz);		cp->rx_ring[rx_tail].opts2 = 0;		rx_tail = NEXT_RX(rx_tail);	}	r3k_flush_dcache_range(0,0);	if (!rx_work)		printk(KERN_WARNING "%s: rx work limit reached\n", cp->dev->name);	cp->rx_tail = rx_tail;#ifdef DELAY_RX	if (RTL_R16(IMR) == 0) {		RTL_W16(IMR, rtl8186_intr_mask); // re-accept all interrupt		RTL_R16(IMR);	}#endif}static inline void rtl8186_interrupt(int irq, void *dev_instance, struct pt_regs *regs){	struct net_device *dev = dev_instance;	struct re_private *cp = dev->priv;	u16 status;	spin_lock(&cp->lock);	status = RTL_R16(ISR);	RTL_W16(ISR,status);	//printk("%s: intr, status %04x cmd %02x \n",dev->name,status,RTL_R8(CMD));	if (!status || (status == 0xFFFF))		return;	//if (status & LINK_CHG)	//	printk("%s: Link change\n",dev->name);	if (netif_msg_intr(cp))		printk(KERN_DEBUG "%s: intr, status %04x cmd %02x \n",		        dev->name, status, RTL_R8(CMD));	if (status & (RX_OK | RX_ERR | RX_EMPTY | RX_FIFOOVR))	{#if 0		if(!(status & RX_OK))			printk("%s rx error =%x\n",dev->name,status);		if(status & RX_EMPTY)			printk("eRDU ");		if(status & RX_FIFOOVR)			printk("eFIFO ");#endif#ifndef DELAY_RX		rtl8186_rx((unsigned long)cp);#else		if (eth_flag & 1)			rtl8186_rx((unsigned long)cp);		else {			RTL_W16(IMR, 0); // disable ISR			tasklet_hi_schedule(&cp->rx_tasklet);		}#endif	}	if (status & (TX_OK | TX_ERR | TX_EMPTY | SW_INT))	{		if (!(status & TX_OK) && !(status & TX_EMPTY))			printk("%s tx error =%x\n", dev->name, status);		rtl8186_tx(cp);	}	spin_unlock(&cp->lock);}static inline void rtl8186_tx(struct re_private *cp){	unsigned tx_head = cp->tx_hqhead;	unsigned tx_tail = cp->tx_hqtail;	while (tx_tail != tx_head) {		struct sk_buff *skb;		u32 status;		status = (cp->tx_hqring[tx_tail].opts1);		if (status & DescOwn)			break;		skb = cp->tx_skb[tx_tail].skb;		cp->tx_hqring[tx_tail].addr = 0x0;		cp->tx_hqring[tx_tail].opts1 = 0x0;		if (!skb)			BUG();		cp->net_stats.tx_packets++;		cp->net_stats.tx_bytes += skb->len;		if (netif_msg_tx_done(cp))			printk(KERN_DEBUG "%s: tx done, slot %d\n", cp->dev->name, tx_tail);		dev_kfree_skb_irq(skb);		cp->tx_skb[tx_tail].skb = NULL;		tx_tail = NEXT_TX(tx_tail);	}	cp->tx_hqtail = tx_tail;	if (netif_queue_stopped(cp->dev) && (TX_HQBUFFS_AVAIL(cp) > (MAX_SKB_FRAGS + 1)))		netif_wake_queue(cp->dev);}static int rtl8186_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct re_private *cp = dev->priv;	unsigned entry;	u32 eor;#if CP_VLAN_TAG_USED	u32 vlan_tag = 0;#endif#ifdef VLAN_QOS	struct qos_node *pbuf;#endif#ifdef DRIVER_SPEEDUP	struct Qdisc *q=dev->qdisc;	int	     deq_loop=0;	unsigned int flags;dequeue_label:	if (deq_loop)	{		save_flags(flags);cli();		// fetch a new skb for tx		if ((skb = q->dequeue(q)) == NULL)		{			// polling TX			RTL_W32(IO_CMD, CMD_CONFIG | TX_POLL);			restore_flags(flags);			return 0;		}		restore_flags(flags);		//printk("next tx skb\n");	}#endif	spin_lock_irq(&cp->lock);	/* This is a hard error, log it. */	if (TX_HQBUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) {		netif_stop_queue(dev);		spin_unlock_irq(&cp->lock);//		printk(KERN_ERR PFX "%s: Tx Ring full when queue awake!\n",//		       dev->name);#ifdef DRIVER_SPEEDUP	 	if (deq_loop)		{			q->ops->requeue(skb, q);			netif_schedule(dev);		}		RTL_W32(IO_CMD, CMD_CONFIG | TX_POLL);#endif		return 0;	}#if CP_VLAN_TAG_USED	if (cp->vlgrp && vlan_tx_tag_present(skb))		vlan_tag = TxVlanTag | vlan_tx_tag_get(skb);#endif#if 0   //sc_yang	if ( (skb->len>1514) )		for(;;)		{			printk("error tx len = %d \n",skb->len);		}#endif	entry = cp->tx_hqhead;	eor = (entry == (RTL8186_TX_RING_SIZE - 1)) ? RingEnd : 0;	// if skb contains a full/single packet	if (skb_shinfo(skb)->nr_frags == 0) {		DMA_DESC  *txd = &cp->tx_hqring[entry];		u32 	  mapping, len;		len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;		eor = (entry == (RTL8186_TX_RING_SIZE - 1)) ? RingEnd : 0;		CP_VLAN_TX_TAG(txd, vlan_tag);		mapping = (u32)skb->data|UNCACHE_MASK;		txd->addr = virt_to_bus((void *)mapping);		cp->tx_skb[entry].skb = skb;		cp->tx_skb[entry].mapping = mapping;		cp->tx_skb[entry].frag = 0;		txd->opts1 = (eor | len | DescOwn | FirstFrag |			LastFrag | TxCRC);#ifdef VLAN_QOS		pbuf = qosnode_lookup(cp, skb->data);		if ((pbuf == 0) || (pbuf->vlan_tagged == 0))			txd->opts2 = 0;		else			txd->opts2 = TxVlanTag | ((skb->cb[0] & 0x07) << 5) |				pbuf->vlan_id_h | (pbuf->vlan_id_l << 8);#endif		entry = NEXT_TX(entry);	} else {	// fragmented packet		DMA_DESC *txd;		u32 first_len, first_mapping;		int frag, first_entry = entry;		/* We must give this initial chunk to the device last.		 * Otherwise we could race with the device.		 */		first_len = skb->len - skb->data_len;		first_mapping = (u32)skb->data|UNCACHE_MASK;		cp->tx_skb[entry].skb = skb;		cp->tx_skb[entry].mapping = first_mapping;		cp->tx_skb[entry].frag = 1;		entry = NEXT_TX(entry);		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {			skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];			u32 len, mapping;			u32 ctrl;			len = this_frag->size;			mapping = (u32)this_frag->page_offset|UNCACHE_MASK;			eor = (entry == (RTL8186_TX_RING_SIZE - 1)) ? RingEnd : 0;			ctrl = eor | len | DescOwn | TxCRC;			if (frag == skb_shinfo(skb)->nr_frags - 1)				ctrl |= LastFrag;			txd = &cp->tx_hqring[entry];			CP_VLAN_TX_TAG(txd, vlan_tag);			txd->addr = virt_to_bus((void *)mapping);			txd->opts1 = (ctrl);			cp->tx_skb[entry].skb = skb;			cp->tx_skb[entry].mapping = mapping;			cp->tx_skb[entry].frag = frag + 2;			entry = NEXT_TX(entry);		}		txd = &cp->tx_hqring[first_entry];		CP_VLAN_TX_TAG(txd, vlan_tag);		txd->addr = virt_to_bus((void *)first_mapping);		eor = (first_entry == (RTL8186_TX_RING_SIZE - 1)) ? RingEnd : 0;		txd->opts1 = (first_len | FirstFrag | DescOwn|TxCRC|eor);	}	cp->tx_hqhead = entry;	if (netif_msg_tx_queued(cp))		printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n",		       dev->name, entry, skb->len);	if (TX_HQBUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))		netif_stop_queue(dev);	spin_unlock_irq(&cp->lock);#ifndef DRIVER_SPEEDUP	RTL_W32(IO_CMD, CMD_CONFIG | TX_POLL);#else	deq_loop++;	goto dequeue_label;#endif	dev->trans_start = jiffies;	return 0;}/* Set or clear the multicast filter for this adaptor.   This routine is not state sensitive and need not be SMP locked. */static void __rtl8186_set_rx_mode(struct net_device *dev){	//struct re_private *cp = dev->priv;	u8 mc_filter[8];	/* Multicast hash filter */	int i, rx_mode;	//u32 tmp;//	printk("%s: %s %d Still Unimplemented !!!!!!!\n",__FILE__,__FUNCTION__,__LINE__);	return;	/* Note: do not reorder, GCC is clever about common statements. */	if (dev->flags & IFF_PROMISC) {		/* Unconditionally log net taps. */		printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys;		for (i=0;i<8;i++)			mc_filter[i] = 0xff;	}	else if ((dev->mc_count > multicast_filter_limit)		|| (dev->flags & IFF_ALLMULTI)) {		/* Too many to filter perfectly -- accept all multicasts. */		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;		for (i=0;i<8;i++)			mc_filter[i] = 0xff;	}	else {		struct dev_mc_list *mclist;		rx_mode = AcceptBroadcast | AcceptMyPhys;		for (i=0;i<8;i++)			mc_filter[i] = 0;		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;			i++, mclist = mclist->next) {#if 0			int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;#endif#if 0 // arthur			int bit_nr = 0;			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);			rx_mode |= AcceptMulticast;#endif		}	}}static void rtl8186_set_rx_mode(struct net_device *dev){	unsigned long flags;	struct re_private *cp = dev->priv;	spin_lock_irqsave (&cp->lock, flags);	__rtl8186_set_rx_mode(dev);	spin_unlock_irqrestore (&cp->lock, flags);}static void __rtl8186_get_stats(struct re_private *cp){	/* XXX implement */}static struct net_device_stats *rtl8186_get_stats(struct net_device *dev){	struct re_private *cp = dev->priv;	/* The chip only need report frame silently dropped. */	spin_lock_irq(&cp->lock); 	if (netif_running(dev) && netif_device_present(dev)) 		__rtl8186_get_stats(cp);	spin_unlock_irq(&cp->lock);	return &cp->net_stats;}/* * Disable TX/RX through IO_CMD register */static void rtl8186_stop_hw(struct net_device *dev, struct re_private *cp){	RTL_W16(IMR, 0);	RTL_W16(ISR, 0xffff);	RTL_W32(IO_CMD, 0); /* timer  rx int 1 packets */	synchronize_irq();	udelay(10);	cp->rx_tail = 0;	cp->tx_hqhead = cp->tx_hqtail = 0;}static void rtl8186_reset_hw(struct re_private *cp){	unsigned work = 1000;   	RTL_W8(CMD, 0x1);	 /* Reset */	while (work--) {		if (!(RTL_R8(CMD) & 0x1))			return;		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout(10);	}	printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name);}static inline void rtl8186_start_hw(struct re_private *cp){	// set TX/RX setting/enable TX/RX	RTL_W32(IO_CMD, CMD_CONFIG);}static void rtl8186_init_hw(struct re_private *cp){	struct net_device *dev = cp->dev;	u8 status;	rtl8186_reset_hw(cp);#ifdef RTL8186_CHECKSUM_OFFLOAD	RTL_W8(CMD, 0x2);#endif#ifdef VLAN_QOS	RTL_W8(CMD, RTL_R8(CMD)|0x4);#endif	RTL_W16(ISR, 0xffff);	RTL_W16(IMR, rtl8186_intr_mask);	RTL_W32(RxFDP, virt_to_bus((void *)(cp->rx_ring)));#if DEBUG	writecheck = RTL_R32(RxFDP);	if (writecheck != ((u32)cp->rx_ring))		for (;;);#endif	RTL_W16(RxCDO, 0);	RTL_W32(TxFDP1, virt_to_bus((void *)(cp->tx_hqring)));#if DEBUG	writecheck = RTL_R32(TxFDP1);	if (writecheck != ((u32)cp->tx_hqring))		for (;;);#endif	RTL_W16(TxCDO1, 0);	RTL_W32(TxFDP2, (u32)cp->tx_lqring);	RTL_W16(TxCDO2, 0);	RTL_W32(RCR, AcceptAll);	RTL_W32(TCR, (u32)(0xC00));	RTL_W8(RxRingSize, RINGSIZE);	status = RTL_R8(MSR);	status = status & ~(TXFCE | RXFCE);	RTL_W8(MSR, status);	mdelay(200);	RTL_W32(MIIAR, BIT(26)|0x30000);				// read PHY type	mdelay(200);	if ((RTL_R32(MIIAR)&0x0000ffff) == 0x8201) {	// if PHY == 8201		printk("%s:phy is 8201\n", dev->name);		RTL_W32(MIIAR, BIT(31)|BIT(26)|0x3300);		// Reset/re-auto-nego	}	else {											// should be 8305		printk("%s:phy is 8305\n", dev->name);		if(dev->base_addr == 0xbd200000)			RTL_W32(MIIAR, BIT(31)|BIT(30)|0x3300);	// LAN MII is open		else			RTL_W32(MIIAR, BIT(31)|BIT(28)|0x1300);	// WAN is port 4 (5th port)	}	mdelay(200);	RTL_W8(IDR0, dev->dev_addr[0]);	RTL_W8(IDR1, dev->dev_addr[1]);	RTL_W8(IDR2, dev->dev_addr[2]);	RTL_W8(IDR3, dev->dev_addr[3]);	RTL_W8(IDR4, dev->dev_addr[4]);	RTL_W8(IDR5, dev->dev_addr[5]);	rtl8186_start_hw(cp);	__rtl8186_set_rx_mode(dev);}static int rtl8186_refill_rx(struct re_private *cp){	unsigned i;	for (i = 0; i < RTL8186_RX_RING_SIZE; i++) {		struct sk_buff *skb;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -